Syscall实现exit()

Tre*_*rey 6 c x86 assembly gcc system-calls

我写了一个简单的C程序,只调用exit()函数,但是strace说二进制文件实际上是调用exit_group,exit()是一个exit_group()包装器吗?这两个功能是否相同?如果是这样,为什么编译器会选择exit_group()而不是exit()?

Pet*_*des 9

Linux和glibc手册页记录了所有这些(请参阅NOTES部分中的"C库/内核差异").

  • _exit(2):在glibc 2.3及更高版本中,这个包装函数实际上调用Linux sys_exit_group系统调用来退出所有线程.在glibc2.3之前,它sys_exit只是退出当前线程的包装器.
  • sys_exit:终止当前线程,让其他线程运行.AFAIK,现代glibc没有这个Linux系统调用的包装函数,因为它通常没用.
  • exit_group(2):glibc包装器sys_exit_group,用于退出所有线程.
  • exit(3):ISO C89函数,它刷新缓冲区然后退出整个过程.(它总是使用,exit_group()因为检查进程是否是单线程并决定使用sys_exitvs. 没有任何好处sys_exit_group). 正如@Matteo所指出的,最近的ISO C或POSIX标准是线程感知的,其中一个或两个可能需要这种行为.

    但显然exit(3)本身不是线程安全的(在C库清理部分),所以我猜不要一次从多个线程调用它.

如果写入管道(使用全缓冲而不是行缓冲),或者如果您忘记了格式字符串,则只会exit(),不会_exit()exit_group()刷新stdout,导致printf新手asm程序中的" 不打印任何内容"问题.例如,如何_exit(0)(由syscall退出)阻止我接收任何标准内容?.如果您使用任何缓冲的I/O函数,或者类似的东西,通常最好直接调用libc 函数而不是系统调用.当然,你可以调用之前.stdout\nat_exitexit(3)fflushsys_exit_group


它当然不是选择任何东西的编译器,它是libc.如果包括头和写read(fd, buf, 123)或者exit(1),C编译器只是看到了一个普通的函数调用.

一些C库(例如musl,但不是glibc)可以使用内联asm将syscall指令内联到二进制文件中,但仍然是头库是C库的一部分,而不是编译器.

  • @ DavidC.Rankin:我现在不必查这个;几年前,我对此感到很好奇。:PI仅通过阅读Linux手册页并查看各种程序使用`strace`所做的工作,便学习了很多系统编程知识。 (2认同)