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

时间:2019-01-31 01:52:40

标签: linux gcc linker weak-symbol

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 $

3 个答案:

答案 0 :(得分:0)

该符号在链接阶段解析,在链接阶段仅可见弱符号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

答案 1 :(得分:0)

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

main.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.o和{ 尽管存在foo,但libfoo.solibfoo.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

尽管foostatic_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的唯一定义, 并且foolibfoo.so的定义仍被忽略,因为该符号 可以静态解决。

但是在这种情况下,不同文件中有foo的两个定义,分别是 可用来静态解决它:static_weak_foo.o中的弱定义和 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 属性

答案 2 :(得分:0)

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