I wrote a simple C program which just calls the exit() function, however strace says that the binary is actually calling exit_group, is exit() a exit_group() wrapper? Are these two functions equivalent? If so why would the compiler choose exit_group() over exit()?
1 Answers
The Linux and glibc man pages document all of this (See especially the "C library/kernel differences" in the NOTES section).
_exit(2)
: In glibc 2.3 and later, this wrapper function actually uses the LinuxSYS_exit_group
system call to exit all threads. Before glibc2.3, it was a wrapper forSYS_exit
to exit just the current thread.exit_group(2)
: glibc wrapper forSYS_exit_group
, which exits all threads.exit(3)
: The ISO C89 function which flushes buffers and then exits the whole process. (It always usesexit_group()
because there's no benefit to checking if the process was single-threaded and deciding to useSYS_exit
vs.SYS_exit_group
). As @Matteo points out, recent ISO C / POSIX standards are thread-aware and one or both probably require this behaviour.But apparently
exit(3)
itself is not thread-safe (in the C library cleanup parts), so I guess don't call it from multiple threads at once.syscall
/int 0x80
withSYS_exit
: terminates just the current thread, leaving others running. AFAIK, modern glibc has no thin wrapper function for this Linux system call, but I thinkpthread_exit()
uses it if this isn't the last thread. (Otherwise exit(3) -> exit_group(2).)
Only exit()
, not _exit()
or exit_group()
, flushes stdout
, leading to "printf
doesn't print anything" problems in newbie asm programs if writing to a pipe (which makes stdout
full-buffered instead of line-buffered), or if you forgot the \n
in the format string. For example, How come _exit(0) (exiting by syscall) prevents me from receiving any stdout content?. If you use any buffered I/O functions, or at_exit
, or anything like that, it's usually a good idea to call the libc exit(3)
function instead of the system call directly. But of course you can call fflush
before SYS_exit_group
.
(Also related: On x64 Linux, what is the difference between syscall, int 0x80 and ret to exit a program? - ret
from main is equivalent to calling exit(3)
)
It's not of course the compiler that chose anything, it's libc. When you include headers and write read(fd, buf, 123)
or exit(1)
, the C compiler just sees an ordinary function call.
Some C libraries (e.g. musl, but not glibc) may use inline asm to inline a syscall
instruction into your binary, but still the headers are part of the C library, not the compiler.
1
ineax
and called the kernel interrupt andstrace
shows anexit_group
call (252
0xfc
)? Which compiler? What were your compile and link strings? (it may also be astrace
issue, though you would think they would have the lookup table right) – David C. Rankinexit()
function in thelibc
library. – Martin Rosenauexit()
should terminate all the running threads; on Linux the plainexit
syscall would just terminate the current thread, so at some point theexit()
libc function was remapped to theexit_group
syscall, which does what is required by the standard. – Matteo Italiaassembly
tag threw me off. (since assembly does have both andexit
andexit_group
syscall. – David C. Rankingcc
to dump to assembler (e.g.gcc -S -masm=intel -o exitcall.asm exitcall.c
and the assembler instruction iscall exit@PLT
, Runningtrace
through, you are correct, I findexit_group(0)
. I then wrote the file in assemblynasm
and ranstrace
on the executable and it callsexit(0) = ?; +++ exited with 0 +++
Strange, I don't have the answer, but I now fully understand the question. Are you usinggcc
as the compiler? – David C. Rankin