SYS_exit,sys_exit()和exit()有什么区别?
我的理解:
man 2 syscalls
。glibc
提供的那些系统调用的包装函数与系统调用的名称大致相同。我的问题:在man 2 syscalls
中,没有提到SYS_exit和sys_exit(),例如。它们是什么?
注意:这里的系统调用exit
只是一个例子。我的问题是:什么是SYS_xxx和sys_xxx()?
答案 0 :(得分:3)
我将在您的示例中使用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)接口来实现从用户模式到内核模式的切换。当模式切换(somtimes称为陷阱)发生时,使用一个小整数在内核表中查找适当的内核例程,该内核将整数映射到内核函数。表格中的条目具有
形式{SYS_exit, sys_exit},
其中SYS_exit是
的预处理器宏#define SYS_exit (1)
并且在你出生之前已经1岁,因为没有理由改变它。它也恰好是系统调用表中的第一个条目,它使查找一个简单的数组索引。
正如您在问题中所述,常规用户模式程序访问sys_exit的正确方法是通过glibc(或类似的核心库)中的瘦包装器。你需要弄乱SYS_exit或sys_exit的唯一原因是你在编写内核代码。
答案 1 :(得分:0)
现在man syscall
本身解决了这个问题,
粗略地说,属于
__NR_xxx
中定义的数字/usr/include/asm/unistd.h
的系统调用的代码可以在例程sys_xxx()
中的Linux内核源代码中找到。 (可以在/usr/src/linux/arch/i386/kernel/entry.S
中找到i386的调度表。)但是,有许多例外,主要是因为较旧的系统调用被新的系统调用取代,并且这在某种程度上是不系统的。在具有专有操作系统仿真的平台上,例如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__));
基本上,内核提供了一个名为__NR_xxx
的接口(C符号)。传统上,人们希望使用预处理器宏sys_exit()
定义SYS_exit
。该宏创建sys_exit()
函数。 exit()
函数是标准C库stdlib.h
的一部分,并移植到完全缺少Linux内核ABI的其他操作系统(可能没有__NR_xxx
函数)并且可能没有sys_*
函数。甚至可以使用exit()
函数(您可以编写var serializerSettings = new JsonSerializerSettings { ContractResolver = MyContractResolver.Instance };
var serializer = JsonSerializer.CreateDefault(serializerSettings);
var serializedString = JObject.FromObject(myObject, serializer).ToString();
来发送中断或在汇编中使用VDSO)。