正在加载 类 - 动态 link 库返回未定义的符号错误
Loading classes - dynamical link library returned undefined symbol error
我正在使用 C++ dlopen() link 在我的主程序(在目录 B 中)中名为 lib*.so(在目录 A 中)的共享库。
我尝试了一些简单的函数加载。每件事都运作良好。但是,当我尝试加载 class 和 return 指向 class 对象的指针的工厂函数时,这让我很头疼。 (我使用的是下面教程中的术语)
我使用的方法基于本教程第 3.3 章中的示例 https://www.tldp.org/HOWTO/C++-dlopen/thesolution.html#externC。
这里有一点多态性……lib*.so 包含一个从主程序目录(目录 B)继承父抽象 class 的子 class。当 dlopen() 尝试在主程序中加载 lib*.so 时,由于 "undefined symbol" 而失败。
我使用nm 命令检查了lib*.so 和主程序二进制文件中的符号表。这些二进制文件中的符号是:
lib*.so : U _ZTI7ParentBox
主程序二进制文件:V _ZTI7ParentBox
ParentBox是lib*.so中ChildBox继承的父class的名称。请注意,父 class 头文件位于目录 B 中的另一个项目中。
尽管存在名称混淆,但符号名称完全相同。
我只是想知道为什么动态 linker 不能 link 他们?并给我 dlopen()?
的 undefeind 符号错误
我是不是错过了对一些关键概念的理解?
P.S。更奇怪的是,它能够解析 lib*.so(T 类型符号)中的子 class(U 类型符号)和父 class 之间的成员函数符号。为什么它能够执行此操作但无法解析父 class 名称的未定义符号?
(我已经搜索了很长时间并尝试了 -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 添加到最终 link 中使用的所有对象。
请参考@Employed Russian 对核心问题的解释。
最终更新:
对于对 C/C++ 程序如何执行以及库如何 linked 感兴趣的程序员,这是 Xeno Kovah 的一个很好的参考网络课程(Life of Binary):http://opensecuritytraining.info/LifeOfBinaries.html
您还可以在 youtube 上找到播放列表。只需搜索 "Life of Binary"
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 _ZTI7ParentBox
而没有来自 main-prog
。
发生这种情况是因为通常 linker 不会从 main-prog
导出任何符号,这些符号不会被参与 link 的某些共享库引用(以及您的 lib*.so
没有 link 与 main-prog
编辑,否则你不需要 dlopen
它)。
要更改该行为,您可以在 linking main-prog
时添加 -Wl,--export-dynamic
linker 标记。这指示 linker 导出 所有 linked 到 main-prog
.
tried -rdynamic
这相当于 -Wl,--export-dynamic
,并且应该有效(假设您将它添加到 main-prog
link 行,而不是其他地方)。
更新:
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
的符号标记为 not 导出,并且 -rdynamic
不导出任何隐藏的符号。
正确的解决方案是从定义您 想要导出的符号的任何对象中删除 -fvisibility=hidden
,并将 -rdynamic
添加到最终的 link.
我正在使用 C++ dlopen() link 在我的主程序(在目录 B 中)中名为 lib*.so(在目录 A 中)的共享库。
我尝试了一些简单的函数加载。每件事都运作良好。但是,当我尝试加载 class 和 return 指向 class 对象的指针的工厂函数时,这让我很头疼。 (我使用的是下面教程中的术语)
我使用的方法基于本教程第 3.3 章中的示例 https://www.tldp.org/HOWTO/C++-dlopen/thesolution.html#externC。
这里有一点多态性……lib*.so 包含一个从主程序目录(目录 B)继承父抽象 class 的子 class。当 dlopen() 尝试在主程序中加载 lib*.so 时,由于 "undefined symbol" 而失败。
我使用nm 命令检查了lib*.so 和主程序二进制文件中的符号表。这些二进制文件中的符号是:
lib*.so : U _ZTI7ParentBox
主程序二进制文件:V _ZTI7ParentBox
ParentBox是lib*.so中ChildBox继承的父class的名称。请注意,父 class 头文件位于目录 B 中的另一个项目中。
尽管存在名称混淆,但符号名称完全相同。 我只是想知道为什么动态 linker 不能 link 他们?并给我 dlopen()?
的 undefeind 符号错误我是不是错过了对一些关键概念的理解?
P.S。更奇怪的是,它能够解析 lib*.so(T 类型符号)中的子 class(U 类型符号)和父 class 之间的成员函数符号。为什么它能够执行此操作但无法解析父 class 名称的未定义符号?
(我已经搜索了很长时间并尝试了 -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 添加到最终 link 中使用的所有对象。 请参考@Employed Russian 对核心问题的解释。
最终更新: 对于对 C/C++ 程序如何执行以及库如何 linked 感兴趣的程序员,这是 Xeno Kovah 的一个很好的参考网络课程(Life of Binary):http://opensecuritytraining.info/LifeOfBinaries.html
您还可以在 youtube 上找到播放列表。只需搜索 "Life of Binary"
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 _ZTI7ParentBox
而没有来自 main-prog
。
发生这种情况是因为通常 linker 不会从 main-prog
导出任何符号,这些符号不会被参与 link 的某些共享库引用(以及您的 lib*.so
没有 link 与 main-prog
编辑,否则你不需要 dlopen
它)。
要更改该行为,您可以在 linking main-prog
时添加 -Wl,--export-dynamic
linker 标记。这指示 linker 导出 所有 linked 到 main-prog
.
tried -rdynamic
这相当于 -Wl,--export-dynamic
,并且应该有效(假设您将它添加到 main-prog
link 行,而不是其他地方)。
更新:
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
的符号标记为 not 导出,并且 -rdynamic
不导出任何隐藏的符号。
正确的解决方案是从定义您 想要导出的符号的任何对象中删除 -fvisibility=hidden
,并将 -rdynamic
添加到最终的 link.