How to make gcc link strong symbol in static library to overwrite weak symbol?

ぃ、小莉子 提交于 2019-11-27 19:45:01
max.haredoom

Generally speaking: if you don't put a weak implementation into your main, the linker will resolve it at last at runtime. But if you implement it in main.c, you will only be able to override it with a strong bound (bar.c) when linking this static.

Please read http://www.bottomupcs.com/libraries_and_the_linker.html - it contains a lot of interesting stuff on this topic.

I've made a test myself:

bar.c

#include <stdio.h>

void bar()
{
        puts("bar.c: i'm the strong bar()");
}

baz.c

#include <stdio.h>

void __attribute__((weak)) bar() 
{
        puts("baz.c: i'm the weak bar()");
}

main.c

#include <stdio.h>

#ifdef V2
        void __attribute__((weak)) bar()
        {
                puts("main: i'm the build in weak bar()");
        }
#else
        void __attribute__((weak)) bar();
#endif

int main()
{
    bar();
    return 0;
}

My Makefile:

all:
    gcc -c -o bar.o bar.c
    gcc -shared -fPIC -o libbar.so bar.o
    gcc -c -o baz.o baz.c
    gcc -shared -fPIC -o libbaz.so baz.o
    gcc -o main1 main.c -L. -lbar -lbaz
    gcc -o main2 main.c -L. -lbaz -lbar
    LD_LIBRARY_PATH=. ./main1                                   # => bar.c
    LD_LIBRARY_PATH=. ./main2                                   # => baz.c
    LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main1              # => baz.c (!!)
    LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main2              # => baz.c
    gcc -o main3 main.c bar.o baz.o
    gcc -o main4 main.c baz.o bar.o
    ./main3                                                     # => bar.c
    ./main4                                                     # => bar.c
    gcc -DV2 -o main5 main.c -L. -lbar -lbaz
    gcc -DV2 -o main6 main.c -L. -lbaz -lbar
    LD_LIBRARY_PATH=. ./main5                                   # => main's implementation
    LD_LIBRARY_PATH=. ./main6                                   # => main's implementation
    gcc -DV2 -o main7 main.c -L. -lbar -lbaz
    gcc -DV2 -o main8 main.c -L. -lbaz -lbar
    LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main7              # => main's implementation
    LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main8              # => main's implementation
    gcc -DV2 -o main9  main.c -L. -lbar -lbaz
    gcc -DV2 -o main10 main.c -L. -lbaz -lbar
    LD_LIBRARY_PATH=. LD_PRELOAD=libbar.so ./main9              # => main's implementation
    LD_LIBRARY_PATH=. LD_PRELOAD=libbar.so ./main10             # => main's implementation
    gcc -c bar.c
    gcc -c baz.c
    gcc -o main11 main.c bar.o baz.o
    gcc -o main12 main.c baz.o bar.o
    ./main11                                                    # => bar.c
    ./main12                                                    # => bar.c
    gcc -o main13 -DV2 main.c bar.o baz.o
    gcc -o main14 -DV2 main.c baz.o bar.o
    ./main13                                                    # => bar.c
    ./main14                                                    # => bar.c

Take a look at main1 && main2... if you don't put any weak implementation into main.c but keep the weak one in a library and the strong one in another lib., you'll be able to override the weak one if the strong lib defines a strong implementation of bar().

Dmitrii Kuvaiskii

I am puzzled by the answer given by max.haredoom (and that it was accepted). The answer deals with shared libraries and dynamic linking, whereas the question was clearly about the behavior of static linking using static libraries. I believe this is misleading.

When linking static libraries, ld does not care about weak/strong symbols by default: it simply resolves an undefined symbol to a first-encountered symbol (so the order of static libraries in the command line is important).

However, this default behavior can be changed using the --whole-archive option. If you rewrite your last step in Makefile as follows:

gcc main.c -L. -Wl,--whole-archive -lbar -Wl,--no-whole-archive

Then you will see:

$ ./a.out
bar

In a nutshell, --whole-archive forces the linker to scan through all its symbols (including those already resolved). If there is a strong symbol that was already resolved by a weak symbol (as in our case), the strong symbol will overrule the weak one.

Also see a great post on static libraries and their linking process "Library order in static linking" by Eli Bendersky and this SO question.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!