C++ 上的段错误具有重复符号的插件库

发布于 2024-08-12 22:01:11 字数 1080 浏览 6 评论 0原文

我有一个跨平台 C++ 应用程序,它分为多个共享库,并从插件共享库加载附加功能。插件库应该是自包含的并且独立运行,无需了解或依赖于调用应用程序。

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

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

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

谢谢! Matt


Edited 2009-12-3

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

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

但我仍然有一个问题,因为该程序有一个并行版本(使用 Open-MPI),并且仍然出现段错误。看来它仍在导出引擎的符号并重新定位插件的位置。这可能与 Open-MPI 执行应用程序的方式有关。

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

I have a cross platform C++ application that is broken into several shared libraries and loads additional functionality from plugin shared libraries. The plugin libraries are supposed to be self contained and function by themselves, without knowledge of or dependency on the calling application.

One of the plugins contains copied code from the main application, so contains symbol names that are duplicate to those in the engine. (Yes I know that's generally a no-no, but at the time the plugin was written the engine was a monolithic binary and couldn't share libraries.) On Windows, everything runs fine. On Linux we were getting segfaults. By looking at the stack trace of the error, it was occurring in the plugin when calling functions in the duplicate class name. It appeared to be a result of the engine and plugin having slightly different versions of the shared code (some class functionality was commented out in the plugin). It was as if the plugin was getting it's symbols runtime linked to the engine's instead of its own. We "fixed" the issue by changing the dlopen's parameters to be dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL).

But when we rewrote the engine to be split into shared libraries (for the eventual purpose of reuse in the plugins), we get the segfault error again. And looking at the stack trace, it goes from the engine -> plugin -> engine.

Is there a way to specify for the runtime linker to not map symbols of the plugin to the engine (especially if they are defined in the plugin)?

Thanks!
Matt


Edited 2009-12-3

I first tried to wrap the plugin's code in it's own namespace. That didn't work because it is statically linked to a library that is also linked to the engine. The versions of the static library are different, so segfault!

Then I changed the build of the engine and it's libraries to be statically linked. And when I run it, I no longer have the issue. So it appears it was a result of having the shared library symbols exported and then being dynamically relocated into the plugin when it was opened. But when all of the engine's code is in a single executable, it doesn't export its symbols (so it doesn't try to relocate the plugin's symbols into the engine).

I still have an issue though, as there is a parallelized version of the program (using Open-MPI) and that still gets the segfault. It appears in that it's still exporting the engine's symbols and relocating the plugin's. That might have to do with how Open-MPI executes the application.

Are there any linker flags that could be used on the plugin shared library that would tell it not to dynamically relocate the symbols at runtime? Or to hide it's symbols so they don't get relocated? I've tried -s ("Omit all symbol information") but that apparently didn't change the dynamic symbols (checked using nm -D <plugin>).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

萌逼全场 2024-08-19 22:01:11

我想我已经找到了解决方案,链接器标志 -Bsymbolic。本质上,此标志在共享库中添加一个标志,以告诉运行时链接器首先尝试解析自身内部的符号名称。当插件与该标志链接时,引擎能够在所有情况下(整体 exe、带共享库的 exe、带和不包装命名空间的插件)与插件一起正常运行。

似乎确实有一些批评者对 -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/

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

I think I've found the solution, the linker flag -Bsymbolic. Essentially this flag adds a flag in the shared library to tell the runtime linker to try and resolve symbol names within itself first. The engine was able to run with the plugin just fine in all cases (monolithic exe, exe w/ shared libs, plugin w/ and w/o wrapping the namespace) when the plugin was linked with that flag.

There does seem to be a few detractors with warnings about -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/

But considering their warnings and what the intention of the plugin is, I think it's the right option for me. At least for now.

始于初秋 2024-08-19 22:01:11

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

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

I agree with Glen - you aren't going to really solve this unless you modify the class names, possibly via namespaces. Even 36 files will probably take less time to modify than trying to reliably fix it without changing symbol names.

Start by identifying all the classes whose names need to be tweaked. Your linker probably lists them for you already. Then I would change the names of both sets of classes (from Foo to Engine::Foo and Plugin::Foo for example) at least temporarily. That way you can get the compiler to find all references to the problematic classes. Chug away at the plugin source until the plugin compiles with references to the correct new plugin class names. Once that is done, change the Engine:: classes back to their old names (unless you want to permanently modify engine source too, which it sounds like you don't). The plugin should now compile and link to the correct, uniquely named classes.

瑶笙 2024-08-19 22:01:11

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

I would just wrap ALL of the plugin's code with a PluginX namespace. That will surely save you from these errors.
It's a very good, important, practice anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文