使用linux系統呼叫ABI

2021-09-02 15:06:23 字數 1406 閱讀 3143

void

prints

(char

*str)

asm(

"movl $4, %%eax \n\t"

"movl $1, %%ebx \n\t"

"movl %0, %%ecx \n\t"

"movl %1, %%edx \n\t"

"int $0x80 \n\t"::

"m"(str)

,"m"

(i))

;return;}

intmain()

這裡的關鍵在於linux系統0x80號中斷是32位系統呼叫,接收4個引數,暫存器ecx中的引數為要顯示的內容的記憶體位址,而在64位系統用gcc編譯,生成的程式預設是64位的,64位程式的記憶體位址也是64位的,我們把記憶體位址傳給ecx,ecx只有32位,所以64位的位址高32位會丟失,系統按照錯誤的位址取定址,肯定找不到內容。

那麼為何堆上的資料可以顯示,段上的不行呢,因為linux系統在給程式分配記憶體空間的時候,堆的記憶體位置就位於低記憶體,位址雖然是64位的,但是高32位全為0;而堆疊卻位於記憶體高位位址,高32位不位零,因此只能正確尋找到堆上的資料。

/usr/include/asm-generic/errno-base.h 

/usr/include/asm-generic/errno.h

通過echo $?可以看到程式返回242(0xf2),也就是-14(負數代表呼叫出錯,絕對值是錯誤碼;若正確呼叫會返回正確輸出的字元數)。實際上printf正確呼叫也會返回寫入的字元數(返回值用eax暫存器傳遞),錯誤呼叫返回負數,這點和系統呼叫的返回值類似。

檢視errno-base.h中定義:

#define    efault        14    /* bad address */
我們怎麼修改我們的程式呢?64位程式不再用int $0x80進行系統呼叫,可以考慮syscall,這個是64位系統的abi入口,系統呼叫號和0x80不同,引數傳遞的暫存器約定也不一樣。詳情可以檢視:

void

prints

(char

*str)

asm(

"syscall \n\t"::

"a"(1)

,"d"(1

),"s"(str)

,"d"

(i));}

intmain()

系統呼叫功能號:rax

引數列表按順序分別是:rdi、rsi、rdx、r10、r8、r9

檢視c函式可以用man 2 write

Linux系統呼叫 使用syscall

博主的另一篇博文介紹了如何使用int 0x80指令進行linux系統呼叫,這一篇博文介紹一下如何使用另一種方式 syscall指令進行linux系統呼叫,然後會簡要說明二者的不同。通過syscall指令進行linux系統呼叫與通過int 0x80指令進行linux系統呼叫在使用上差別不大,系統呼叫號...

linux 系統呼叫 open函式使用

函式介紹 本文僅僅將open系統呼叫的使用簡單總結一下,關於其實現原理大批的大佬分享可以自行學習。open系統呼叫主要用於開啟或者建立乙個檔案,並返回檔案描述符。以上兩個函式引數含義如下 返回值 作業系統會為當前程序從3開始分配乙個未使用的檔案描述符,因為0,1,2已經被stdin,stdout,s...

linux 系統呼叫

使用者應用可以通過兩種方式使用系統呼叫。第一種方式是通過c庫函式,包括系統呼叫在c庫中的封裝函式和其他普通函式。圖5.2 使用系統呼叫的兩種方式 第二種方式是使用 syscall巨集。2.6.18版本之前的核心,在include asm i386 unistd.h檔案中定義有7個 syscall巨集...