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

时间:2019-04-13 10:32:41

标签: linux ld elf gas

我有一个独立于Linux的独立x86_64 hello世界:

main.S

.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

我可以组装并运行它:

as -o main.o main.S
ld -o main.out main.o
./main.out

由于受RIP relative load的影响,位置无关,所以我现在想link it as a PIE and see it get loaded at random addresses every time找点乐子。

首先我尝试:

ld -pie -o main.out main.o

但随后运行失败并显示以下信息:

-bash: ./main.out: No such file or directory

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

然后我在5.2.1“程序解释器”中得知,他实际上是推荐的System V AMD64 ABI解释器名称。

无论如何,我然后尝试通过以下方式强制解决问题:

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o main.out main.o

现在可以正常工作:我得到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

-static似乎没有什么区别:我仍然得到dynamic executables

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

所以我想当我实现自己想要的功能时,我将拥有一个有效的解释器,因此,我将使用自己最小的hello世界作为另一个程序的解释器。

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

相关问题:Compile position-independent executable with statically linked library on 64 bit machine,但其中提到了一个外部库,因此希望它是最小化和可回答的。

在Ubuntu 18.10中进行了测试。

1 个答案:

答案 0 :(得分:2)

您要将--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
  

所以我想当我实现自己想要的功能时,我将拥有一个有效的解释器,因此,我将使用自己最小的hello世界作为另一个程序的解释器。

我不确定我是否理解您的正确说法。如果您想将main.out用作解释器,那是错误的。

P.S。 GLIBC-2.27 -static-pie的{​​{3}},因此您不再需要借助汇编来获得静态链接的PIE二进制文件。但是您必须使用最新的GCC和GLIBC。