对包含符号的.so进行dlopen导致未定义符号

时间:2018-08-24 02:42:42

标签: c++ linker shared-libraries dlopen undefined-symbol

问题

具体来说,我正在为应用程序使用cblas。我创建了一个使用foo.so作为子例程的cblas,然后我dlopen('foo.so', RTLD_LAZY)

这是我用来编译的标志(删除了一些-I标志):

g++-8 -std=c++17 -shared -O3 -xc++ 
    -ffast-math -fPIC -fopenmp -lcblas - -o /mnt/xxx/python/test.so

这是我在dlopen()上遇到的错误:

test.so: undefined symbol: cblas_dgemm

在这里我们看到cblas_dgemm中包含了.so

root@cd872c4b85ff:/mnt/xxx/python# objdump -TC test.so | grep cblas
0000000000000000      D  *UND*  0000000000000000              cblas_ddot
0000000000000000      D  *UND*  0000000000000000              cblas_dsyrk
0000000000000000      D  *UND*  0000000000000000              cblas_dgemm
0000000000000000      D  *UND*  0000000000000000              cblas_dgemv

但是在ldd中,它没有作为依赖项列出。

root@cd872c4b85ff:/mnt/xxx/python# ldd test.so
    linux-vdso.so.1 (0x00007ffdbb3c4000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f43f23a7000)
    libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f43f2177000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f43f1f5f000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f43f1b6e000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f43f17d0000)
    /lib64/ld-linux-x86-64.so.2 (0x0000562eb733a000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f43f15cc000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f43f13ab000)

我进行了一次测试编译,结果表明已成功找到-lcblas

g++-8 -lcblas -Wl,--verbose | grep blas
attempt to open /usr/lib/gcc/x86_64-linux-gnu/8/libcblas.so failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/8/libcblas.a failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libcblas.so succeeded
-lcblas (/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libcblas.so)
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status

什么起作用

重要的一点是,如果我将环境变量设置为LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libcblas.so,则可执行文件将正确运行。但是,这显然不是使可执行文件正常工作的正确方法。 -Wl,rpath=也不是正确的方式,因为cblas将驻留在不同的目录中(即,在OS X上它位于/usr/lib/libcblas.so中,而在ubuntu中它位于/usr/lib/x86_64-linux-gnu/libcblas.so中,我猜测将会有更多无法预测的位置。

可能是什么原因?我没有正确链接吗?动态链接器是否由于某种原因找不到符号?

由于部分信息已被删除,请让我知道是否需要任何信息,并将其添加到上面的信息中。谢谢。

编辑:符号确实存在于libcblas.so中:

root@3841c2760800:/usr/lib/x86_64-linux-gnu# nm -D libcblas.so | grep cblas_ddot
000000000000a0a0 T cblas_ddot
root@3841c2760800:/usr/lib/x86_64-linux-gnu# nm -D libcblas.so | grep cblas_dgemm
0000000000005790 T cblas_dgemm
root@3841c2760800:/usr/lib/x86_64-linux-gnu# nm -D libcblas.so | grep cblas_dgemv
00000000000077f0 T cblas_dgemv
root@3841c2760800:/usr/lib/x86_64-linux-gnu# nm -D libcblas.so | grep cblas_dsyrk
00000000000065f0 T cblas_dsyrk

编辑:

我相信依赖图看起来像:

main --(dlopens)--> test.so 
    --(includes)--> header-only linear algebra library 
    --(calls cblas subroutine)--> /usr/lib/x86.../libcblas.so

1 个答案:

答案 0 :(得分:0)

所以-这是因为我的链接的顺序。我要做的是将C ++文件(或字符串)流式传输到此g ++编译过程中。要进行流式传输,可以这样做:

ifelse

g++ ... -xc++ - ... 告诉-xc++它正在接收c ++文件(必须),而g++是文件字符串的占位符。在我的汇编中,我有:

-

这意味着它实际上未正确链接(linker_flags必须在文件名之后)。

我知道排序很重要,但是在这种情况下,当我在文件中流式传输时,我忘记了这一原理,这就是为什么未定义符号的原因。