我正在使用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上找到播放列表。只需搜索“二进制生命”
答案 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
添加到最终链接。