在Linux中强制动态链接器在运行时加载库 [英] Force dynamic linker to load library at runtime in Linux

查看:455
本文介绍了在Linux中强制动态链接器在运行时加载库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一点历史,我有3个库:

  • 没有依赖项的"lib1.so"
  • 与"lib1.so"链接的"lib2.so"
  • 没有依赖项的测试"可执行程序

我需要的是在运行时通过"dlopen"方法从测试"可执行文件动态加载"lib2.so".问题在于"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"正试图加载两次:第一次是当我为"lib1.so"调用dlopen时,第二次是当我为"lib2.so"调用dlopen时.

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

更新. 经过一番研究,我做到了:

LD_DEBUG=all ./test

并发现库lib1.so试图被加载两次(第一次,当我调用dlopen时,第二次,当LD试图解决lib2.so的依赖关系时"):

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日志

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

解决方案

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的 如何编写共享库 有关详细信息.仔细阅读 ld-linux(8) lib2

dlopen失败,因为未找到其依赖项lib1.您需要解决此问题(通过rpath,LD_LIBRARY_PATHldconfig等...)

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

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

So a little bit of history, I have 3 libs:

  • "lib1.so" with no dependencies
  • "lib2.so" which is linked with "lib1.so"
  • "test" executable program with no dependencies

What I need is to dynamically load "lib2.so" during runtime from "test" executable via "dlopen" method. The problem is that "lib1.so" cannot be loaded automatically due to linker doesn't know where to find it.

I've tried to load "lib1.so" at first like that:

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);

But that's not working by some reason, it gives me error after calling second dlopen (text from dlerror):

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

It means that "lib1.so" is trying to be loaded twice: first time when I call dlopen for "lib1.so", and second when I call dlopen for "lib2.so".

Can anyone explain why and what to do to fix that? Please, don't advise to modify LD_LIBRARY_PATH before starting executable. Also don't advise to modify linker flags of executable. I need to be able load that libs at runtime from any folder.

UPDATE. After some research I did this:

LD_DEBUG=all ./test

And found that library lib1.so is trying to be loaded twice (first when I call dlopen, second when LD trying to resolve dependency for lib2.so"):

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 

Still don't understand what is going on...

UPDATE2. There is full LD_DEBUG log

Note: there is another library lib_other.so, just ignore it

解决方案

When dlopen(3) fails, you should use dlerror(3) to get some useful message.

So code at least:

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);
}

and likewise for other dlopens

Notice that dlerror is giving a detailed error message. If you don't understand it, put it in your question.

You probably forgot to set some rpath when linking lib1.so or lib2.so. Or you need to set explicitly LD_LIBRARY_PATH, or run ldconfig

Read Drepper's How To Write Shared Libraries paper for details. Read carefully ld-linux(8)

dlopen of lib2 fails because its dependency lib1 is not found. You need to fix that (thru rpath, LD_LIBRARY_PATH, ldconfig etc...)

You could add some -Wl,-rpath,/usr/local/test/lib1.so in lib1 options, etc

You could also (more simply) decide that all your shared libraries go into /usr/local/lib/ which you would mention in /etc/ld.so.conf. Then you need to run ldconfig after every library addition there.

这篇关于在Linux中强制动态链接器在运行时加载库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆