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

时间:2011-12-03 00:50:08

标签: c++ compilation linker shared-libraries dlopen

我正在尝试加载一个共享库(插件)我在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返回所有符号,包括在它引用的库中定义的那些符号。

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

另外,我读到了每列的含义,但这些值很奇怪。你如何解释这个符号描述?为什么地址为0?为什么键入NOTYPE?

2 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:0)

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

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

错误的链接顺序(-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 -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”这次没有显示此错误。