强制动态链接器在Linux

时间:2018-03-26 11:38:36

标签: linux ld dlopen

所以有点历史,我有3个库:

  • " lib1.so"没有依赖
  • " lib2.so"与" lib1.so"
  • 相关联
  • "测试"没有依赖关系的可执行程序

我需要的是动态加载" lib2.so"在运行期间从" test"通过" dlopen"执行方法。问题是" lib1.so"由于链接器不知道在哪里找到它,因此无法自动加载。

我试图加载" lib1.so"起初就是这样:

void* ptr_lib1 = dlopen("/usr/local/test/lib1.so", RTLD_NOW | RTLD_GLOBAL);
void* ptr_lib2 = dlopen("/usr/local/test/lib2.so", RTLD_NOW | RTLD_GLOBAL);

但由于某种原因,它不起作用,它在调用第二个dlopen(来自dlerror的文本)后给了我错误:

"lib1.so: cannot open shared object file: No such file or directory"

这意味着" lib1.so"试图加载两次:第一次调用dlopen用于" lib1.so",然后第二次调用dlopen用于" lib2.so"。

任何人都可以解释为什么以及如何解决这个问题?请不要建议在启动可执行文件之前修改LD_LIBRARY_PATH。也不建议修改可执行文件的链接器标志。我需要能够在运行时从任何文件夹加载libs。

更新 经过一些研究,我做到了这一点:

LD_DEBUG=all ./test

发现库lib1.so正在尝试加载两次(第一次调用dlopen时,第二次当LD尝试解析lib2.so&#34时的依赖项时):

add /usr/local/test/lib1.so [0] to global scope
opening file=/usr/local/test/lib1.so [0]; direct_opencount=1
...
    30031:  file=lib1.so [0];  needed by /usr/local/test/lib2.so [0]
 30031: find library=lib1.so [0]; searching
 30031:  search path=./tls/x86_64:./tls:./x86_64:.      (RPATH from file ./test)
 30031:   trying file=./tls/x86_64/lib1.so
 30031:   trying file=./tls/lib1.so
 30031:   trying file=./x86_64/lib1.so
 30031:   trying file=./lib1.so
 30031:  search cache=/etc/ld.so.cache
 30031:  search path=/lib64/tls/x86_64:/lib64/tls:/lib64/x86_64:/lib64:/usr/lib64/tls/x86_64:/usr/lib64/tls:/usr/lib64/x86_64:/usr/lib64        (system search path)
 30031:   trying file=/lib64/tls/x86_64/lib1.so
 30031:   trying file=/lib64/tls/lib1.so
 30031:   trying file=/lib64/x86_64/lib1.so
 30031:   trying file=/lib64/lib1.so
 30031:   trying file=/usr/lib64/tls/x86_64/lib1.so
 30031:   trying file=/usr/lib64/tls/lib1.so
 30031:   trying file=/usr/lib64/x86_64/lib1.so
 30031:   trying file=/usr/lib64/lib1.so
 30031:
 30031:
 30031: file=/usr/local/test/lib2.so [0];  destroying link map 

仍然不明白发生了什么......

UPDATE2。有完整的LD_DEBUG log

注意:还有另一个库lib_other.so,只需忽略它

3 个答案:

答案 0 :(得分:1)

dlopen(3)失败时,您应该使用dlerror(3)来获取有用的信息。

至少代码:

void* ptr_lib1 
   = dlopen("/usr/local/test/lib1.so", RTLD_NOW | RTLD_GLOBAL);
if (!ptr_lib1) {
   fprintf(stderr, "dlopen lib1 failure: %s\n", dlerror());
   exit(EXIT_FAILURE);
}

同样适用于其他dlopen s

请注意,dlerror正在提供详细的错误消息。如果你不理解,请把它放在你的问题中。

在关联lib1.solib2.so时,您可能忘记设置一些rpath。或者您需要明确设置LD_LIBRARY_PATH,或运行ldconfig

阅读Drepper的How To Write Shared Libraries论文了解详情。仔细阅读ld-linux(8)

dlopen

lib2失败,因为找不到其依赖项lib1。你需要解决这个问题(通过rpath,LD_LIBRARY_PATHldconfig等......)

您可以在-Wl,-rpath,/usr/local/test/lib1.so选项等中添加一些lib1

您还可以(更简单地)决定所有共享库都进入/usr/local/lib/,您将在/etc/ld.so.conf中提及。然后,您需要在每个库添加后运行ldconfig

答案 1 :(得分:0)

此问题的根本原因似乎是lib1.so NEEDEDlib2.so,这是因为您在构建时链接了它。因此,只需在构建时不要链接它 - 在构建lib1时根本不要提及lib2。然后,您可以根据需要使用dlopen()加载它,lib2将不会尝试单独加载它。

答案 2 :(得分:0)

我有类似的问题,但它确实有效。我只使用“RTLD_LAZY”代替“RTLD_NOW”。

你可以尝试一下。