Why doesn't __attribute__((constructor)) work

2019-02-16 04:52发布

问题:

In the following example, the program should print "foo called":

// foo.c
#include <stdio.h>

__attribute__((constructor)) void foo()
{
    printf("foo called\n");
}

// main.c
int main()
{
    return 0;
}

If the program is compiled like this, it works:

gcc -o test main.c foo.c

However, if foo.c is compiled into a static library, the program prints nothing.

gcc -c main.c
gcc -c foo.c
as rcs foo.a foo.o
gcc -o test foo.a main.o

Why does this happen?

回答1:

The linker does not include the code in foo.a in the final program because nothing in main.o references it. If main.c is rewritten as follows, the program will work:

//main.c

void foo();

int main()
{
    void (*f)() = foo;
    return 0;
}

Also, when compiling with a static library, the order of the arguments to gcc (or the linker) is significant: the library must come after the objects that reference it.

gcc -o test main.o foo.a


回答2:

As it was stated, unreferenced symbols from archive does not make it to the output binary, because linker discards them by default.

To override this behaviour when linking with static library, --whole-archive/--no-whole-archive options for the linker may be used, like this:

gcc -c main.c
gcc -c foo.c
ar rcs foo.a foo.o
gcc -o test -Wl,--whole-archive foo.a -Wl,--no-whole-archive main.o

This may lead to bloated binary, because all symbols from foo.a will be included by the linker to the output, but sometimes it is justified.