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

彭先生:
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 $
迈克·金汉(Mike Kinghan):

最起码,您在这里观察到的事实是,如果链接程序可以静态解析符号,则它不会动态解析符号。看到:

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静态解析为from static_foo.o的定义,而foofrom 的定义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

尽管现在声明fooin 的定义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,并且fooin 的定义libfoo.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 属性,该竞争定义会引发多定义错误

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章