SYS_exit、sys_exit() 和 exit() 有什么区别?
我的理解:
- linux 内核提供了系统调用,在
man 2 syscalls
. - 这些系统调用提供的包装函数与系统调用的
glibc
名称大多相似。
我的问题:例如man 2 syscalls
,没有提到 SYS_exit 和 sys_exit()。这些是什么?
注意:这里的系统调用exit
只是一个例子。我的问题真的是:SYS_xxx 和 sys_xxx() 是什么?
SYS_exit、sys_exit() 和 exit() 有什么区别?
我的理解:
man 2 syscalls
.glibc
名称大多相似。我的问题:例如man 2 syscalls
,没有提到 SYS_exit 和 sys_exit()。这些是什么?
注意:这里的系统调用exit
只是一个例子。我的问题真的是:SYS_xxx 和 sys_xxx() 是什么?
我将在您的示例中使用 exit() ,尽管这适用于所有系统调用。
sys_exit() 形式的函数是内核例程的实际入口点,它实现了您认为的 exit() 函数。这些符号甚至对用户模式程序员都不可用。也就是说,除非您正在破解内核,否则您无法链接到这些函数,因为它们的符号在内核之外不可用。如果我写了 libmsw.a ,它有一个文件范围函数,比如
static int msw_func() {}
在其中定义,您将无法尝试链接到它,因为它没有在 libmsw 符号表中导出;那是:
cc your_program.c libmsw.a
会产生如下错误:
ld: cannot resolve symbol msw_func
因为它没有被导出;这同样适用于内核中包含的 sys_exit()。
为了让用户程序进入内核例程,需要使用 syscall(2) 接口来实现从用户模式到内核模式的切换。当模式切换(有时称为陷阱)发生时,会使用一个小整数在将整数映射到内核函数的内核表中查找正确的内核例程。表中的条目具有以下形式
{SYS_exit, sys_exit},
其中 SYS_exit 是一个预处理器宏,它是
#define SYS_exit (1)
并且在你出生之前就一直是 1,因为没有理由改变它。它也恰好是系统调用表中的第一个条目,这使得查找一个简单的数组索引。
正如您在问题中指出的那样,常规用户模式程序访问 sys_exit 的正确方法是通过 glibc (或类似的核心库)中的瘦包装器。您需要弄乱 SYS_exit 或 sys_exit 的唯一原因是您正在编写内核代码。
现在这个问题man syscall
本身就解决了,
粗略地说,属于系统调用的代码,编号
__NR_xxx
为 ,/usr/include/asm/unistd.h
可以在 Linux 内核源代码中找到sys_xxx()
。(可以在 中找到 i386 的调度表/usr/src/linux/arch/i386/kernel/entry.S
。)但是,也有许多例外,主要是因为较旧的系统调用被较新的系统调用所取代,而且这种处理方式有些不系统。在具有专有操作系统仿真的平台上,例如 parisc、sparc、sparc64 和 alpha,还有许多额外的系统调用;mips64 还包含一整套 32 位系统调用。
至少现在/usr/include/asm/unistd.h
是一个链接到任何一个的预处理器黑客,
/usr/include/asm/unistd_32.h
/usr/include/asm/unistd_x32.h
/usr/include/asm/unistd_64.h
C 函数exit()
定义在stdlib.h
. 把它想象成一个高级事件驱动的接口,它允许你注册一个回调atexit()
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered,
perform stdio cleanup, and terminate program execution with STATUS. */
extern void exit (int __status) __THROW __attribute__ ((__noreturn__));
所以本质上内核提供了一个接口(C 符号),称为__NR_xxx
. 传统上人们想要sys_exit()
的是用预处理器宏定义的SYS_exit
。该宏创建sys_exit()
函数。该exit()
函数是标准 C 库的一部分,stdlib.h
并移植到完全缺乏 Linux Kernel ABI 的其他操作系统(可能没有__NR_xxx
函数)并且可能甚至没有sys_*
可用的函数(您可以编写exit()
发送中断或使用 VDSO在大会)。