具有重复符号的C ++插件库的Segfault

时间:2009-11-30 17:20:46

标签: c++ gcc linker runtime shared-libraries

我有一个跨平台的C ++应用程序,它被分成几个共享库并从插件共享库中加载其他功能。插件库应该是自包含的,并且在不知道或不依赖于调用应用程序的情况下自行运行。

其中一个插件包含来自主应用程序的复制代码,因此包含与引擎中的代码名称重复的符号名称。 (是的,我知道这通常是禁止的,但在插件编写时,引擎是单片二进制文件,无法共享库。)在Windows上,一切运行正常。在Linux上我们得到了段错误。通过查看错误的堆栈跟踪,在调用重复类名中的函数时,它在插件中发生。它似乎是由于引擎和插件具有略微不同版本的共享代码(某些类功能在插件中被注释掉)。就好像插件将它的符号运行时链接到引擎而不是它自己。我们通过将dlopen的参数更改为dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL)来“修复”此问题。

但是当我们重写引擎被拆分为共享库时(为了最终在插件中重用),我们再次得到了段错误。并且看着堆栈跟踪,它来自引擎 - >插件 - >发动机。

有没有办法指定运行时链接器不将插件的符号映射到引擎(特别是如果它们是在插件中定义的那样)?

谢谢! 马特

<小时/> 编辑2009-12-3

我首先尝试将插件的代码包装在自己的命名空间中。这不起作用,因为它静态链接到也链接到引擎的库。静态库的版本是不同的,所以segfault!

然后我改变了引擎的构建,并且它的库是静态链接的。当我运行它时,我不再有问题。因此,它似乎是导出共享库符号然后在打开时动态重定位到插件中的结果。但是当所有引擎的代码都在一个可执行文件中时,它不会导出其符号(因此它不会尝试将插件的符号重定位到引擎中)。

我仍然有一个问题,因为有一个程序的并行版本(使用Open-MPI)并且仍然得到段错误。它似乎仍在导出引擎的符号并重新定位插件。这可能与Open-MPI如何执行应用程序有关。

是否有任何链接器标志可以在插件共享库上使用,它会告诉它不要在运行时动态重定位符号?或者隐藏它的符号,以便它们不被重新定位?我已经尝试-s(“省略所有符号信息”),但显然没有更改动态符号(使用nm -D <plugin>进行检查)。

3 个答案:

答案 0 :(得分:4)

我想我找到了解决方案,链接标志-Bsymbolic。本质上,此标志在共享库中添加一个标志,以告知运行时链接程序首先尝试解析其自身内的符号名称。当插件与该标志链接时,引擎能够在所有情况下使用插件运行(单片exe,exe w /共享库,插件w /和包装命名空间)。

似乎有一些批评者对-Bsymbolic发出警告:
http://www.technovelty.org/code/c/bsymbolic.html
http://software.intel.com/en-us/articles/performance-tools-for-software-developers-bsymbolic-can-cause-dangerous-side-effects/

但考虑到他们的警告以及该插件的意图,我认为这对我来说是正确的选择。至少现在。

答案 1 :(得分:1)

我同意Glen - 你不会真正解决这个问题,除非你修改类名,可能是通过命名空间。即使是36个文件也可能需要更少的时间进行修改,而不是尝试在不更改符号名称的情况下进行可靠修复。

首先确定需要调整名称的所有类。您的链接器可能已经为您列出了它们。然后我会至少暂时更改两个类的名称(从Foo到Engine :: Foo和Plugin :: Foo)。这样您就可以让编译器找到对有问题的类的所有引用。清除插件源,直到插件编译引用正确的新插件类名。完成后,将Engine :: classes更改回旧名称(除非您想永久修改引擎源,听起来就像你没有这样)。该插件现在应该编译并链接到正确的,唯一命名的类。

答案 2 :(得分:0)

我只想用PluginX命名空间包装所有插件的代码。这肯定会让你免于这些错误。 无论如何,这是一个非常好的,重要的练习。