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 $
答案 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
因此foo
和need_static_foo
被静态解析为static_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
中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
中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
属性。
答案 2 :(得分:0)
Сompiler或链接器从命令行以相反的顺序生成文件。换句话说,带有((weak))的文件应该比动态文件更早地位于命令行中。