遇到如下情况,主程序通过dlopen来打开.so文件,但是.so用到了主程序的log函数。 编译so时,通过引用主程序头文件来编译通过,头文件有log函数声明: extern "C" { 在主程序的.c文件里有函数的具体实现。
但是dlopen后运行so中函数时,出现找不到相应的symbol。 这时候就需要在编译主程序ld时加上参数-rdynamic,该参数的作用是:将指示连接器把所有符号(而不仅仅只是程序已使用到的外部符号,但不包括静态符号,比如被static修饰的函数)都添加到动态符号表(即.dynsym表)里,以便那些通过dlopen()或backtrace()(这一系列函数使用.dynsym表内符号)这样的函数使用。
-rdynamic
-g是编译选项,而-rdynamic是链接选项 参考:http://www./archives/2013/01/2190
小例子:
a.cc [cpp] view plaincopy
a.h [cpp] view plaincopy
[cpp] view plaincopy
foo.h [python] view plaincopy
foo.cc [cpp] view plaincopy
main.cc [cpp] view plaincopy
Makefile [cpp] view plaincopy
运行dynamic后输出为: [python] view plaincopy
[python] view plaincopy
--whole-archive 可以把 在其后面出现的静态库包含的函数和变量输出到动态库,--no-whole-archive 则关掉这个特性 使用readelf -s libso.so | grep fun来查看libso.so的符号表里是否有fun这个函数暴露出来。有--whole-archive的可以查到fun,而没有--whole-archive的,则找不到fun 先理清一下code 可执行文件dynamic依赖与libso.so,而libso.so有包含liba.a,在liba.a的函数fun调用dlopen来打开libtmp.so 主函数调用liba.a的函数来打开libtmp.so
-fvisibility=hidden 设置默认的ELF镜像中符号的可见性为隐藏。使用这个特性可以非常充分的提高连接和加载共享库的性能,生成更加优化的代码,提供近乎完美的API输出和防止符号碰撞。我们强烈建议你在编译任何共享库的时候使用该选项。 -fvisibility-inlines-hidden 默认隐藏所有内联函数,从而减小导出符号表的大小,既能缩减文件的大小,还能提高运行性能,我们强烈建议你在编译任何共享库的时候使用该选项
所以编译的时候也不能有-fvisibility=hidden和-fvisibility-inlines-hidden。如果有,也会在dlopen时造成错误:undefined symbol 本实例虽小,但用到了不少编译选项 a: __attribute__((constructor)) b: -rdynamic ld时将动态库的的所有符号都输出到符号表,以便dlopen和backtrace也能调用 c: --whole-archive -la -Wl,--no-whole-archive 静态库的符号导入到动态库的符号表中,默认是hidden的 d: -fvisibility=hidden和-fvisibility-inlines-hidden ELF镜像中符号的可见性为隐藏(在实验过程中不太好用,待研究)
参考: http://www./qa-225-106759.aspx http://os./a2010/0112/1060/000001060902_3.shtml 版权声明:本文为博主原创文章 |
|