[英]bash: ./loopy: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
[英]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实用程序将硬编码路径更改为另一个硬编码路径。 出于这个原因,我想链接到ld库的静态版本,但是不会生成。 所以这是我的问题,请您解释一下如何构建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 ABI和ELF规范。 还有执行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实现(提供其自己的动态链接器)。 另请阅读有关VDSO和ASLR和initrd的信息 。
在实践中,接受一个事实,即现代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.