Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
270 views
in Technique[技术] by (71.8m points)

ld - How to create a statically linked position independent executable ELF in Linux?

I have a working position independent Linux freestanding x86_64 hello world:

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
"
len = . - msg

which I can assemble and run with:

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

Since it is position independent due to the RIP relative load, now I wanted to link it as a PIE and see it get loaded at random addresses every time to have some fun.

First I tried:

ld -pie -o main.out main.o

but then running it fails with:

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

and readelf -Wa says that a weird interpreter /lib/ld64.so.1 was used instead of the regular one /lib64/ld-linux-x86-64.so.2 for some reason.

I then learnt that his is actually the recommended System V AMD64 ABI interpreter name at 5.2.1 "Program Interpreter".

In any case, I then try to force matters with:

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

and now it works: I get hello and the executable gets loaded to a different address every time according to GDB.

Finally, as a final step, I wanted to also make that executable be statically linked to make things even more minimal, and possibly get rid of the explicit -dynamic-linker.

That's what I could not do, and this is why I'm asking here.

If I try either of:

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 does not seem to make any difference: I still get dynamic executables.

After quickly glancing at the kernel 5.0 source code in fs/binfmt_elf.c I saw this interesting comment:

         * 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

so I guess when I achieve what I want, I will have a valid interpreter, and I'm so going to use my own minimal hello world as the interpreter of another program.

One thing I might try later on is see how some libc implementation compiles its loader and copy it.

Related question: Compile position-independent executable with statically linked library on 64 bit machine but that mentions an external library, so hopefully this is more minimal and answerable.

Tested in Ubuntu 18.10.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You want to add --no-dynamic-linker to your link command:

$ 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

so I guess when I achieve what I want, I will have a valid interpreter, and I'm so going to use my own minimal hello world as the interpreter of another program.

I am not sure I understood what you are saying correctly. If you meant that main.out would have itself as its interpreter, that's wrong.

P.S. GLIBC-2.27 added support for -static-pie, so you no longer have to resort to assembly to get a statically linked PIE binary. But you'll have to use very recent GCC and GLIBC.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...