[英]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.