9

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

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

结果是此消息失败:

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

我试图用 nm 查看库内部,但似乎 lib 已被剥离,找不到符号。我也尝试使用 readelf -s,事实上,我得到了这个结果:

12663: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND <symbol_name>

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

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

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

4

2 回答 2

6

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

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

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

于 2011-12-03T03:39:10.907 回答
4

如果应用程序的链接命令中静态库的顺序错误,也会出现此问题。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”这次没有显示这个错误。

于 2019-08-06T15:50:14.450 回答