找到了当时发生同名符号冲突的原因。当程序A调用.so模块B时,为了让被调用的B模块能够使用A模块中的一些函数,在编译A程序时使用了--export-dynamic选项。
如果在创建动态链接的可执行文件不加–export-dynamic选项,则它所export的动态符号仅仅包括在链接时动态对象所用到的,因为dlopen是自行加载动态库,并不存在与可执行文件动态符号解析的过程,所以如果dlopen加载的动态库需要了程序中定义的函数,则会出现找不到。
将程序A的符号加入动态符号表后,如果在B模块中出现了与A中符号相同的符号,A的符号优先级较高。比如程序A和.so文件B中各自实现了一个函数do_job_func,B本打算调用自己的do_job_func时,实际调用的是程序A中的do_job_func,出现混乱。
在编译模块B时加上编译选项-fvisibility=hidden后就可以解决冲突的问题。
下面这篇文章详细的解释了--export-dynamic的用途。
http://zhabin.org/2011/01/23/rdynamic/
------------以上2011-9-29更新----------------------------
工作中遇到运行时用dlopen/dlsym加载链接库时发生同名符号冲突导致跳转混乱的问题。
http://blog.csdn.net/zhongyunde/archive/2010/10/14/5939733.aspx
上面这篇博文中提到的方法是用来解决链接时重定位出现的 问题,但是当我使用运行时重定位机制仍然出现了冲突现象,用文中的方法加编译选项-fvisibility=hidden得到解决。但是当我写小程序试图重现,却失败了。困惑中。。。
-----------以上2011-3-28更新-----------------------------
Linux的动态链接库在链接时,如果在不同模块中出现相同的函数名会发生冲突,导致一个共享对象里面的全局符号被另一个共享对象的同名全局符号覆盖。以下面的例子来说明这一现象:
a1.c和a2.c各自实现了一个函数void a(),分别被函数b1和函数b2调用。
另外有一个main.c,其内部也实现了一个a(),同时他也需要调用b1()和b2()。
编译并运行:
$ gcc -fPIC -shared a1.c -o a1.so
$ gcc -fPIC -shared a2.c -o a2.so
$ gcc main.c a1.so a2.so -o main -Xlinker -rpath ./
$ ./main
main.c
main.c
这与大多数时候我们期待的打印a1.c/na2.c/n不同。
如果我们将main.c改写为下面的,在运行时进行加载,使用dlsym方式调用b1()和b2()
编译并运行,可见已经避免这一问题。
$gcc gcc main.c -o main -ldl
$./main
a1.c
a2.c
总结:
下一章讲更复杂的情况。