__attribute__(弱))不适用于全局变量


pqy@localhost ~/src/test/a $ cat m.c
#include <stdio.h>
int aaaaa __attribute__ ((weak)) =8;
int main(void){
printf("%dn", 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("%dn", 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 $

在底部,您在这里观察到的只是链接器不会 如果符号可以静态解析,则动态解析符号。看:

主.c

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

因此,fooneed_static_foo被静态解析为来自static_foo.olibfoo.sofoo的定义被忽略了,尽管事实上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

尽管static_weak_foo.c中对foo的定义现在被宣布为薄弱,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的唯一定义, 并且libfoo.sofoo的定义仍然被忽略,因为符号 可以静态解析。

但在这种情况下,不同文件中foo有两种定义,它们是 可用于静态解决它:static_weak_foo.ostatic_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属性

符号在链接阶段解析,在链接阶段,只有弱符号aaaaa = 8可见。

如果符号可以在链接阶段解析,它不会生成重新定位条目,那么在加载阶段不会发生任何事情

重新定位表中没有aaaaa

% objdump -R m         
m:     file format elf64-x86-64
DYNAMIC RELOCATION RECORDS
OFFSET           TYPE              VALUE 
0000000000003dc8 R_X86_64_RELATIVE  *ABS*+0x0000000000001130
0000000000003dd0 R_X86_64_RELATIVE  *ABS*+0x00000000000010f0
0000000000004028 R_X86_64_RELATIVE  *ABS*+0x0000000000004028
0000000000003fd8 R_X86_64_GLOB_DAT  _ITM_deregisterTMCloneTable
0000000000003fe0 R_X86_64_GLOB_DAT  __libc_start_main@GLIBC_2.2.5
0000000000003fe8 R_X86_64_GLOB_DAT  __gmon_start__
0000000000003ff0 R_X86_64_GLOB_DAT  _ITM_registerTMCloneTable
0000000000003ff8 R_X86_64_GLOB_DAT  __cxa_finalize@GLIBC_2.2.5
0000000000004018 R_X86_64_JUMP_SLOT  printf@GLIBC_2.2.5

Сompiler 或链接器以相反的顺序从命令行构建文件。换句话说,带有(弱))的文件应该比动态文件更早地位于命令行中。

相关内容

  • 没有找到相关文章

最新更新