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

时间:2011-01-13 21:29:26

标签: gcc linker ld shared-objects

假设我有:

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

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

如果我使用gcc-lsomething(或甚至/usr/lib/libsomething.so)进行关联,则会按照符号链接进行操作,而机器A上的ldd会产生如下内容:

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

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

现在我知道这些是主要的版本号更改,我知道它们可能不兼容,但我愿意冒这个风险。我想告诉链接器的是查找libsomething.so,不要按照符号链接,ldd将显示

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

在A但

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

在B.然后加载器将遵循符号链接到任何版本。

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

这甚至可能吗?

2 个答案:

答案 0 :(得分:8)

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

问题是您将可执行文件链接到特定于版本的 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,就会:

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

加载器(运行ldd)将选择无版本的符号链接,无论它指向何处:

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

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


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

为了清晰起见,我使用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)
    
  • 编译可执行文件并确保它引用NEEDED中没有版本的同一个soname。

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

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

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

答案 1 :(得分:2)

  

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

无论如何也不应该这样。

根据soversions的定义,libsomething.so.2表示API / ABI与libsomething.so.1不兼容。因此,在程序的要加载的库表中添加libsomething.so实际上是错误的。 libsomething.so符号链接仅作为ld提示默认选择哪个sovers。

无论实际最终打开的文件是什么,都需要DTNAME / SONAME字段在程序中进行编码。如果你不想那样,不要用libameomething装配一个soname。但它很容易变得很痛苦......从尝试运行程序时遇到不可用的符号开始。