dlopen 不尊重 `RTLD_LOCAL`?

dlopen doesn't respect `RTLD_LOCAL`?

我有 A.so,它链接到其自己目录中的特定版本 libstdc++.so.6(通过 rpath 设置为 $ORIGIN)。

如果我 dlopen A.so 一个人,它工作正常。

如果我dlopen我的系统libstdc++.so.6(不同版本)处于RTLD_LOCAL模式,然后dlopenA.so

OSError: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by A.so)

为什么 dlopen 不尊重 RTLD_LOCAL

Why doesn't dlopen respect RTLD_LOCAL

RTLD_LOCAL并不代表你想的那样。来自 man dlopen:

RTLD_LOCAL
          This is the converse of RTLD_GLOBAL, and the default if
          neither flag is specified.  Symbols defined in this shared
          object are not made available to resolve references in
          subsequently loaded shared objects.

请注意,这没有关于加载程序正在加载的库。

加载程序将永远不会加载给定SONAME的多个实例(除非您使用dlmopen使用不同的链接器范围),所以当你dlopen系统libstdc++.so.6,那就是只有libstdc++.so.6你会永远得到。当你稍后dlopen("A.so", ...)时,运行时加载器:

  1. 寻找A.so依赖的库,发现libstdc++.so.6在其中,发现已经加载了libstdc++.so.6 ,所以它不会搜索,也不会加载另一个副本,
  2. 查找 A.so 需要的 版本 符号。正是在这一点上你得到了错误,因为 A.so 需要来自 libsstdc++.so.6GLIBCXX_3.4.20,并且因为已经加载的系统 libstdc++.so.6 较旧并且不提供 GLIBCXX_3.4.20版本。
  3. 由于第 2 步失败,您的 dlopen 被拒绝。

请注意,您永远无法解析 libstdc++.so.6 中的 任何 符号(其中 RTLD_LOCAL 很重要);你在 之前就失败了。

现在,您可能试图做的是构建A.so,使其可以动态加载到任意程序中,可能是使用libstdc++.so.6 的旧版本,无需强制最终用户更新系统 libstdc++.so.6。不幸的是,这根本无法完成。