dlopen不遵守`RTLD_LOCAL`吗?

8
我有一个名为 A.so 的文件,它链接到一个特定版本的 libstdc++.so.6,该库在其自己的目录中(通过将 rpath 设置为 $ORIGIN)。
如果我只 dlopen A.so,那么它可以正常工作。
但是,如果我以 RTLD_LOCAL 模式打开系统中不同版本的 libstdc++.so.6,然后再打开 A.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选项?
1个回答

13

为什么dlopen不遵守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。不幸的是,这根本无法做到。


2
关于您最后一段的问题,使用dlmopen()不可能吗?显然,您不能在接口之间传递STL类型(即在使用不同实例的libstdc++.so的代码之间),但是在库内部进行私有使用不会起作用吗? - Droid Coder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接