ld-linux动态链接器/解释器的相对可执行路径

时间:2019-02-23 10:03:37

标签: linux installation elf dynamic-linking relocation

我想运送和归档二进制文件(带有库的可执行文件),这些二进制文件应与尽可能多的Linux发行版本向后和向前兼容,并且整个软件包都可重定位。 据我了解,还需要交付libc之类的系统库,因为在libc的其他版本下,可执行文件将崩溃。同时libc似乎与ld-linux耦合 (例如,在Debian测试中编译的二进制文件已经无法在Ubuntu 18.04 LTS上运行),因此我也需要打包ld-linux

我的解决方案是将所有可执行文件和库放入一个目录,并将rpath设置为$ORIGIN(通过与-Wl,rpath=$ORIGIN链接或通过chrpathpatchelf进行设置)。这样可以使这些库与可执行文件一起重新定位,并且可以对除链接器本身的ld-linux以外的所有库使用。

可以通过-Wl,--dynamic-linker=/my/path/ld-linux.so更改动态链接器路径,也可以使用patchelf设置动态链接器路径,但该路径必须是绝对路径:

  1. $ORIGIN技巧不起作用
  2. ./这样的相对路径有效,但仅当当前目录与加载器本身相同时(从其他位置启动时,可执行文件崩溃并出现错误)
  3. 我可以编写一个shell脚本来检测所有路径并使用/my/path/ld-linux.so /my/path/myexecutable $@启动可执行文件,但这意味着我还要避免另一层间接和开销。

是否可以将相对于可执行文件的ld-linux路径直接设置为可执行文件?

也许有一种方法可以静态链接ld-linux加载程序?

1 个答案:

答案 0 :(得分:0)

  

据我了解,像libc这样的系统库也需要交付,因为在使用其他版本的libc时,可执行文件将崩溃。

那是不正确:GLIBC保证了向后兼容性(在较旧版本的系统上构建的可执行文件将继续在较新版本的GLIBC上运行)。

实现所需目标的唯一明智方法是针对您希望支持的最旧版本的GLIBC进行编译。

  

同时libc似乎与ld-linux结合

正确的:libc.so.6ld-linux是GLIBC的一部分,必须来自同一内部版本,任何不匹配都可能导致灾难性的故障(内部的SIGSEGV libc.so.6ld-linux内部。)

  

我也需要打包ld-linux。

这很复杂:ld-linux absolute 路径被硬编码到a.out中,并且不能更改。使可重定位 a.out可以容忍对ld-linux路径的更改是不可能的(缺少您已经尝试过的显式加载程序调用;这对于可执行文件不起作用自己重新执行)。

更新

  

我可以尝试在旧的Ubuntu LTS上构建并获得大多数向后兼容性,但是后来我没有获得新的C ++ 17编译器,这基本上使现代软件工程学的观点败了。

可以在较旧的系统上安装较新的编译器,并使用较旧的GLIBC获得C ++ 17。

这样做的一个困难是您可能需要更新的libstdc++.so.6

好消息是-Wl,-rpath=$ORIGIN可以正常工作-只有GLIBC很难重定位。您也可以将libstdc++.a的可执行文件与--static-libstdc++链接。

但是,在任何一种情况下都可能涉及许可问题(但是,您的计划又一次已经包括分发所有库,因此,这不是新问题)。