linux 下同名符号冲突问题解决方案
linux下同名符号冲突问题解决方案
最近的工作中遇到如下令人蛋疼的问题:
Linux下有三个模块aa、bb、cc,基本情况如下:
cc编译连接得到cc.so动态库,cc中有如下接口:
cc_fun { …… do();//调用名为do的cc模块内部函数 …… }
bb编译连接得到bb.a静态库,bb中有如下接口:
bb_fun { …… handle=dlopen(cc.so,RTLD_LAZY);//加载cc.so pccfun=dlsym(handle,“cc_fun”);//获取cc_fun函数指针 (*pccfun)();//调用cc_fun函数,此时应该会调用cc模块中的do()函数 do();//调用名为do的bb模块内部函数(与cc模块中的do()函数同名,实现却不相同) …… }
aa编译后通过-lbb链接选项的方式连接bb.a得到aa可执行程序,并调用bb.a的接口函数bb_fun():
main { …… bb_fun();//调用bb_fun函数 …… }
工作中发现aa在运行时行为异常,总是有内存泄露和功能异常,通过定位发现问题集中在同名的do()函数上。通过输出打印发现程序中两次调用do()函数都调用到了bb模块中的do()函数,而cc模块中的do()函数从未被调用到,导致程序行为异常和内存泄露。
后经多方查证了解到因为linux程序中各个库中的符号表最终都会加载到程序所在的全局符号表中,此时如果有同名符号就只能调用到第一个加载进来的符号,也就是说后边加载的同名符号都会被之前的覆盖。cc模块中的do()函数被bb模块中的do()函数覆盖了,所以无法被调用到。
废话不多说。。。
在试验过很多不满意的方法之后,最终的解决方法如下:
1.在cc的makefile中加入-Wl,-Bsymbolic-Wl,--version-script,version的连接选项,意思是用version文件中的脚本指定其导出哪些函数。
2.version文件的实现如下:
VERS{ global: cc_fun; local:*; };
意思是指定cc模块只导出接口函数cc_fun,其余函数都设为local不做导出。
将该文件保存在makefile所在目录即可。
3.重新编译连接三个模块,问题解决。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!