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

Alb*_*ert 10 linux

我需要一个比我的系统为我想要运行的二进制文件提供的更新的 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

一些相关的讨论是here

请注意,我不想修补/bin/ls或其他二进制文件来使其工作。

Mar*_*iae 10

Tl:dr:如果您需要像我们许多人一样继续使用多个版本的libc,那么要使用的一个关键实用程序是PatchElf

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

gcc -Wl,-dynamic-linker,/my/lib/ld-linux.so.2 ...
Run Code Online (Sandbox Code Playgroud)

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

patchelf --set-interpreter /my/lib/my-ld-linux.so.2 someprogram
Run Code Online (Sandbox Code Playgroud)

这不仅仅是用十六进制编辑器编辑旧的可执行文件并用新的解释器地址覆盖旧的解释器地址的问题,原因在于两者不必具有相同的长度;patchelf负责为您扩大可执行文件。

您还可以更改rpath变量,如下所示:

patchelf --set-rpath /my_libs:$LD_LIBRARY_PATH someprogram 
Run Code Online (Sandbox Code Playgroud)

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

至于execve,它必须是 Unix 中最基本的系统调用:execve(filename)执行给定的文件名。例如,您的 shell 通过调用execve系列来执行命令:它首先派生,然后由此生成的子进程execve的命令(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)
Run Code Online (Sandbox Code Playgroud)

当您加载ls 时,它不是首先使用的二进制普通入口点,而是ld-linux:它负责加载所有未解析的、需要的库,然后将控制权转移到实际应用程序中,ls在此案件。它通过执行此execve的“荷兰国际集团的程序文件。

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

    $ readelf -l /bin/ls

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

    程序标题:
      类型 Offset VirtAddr PhysAddr
                     FileSiz MemSiz 标志对齐
      PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
                     0x00000000000001f8 0x00000000000001f8 RE 8
      INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
                     0x000000000000001c 0x000000000000001c R 1
          [请求程序解释器:/lib64/ld-linux-x86-64.so.2]
    ……………………………………………………………………………………………………………………………………………………………………

(重点是我的......)。

编辑execveat系统调用的作者之一的精彩讨论可以在这里找到,相关的内核代码在这里。代码显示没有读取系统变量,例程load_elf_binary查看程序解释器PT_INTERP