系统调用:sys_exit(),SYS_exit和exit()之间的区别

时间:2013-09-24 03:34:06

标签: linux kernel system-calls

SYS_exit,sys_exit()和exit()有什么区别?

我的理解:

  • linux内核提供系统调用,列在man 2 syscalls
  • glibc提供的那些系统调用的包装函数与系统调用的名称大致相同。

我的问题:在man 2 syscalls中,没有提到SYS_exit和sys_exit(),例如。它们是什么?

注意:这里的系统调用exit只是一个例子。我的问题是:什么是SYS_xxx和sys_xxx()?

2 个答案:

答案 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)。