加载类-动态链接库返回了未定义的符号错误

时间:2019-04-05 01:12:48

标签: c++ linker shared-libraries dynamic-linking undefined-symbol

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

我尝试了一些简单的函数加载。一切都很好。但是,当我尝试加载返回指向类对象的指针的类和工厂函数时,这让我头疼。 (我正在使用下面教程中的术语)

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

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

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

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

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

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

我在这里缺少对一些关键概念的理解吗?

P.S。更奇怪的是,它能够解析lib * .so中的子类(U型符号)和父类之间的成员函数符号。为什么能做到这一点,却无法解析父类名称的未定义符号?

(我已经搜寻了很长时间,并尝试了-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”是否做得很好。无论如何,我都将其全部删除了。我知道这不是最好的方法,但是稍后我会担心速度在一切正常的情况下。 :)

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

最终更新: 对于对C / C ++程序如何执行以及如何链接库感兴趣的程序员,这里是Xeno Kovah撰写的很好的参考网络课程(二进制生活):http://opensecuritytraining.info/LifeOfBinaries.html

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

1 个答案:

答案 0 :(得分:0)

  

尽管存在名称修饰,符号名称却完全相同。我只是想知道为什么动态链接器无法链接它们?

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

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

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

有机会,您会看到lib*.so: U _ZTI7ParentBox,而main-prog中什么也没有。

之所以会发生这种情况,是因为链接器通常不会从main-prog导出任何符号,而该符号不会被参与该链接的某些共享库所引用(并且您的lib*.so未与{{1}链接) },否则您不需要main-prog

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

  

尝试-rdynamic

这等效于main-prog,并且应该可以工作(假设您将其添加到了-Wl,--export-dynamic链接行中,而不是其他位置)。

更新

  

现在一切正常!由于main-prog也依赖于其他一些对象,因此似乎将-rdynamic添加到最终的main-prog链接中并不能解决问题。我们需要在那些依赖对象的编译中添加“ -rdynamic”。

那是错误的解决方案。您的问题是main-prog告诉编译器将进入-fvisibility=hidden的所有符号标记为 not 导出的,而main-prog不会导出任何隐藏的符号。 / p>

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