GCC/LD编译链接潜规则 (第五弹) : 为什么会有undified symbol?


04d0ugKnyvJtx1snIGoTteO5TVfXOayBPxCk5BMqr94zlCu6xFw
问题一:
你是否遇到过: 经常遇到加载一些so时, 提示undified symbol,导致加载失败, 可是makefile明明包含了指定的库呀, 怎么还会undified ?

问题二:
你是否还遇到过, 通过ldd -r 查看so, 发现输出包含有undified symbol, 但却仍能正常加载.

问题一的解决之道
我们要解决的是, 如何让so正确的找到symbol.
可能原因之一:
假设我们知道undified symbol的符号确定存在xxx.a里面.
虽然使用了Makefile里面加上了xxx.a的依赖, 但是, 一定要把xxx.a放在最后面. 因为有可能so依赖的其他的.a库也用到了xxx.a.
(PS:为什么要放在后面, 参考本系列的其他文章)

现实案例:
某次编译so时, 对编译结果so文件ldd -r, 发现有undified symbol, 但是明明链接了对应的open_l5库, 为何还提示未找到符号?
file bin/spp_appwork.so
bin/spp_appwork.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped

ldd -r bin/spp_appwork.so 2>&1 | grep -v "tbase\|Tencent\|write_log\|dl"
linux-gate.so.1 => (0xbfffe000)
libpthread.so.0 => /lib/libpthread.so.0 (0xb7e7e000)
libz.so.1 => /usr/lib/libz.so.1 (0xb7e6c000)
libcrypto.so.0.9.8 => /usr/lib/libcrypto.so.0.9.8 (0xb7d40000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7c5f000)
libm.so.6 => /lib/libm.so.6 (0xb7c3a000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7c2f000)
libc.so.6 => /lib/libc.so.6 (0xb7b0f000)
/lib/ld-linux.so.2 (0x80000000)
undefined symbol: _ZN7COpenL54LoadEii (bin/spp_appwork.so)
undefined symbol: _ZN7COpenL56UpdateEi (bin/spp_appwork.so)

通过调整open_l5库的位置, 问题解决.

可能原因之二:
该符号本来是应该属于其所依赖的某个so的, 但是由于当前环境的so版本较低, 没有包含指定的符号.

该猜测通过如下方式验证

// 按照正常的流程编译ld_so, 可以正常运行
nemo@vm04_sles10:[ld_so]$ g++ -o ld_so ld_so.cpp -L. -la
nemo@vm04_sles10:[ld_so]$ ./ld_so 
lalala
call in funa()

// 找一个其他的so替换liba.so, 
nemo@vm04_sles10:[ld_so]$ cp liba.so liba.so.bk
nemo@vm04_sles10:[ld_so]$ cp d.so liba.so

// 启动时会发现undefined symbol
nemo@vm04_sles10:[ld_so]$ ./ld_so 
lalala // <========== 程序的前半部分代码执行了, 输出了lalala
./ld_so: symbol lookup error: ./ld_so: undefined symbol: _Z4funav // <========== 报错了.

// 通过ldd -r 查看, 也可以看出未定义的符号.
nemo@vm04_sles10:[ld_so]$ ldd -r ld_so
undefined symbol: _Z4funav (./ld_so) // <============= 未定义的符号.
linux-gate.so.1 => (0xbfffe000)
liba.so (0xb7f87000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e9d000)
libm.so.6 => /lib/libm.so.6 (0xb7e78000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7e6d000)
libc.so.6 => /lib/libc.so.6 (0xb7d4c000)
/lib/ld-linux.so.2 (0xb7f8a000)

现实案例二:
本人在制作绿色版lamp时也遇到类似问题. 在启动apache时, 提示加载libphp5.so失败: undefined symbol: xmlTextReaderSetup
经排查发现, 系统的/usr/local/bin目录存在一个libxml2.so, 和我在当时编译php时使用的libxml2的版本不一致, 通过修改 LD_LIBRARY_PATH, 使之优先寻找我指定目录下的的libxml2库解决.

问题二的解决之道
即使有undefined symbol:, 只要代码在执行的过程中用不到 也能正常加载so ? 
是的. 但是, 一旦在用到的时候, 就会报错了. 就比如上面的例子, 执行ld_so输出了lalala, 然后才报错未找到符号undefined symbol: _Z4funav.

说明: 
ld 在链接生成so的时候, 允许undefined symbol, 因为这些确实的符号可能在so被加载时就解决了. 
ld 在链接生成可执行文件的时候, 是不允许undefined symbol的
2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值