尝试使用 dlopen 加载库时未定义的符号

Posted

技术标签:

【中文标题】尝试使用 dlopen 加载库时未定义的符号【英文标题】:Undefined symbol when trying to load a library with dlopen 【发布时间】:2012-01-11 23:13:33 【问题描述】:

我正在尝试加载我在 Linux ARM 平台下使用 dlopen 提供(封闭源代码)的共享库(插件)。我正在尝试以这种方式加载:

void* handle = dlopen(<library_path>/<library_name>, RTLD_NOW);

结果是失败并显示此消息:

Failed to load <library_path>/<library_name>: undefined symbol: <symbol_name>.

我试图用 nm 查看库内部,但似乎库已被剥离,找不到符号。我也试过用readelf -s,其实我得到了这样的结果:

12663: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND <symbol_name>

通过阅读,我了解到 readelf -s 返回所有符号,包括在它引用的库中定义的那些符号。

this 问题的答案对我来说并不完全清楚:这是一个应该在库中的符号,而它不存在是因为它以错误的方式编译还是我应该是这个符号找别的地方? readelf -d 的输出似乎表明我提供了所有需要的共享库。此错误可能与我编译可执行文件的方式错误有关,还是与加载程序无关?

另外,我阅读了每一列的含义,但这些值很奇怪。您如何解释该符号描述?为什么地址是0?为什么是 NOTYPE 类型?

【问题讨论】:

使用nm -D 而不仅仅是nm 您是否特别应该使用RTLD_NOW?否则,您可能只需要切换到RTLD_LAZY @n.m.:啊!我真的不知道。符号被列为:U . @DavidSchwartz:嗯,我不确定,但我认为最好了解为什么会发生这种情况并引起注意。无论如何,重点也是学习。 file &lt;name of so file&gt; 返回什么?如果我针对 /lib/libm-2.11.1.so 运行它,我会得到“ELF 32-bit LSB ...,剥离”并运行 nm /lib/libm-2.11.1.so 我会得到“无符号”。但是做什么@n.m。说,我得到一个函数列表。它们是可见的,否则任何程序将如何工作。 【参考方案1】:

如果应用程序的链接命令中静态库的顺序错误,也会出现此问题。 Unix ld 链接器要求在引用函数的库之后指定实现函数的库。

我在尝试构建 libtesseract 共享库时遇到了这个问题,该共享库从自定义位置获取 libz 库(不是来自主机的标准 libz,而是从源代码手动构建)。我在下面举了一个例子:

错误的链接顺序(-lz 在 -llept 之前):

$ g++  -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o  -Wl,--whole-archive ....(some libs) -Wl,--no-whole-archive  -L/home/build/jenkins/workspace/tesseract/zlib/bin/lib -L/home/build/jenkins/workspace/tesseract/leptonica/bin/lib -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/x86_64-linux-gnu -lz -llept -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o  -g -O2   -Wl,-soname -Wl,libtesseract.so.4 -o .libs/libtesseract.so.4.0.1

用“nm -D”检查:

$ nm -D .libs/libtesseract.so.4.0.1 | grep deflateInit
                 U deflateInit_

用“dlopen”检查:

Cannot load ./tesseract/src/api/.libs/libtesseract.so.4.0.1 (./tesseract/src/api/.libs/libtesseract.so.4.0.1: undefined symbol: deflateInit_)

发生这种情况是因为链接器正在循环中处理命令行中传递的所有静态库,并且跳过了那些没有被任何前面的库使用的静态库。由于在检查 libz.a 的那一刻,链接器发现所有已检查的库都没有使用 libz.a 中的任何函数,因此链接器只是“忘记”了 libz.a。

正确的链接顺序(-llept 之后的-lz):

$ g++  -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o  -Wl,--whole-archive ....(some libs) -Wl,--no-whole-archive  -L/home/build/jenkins/workspace/tesseract/zlib/bin/lib -L/home/build/jenkins/workspace/tesseract/leptonica/bin/lib -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/x86_64-linux-gnu  -llept -lz -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o  -g -O2   -Wl,-soname -Wl,libtesseract.so.4 -o .libs/libtesseract.so.4.0.1

用“nm -D”检查:

$ nm -D .libs/libtesseract.so.4.0.1 | grep deflateInit
000000000041fb5b T deflateInit_
000000000041fba3 T deflateInit2_

“dlopen”这次没有显示这个错误。

【讨论】:

【参考方案2】:

未定义符号:X 始终意味着 X 应该从已加载的库之一中导出,但事实并非如此。您应该找出请求的符号在哪个库中并链接到它。

您应该知道,此消息始终是库问题的结果,不是故障。图书馆应该知道如何获取它的所有符号。如果没有,您可以将您的可执行文件链接到所需的库,以便在加载插件时,请求的符号是已知的。

此错误可能有更复杂的原因。如果插件和主应用程序都链接到库,那么尝试链接它可能会以未定义的符号结束。如果主应用程序和插件使用不同版本的库(即插件使用较新的库),则可能会发生这种情况。然后在加载插件时旧版本已经加载,所以加载器假设一切正常,但新版本可能包含新符号。如果插件使用它们,你会得到未定义的符号错误。

【讨论】:

由于版本不匹配,我无法加载库。谢谢 +1

以上是关于尝试使用 dlopen 加载库时未定义的符号的主要内容,如果未能解决你的问题,请参考以下文章

为 C 库生成 Python SWIG 绑定时未定义的符号

尝试使用外部库时未定义的引用

erlang nif共享库上的未定义符号

在 Gradle Android 中实现自定义库时未解析类

_ctypes.cpython-39-x86_64-linux-gnu.so:未定义符号:使用 dlopen 加载的嵌入式 Python 中的 PyFloat_Type

尝试使用 Cython 扩展时未定义的符号