C+上的Segfault+;具有重复符号的插件库 我有一个跨平台的C++应用程序,它被分成几个共享库,并从插件共享库中加载附加功能。插件库应该是自包含的,并且可以自己运行,而不需要知道或依赖于调用的应用程序

C+上的Segfault+;具有重复符号的插件库 我有一个跨平台的C++应用程序,它被分成几个共享库,并从插件共享库中加载附加功能。插件库应该是自包含的,并且可以自己运行,而不需要知道或依赖于调用的应用程序,c++,gcc,linker,runtime,shared-libraries,C++,Gcc,Linker,Runtime,Shared Libraries,其中一个插件包含从主应用程序复制的代码,因此包含与引擎中的符号名称重复的符号名称。(是的,我知道这通常是否定的,但在编写插件时,引擎是一个单片二进制文件,无法共享库。)在Windows上,一切运行正常。在Linux上,我们遇到了错误。通过查看错误的堆栈跟踪,它是在插件中以重复的类名调用函数时发生的。这似乎是引擎和插件共享代码版本略有不同的结果(一些类功能在插件中被注释掉)。这就好像插件将它的符号运行时链接到引擎的符号,而不是它自己的符号。我们通过将dlopen的参数更改为dlopen(pFile

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

但是,当我们重写引擎以将其拆分为共享库(最终目的是在插件中重用)时,我们再次得到segfault错误。查看堆栈跟踪,它来自引擎->插件->引擎

是否有一种方法可以指定运行时链接器不将插件的符号映射到引擎(特别是在插件中定义了符号的情况下)

谢谢! 马特


编辑日期:2009-12-3

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

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

尽管如此,我仍然有一个问题,因为有一个并行版本的程序(使用openmpi),并且仍然会出现segfault。它似乎仍然在导出引擎的符号并重新定位插件的位置。这可能与OpenMPI执行应用程序的方式有关


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

我同意Glen的观点-除非修改类名,可能通过名称空间,否则无法真正解决这个问题。即使修改36个文件,也可能比在不更改符号名称的情况下可靠地修复它花费更少的时间


首先确定需要调整名称的所有类。你的链接器可能已经为你列出了它们。然后我将至少暂时更改这两组类的名称(例如从Foo到Engine::Foo和Plugin::Foo)。这样,您就可以让编译器找到对有问题类的所有引用。在插件编译时引用正确的新插件类名之前,不断地搜索插件源代码。完成后,将Engine::Class更改回它们的旧名称(除非您也想永久性地修改Engine source,听起来您不想这样做)。插件现在应该编译并链接到正确的、唯一命名的类。

我只想用一个PluginX名称空间包装插件的所有代码。这肯定会帮你避免这些错误。
无论如何,这是一个非常好的、重要的实践。

我想我已经找到了解决方案,链接器标志
-b符号
。本质上,该标志在共享库中添加了一个标志,告知运行时链接器首先尝试在其自身内解析符号名称。当插件与该标志链接时,引擎能够在所有情况下(单片exe、exe w/shared libs、插件w/和w/o包装名称空间)与插件一起正常运行

似乎确实有一些诽谤者发出了关于
-b符号的警告:


但是考虑到他们的警告和插件的意图,我认为这是我的正确选择。至少现在是这样。

这些符号是全局的还是函数名?你能对代码做些小改动吗?它们是类和它们的成员函数。引擎代码库中使用了36个文件,所以我不想修改每个类名或文件。虽然最终的目标是重写插件,但由于时间限制和代码验证,如果不需要的话,我不想这么做。@CuppM,例如,您有一个类“Foo”,其成员“bar”定义在两个位置?在这两种情况下,“Foo”在同一名称空间中?如果是这样,这将永远不会为您正常工作。将其中一个“Foo”移到它自己的名称空间,生活就会更轻松。好吧,我有“Foo”、“FoosFriend”、“FoosUncleJim”等,我想让文件尽可能靠近源代码(以便更容易保持最新)。Linux处理共享库的方式是否让它变得不可能?链接器在构建库时是否应该正确映射符号(到自身)?为什么它要在运行时重新映射它们呢?虽然你可能是对的。但这不是一个令人满意的答案,所以我将暂时不回答这个问题,以防万一。我将修改插件代码,为有问题的bi添加名称空间