gpt4 book ai didi

c++ - 加载类 - 动态链接库返回 undefined symbol 错误

转载 作者:行者123 更新时间:2023-12-03 12:47:19 52 4
gpt4 key购买 nike

我正在使用 C++ dlopen() 在我的主程序(在目录 B 中)中链接名为 lib*.so (在目录 A 中)的共享库。

我尝试了一些简单的函数加载。每件事都运作得很好。然而,当我尝试加载返回类对象指针的类和工厂函数时,这让我很头疼。 (我使用下面教程中的术语)

我使用的方法基于本教程第 3.3 章中的示例 https://www.tldp.org/HOWTO/C++-dlopen/thesolution.html#externC .

这里有一点多态性...... lib*.so 包含一个从主程序目录(目录 B)继承父抽象类的子类。当 dlopen() 尝试在主程序中加载 lib*.so 时,由于“ undefined symbol ”而失败。

我使用 nm 命令检查 lib*.so 和主程序二进制文件中的符号表。这些二进制文件中的符号是:

lib*.so : U _ZTI7ParentBox
主程序二进制文件:V _ZTI7ParentBox

ParentBox是lib*.so中ChildBox继承的父类的名称。请注意,父类头文件位于目录 B 中的另一个项目中。

尽管存在名称修改,但符号名称完全相同。我只是想知道为什么动态链接器无法链接它们?并给我 dlopen() 的 undefined symbol 错误?

我是否缺少对一些关键概念的理解?

附注更奇怪的是,它能够解析lib*.so中的子类(U型符号)(T型符号)和父类之间的成员函数符号。为什么可以做到这一点却无法解析父类名的 undefined symbol ?

(我已经搜索了很长时间并尝试了 -rdynamic、-ldl 的东西,尽管我不完全理解它们是什么,但没有任何效果)

2019 年 4 月 4 日更新:这是我用来制作主程序二进制文件的 g++ 命令行。

g++ -fvisibility=hidden -pthread -static-libgcc -static-libstdc++ \
-m64 -fpic -ggdb3 -fno-var-tracking-assignments -std=c++14 \
-rdynamic \
-o ./build/main-prog \
/some_absolute_path/ParentBox.o \
/some_other_pathen/Triangle.o \
/some_other_pathen/Circle.o \
/some_other_pathen/<lots_of_depending_obj> \
/some_absolute_path/librandom.a \
-lz -ldl -lrt -lbz2

我在 https://gcc.gnu.org/onlinedocs/gcc/Option-Index.html 中搜索了该命令行的每个参数(对于所有处理具有复杂 g++ 行的大型项目的程序员同事来说,这似乎是一个很好的引用站点:))

感谢@Employed Russian 。根据他的指示,问题缩小到导出主程序二进制文件中的符号。

但是,主程序二进制文件有很多依赖项,正如您从上面的命令、Circle、Triangle 和许多其他目标文件中看到的那样。我们还需要在 Circle、Triangle 等依赖对象文件的编译中添加“-rdynamic”。否则它不起作用。

就我而言,我向项目中的所有文件添加了“-rdynamic”以导出所有符号。不确定“-fvisibility=hidden”有什么好处。无论如何,我在我的 Makefile 中删除了所有这些...我知道这不是最好的方法,但稍后当一切功能正确时我会担心速度。 :)

更多更新:正确的解决方案在@Employed Russian 的答案更新中。我之前的解决方案恰好有效,因为我还删除了“-fvisibility=hidden”。没有必要(而且可能是错误的)将 -rdynamic 添加到最终链接中使用的所有对象中。请参阅@Employed Russian 的解释,它解决了核心问题。

最终更新:对于对 C/C++ 程序如何执行以及如何链接库感兴趣的程序员同行,这里有一个很好的引用网络类(class)(二进制的生命),作者是 Xeno Kovah:http://opensecuritytraining.info/LifeOfBinaries.html

您还可以在 YouTube 上找到播放列表。只需搜索“二进制的生命”

最佳答案

Although there is name mangling the symbol names are exactly the same. I'm just wondering why the dynamic linker cannot link them?

最可能的解释:该符号从主二进制文件中导出。

使用nm -D重复您的命令:

nm -AD lib*.so main-prog | grep ' _ZTI7ParentBox$'

很可能,您会看到 lib*.so: U _ZTI7ParentBoxmain-prog 中没有任何内容。

发生这种情况是因为链接器通常不会从 main-prog 导出任何符号,该符号未被参与链接的某些共享库引用(以及您的 lib*.so code> 未与 main-prog 链接,否则您不需要 dlopen 它)。

要更改该行为,您可以在链接 main-prog 时添加 -Wl,--export-dynamic 链接器标志。这指示链接器导出链接到 main-prog所有内容

tried -rdynamic

这相当于-Wl,--export-dynamic,并且应该有效(假设您将其添加到main-prog链接行,而不是某个地方其他)。

更新:

Everything works now! Since main-prog also depends on some other objects, it appears that simply add -rdynamic to the final main-prog linking does not resolve the problem. We need to add "-rdynamic" to the compilation of those depending objects.

这是错误的解决方案。您的问题是 -fvisibility=hidden 告诉编译器将进入 main-prog 的所有符号标记为导出,并且 -rdynamic 不导出任何隐藏符号。

正确的解决方案是从定义您想要导出的符号的任何对象中删除 -fvisibility=hidden,并添加 -rdynamic到最后的链接。

关于c++ - 加载类 - 动态链接库返回 undefined symbol 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55526965/

52 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com