【发布时间】:2009-11-30 17:20:45
【问题描述】:
我有一个跨平台的 C++ 应用程序,它被分成几个共享库并从插件共享库加载附加功能。插件库应该是自包含的并自行运行,无需了解或依赖于调用应用程序。
其中一个插件包含从主应用程序复制的代码,因此包含与引擎中的符号名称重复的符号名称。 (是的,我知道这通常是一个禁忌,但在编写插件时,引擎是一个单一的二进制文件,无法共享库。)在 Windows 上,一切运行良好。在 Linux 上,我们遇到了段错误。通过查看错误的堆栈跟踪,它是在插件中调用重复类名中的函数时发生的。这似乎是由于引擎和插件的共享代码版本略有不同(某些类功能在插件中被注释掉了)。就好像插件将它的符号运行时链接到引擎而不是它自己的。我们通过将dlopen 的参数更改为dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL) 来“修复”该问题。
但是当我们重写引擎以将其拆分为共享库时(为了最终在插件中重用),我们再次收到段错误错误。查看堆栈跟踪,它来自引擎 -> 插件 -> 引擎。
有没有办法指定运行时链接器不将插件的符号映射到引擎(特别是如果它们在插件中定义)?
谢谢! 马特
2009-12-3 编辑
我首先尝试将插件的代码包装在它自己的命名空间中。这不起作用,因为它静态链接到一个也链接到引擎的库。静态库的版本不一样,所以segfault!
然后我更改了引擎的构建和静态链接的库。当我运行它时,我不再有这个问题。因此,这似乎是导出共享库符号然后在打开插件时动态重定位到插件中的结果。但是当引擎的所有代码都在一个可执行文件中时,它不会导出其符号(因此它不会尝试将插件的符号重新定位到引擎中)。
我仍然有一个问题,因为有一个并行版本的程序(使用 Open-MPI)并且仍然会出现段错误。它似乎仍在导出引擎的符号并重新定位插件的符号。这可能与 Open-MPI 执行应用程序的方式有关。
是否有可以在插件共享库上使用的链接器标志,告诉它不要在运行时动态重定位符号?或者隐藏它的符号,这样它们就不会被重新定位?我试过-s(“省略所有符号信息”),但这显然没有改变动态符号(使用nm -D <plugin>检查)。
【问题讨论】:
-
这些符号是全局的还是函数名?你能对代码做些小改动吗?
-
它们是类和它们的成员函数。引擎代码库中使用了 36 个文件,因此我不想修改每个类名或文件。虽然最终目标是重写插件,但由于时间限制和代码验证,如果我不需要,我不想这样做。
-
@CuppM,例如,您有一个类“Foo”,其成员“bar”在 2 个地方定义?并且“Foo”在这两种情况下都在同一个命名空间中?如果是这样,这将永远不会为您正常工作。将其中一个“Foo”移动到它自己的命名空间中,生活会更轻松。
-
嗯,我有“Foo”、“FoosFriend”、“FoosUncleJim”等,我想将文件尽可能靠近源(以便更容易跟上日期)。 Linux 处理共享库的方式是否使其成为不可能?链接器不应该在库的构建时正确映射符号(到自身)吗?为什么它会尝试在运行时重新映射它们?
标签: c++ gcc linker runtime shared-libraries