代码之家  ›  专栏  ›  技术社区  ›  CuppM

Segfault在具有重复符号的C++插件库中的应用

  •  7
  • CuppM  · 技术社区  · 16 年前

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

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

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

    马特


    编辑日期:2009-12-3

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

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

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

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

    3 回复  |  直到 16 年前
        1
  •  4
  •   CuppM    16 年前

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

    :
    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/

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

        2
  •  1
  •   Darryl    16 年前

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

    二者都 类集(例如,从Foo到Engine::Foo和Plugin::Foo)至少是暂时的。这样,您就可以让编译器找到对有问题类的所有引用。在插件编译时引用正确的新插件类名之前,不断地搜索插件源代码。完成后,将Engine::Class更改回它们的旧名称(除非您也想永久性地修改Engine source,听起来您不想这样做)。插件现在应该编译并链接到正确的、唯一命名的类。

        3
  •  0
  •   rmn    16 年前

    我会用一个PluginX名称空间来包装插件的所有代码。这肯定会帮你避免这些错误。