使用PROVIDE语句为错误命名符号设别名的ld链接脚本正确语法
GNU ld 符号别名配置问题解决
问题场景
尝试为错误命名的符号创建别名,期望通过在链接脚本中添加PROVIDE(foo_ = foo);实现将foo_指向已定义的foo符号,但编译链接时报错,提示foo符号未定义。
相关代码与操作如下:
源文件
foo.c:
int foo(int a) { return a + 1; }
foo.h:
int foo(int a);
main.c:
#include "foo.h" #include <stdio.h> int main(int argc, char *argv[]) { int b = foo_(1); // 误调用foo_而非foo printf("%d\n", b); return 0; }
链接脚本(script.ld)
PROVIDE(foo_ = foo);
编译链接命令
gcc -c -o foo.o foo.c ar rcs foo.a foo.o gcc -I. -c -o main.o main.c gcc main.o foo.a -o test script.ld
报错信息
/usr/bin/ld:script.ld:1: undefined symbol 'foo' referenced in expression
nm符号检查结果
nm foo.a foo.o: 0000000000000000 T foo nm main.o U foo_ U _GLOBAL_OFFSET_TABLE_ 0000000000000000 T main U printf
错误原因
GNU ld处理输入文件的顺序是先处理链接脚本,再处理归档库。当链接脚本执行PROVIDE(foo_ = foo);时,归档库foo.a还未被处理,foo符号尚未被加载,因此ld认为foo是未定义符号,抛出错误。
正确解决方案
方案1:调整输入文件顺序
将归档库放在链接脚本之前,确保ld先加载foo符号,再处理链接脚本:
gcc main.o foo.a script.ld -o test
方案2:使用--defsym命令行参数替代链接脚本
直接通过gcc传递链接器参数定义符号别名,无需编写链接脚本,更简洁:
gcc main.o foo.a -o test -Wl,--defsym=foo_=foo
方案3:修改链接脚本结构(适用于多符号别名场景)
将PROVIDE语句放入SECTIONS块中,同时确保符号已被解析,示例链接脚本:
SECTIONS { .text : { *(.text) PROVIDE(foo_ = foo); } }
使用该脚本时仍需保证归档库在脚本之前输入,或者结合EXTERN(foo)强制ld查找该符号:
EXTERN(foo); PROVIDE(foo_ = foo);
问题排查提示
- 检查输入顺序:链接脚本中引用的符号必须在脚本之前被定义,因此依赖的归档库/目标文件要放在链接脚本前面
- 优先使用
--defsym:单个符号别名场景下,命令行参数比链接脚本更直观,避免顺序问题 - 用
nm确认符号:确保目标文件/归档库中确实存在要引用的符号,避免拼写错误 - 查看链接详细过程:添加
-v参数(如gcc -v main.o foo.a -o test script.ld),查看ld的符号加载顺序,定位符号未找到的环节
内容的提问来源于stack exchange,提问作者Patrick Kwok
相关产品推荐
相关产品推荐

