繁体   English   中英

如何将elf解释器(ld-linux.so.2 / ld-2.17.so)构建为静态库?

[英]How to build the elf interpreter (ld-linux.so.2/ld-2.17.so) as static library?

如果我的问题不准确,我很抱歉,因为我没有很多与Linux相关的经验。 我目前正在从头开始构建Linux(主要遵循linuxfromscratch.org 7.3版的指南)。 我遇到了以下问题:构建可执行文件时,它会得到指向ELF解释器的硬编码路径。

readelf -l program

显示类似

[Requesting program interpreter: /lib/ld-linux.so.2]

我追踪到这个库ld-linux-so.2是glibc的一部分。 我对这种行为不太满意,因为它使二进制文件非常不可移植-如果我更改/lib/ld-linux.so.2的位置,则可执行文件将不再起作用,而我发现的唯一“修复”是使用patchelf NixOS实用程序将硬编码路径更改为另一个硬编码路径。 出于这个原因,我想链接到l​​d库的静态版本,但是不会生成。 所以这是我的问题,请您解释一下如何构建glibc,以便它将生成ld-linux.so.2的静态版本,以后可以将其链接到我的可执行文件。 我不完全了解此ld库的功能,但是我认为这是加载其他动态库(或至少是glibc.so)的部分。 我想动态链接我的可执行文件,但我希望将动态链接器本身静态地内置到它们中,因此它们将不依赖于硬编码路径。 或者,我希望能够使用类似于LD_LIBRARY_PATH,也许是LD_INTERPRETER_PATH的环境变量来设置解释器的路径。 目标是能够产生可移植的二进制文件,无论目录结构如何,该二进制文件都可以在具有相同ABI的任何平台上运行。

可能相关的一些背景:我正在使用Slackware 14 x86来构建i686编译器工具链,因此总的来说,这都是x86主机和目标。 我正在使用glibc 2.17和gcc4.7.x。

我希望能够使用类似于LD_LIBRARY_PATH,也许是LD_INTERPRETER_PATH的环境变量来设置解释器的路径。

这根本不可能。 仔细阅读(并多次阅读) execve(2)elf(5)ld.so(8)手册页以及Linux ABIELF规范。 还有执行execve的内核代码。

ELF解释器负责动态链接。 它必须是文件层次结构中某个固定位置的文件(通常是静态链接的ELF共享库)(通常是/lib/ld.so.2/lib/ld-linux.so.2/lib64/ld-linux-x86-64.so.2 /lib/ld-linux.so.2 /lib64/ld-linux-x86-64.so.2

1990年代的旧a.out格式具有内置的动态链接器,部分在旧的Linux 1.x内核中实现。 它没有那么灵活,也没有那么强大。

内核通过这种(原则上)任意的动态链接器路径,使之具有各种动态链接器。 但是大多数系统只有一个。 这是参数化动态链接器的好方法。 如果您想尝试另一个,请将其安装在文件系统中并生成提及该路径的ELF可执行文件。

付出巨大的努力和精力,您可能会希望像自己的ld.so的动态链接器实现LD_INTERPRETER_PATH愿望,但是该链接器仍然必须是位于文件树中某个固定位置的ELF共享库。

如果您希望系统不需要任何文件(在某些预定义和有线位置,例如/lib/ld.so /dev/null/sbin/init ...),则需要构建其所有可执行二进制文件静态地。 您可能希望(但是当前的Linux发行版通常不这样做)具有一些静态链接的可执行文件(例如/sbin/init/bin/sash ...),这些文件将使您能够修复损坏的系统。没有任何动态链接器。

顺便说一句, /sbin/init/bin/sh路径连接在内核本身内部 您可以在引导加载时将一些参数传递给内核(例如,使用GRUB)以覆盖默认值。 因此,即使内核也希望某些文件在此处!

正如我所评论的,您可能会考虑使用MUSL-Libc作为替代的Libc实现(提供其自己的动态链接器)。 另请阅读有关VDSOASLRinitrd的信息

在实践中,接受一个事实,即现代Linux和Unix期望使用一些非空文件系统...请注意,动态链接和共享库是一个巨大的进步(在1990年代Linux内核和发行版中这要痛苦得多)。

或者,定义您自己的二进制格式,然后制作一个内核模块或binfmt_misc条目来处理它。

顺便说一句,大多数(或全部)Linux是免费软件 ,因此您可以对其进行改进(但这将需要花费数月甚至数年的时间)。 请通过发布分享您的改进。

另请参阅Drepper的《撰写共享库的论文》; 还有这个问题

我遇到了同样的问题。 在我的情况下,我想将我的应用程序与不同于系统安装的GLIBC捆绑在一起。 由于ld-linux.so必须与GLIBC版本匹配,所以我不能简单地使用相应的GLIBC部署我的应用程序。 问题是我无法在没有所需GLIBC版本的较旧安装上运行我的应用程序。

可以使用--dynamic-linker = / path / to / interp修改加载程序解释器的路径。 但是,这需要在编译时进行设置,因此需要将我的应用程序安装在该位置(或者至少需要部署ld-linux.so,这与我的GLIBC一起使用,这与简单的安装方式背道而驰。 xcopy部署。

因此,需要的是一个$ ORIGIN选项,该选项与-rpath选项可以处理的选项等效。 这将允许完全动态的部署。

鉴于缺少动态解释器路径(在运行时),留下了两个选择:

a)在启动可执行文件之前,使用patchelf修改路径。 b)以可执行文件作为参数直接调用ld-linux.so。

这两个选项都不像可执行文件本身中的$ ORIGIN编译路径那样“集成”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM