似乎有3种方法告诉GCC弱连接符号:
__attribute__((weak_import))
__attribute__((weak))
#pragma weak symbol_name
这些都不适合我:
#pragma weak asdf
extern void asdf(void) __attribute__((weak_import, weak));
...
{
if(asdf != NULL) asdf();
}
我总是收到这样的链接错误:
Undefined symbols: "_asdf", referenced from: _asdf$non_lazy_ptr in ccFA05kN.o ld: symbol(s) not found collect2: ld returned 1 exit status
我在OS X 10.5.5上使用GCC 4.0.1。我做错了什么?
答案 0 :(得分:29)
我只是调查了这一点,并认为其他人可能会对我的发现感兴趣。
与weak_import的弱链接实际上只适用于动态库。您可以使用静态链接(通过如上所述指定-undefined dynamic_lookup),但这不是一个好主意。这意味着在运行时之前不会检测到任何未定义的符号。我个人会在生产代码中避免这种情况。
这是一个Mac OS X终端会话,展示如何使其工作:
这是f.c
int f(int n)
{
return n * 7;
}
这是whatnof.c
#include <stdio.h>
#include <stdlib.h>
extern int f (int) __attribute__((weak_import));
int main() {
if(f == NULL)
printf("what, no f?\n");
else
printf("f(8) is %d\n", f(8));
exit(0);
}
从f.c:
创建一个动态库$ cc -dynamiclib -o f.dylib f.c
编译并链接动态库,列出动态库。
$ cc -o whatnof whatnof.c f.dylib
$ otool -L whatnof
whatnof:
f.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)
运行whatnof以查看会发生什么:
$ whatnof
f(8) is 56
现在用空库(无符号)替换f.dylib:
$ mv f.dylib f.dylib.real
$ touch null.c
$ cc -dynamiclib -o f.dylib null.c
运行相同的内容以查看会发生什么:
$ whatnof
what, no f?
weak_import的基本思想(或“用例”)是它允许您链接一组动态(共享)库,但是对相同库的早期版本运行相同的代码。您可以检查函数是否为NULL,以查看它们是否在代码当前运行的特定动态库中受支持。这似乎是Xcode支持的基本开发模型的一部分。我希望这个例子很有用;它帮助我放松了解Xcode设计的这一部分。
答案 1 :(得分:6)
将-Wl,-flat_namespace,-undefined,dynamic_lookup
添加到用于执行最终链接的gcc编译器行。
答案 2 :(得分:4)
您需要将MACOSX_DEPLOYMENT_TARGET变量设置为10.2或更高版本。有关弱链接,请参阅Apple's documentation及其technote。
答案 3 :(得分:1)
最小的可运行Linux示例
main.c
#include <stdio.h>
int my_weak_var __attribute__((weak)) = 1;
int main(void) {
printf("%d\n", my_weak_var);
}
notmain.c
int my_weak_var = 2;
编译并运行两个对象:
gcc -c -std=c99 -Wall -Wextra -pedantic -o main.o main.c
gcc -c -std=c99 -Wall -Wextra -pedantic -o notmain.o notmain.c
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.o notmain.o
./main.out
输出:
2
无需运行notmain.o
即可编译和运行:
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.o
./main.out
输出:
1
因此我们看到,如果在notmain.o
上给出,则非弱符号将按预期优先。
我们可以使用以下方法分析ELF object file符号:
nm main.o notmain.o
给出:
main.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
0000000000000000 V my_weak_var
U printf
notmain.o:
0000000000000000 D my_weak_var
然后:
man nm
包含:
符号类型。至少使用以下类型;其他的也取决于目标文件格式。如果是小写,则该符号通常是局部的;如果为大写,则符号为全局(外部)。但是,有一些小写的符号显示为特殊的全局符号(“ u”,“ v”和“ w”)。
“ D”
“ d”该符号在初始化的数据部分中。“ V”
“ v”该符号是一个弱对象。当弱定义符号与普通定义符号链接时,使用普通定义符号不会出错。当链接了一个未定义的弱符号并且未定义该符号时,该弱符号的值将变为零而不会出现错误。在某些系统上,大写表示已指定默认值。
但是,如果要处理.a
静态库,则可能必须使用-Wl,--whole-archive
,具体说明如下:How to make gcc link strong symbol in static library to overwrite weak symbol?
弱符号也可以保留为未定义状态,这在Binutils中导致“特定于平台的行为”,请参见:GCC behavior for unresolved weak functions
在Ubuntu 18.10,GCC 8.2.0上进行了测试。
答案 4 :(得分:0)
来自gcc doc手册:
<强>弱强>
weak属性导致声明以弱的形式发出 符号而不是全球。这主要用于定义 可以在用户代码中覆盖的库函数,尽管它 也可以与非函数声明一起使用。弱符号是 支持ELF目标,以及使用时的a.out目标 GNU汇编器和链接器。
这意味着对象合法化以覆盖弱符号(在另一个对象/库中定义)而不会在链接时获得错误。不清楚的是您是否将库与弱符号链接起来。似乎您没有定义符号,并且库没有正确链接。