主程序和使用dlopen加载的库需要不同版本的libsqlite3.so。

huangapple go评论64阅读模式
英文:

Both main program and dlopen'ed library need different versions of libsqlite3.so

问题

我有一个依赖于 libsqlite3.so 的主程序。通过运行 LD_DEBUG=libs ./my_executable,我观察到以下情况(我编辑了搜索路径以使其看起来更简单):

    386600:     find library=libsqlite3.so.0 [0]; searching
    386600:      search path=/a:/b:/c:/d:/e              (RPATH from file /home/me/my_executable)
    386600:       trying file=/a/libsqlite3.so.0
    386600:       trying file=/b/libsqlite3.so.0
    386600:       trying file=/c/libsqlite3.so.0
    386600:       trying file=/d/libsqlite3.so.0
    386600:       trying file=/e/libsqlite3.so.0

到目前为止一切正常,运行时链接器正确使用了来自 my_executableRPATH 最终在 /e 中找到了 libsqlite3.so

随后,my_executable 继续运行一个 Python 解释器。最终,一个 Python import 调用尝试加载 libsqlite3,它根据 my_executableRPATH 进行解析,ldd 报告了有关未解析符号的错误。

幸运的是,在这种特定情况下,我可以运行 LD_DEBUG=libs python -c "import IPython" 来查看 Python 需要什么:

    396818:     find library=libsqlite3.so.0 [0]; searching
    396818:      search path=/home/me/miniconda3/lib/python3.9/lib-dynload/../..             (RPATH from file /home/me/miniconda3/lib/python3.9/lib-dynload/zlib.cpython-39-x86_64-linux-gnu.so)
    396818:       trying file=/home/me/miniconda3/lib/python3.9/lib-dynload/../../libsqlite3.so.0

因此,my_executable 和 Python 需要不同版本的 libsqlite3。首先,是否可以在运行时使用 dlopen 打开共享库的第二个版本,以及如何告诉 dlopen 忽略来自 my_executableRPATH

英文:

I have a main program that depends on libsqlite3.so. By running it with LD_DEBUG=libs ./my_executable, I observe the following (I edited the search paths to look simpler):

    386600:     find library=libsqlite3.so.0 [0]; searching
    386600:      search path=/a:/b:/c:/d:/e              (RPATH from file /home/me/my_executable)
    386600:       trying file=/a/libsqlite3.so.0
    386600:       trying file=/b/libsqlite3.so.0
    386600:       trying file=/c/libsqlite3.so.0
    386600:       trying file=/d/libsqlite3.so.0
    386600:       trying file=/e/libsqlite3.so.0

So far so good, the runtime linker correctly uses the RPATH from my_executable to eventually find libsqlite3.so in /e.

Later on, my_executable goes on to run a python interpreter. Eventually, a python import call tries to load libsqlite3 and it gets resolved according to the RPATH from my_executable, and ldd throws an error about unresolved symbols.

Thankfully, in this specific case, I can just run LD_DEBUG=libs python -c "import IPython" to see what Python wants:

    396818:     find library=libsqlite3.so.0 [0]; searching
    396818:      search path=/home/me/miniconda3/lib/python3.9/lib-dynload/../..             (RPATH from file /home/me/miniconda3/lib/python3.9/lib-dynload/zlib.cpython-39-x86_64-linux-gnu.so)
    396818:       trying file=/home/me/miniconda3/lib/python3.9/lib-dynload/../../libsqlite3.so.0

So, my_executable and python want different versions of libsqlite3. First of all, is it possible to dlopen a second version of a shared library at runtime, and how do I tell dlopen to ignore the RPATH from my_executable?

答案1

得分: 0

首先,可以在运行时使用dlopen打开共享库的第二个版本,只要这两个库在其SONAME上不同(它们可能不同,但您可以对其中一个或两个进行二进制修补)。

然而,这样做实际上是一个非常糟糕的主意——这两个库很可能会定义相同的一组符号,而且Linux的规则是第一个定义会生效。

这样做可能会导致非常难以调试的崩溃。

实际上,这里发生的情况是你有两个具有相同SONAME但ABI不同的库(我们知道ABI不同,因为如果它们相同,你就不会遇到未解析的符号——一切都会正常工作)。

然后,如何告诉dlopen忽略my_executable的RPATH?

你不能。但是,您可以使用绝对路径(假设具有不同SONAMEdlopen()另一个libsqlite3.so.0

您最好的选择可能是按照n.m.的建议做:在主程序中使用dlmopen将您的libsqlite3.so.0版本加载到单独的加载器命名空间。

英文:

> First of all, is it possible to dlopen a second version of a shared library at runtime

Yes, so long as the two libraries differ in their SONAME (which they probably don't, but you can binary-patch one or both).

However, doing that is really bad idea -- the two libraries are exceedingly likely to define the same set of symbols, and the linux rules are that the first definition wins.

Doing this will probably cause very hard to debug crashes.

Effectively what's happened here is that you have two libraries with the same SONAME, but different ABI (we know the ABI's are different because if they weren't, you would not have gotten unresolved symbols -- it would all have just worked).

> and how do I tell dlopen to ignore the RPATH from my_executable

You can't. But you can dlopen() the other libsqlite3.so.0 using absolute path (provided it has different SONAME).


Your best bet is probably to do what n.m. suggested: use dlmopen in your main program to load your version of libsqlite3.so.0 into a separate loader namespace.

huangapple
  • 本文由 发表于 2023年6月15日 20:18:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76482388.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定