'dlopen''ing 包含符号的 .so 会导致未定义的符号

`dlopen`'ing a .so that contains symbols results in undefined symbols

本文关键字:符号 未定义 so ing dlopen 包含      更新时间:2023-10-16

>问题

具体来说,我正在为我的应用程序使用cblas。我创建了一个使用cblas作为子例程的foo.so,我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

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

g++ ... -xc++ - ...

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

g++ ... linker_flags ...  -xc++ -

这意味着它实际上没有正确链接(linker_flags需要在文件名之后(。

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