Why can't ld ignore an unused unresolved symbol?

Issue

Consider the following source files:

a.c:

extern int baz();

int foo() { return 123; }
int bar() { return baz() + 1; }

b.c:

extern int foo();

int main() { return foo(); }

Now, when I try to build a program using these sources, here’s what happens:

$ gcc -c -o a.o a.c
$ gcc -c -o b.o b.c
$ gcc -o prog a.o b.o
/usr/bin/ld: a.o: in function `bar':
a.c:(.text+0x15): undefined reference to `baz'
collect2: error: ld returned 1 exit status

This is on Devuan GNU/Linux Chimaera, with GNU ld 2.35.2, GCC 10.2.1.

Why does this happen? I mean, one does not need any complex optimization to know that baz() is not really needed in foo() – ld naturally notices this at some point – e.g. when finishing its traversal of foo() without noticing a location where baz() is used.

Now, you could say "einpoklum, you didn’t ask the compiler to go to any trouble for you" – and that’s fair, I guess, but even if I use -O3 with these instructions, I get the same error.

Note: with LTO and optimization enabled, we can circumvent this issue:

$ gcc -c -flto -O1 -o b.o b.c
$ gcc -c -flto -O1 -o a.o a.c
$ gcc -o prog -O1 -flto a.o b.o
$ /prog ; echo $?;
123

Solution

If you use gcc and binutils ld to build your programs you need to place functions in separate sections. It is archived by -fdata-sections & -ffunction-sections command line options.

Same with data. Then if you do not want dead code to be included in your executable you need to enable it by using --gc-sections ld option.

Putting this all together:

$ gcc -fdata-sections -ffunction-sections -c -o a.o a.c
$ gcc -c -o b.o b.c
$ gcc -Wl,--gc-sections -o prog a.o b.o
$ /prog ; echo $?
123

If you want to enable it by default simple build GCC with those options enabled.

Answered By – 0___________

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published