linux - __attribute__ ((weak)) 不适用于全局变量
问题描述
pqy@localhost ~/src/test/a $ cat m.c
#include <stdio.h>
int aaaaa __attribute__ ((weak)) =8;
int main(void){
printf("%d\n", aaaaa);
return 0;
}
pqy@localhost ~/src/test/a $ cat lib.c
int aaaaa = 5;
pqy@localhost ~/src/test/a $ gcc lib.c -fPIC -shared -o libb.so;gcc m.c -o m -L. -lb -Wl,-rpath=$PWD;./m
8
以上是我的代码和测试结果。我很困惑为什么它不能按预期工作。
也尝试功能,而不是以太。下面是测试结果。
pqy@localhost ~/src/test/a $ cat lib.c
int fun() {
return 5;
}
pqy@localhost ~/src/test/a $ cat m.c
#include <stdio.h>
__attribute__((weak)) int fun() {
return 8;
}
int main(void){
printf("%d\n", fun());
return 0;
}
pqy@localhost ~/src/test/a $ gcc lib.c -fPIC -shared -o libb.so;gcc m.c -O0 -o m -L. -lb -Wl,-rpath=$PWD;./m
8
pqy@localhost ~/src/test/a $ ldd m
linux-vdso.so.1 (0x00007ffd819ec000)
libb.so => /home/pqy/src/test/a/libb.so (0x00007f7226738000)
libc.so.6 => /lib64/libc.so.6 (0x00007f7226533000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7226744000)
pqy@localhost ~/src/test/a $
解决方案
归根结底,您在此处观察到的事实是,如果链接器可以静态解析符号,则链接器将不会动态解析符号。看:
主程序
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
推荐阅读
- javascript - 在 package.json 上使用 postbuild 脚本将 /Build 移动到“npm run build”上的自定义目录时删除现有的 React /Build
- ruby-on-rails - 使用 capistrano+nginx 在单个数字海洋水滴中部署多个 Rails 应用程序
- python - 如何使用 h5py 将数据写入复合数据?
- reactjs - 如何在 React 中显示 Bootswatch 模式?
- python-3.x - AWS NEXRAD 和 pyart grid_from_radars
- c# - AutoFixture - 添加自定义,以便使用对象 ID 创建所有字典键
- spring - 自定义 Spring Boot Actuator 健康检查的整体健康状况
- sql-server-2008 - 仅当表 B 中不存在特定值时才从表 A 中获取值
- typescript - 使用 polyfill 时的安全打字稿编译
- python - 根据一列中的值替换整个数据框中的空值