Linux中的標準編程語言是C.因此,系統調用的最佳描述將顯示它們爲要調用的C函數。將它們的描述作爲C函數,並且知道如何將它們映射到實際的彙編系統調用中,您將能夠輕鬆使用任何系統調用。
首先,您需要所有系統調用的參考,因爲它們看起來像一個C程序員。我所知道的最好的是Linux man-pages project,特別是system calls部分。
讓我們以write
系統調用爲例,因爲它是你問題中的一個。正如你所看到的,第一個參數是一個有符號整數,它通常是由系統調用返回的文件描述符。這些文件描述符也可能已經從父進程繼承,通常發生在前三個文件描述符(0 = stdin,1 = stdout,2 = stderr)。第二個參數是指向緩衝區的指針,第三個參數是緩衝區的大小(作爲無符號整數)。最後,函數返回一個有符號的整數,它是寫入的字節數,或者是一個錯誤的負數。
現在,如何將其映射到實際的系統調用?有許多方法可以在32位x86上執行系統調用(這可能是您使用的,基於您的註冊名稱);請注意,它在64位x86上完全不同(請確保您正在以32位模式進行組裝,並鏈接一個32位可執行文件;請參閱this question,以獲取有關如何防止事情發生錯誤的示例)。 32位x86中最老,最簡單和最慢的方法是int $0x80
方法。
對於int $0x80
方法,你把系統調用號在%eax
,並在參數%ebx
,%ecx
,%edx
,%esi
,%edi
和%ebp
,按照這個順序。然後您撥打int $0x80
,系統調用返回值爲%eax
。注意這個返回值是不同於這個參考文獻說的;該參考顯示C庫將如何返回它,但系統調用返回-errno
錯誤(例如-EINVAL
)。在這種情況下,C庫將把它移動到errno
並返回-1
。有關更多詳細信息,請參見syscalls(2)和intro(2)。
所以,在write
例如,可以把在%eax
的write
系統調用號,在%ebx
第一個參數(文件描述符),在%ecx
第二個參數(字符串指針),第三個參數(字符串的長度)在%edx
。系統調用將返回%eax
或者寫入的字節數,或者返回錯誤編號(如果返回值在-1和-4095之間,則爲錯誤編號)。
最後,你如何找到系統呼叫號碼?他們可以在/usr/include/linux/unistd.h
找到。在我的系統上,這隻包括/usr/include/asm/unistd.h
,最後包括/usr/include/asm/unistd_32.h
,所以數字在那裏(對於write
,你可以看到__NR_write
是4
)。錯誤號碼來自/usr/include/linux/errno.h
(在我的系統中,在追逐包含鏈後,我在/usr/include/asm-generic/errno-base.h
找到第一個,其餘的爲/usr/include/asm-generic/errno.h
)。對於使用其他常量或結構的系統調用,它們的文檔會告訴您應該查看哪些頭以找到相應的定義。
現在,正如我所說,int $0x80
是最古老和最慢的方法。較新的處理器具有更快的特殊系統調用指令。爲了使用它們,內核提供了一個虛擬的動態共享對象(vDSO
;它就像一個共享庫,但只在內存中),並且可以調用一個函數來使用可用於硬件的最佳方法進行系統調用。它還提供特殊功能來獲取當前時間,而無需執行系統調用等幾件事情。當然,如果你不使用動態鏈接器,使用起來會有點困難。
還有另一種較舊的方法,vsyscall
,它類似於vDSO
,但在固定地址使用單個頁面。如果您使用的是最新的內核,可能會在最近的內核上引導時禁用此方法,並且可能會在將來刪除此方法,但會導致系統日誌中出現警告。不要使用它。
當然,即使你在谷歌或任何源代碼搜索工具中搜索它的每一個實現,你可以找到直接的例子如何使用它們 - 我做了什麼。我的文章的要點是跳過搜索和分析一些不錯的小抄。謝謝。 –