Syscall实现exit()

时间:2017-10-24 05:59:22

标签: c gcc assembly x86 system-calls

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

1 个答案:

答案 0 :(得分:9)

Linux和glibc手册页记录了所有这些(特别参见" C库/内核差异"在NOTES部分中)。

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

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

只有exit(),而非_exit()exit_group()才会刷新stdout,导致" printf无法打印任何内容&#34 ;新手asm程序中的问题,如果写入管道(使stdout全缓冲而不是行缓冲),或者您忘记了格式字符串中的\n。例如,How come _exit(0) (exiting by syscall) prevents me from receiving any stdout content?。如果您使用任何缓冲的I / O函数,或at_exit或类似的东西,通常最好直接调用libc exit(3)函数而不是系统调用。但是,您当然可以在fflush之前致电sys_exit_group

它当然不是选择任何东西的编译器,它是libc。当您包含标头并写入read(fd, buf, 123)exit(1)时,C编译器只会看到普通的函数调用。

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