t.c: #include <stdio.h> int main() { printf("Hello world\n"); } # gcc -O2 t.c -o shared # gcc -O2 t.c -static -o static # gcc -O2 t.c -Wl,--gc-sections -static -o gc-sect # ./shared | cat Hello world # ./static | cat Hello world # ./gc-sect | cat The last command outputs nothing. Adding fflush(stdout) after printf makes it work. (Pipe is needed to make stdout buffered). IOW: static link with section garbage collection desn't work correctly, which is a pity because it is such a handy optimization. This is why: Makerules: PROVIDE(__start___libc_atexit = .);\ __libc_atexit : { *(__libc_atexit) }\ PROVIDE(__stop___libc_atexit = .);\ libio/genops.c: #ifdef text_set_element text_set_element(__libc_atexit, _IO_cleanup); #endif include/libc-symbols.h: #ifdef HAVE_ELF /* Make SYMBOL, which is in the text segment, an element of SET. */ # define text_set_element(set, symbol) _elf_set_element(set, symbol) /* These are all done the same way in ELF. There is a new section created for each set. */ # ifdef SHARED /* When building a shared library, make the set section writable, because it will need to be relocated at run time anyway. */ # define _elf_set_element(set, symbol) \ static const void *__elf_set_##set##_element_##symbol##__ \ __attribute__ ((used, section (#set))) = &(symbol) # else And of course: void exit (int status) { ... RUN_HOOK (__libc_atexit, ()); _exit (status); } You have to explain to ld that it should never drop __libc_atexit sections...
You simply cannot use that option. Period. Static linking is not really supported. I'm not closing the bug outright so that somebody with interest can think of a clean and non-intrusive way to handle this. But I sure as hell won't spend a second thinking about static linking.
It is a linker bug. *** This bug has been marked as a duplicate of 11133 ***