Bug 3315 - ld --gc-sections *.o produces big(ger than possible) executables
Summary: ld --gc-sections *.o produces big(ger than possible) executables
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.17
: P2 normal
Target Milestone: ---
Assignee: unassigned
Depends on:
Reported: 2006-10-06 15:47 UTC by Denis Vlasenko
Modified: 2006-10-10 08:55 UTC (History)
1 user (show)

See Also:
Host: i386-pc-linux-gnu
Target: i386-pc-linux-gnu
Build: i386-pc-linux-gnu
Last reconfirmed:

objdump of ld *.o result (30.53 KB, text/plain)
2006-10-06 15:48 UTC, Denis Vlasenko
objdump of ld main.o lib.a result (9.44 KB, text/plain)
2006-10-06 15:49 UTC, Denis Vlasenko

Note You need to log in before you can comment on or make changes to this bug.
Description Denis Vlasenko 2006-10-06 15:47:14 UTC
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.
Comment 1 Denis Vlasenko 2006-10-06 15:48:48 UTC
Created attachment 1354 [details]
objdump of ld *.o result
Comment 2 Denis Vlasenko 2006-10-06 15:49:31 UTC
Created attachment 1355 [details]
objdump of ld main.o lib.a result
Comment 3 Alan Modra 2006-10-10 08:55:59 UTC
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.