系统调用:sys之间的区别
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
本身中解决,
粗略地说,在例程sys_xxx()
的Linux内核源代码中可以找到/usr/include/asm/unistd.h
定义的属于系统调用编号__NR_xxx
的代码。 (i386的调度表可以在/usr/src/linux/arch/i386/kernel/entry.S
找到)。然而,有很多例外,主要是因为较旧的系统调用被较新的系统调用所取代,并且这已经有点不系统地处理。 在具有专有操作系统仿真的平台上,如parisc,sparc,sparc64和alpha,还有许多额外的系统调用; mips64还包含一整套32位系统调用。
至少现在/usr/include/asm/unistd.h
是一个预处理器hack,它链接到,
/usr/include/asm/unistd_32.h
/usr/include/asm/unistd_x32.h
/usr/include/asm/unistd_64.h
C函数exit()
在stdlib.h
定义。 把它看作一个高级别的事件驱动接口,允许你用atexit()
注册一个回调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__));
所以基本上内核提供了一个称为__NR_xxx
的接口(C符号)。 传统上,人们希望使用预处理器宏SYS_exit
定义的sys_exit()
。 这个宏创建sys_exit()
函数。 exit()
函数是标准C库stdlib.h
一部分,并且可以移植到其他缺乏Linux Kernel ABI的操作系统(可能不会有__NR_xxx
函数),甚至可能甚至没有sys_*
函数可用可以写入exit()
发送中断或在Assembly中使用VDSO)。