如何在 Linux 中创建静态链接位置无关的可执行 ELF?

Cir*_*四事件 5 linux gnu-assembler elf ld

我有一个独立的 Linux 独立 x86_64 hello world 工作岗位:

电源

.text
.global _start
_start:
asm_main_after_prologue:
    /* Write */
    mov $1, %rax    /* syscall number */
    mov $1, %rdi    /* stdout */
    lea msg(%rip), %rsi  /* buffer */
    mov $len, %rdx  /* len */
    syscall

    /* Exit */
    mov $60, %rax   /* syscall number */
    mov $0, %rdi    /* exit status */
    syscall
msg:
    .ascii "hello\n"
len = . - msg
Run Code Online (Sandbox Code Playgroud)

我可以组装和运行:

as -o main.o main.S
ld -o main.out main.o
./main.out
Run Code Online (Sandbox Code Playgroud)

由于RIP 相对负载,它与位置无关,现在我想将它链接为 PIE,并看到它每次都以随机地址加载,以获得一些乐趣。

首先我试过:

ld -pie -o main.out main.o
Run Code Online (Sandbox Code Playgroud)

但随后运行它失败:

-bash: ./main.out: No such file or directory
Run Code Online (Sandbox Code Playgroud)

readelf -Wa说由于某种原因/lib/ld64.so.1使用了一个奇怪的解释器而不是常规解释器/lib64/ld-linux-x86-64.so.2

然后我了解到他实际上是5.2.1 "Program Interpreter" 中推荐的System V AMD64 ABI解释器名称。

无论如何,我然后尝试用以下方法强制处理:

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o main.out main.o
Run Code Online (Sandbox Code Playgroud)

现在它可以工作了:hello根据 GDB,我每次都将可执行文件加载到不同的地址。

最后,作为最后一步,我还想让该可执行文件静态链接,使事情变得更小,并可能摆脱显式的-dynamic-linker.

那是我做不到的,这就是我在这里问的原因。

如果我尝试以下任一方法:

ld -static -pie -o main.out main.o
ld -static -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o main.out main.o
Run Code Online (Sandbox Code Playgroud)

-static似乎没有任何区别:我仍然得到动态可执行文件

在快速浏览fs/binfmt_elf.c中的内核 5.0 源代码后,我看到了这个有趣的评论:

         * There are effectively two types of ET_DYN
         * binaries: programs (i.e. PIE: ET_DYN with INTERP)
         * and loaders (ET_DYN without INTERP, since they
         * _are_ the ELF interpreter). The loaders must
Run Code Online (Sandbox Code Playgroud)

所以我想当我实现我想要的时,我会有一个有效的解释器,我将使用我自己的最小 hello world 作为另一个程序的解释器。

我稍后可能会尝试的一件事是查看某些 libc 实现如何编译其加载程序并复制它。

相关问题:在 64 位机器上使用静态链接库编译位置无关的可执行文件,但提到了一个外部库,所以希望这是更小的和可回答的。

在 Ubuntu 18.10 中测试。

Emp*_*ian 5

您想添加--no-dynamic-linker到您的链接命令:

$ ld main.o -o main.out -pie --no-dynamic-linker

$ file main.out
main.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped

$ ./main.out
hello
Run Code Online (Sandbox Code Playgroud)

所以我想当我实现我想要的时,我会有一个有效的解释器,我将使用我自己的最小 hello world 作为另一个程序的解释器。

我不确定我是否理解您所说的正确。如果您的意思是main.out将其自身作为其解释器,那就错了。

PS GLIBC-2.27添加支持-static-pie,所以你不再需要求助于汇编获得静态链接PIE二进制文件。但是您必须使用最新的 GCC 和 GLIBC。