Basically, I compile an executable from same set of source files. First I compile .c modules into .o with -ffunction-sections -fdata-sections, and then I can do something a-la "gcc -o executable -Wl,--gc-sections *.o" or I can bundle almost all .o files into lib.a using ar and do "gcc -o executable -Wl,--gc-sections main.o lib.a" The second method gives much better results: # size */busybox text data bss dec hex filename 14186 868 24 15078 3ae6 busybox.1.t/busybox 2682 304 24 3010 bc2 busybox.2.t/busybox However, there is no reason to believe that all is good now. I tent to fear than suboptimal link-time dead code elimination is still happening, only on lesser scale (within each individual .o file pulled from lib.a, not over whole set of .o files). Extended explanation is at http://busybox.net/~vda/Kbuild_new_2006/ I will attach objdump -xsdr of both executables. comparing those, I see: * extra EH_FRAME section * sections .hash, .dynstr, .dynsym,.... are much longer Unstripped executables also available for comparison at the above URL. One thing has been tracked down to this test case: /* Compile: ** gcc -ffunction-sections -fdata-sections -c -o test.o test.c ** gcc -o test -Wl,--gc-sections test.o ** ** First call to notexist() is optimized away by linker because ** function eliminated() is, er, eliminated by section GC. ** ** But second call to notexist() is not optimized away, ** despite the fact that getpwnam_r() is not called from anywhere. ** Then linking fails because notexist() isn't exist. ** ** Renaming getpwnam_r to any other name "fixes" this! */ void notexist(void); int main(void) { return 0; } void eliminated(void) { notexist(); } void getpwnam_r(void) { notexist(); } // HERE Rest are not researched in depth.
Created attachment 1354 [details] objdump of ld *.o result
Created attachment 1355 [details] objdump of ld main.o lib.a result
getpwnam_r is kept because you are linking against a shared libc that also defines this symbol. In this case the linker keeps your getpwnam_r, because it is assumed you are defining a function to override the one in the shared lib. The linker can't know whether getpwnam_r is actually called, because there might be a call from a dlopen'd library at runtime.