覆盖默认的 /lib64/ld-linux-x86-64.so.2 来调用可执行文件

覆盖默认的 /lib64/ld-linux-x86-64.so.2 来调用可执行文件

我需要一个比我的系统提供的更新的 Glibc 来运行我想要运行的二进制文件。所以我有一个目录,/my_libs其中包含来自最新 Ubuntu 的大多数 lib 文件,包括新的 Glibc ( libc.so.6)。

现在我导出LD_LIBRARY_PATH=/my_libs:$LD_LIBRARY_PATH并尝试运行我的可执行文件。这将因 SEGFAULT 而崩溃。事实上,现在每个二进制文件都会因 SEGFAULT 而崩溃(即使是像 这样的简单事情/bin/ls)。所以我猜想来自 和我的主机系统的不同库之间存在一些混淆/my_libs。我用LD_DEBUG=libs(或LD_DEBUG=all) 进行跟踪并解决了除 之外的所有问题ld-linux-x86-64.so.2。无论我到目前为止做了什么,它总是使用/lib64/ld-linux-x86-64.so.2而不是/my_libs/ld-linux-x86-64.so.2

有没有办法设置路径ld-linux?据我了解,该库也是可执行文件,始终用于运行任何程序,而我的环境使用/lib64/ld-linux-x86-64.so.2

如果我直接运行/my_libs/ld-linux-x86-64.so.2 /bin/ls,它就可以工作。我也可以通过这种方式执行我的新二进制文件——我只需确保所有库都已在中提供/my_libs,或者系统中的库兼容。

那么,我该怎么做才能直接/bin/ls调用呢/my_libs/ld-linux-x86-64.so.2

一些相关的讨论是这里

请注意,我不想修补/bin/ls或使用其他二进制文件来实现该功能。

答案1

太长不看:如果您需要继续使用多个版本的就像我们许多人一样,那么要使用的一个关键工具是补丁精灵

通常,如果您在构建自己的程序时想要强制使用自己的程序解释器版本,那么您需要做的就是使用以下选项进行编译:

gcc -Wl,-dynamic-linker,/my/lib/ld-linux.so.2 ...

但这不适用于第三方实用程序和一些可自行执行的共享对象,因此您可以调用补丁对给定的 ELF 程序执行如下操作:

patchelf --set-interpreter /my/lib/my-ld-linux.so.2 someprogram

这不仅仅是一个编辑问题十六进制编辑旧的可执行文件并用新的解释器地址覆盖旧的解释器地址,两者的长度不必相同;补丁负责扩大您的可执行文件。

您还可以更改路径变量,如下:

patchelf --set-rpath /my_libs:$LD_LIBRARY_PATH someprogram 

我发现这比使用通常的命令包装器更方便LD_LIBRARY_PATH

至于执行,它肯定是Unix中最基本的系统调用:execve(文件名)执行给定的文件名。例如,你的 shell 通过调用执行家庭:首先分叉,然后生成子进程执行是命令(ls,cd,,...随便你怎么说)。大多数程序都需要动态链接库,例如ls

$ ldd $(which ls)
    linux-vdso.so.1 =>  (0x00007ffe3b0e7000)
    libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f1423dda000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1423a11000)
    libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f14237a0000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f142359c000)
    /lib64/ld-linux-x86-64.so.2 (0x0000563800043000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f142337f000)

当你加载时ls, 这是不是最先使用的二进制正常入口点,但是ld-linux相反:它负责加载所有未解析的必需库,然后将控制权转交给真正的应用程序,ls在这种情况下。它通过以下方式实现执行'程序文件。

我无法确切地说出您的程序崩溃的原因,但我会尝试检查所有调用的程序是否都需要相同的程序解释器;您可以通过检查以下输出来做到这一点:

    $ readelf -l /bin/ls

    Elf 文件类型为 EXEC(可执行文件)
    入口点 0x4049a0
    有 9 个程序头,从偏移量 64 开始

    程序头:
      类型偏移VirtAddrPhysAddr
                     FileSiz MemSiz 标志对齐
      PHDR 0x000000000000040 0x000000000400040 0x000000000400040
                     0x00000000000001f8 0x00000000000001f8 RE 8
      插值 0x0000000000000238 0x000000000400238 0x0000000000400238
                     0x000000000000001c 0x000000000000001c R 1
          [请求程序解释器:/lib64/ld-linux-x86-64.so.2]
    ...........................

(重点是我的……)。

编辑:作者之一的精彩讨论执行可以找到系统调用这里,相关内核代码为这里代码显示没有读取任何系统变量,并且例程加载_elf_二进制查看程序解释器点对点

答案2

我编写了一个 shell 脚本来实现@MariusMatutiae 提到的步骤。

给定一个ELF文件,将其所有依赖的文件复制到指定目录,并修改其所有依赖的动态库的信息到指定目录,特别是修改libc和loader的依赖关系。

github: https://github.com/EmptyWatson/linux_mk_selfdeps_run

相关内容