我已经构建了一个共享库 (OpenSSL) 的调试版本,因此我可以使用调试器逐步执行某个函数,以更好地了解正在发生的事情。
但是,我很难真正链接到我构建的调试版本。出于某种原因,无论我做什么,链接器总是最终链接到预安装的系统版本,即使这两个版本都在 usr/lib
目录中,软链接(soft link)设置正确(AFAIK),并且我在编译时在命令行上明确指定了调试库。
所以共享库的原始(系统安装)版本是:
>ls /usr/lib/x86_64-linux-gnu/ -lh | grep libssl
lrwxrwxrwx 1 root root 15 Sep 23 2016 libssl.so -> libssl.so.1.0.0
-rw-r--r-- 1 root root 386K Sep 23 2016 libssl.so.1.0.0
我从源代码编译并配置为共享库(对所有目标文件使用 fPIcflags)的调试版本是:
>ls /usr/lib/ -lh | grep libssl
lrwxrwxrwx 1 root root 29 Oct 19 11:31 libssldebug.so -> /usr/lib/libssldebug.so.1.0.2
-rwxr-xr-x 1 root root 2.3M Oct 19 00:53 libssldebug.so.1.0.2
另外一个 OpenSSL 共享库 libcrypto 也是如此。我在 /usr/lib
中有一个 libcryptodebug.so.1.0.2 和相应的软链接(soft link)。
因此,我尝试构建一个可执行文件并像这样链接到调试共享库:
>g++ test.cpp -o test -std=c++14 -lssldebug -lcryptodebug -I openssl-1.0.2p/include/
它编译和链接没有错误。
然而...当我使用 ldd
检查可执行文件时,我看到:
>ldd test
linux-vdso.so.1 (0x00007ffcaa39b000)
libssl.so.1.0.0 => /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007ff717d37000)
libcrypto.so.1.0.0 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007ff71793b000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff717630000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff71732f000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff717119000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff716d6e000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff716b6a000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff717f98000)
因此,即使我明确链接了 -lssldebug
,并且编译和链接没有错误,ldd
仍然显示链接器出于某种原因正在链接非- 调试版本 (/usr/lib/x86_64-linux-gnu/libssl.so.1.0.0
)。我还尝试运行 ldconfig
然后重新编译/链接,但它仍然与旧(非调试)版本链接。
那么这里发生了什么?我做错了什么导致它默默地忽略命令行链接器参数并以某种方式默认使用非调试版本(它有一个完全不同的共享库名称!)不知何故?
最佳答案
So even though I explicitly linked with -lssldebug, and it compiled and linked with no errors, ldd still shows that the linker for some reason is linking with the non-debug version (/usr/lib/x86_64-linux-gnu/libssl.so.1.0.0
您混淆了静态链接和运行时加载(有时也称为动态链接)。
当您链接到 g++ test.cpp ... -lssldebug ...
时,您正在链接libssldebug.so
,但是(如 ldd
输出告诉您的那样)在运行时加载期间不使用该库。
发生这种情况是因为 libssldebug.so
有一个特殊的动态标签DT_SONAME
,其中包含 "libssl.so.1.0.0"
,并且静态链接器将那个名称记录为要在运行时加载的库。
您可以通过以下方式确认:
readelf -d libssldebug.so | grep SONAME
您可以检查运行时加载程序将尝试为给定可执行文件定位的库:
readelf -d ./test | grep NEEDED
既然您了解了问题所在,您将如何解决它?
两种方式之一:
- 您可以更改
SONAME
编码为libssldebug.so
, 通过将其与-Wl,--soname=libssldebug.so.1.0.2
重新链接,然后重新链接您的test
程序。使用上面readelf
验证SONAME
的命令和NEEDED
现在包含"libssldebug.so.1.0.2"
, 然后ldd
验证libssldebug.so.1.0.2
是运行时加载程序将使用的内容。 - 或者,安装
libssldebug.so
可能更简单进入不同的目录(比如/tmp/libssldebug
),创建一个符号链接(symbolic link)libssl.so.1.0.0 -> lissldebug.so
在该目录中,然后要求运行时加载程序首先使用g++ test.cpp ... -Wl,--rpath=/tmp/libssldebug
搜索该目录.使用此解决方案,可执行文件仍将搜索libssl.so.1.0.0
, 但它会在/tmp/libssldebug
中搜索它目录首先,然后会找到您的拷贝。
关于c++ - 链接器似乎忽略了库并默认为旧版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52895787/