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

发布于 2024-10-11 22:01:09 字数 852 浏览 6 评论 0原文

假设我

  • 在机器 A 上有: /usr/lib/libsomething.so.1
  • 机器 B 上的 /usr/lib/libsomething.so.2

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

如果我使用 gcc-lsomething (甚至 /usr/lib/libsomething.so)链接,它将遵循符号链接,并且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 或其他任何东西延迟加载。我希望它在编译时链接到共享对象。

这可能吗?

Suppose I have:

  • /usr/lib/libsomething.so.1 on machine A;
  • /usr/lib/libsomething.so.2 on machine B.

Both machines have /usr/lib/libsomething.so symlinking to their respective libs.

If I link using gcc with -lsomething (or even /usr/lib/libsomething.so) it will follow the symlink, and ldd on machine A produces something like:

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

This means it won't be able to find the library on machine B.

Now I know these are major version number changes and I know they may not be compatible, but I'm willing to take that risk. What I'd like to tell the linker is to look for libsomething.so, and don't follow the symlink so ldd will show

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

on A but

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

on B. And then the loader will follow the symlink to whatever version is there.

Also, I don't want delayed loading with dlopen or anything. I want it to link to the shared object at compile time.

Is this even possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不即不离 2024-10-18 22:01:09

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

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

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

根据共享库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)将选择无版本控制的符号链接,无论它指向何处:

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

。Linux 动态加载程序 (ld.so) 根据可执行文件中写入的 soname 值解析库(ELF NEEDED< /代码>)。该值是在构建可执行文件时从库文件 (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) 库 soname: [libsomething.so]
    
    readelf -a libsomething.so.2 | grep SONAME
    0xNNNNNNNN (SONAME) 库 soname: [libsomething.so]
    
  • 将库安装到各自计算机的 /lib/ 目录下。在两台计算机上运行 ldconfig -v 并验证输出。

    <前><代码>ldconfig -v 2>&1 | grep 一些东西
    libsomething.so ->; libsomething.so.1(已更改)

    ldconfig -v 2>&1 | ldconfig -v 2>&1 | grep 一些东西
    libsomething.so ->; libsomething.so.2(已更改)

  • 编译可执行文件并确保它引用相同的soname,但NEEDED中没有版本。

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

    ldd 可执行文件
    libsomething.so =>; /lib/libsomething.so (0xNNNNNNNN)
    

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

Making executable which uses any available version of shared library is, of course, possible.

The problem was that you linked your executable to version-specific soname (libsomething.so.1 and libsomething.so.2). You should have done it with unversioned soname libsomething.so instead.

In order to achieve this, on the build machine you should compile and install library with soname (ELF SONAME) equal to libsomething.so (without version) so that linker can choose this soname while executable is built.

According to the Shared Libraries HOWTO, you can pass required unversioned soname while building the library:

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

Then, as soon as you install the library and run ldconfig, you have:

  • symlink /lib/libsomething.so pointing to /lib/libsomething.so.1 on machine A;
  • symlink /lib/libsomething.so pointing to /lib/libsomething.so.2 on machine B.

The loader (run ldd) will choose unversioned symlinks regardless where it points to:

  • libsomething.so => /lib/libsomething.so (0xNNNNNNNN) on machine A;
  • libsomething.so => /lib/libsomething.so (0xNNNNNNNN) on machine B.

Linux dynamic loader (ld.so) resolves libraries based on their soname value written in the executable (ELF NEEDED). The value is copied from library file (ELF SONAME) while building the executable. As long as there is a symlink on the target system matching the soname recorded in the executable, the library pointed by this symlink will be loaded.


Let's run through your setup and show commands to verifing assumptions.

I used Fedora 18 X86_64 for the test and adjusted output to i686 for clarity.

  • Compile both libsomething.so.1 and libsomething.so.2. Make sure SONAME is set to unversioned 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]
    
  • Install the libraries into their respective machines under /lib/ directory. Run ldconfig -v on both machines and verify the output.

    ldconfig -v 2>&1 | grep something
    libsomething.so -> libsomething.so.1 (changed)
    
    ldconfig -v 2>&1 | grep something
    libsomething.so -> libsomething.so.2 (changed)
    
  • Compile executable and make sure that it refers to the same soname without version in NEEDED.

    readelf -a executable | grep NEEDED
    0xNNNNNNNN (NEEDED)             Shared library: [libsomething.so]
    
  • You executable depends on unversioned libsomething.so now. Copy executable to both machines and run ldd against both copies.

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

    The last output is the same on both machines as the executable was built with soname without version. This makes loader take unversioned symlinks on targets machines. And depending on the machine, the symlink can point to different implementation of the library libsomething.so.1 or libsomething.so.2.

从﹋此江山别 2024-10-18 22:01:09

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

而且无论如何也不应该找到。

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

无论 ld 最终打开什么文件,它都将使用 DTNAME/SONAME 字段在程序中进行编码。如果您不想这样,请不要为 libsomething 配备 soname。但它很容易变得痛苦......从尝试运行程序时遇到不可用的符号开始。

This means it won't be able to find the library on machine B.

And it's not supposed to anyway.

By the very definition of soversions, libsomething.so.2 denotes that the API/ABI is incompatible to libsomething.so.1. Therefore, just adding libsomething.so in the program's table of libraries to be loaded would be factually wrong. The libsomething.so symlink merely serves as a hint to ld as to which soversion to pick by default.

Of whatever file ld actually ended up opening, it will take the DTNAME/SONAME field to encode in the program. If you don't want that, don't equip libsomething with a soname. But it can easily become pain... starting with running into unavailable symbols when trying to run the program.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文