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

时间:2015-03-20 20:29:16

标签: c++ c gcc arm cross-compiling

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

  

未定义的符号:_dl_hwcap

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

让我详细说明如何在libmyplugin.so上构建共享库(x86)。我使用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库。特别是,--no-as-needed是必需的,因为X11库并非module1.omodule2.o直接引用;相反,X11库仅由静态库引用。
  5. 请注意,以上所有设置均适用于x86。只是我不明白当程序试图在_dl_hwcap加载库时ARM符号未解决的原因是什么。

    您是否知道如何调查此问题?

2 个答案:

答案 0 :(得分:7)

有无数的事情可能会有问题,但这里有四条探索途径。我专注于链接行中的-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中,您可以查找感兴趣的符号: 例如,Is' initgc'在libpython中定义或使用?

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

' T'表示TEXT,或者是,它是在那里定义的。看看你是否可以使用grep和nm在感兴趣的模块中找到符号。 (A' 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)我有点担心你看到一个' .a'带有-shared选项的文件。有些编译器/链接器不能使用' .a' (存档)文件来创建' .so'文件。 '。所以'文件通常必须由其他' .so'文件或' .o'使用-fPIC编译的文件。

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

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

我希望这会有所帮助。

答案 1 :(得分:0)

我认为这个符号可能出现在" ld-lsb" " Xext"所需的图书馆。在我的系统上,库是一个符号链接" /lib64/ld-lsb-x86-64.so - > ld-linux-x86-64.so.2",但我确信这在手臂上是不一样的。也许在链接器线上旋转一下?