归根结底,您在此处观察到的事实是,如果链接器可以静态解析符号,则链接器将不会动态解析符号。看:
主程序
extern void foo(void);
extern void need_dynamic_foo(void);
extern void need_static_foo(void);
int main(void){
foo();
need_dynamic_foo();
need_static_foo();
return 0;
}
dynamic_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (dynamic)");
}
void need_dynamic_foo(void)
{
puts(__func__);
}
static_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (static)");
}
void need_static_foo(void)
{
puts(__func__);
}
编译源代码:
$ gcc -Wall -c main.c static_foo.c
$ gcc -Wall -fPIC -c dynamic_foo.c
创建一个共享库:
$ gcc -shared -o libfoo.so dynamic_foo.o
并链接一个程序:
$ gcc -o prog main.o static_foo.o libfoo.so -Wl,-rpath=$PWD
它运行如下:
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo
因此foo
andneed_static_foo
被静态解析为 from的定义,而fromstatic_foo.o
的定义被忽略,尽管事实上需要并提供了. 如果我们将链接顺序更改为:foo
libfoo.so
libfoo.so
need_dynamic_foo
$ gcc -o prog main.o libfoo.so static_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo
如果我们替换static_foo.c
为:
static_weak_foo.c
#include <stdio.h>
void __attribute__((weak)) foo(void)
{
puts("foo (static weak)");
}
void need_static_foo(void)
{
puts(__func__);
}
编译并重新链接:
$ gcc -Wall -c static_weak_foo.c
$ gcc -o prog main.o libfoo.so static_weak_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static weak)
need_dynamic_foo
need_static_foo
尽管foo
in的定义现在被声明为弱,但可以static_weak_foo.c
静态解析为该定义的事实仍然抢占了动态解析它的任何需要。foo
现在,如果我们编写另一个包含另一个强定义的源文件
foo
:
static_strong_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (static strong)");
}
并编译它并链接如下:
$ gcc -Wall -c static_strong_foo.c
$ gcc -o prog main.o static_weak_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
我们看:
$ ./prog
foo (static strong)
need_dynamic_foo
need_static_foo
现在,libfoo.so
仍然提供 的定义need_dynamic_foo
,因为没有别的;static_weak_foo.o
仍然提供 的唯一定义need_static_foo
,而foo
in的定义libfoo.so
仍然被忽略,因为符号可以静态解析。
但是在这种情况下,有两个foo
不同文件中的定义可用于静态解析:弱定义 instatic_weak_foo.o
和强定义 in static_strong_foo.o
。通过您熟悉的链接规则,强定义获胜。
如果这两个静态链接的定义foo
都很强,那么当然会出现多重定义错误,就像:
$ gcc -o prog main.o static_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
static_strong_foo.o: In function `foo':
static_strong_foo.c:(.text+0x0): multiple definition of `foo'
static_foo.o:static_foo.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
其中的动态定义libfoo.so
不起作用。因此,您可以遵循以下实用原则:您熟悉的用于在链接中对同一符号的弱定义和强定义进行仲裁的规则仅适用于在没有属性的情况下会引发多重定义错误的 竞争定义。weak