mar*_*usm 10 linux installation elf relocation dynamic-linking
我想要发布和归档二进制文件(带有库的可执行文件),它们向后和向前兼容尽可能多的 Linux 发行版,并且整个包可重定位。libc
据我了解,还需要提供系统库,因为给定不同版本的libc
. 同时libc
似乎是耦合的ld-linux
(例如,在 Debian 测试上编译的二进制文件已经无法在 Ubuntu 18.04 LTS 上工作),所以我ld-linux
也需要打包。
我的解决方案是将所有可执行文件和库放入一个目录并将 rpath 设置为$ORIGIN
(通过使用 链接-Wl,rpath=$ORIGIN
或设置chrpath
或patchelf
)。这使得库可以与可执行文件一起重定位,并且适用于除ld-linux
链接器本身之外的所有库。
可以通过以下方式更改动态链接器路径-Wl,--dynamic-linker=/my/path/ld-linux.so
或设置它patchelf
,但路径必须是绝对路径:
$ORIGIN
不起作用./
有效,但仅当当前目录与加载器本身相同时才有效(从其他地方启动时,可执行文件会因错误而崩溃)/my/path/ld-linux.so /my/path/myexecutable $@
,但这意味着我想避免另一层间接和开销。有没有办法将ld-linux相对于可执行文件的路径直接设置为可执行文件?
也许有一种方法可以静态链接 ld-linux 加载程序?
据我了解,像 libc 这样的系统库也需要提供,因为给定不同版本的 libc 时可执行文件会崩溃。
这是不正确的:GLIBC 保证向后兼容性(在旧系统上构建的可执行文件将继续在较新版本的 GLIBC 上运行)。
实现您想要的目标的唯一明智的方法是针对您希望支持的最旧版本的 GLIBC 进行编译。
同时 libc 似乎与 ld-linux 结合在一起
正确:libc.so.6
和ld-linux
是 GLIBC 的一部分,必须来自同一版本,任何不匹配都可能导致灾难性故障(SIGSEGV
insidelibc.so.6
或 inside ld-linux
)。
我也需要打包 ld-linux 。
这很复杂: 的绝对路径ld-linux
被硬编码到a.out
, 中并且无法更改。制作一个可以容忍 a.out
路径更改的可重ld-linux
定位是不可能的(缺少您已经尝试过的显式加载程序调用;这对于重新执行自身的可执行文件来说效果不佳)。
更新:
我可以尝试在旧的 Ubuntu LTS 上构建并获得大部分向后兼容性,但随后我不会获得新的 C++17 编译器,这基本上违背了现代软件工程的全部要点。
您可以在旧系统上安装更新的编译器,并使用旧的 GLIBC 获取 C++17。
这样做的一个困难是您可能需要更新的libstdc++.so.6
.
好消息是-Wl,-rpath=$ORIGIN
工作正常——只有 GLIBC 很难重新定位。您还可以将可执行文件链接libstdc++.a
到--static-libstdc++
.
但是,执行任一操作都可能会产生许可问题(但您的计划已经包括分发所有库,因此这个问题并不新鲜)。