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巨集...