[英]where did the _syscallN macros go in <linux/unistd.h>?
過去的情況是,如果你需要在不使用現有庫的情況下直接在linux中進行系統調用,你可以只包含<linux/unistd.h>
,它將定義一個類似於此的宏:
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3))); \
if (__res>=0) \
return (type) __res; \
errno=-__res; \
return -1; \
}
然后你可以把代碼放在你的代碼中:
_syscall3(ssize_t, write, int, fd, const void *, buf, size_t, count);
這將為您正確執行系統調用定義一個write
函數。
似乎這個系統已經被某些東西所取代(我猜測每個進程得到的“[vsyscall]”頁面更強大)。
那么一個程序直接在較新的Linux內核上執行系統調用的正確方法(具體而言)是什么? 我意識到我應該使用libc並讓它為我工作。 但是我們假設我有一個很好的理由想要知道如何做到這一點:-)。
好的,所以我進一步研究了一下,因為我沒有得到很多回復,並找到了一些很好的信息。 首先是在linux上啟動應用程序,除了傳統的argc,argv,envp參數。 還有另一個數組傳遞了一些名為auxv的數據。 詳情請見此處 。
其中一個鍵/值對具有與AT_SYSINFO
等效的鍵。 在/usr/include/asm/auxvec.h
或/usr/include/elf
。
與此鍵關聯的值是系統調用函數的入口點(在映射到每個進程的“vdso”或“vsyscall”頁面中)。
您可以通過調用此地址來替換傳統的int 0x80
或syscall
指令,它實際上會進行系統調用。 不幸的是,這很難看。 所以libc人員提出了一個很好的解決方案。 當他們分配TCB
並將其分配給gs
段時。 他們將AT_SYSINFO
的值放在TCB
中的某個固定偏移量中(遺憾的是,它不是跨版本固定的,所以你不能總是依賴於偏移是一個相同的常量)。 因此,您可以只call *%gs:0x10
而不是傳統的int 0x80
,這將調用vdso
部分中的系統調用例程。
我想這里的目標是讓libc更容易編寫。 這允許libc人員編寫一個代碼塊來處理系統調用,而不必再擔心它。 內核人員可以在任何時間點改變系統調用的方式,他們只需要更改vdso
頁面的內容以使用新機制,這樣做很好。 實際上,您甚至不需要重新編譯您的libc! 然而,這確實讓我們的人們在編寫內聯匯編並嘗試使用引擎蓋下的東西時會感到痛苦。
幸運的是,如果你真的想手動做事,舊的方式仍然有效:-)。
編輯:我注意到的一件事我的經驗是AT_SYSINFO
似乎沒有給我的x86_64盒子上的程序( AT_SYSINFO_EHDR
是,但我不知道如何使用它)。 所以我不能100%確定在這種情況下如何確定系統調用函數的地址。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.