简体   繁体   English

如何在静态库中使用gcc链接强符号来覆盖弱符号?

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

My problem can be summarised in the following: 我的问题可归纳如下:

bar.c : bar.c

#include <stdio.h>

void bar() {
    printf("bar\n");
}

main.c : main.c

#include <stdio.h>

void __attribute__((weak)) bar() {
    printf("foo\n");
}

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

Makefile : Makefile

all:
    gcc -c bar.c
    ar -rc libbar.a bar.o
    gcc main.c -L. -lbar

Output : 输出

$ ./a.out
foo

So the weak symbol bar in main.c is not overwritten by the strong symbol in bar.c due to bar.c being linked to main.c in a static library libbar.a. 所以main.c中的弱符号栏不会被bar.c中的强符号覆盖,因为bar.c被链接到静态库libbar.a中的main.c.

How can I tell gcc to make the strong symbol in libbar.a to overwritten the weak symbol in main.c? 我如何告诉gcc在libbar.a中使用强符号来覆盖main.c中的弱符号?

I am puzzled by the answer given by max.haredoom (and that it was accepted). 我对max.haredoom给出的答案感到困惑(并且它被接受了)。 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). 链接静态库时, ld 默认 关心弱/强符号:它只是将未定义的符号解析为第一个遇到的符号(因此命令行中静态库的顺序很重要)。

However, this default behavior can be changed using the --whole-archive option. 但是,可以使用--whole-archive选项更改此默认行为。 If you rewrite your last step in Makefile as follows: 如果您重写Makefile中的最后一步,如下所示:

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). 简而言之,-- --whole-archive强制链接器扫描其所有符号(包括已经解析的符号)。 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 . 另请参阅Eli Bendersky关于静态库及其链接过程“静态链接中的库顺序”的精彩帖子以及此SO问题

Generally speaking: if you don't put a weak implementation into your main , the linker will resolve it at last at runtime. 一般来说:如果你没有将弱实现放入main ,链接器最终会在运行时解析它。 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. 但是如果你在main.c实现它,你只能在链接这个静态时用强绑定( bar.c )覆盖它。

Please read http://www.bottomupcs.com/libraries_and_the_linker.html - it contains a lot of interesting stuff on this topic. 请阅读http://www.bottomupcs.com/libraries_and_the_linker.html - 它包含很多关于此主题的有趣内容。

I've made a test myself: 我自己做了一个测试:

bar.c bar.c

#include <stdio.h>

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

baz.c baz.c

#include <stdio.h>

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

main.c 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: 我的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() . 看一下main1 && main2 ...如果你没有把任何弱实现放到main.c但是把弱文件保存在库中而将强文件放在另一个库中,你将能够覆盖弱文件。如果强大的lib定义了bar()的强大实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM