c++ - 链接器似乎忽略了库并默认为旧版本

标签 c++ gcc linker shared-libraries linker-errors

我已经构建了一个共享库 (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

既然您了解了问题所在,您将如何解决它?

两种方式之一:

  1. 您可以更改 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是运行时加载程序将使用的内容。
  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/

相关文章:

object - ELF 和 PE 的基本链接过程如何工作

ubuntu - 如何在Ubuntu中简洁地链接库文件地址较长的文件

c - 从目标文件内联函数

c++ - 在 gcc 和 Visual C++ 中使用 '>>'

c++ - 是否可以使用 boost::thread 终止线程?

java - 我可以在崩溃的 OS API 周围放置 try/catch 吗?

c - 如何在 C 中链接目标文件? "Undefined symbols for architecture x86_64"失败

c - 警告 : cannot find entry symbol Reset_Handler

C++17 标准 - 抛弃 const of static

使用 pthread 时,使用全局变量的 C++ 显示比指针慢 100%?