[英]What is the type of system call arguments on Linux?
我想寫一個執行系統調用的泛型函數。 就像是
long my_syscall2(long number, long arg1, long arg2);
我希望它盡可能便攜。 對於所有體系結構,實現明顯不同。 功能的簽名是否也需要不同? 我可以long
使用long
還是應該使用別的東西?
以下是我找到的可能的解決方案:
所以我想問題是“是否有一些規則說'系統調用參數的類型總是long
有一些像x32這樣的例外',或者我是否需要查找每個架構和編譯器的文檔?”
編輯:我知道一些系統調用將指針和其他類型作為參數。 我想編寫可以調用任何系統調用的泛型函數,使用泛型參數類型。 這些通用參數類型應足夠大,以容納任何實際參數類型。 我知道這是可能的,因為syscall()函數存在。
Edit2:這是此問題的另一個部分解決方案。
這些功能的實現目前如下所示:
static __inline long my_syscall2(long number, long arg1, long arg2)
{
unsigned long ret;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(number), "D"(arg1), "S"(arg2)
: "rcx", "r11", "memory");
return ret;
}
有趣的部分是"=a"(ret)
,這意味着存儲在寄存器a
中的系統調用返回值應保存到變量ret
。 使用syscall而不是編寫創建局部變量的函數,而是將其返回值保存到變量中並返回變量,我可以編寫一個宏來進行系統調用並將結果存儲到調用者提供的變量中。 它看起來像這樣:
#define my_syscall2(RET, NUMBER, ARG1, ARG2) \
__asm__ __volatile__ ("syscall" : "=a"(RET) : "a"(NUMBER), "D"(ARG1), "S"(ARG2) \
: "rcx", "r11", "memory");
它會像這樣使用:
long result;
void * arg1;
int arg2;
my_syscall2(result, <syscall number>, arg1, arg2);
這樣我就不需要知道足夠大的寄存器大小和整數類型來保存寄存器的值。
系統調用參數在寄存器中傳遞。 因此,大小限於CPU寄存器的大小。 也就是說,32位架構上的32位,64位架構上的64位。 浮點數不能以這種方式傳遞給內核。 傳統上,內核不使用浮點指令(並且可能無法在進入內核時保存FPU狀態),因此請盡量避免在自己的系統調用中使用浮點數。
使用較小類型零或符號的參數的系統調用會擴展它們。 使用較大參數類型的系統調用可能會將參數拆分為多個寄存器。
具有許多參數的系統調用(如mmap()
)可以通過將參數作為指針傳遞給結構來實現,但這具有可測量的性能開銷,因此避免設計具有五個以上參數的系統調用。
在一天結束時,使用適合您要發送的值的類型。 讓libc處理將數據放在正確的位置。
我建議您使用現有的系統調用系統調用,而不是嘗試自己編寫一個。 它似乎完全符合你的要求。 查看手冊頁的“體系結構特定要求”部分,以討論您提出的有效問題。
沒有通用的解決方案。 如果你想讓你的代碼超多任務,你可以做這樣的事情:
#if ARCH_WITH_32BIT_REGS
typedef uint32_t reg_size_int_t;
#elif ARCH_WITH_64BIT_REGS
typedef uint64_t reg_size_int_t;
#elif ARCH_WITH_16BIT_REGS
typedef uint16_t reg_size_int_t;
....
#endif
reg_size_int_t syscall_1( reg_size_t nr, reg_size_t arg0);
...
但對於大多數常用的體系結構,寄存器的大小等於long。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.