加载共享库时未定义的符号

在我的程序中,我需要使用dlopen()动态加载共享库。 程序和共享库都成功交叉编译为ARM体系结构,并在我的x86上安装了交叉编译器。 但是,每当程序尝试在ARM上运行时加载库时,它都会失败,并显示以下错误:

未定义的符号:_dl_hwcap

我找不到这个错误的罪魁祸首。

让我详细介绍如何在x86上构建共享库( libmyplugin.so )。 我使用g++交叉编译器如下:

 /home/me/arm/gcc-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ -march=armv7-a -mfloat-abi=hard -c -s -fPIC -o build/module1.o module1.cpp /home/me/arm/gcc-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ -march=armv7-a -mfloat-abi=hard -c -s -fPIC -o build/module2.o module2.cpp /home/me/arm/gcc-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ -o dist/libmyplugin.so build/module1.o build/module2.o --sysroot /home/me/arm/sysroot/ -Wl,--no-as-needed -ldl -lX11 -lXext /home/me/arm/libstatic.a -shared -s -fPIC 

请注意以下注意事项:

  1. module1.cppmodule2.cpp是我的源代码文件。
  2. libstatic.a是一个大型的对象.o文件存档,它实现了module1.cppmodule2.cpp直接调用/引用的东西。 这些目标文件已由其他人编译为与我相同的ARM体系结构,具有相同的编译器标志,但使用稍微更新的g++编译器( v4.9而不是我的v4.8.3 )。 不幸的是,我无法控制这些物体的构建。
  3. --sysroot /home/me/arm/sysroot/表示我的ARM OS的远程文件系统,本地g++交叉编译器在链接时可以从中获取本机库。
  4. -Wl,--no-as-needed -ldl -lX11 -lXext :当程序加载我的共享库时,需要这些标志来强制动态加载程序加载系统中存在的X11库。 特别是,因为X11库不是由module1.omodule2.o直接引用的, module1.o --no-as-needed 。 相反, X11库仅由静态库引用。

请注意,以上所有设置都适用于x86 。 只是我不明白当程序试图在ARM上加载库时, _dl_hwcap符号未解析的原因是什么。

你知道如何调查这个问题吗?

有无数的事情可能会有问题,但这里有四种探索途径。 我专注于链接行中的-shared,但最后一项也解决了这个问题。 (关于共享库的一个不错的HOWTO在这里: http : //tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

a)检查环境变量LD_LIBRARY_PATH。 由于您没有将RPATH用于链接器(RPATH嵌入.so的完整路径以便您可以在运行时找到它),因此链接器可以找到代码的唯一方法是搜索LD_LIBRARY_PATH。 确保您想要的.so或.0在路径中。

b)使用UNIX实用程序“nm”搜索该符号的.so(共享对象)和.a文件。 例如,’nm -D /usr/lib64/libpython2.6.so’将显示libpython.so中的所有动态符号,您可以查找感兴趣的符号:例如,在libpython中定义或使用的是’initgc’ ?

 % nm -D /usr/lib64/libpython2.6.so | grep initgc 000003404300cf0 T initgc 

‘T’表示TEXT,或者是,它在那里定义。 看看你是否可以使用grep和nm在感兴趣的模块中找到符号。 (’U’表示未定义,表示它在另一个模块中定义)。

c)另一个有用的工具是’ldd’。 它显示了您正在查看的库所依赖的所有动态库。 例如:

 % ldd /usr/lib64/libpython2.6.so linux-vdso.so.1 => (0x00007fffa49ff000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00000033f0200000) libdl.so.2 => /lib64/libdl.so.2 (0x00000033f0600000) libutil.so.1 => /lib64/libutil.so.1 (0x00000033fea00000) libm.so.6 => /lib64/libm.so.6 (0x00000033f0a00000) libc.so.6 => /lib64/libc.so.6 (0x00000033efe00000) /lib64/ld-linux-x86-64.so.2 (0x00000033efa00000) 

如果找不到库(因为它不在LD_LIBRARY_PATH上或未在RPATH中指定),则库将变为空。

d)我看到带有-shared选项的’.a’文件的链接线有点担心。 某些编译器/链接器不能使用“.a”(存档)文件来创建“.so”文件。 ‘.so’文件通常必须使用-fPIC编译的其他’.so’文件或’.o’文件。

我建议(如果可以的话),重新编译/home/me/arm/libstatic.a以便它是一个.so。 如果你不能这样做,你可能还必须使你的最终输出成为’.a’文件。 (换句话说,摆脱-shared命令行选项)。

总结:检查你的LD_LIBRARY_PATH,使用nm和ldd来查看.a和.so文件,但我认为最终结果是你可能无法组合.so和.a文件。

我希望这有帮助。

我认为这个符号可能位于“Xext”所需的“ld-lsb”库中。 在我的系统上,该库是一个符号链接“/lib64/ld-lsb-x86-64.so – > ld-linux-x86-64.so.2”,但我确信它在arm上是不一样的。 也许在你的链接器线上旋转一下?