gpt4 book ai didi

GCC 链接到共享对象的链接器名称

转载 作者:行者123 更新时间:2023-12-02 18:36:15 26 4
gpt4 key购买 nike

假设我有:

  • /usr/lib/libsomething.so.1 在机器 A 上;
  • /usr/lib/libsomething.so.2 在机器 B 上。

两台机器都有 /usr/lib/libsomething.so 符号链接(symbolic link)到各自的库。

如果我使用 gcc-lsomething (甚至 /usr/lib/libsomething.so)链接,它将遵循符号链接(symbolic link),机器 A 上的 ldd 会生成如下内容:

libsomething.so.1 => /usr/lib/libsomething.so.1

这意味着它将无法在机器 B 上找到该库。

现在我知道这些是主要版本号更改,并且我知道它们可能不兼容,但我愿意冒这个风险。我想告诉链接器的是寻找 libsomething.so,并且不要遵循符号链接(symbolic link),这样 ldd 将显示

libsomething.so => /usr/lib/libsomething.so.1

在A但是

libsomething.so => /usr/lib/libsomething.so.2

在 B 上。然后加载程序将按照符号链接(symbolic link)到达那里的任何版本。

另外,我不想使用 dlopen 或其他任何东西延迟加载。我希望它在编译时链接到共享对象。

这可能吗?

最佳答案

制作使用任何可用版本的共享库的可执行文件当然是可能的。

问题是您将可执行文件链接到特定于版本的soname(libsomething.so.1libsomething.so.2) 。您应该使用未版本化的soname libsomething.so 来完成此操作。

为了实现这一点,在构建机器上,您应该编译并安装soname(ELF SONAME)等于libsomething.so(没有版本)的库,以便链接器可以在构建可执行文件时选择此soname。

根据Shared Libraries HOWTO ,您可以在构建库时传递所需的未版本化的soname:

gcc -shared -Wl,-soname,libsomething.so -o libsomething.so.X objectsomething.o

然后,一旦您安装了库并运行 ldconfig,您就可以:

  • 符号链接(symbolic link)/lib/libsomething.so指向机器A上的/lib/libsomething.so.1
  • 符号链接(symbolic link)/lib/libsomething.so指向机器B上的/lib/libsomething.so.2

加载程序(运行ldd)将选择未版本化的符号链接(symbolic link),无论它指向何处:

  • libsomething.so =>/lib/libsomething.so (0xNNNNNNNN) 在机器 A 上;
  • libsomething.so =>/lib/libsomething.so (0xNNNNNNNN) 在机器 B 上。

Linux 动态加载器 (ld.so) 根据可执行文件中写入的 soname 值来解析库 (ELF NEEDED)。该值是在构建可执行文件时从库文件 (ELF SONAME) 复制的。只要目标系统上存在与可执行文件中记录的soname匹配的符号链接(symbolic link),就会加载该符号链接(symbolic link)指向的库。

<小时/>

让我们运行一下您的设置并显示命令来验证假设。

我使用 Fedora 18 X86_64 进行测试,并为了清晰起见将输出调整为 i686

  • 编译 libsomething.so.1libsomething.so.2。确保 SONAME 设置为未版本化的 libsomething.so:

    readelf -a libsomething.so.1 | grep SONAME
    0xNNNNNNNN (SONAME) Library soname: [libsomething.so]

    readelf -a libsomething.so.2 | grep SONAME
    0xNNNNNNNN (SONAME) Library soname: [libsomething.so]
  • 将库安装到各自计算机的 /lib/ 目录下。在两台计算机上运行 ldconfig -v 并验证输出。

    ldconfig -v 2>&1 | grep something
    libsomething.so -> libsomething.so.1 (changed)

    ldconfig -v 2>&1 | grep something
    libsomething.so -> libsomething.so.2 (changed)
  • 编译可执行文件并确保它引用相同的soname,但NEEDED中没有版本。

    readelf -a executable | grep NEEDED
    0xNNNNNNNN (NEEDED) Shared library: [libsomething.so]
  • 您的可执行文件现在依赖于未版本化的libsomething.so。将可执行文件复制到两台计算机并针对两个副本运行 ldd

    ldd executable
    libsomething.so => /lib/libsomething.so (0xNNNNNNNN)

    最后的输出在两台机器上是相同的,因为可执行文件是使用 soname 构建的,没有版本。这使得加载程序在目标机器上采用未版本化的符号链接(symbolic link)。根据机器的不同,符号链接(symbolic link)可以指向库 libsomething.so.1libsomething.so.2 的不同实现。

关于GCC 链接到共享对象的链接器名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4685493/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com