Hi
I'm working with a very simple example and discovered the same problem. GCC emits LEA instructions to pass local C functions as parameter and MOV instructions to pass extern functions:
Code: Select all
lea 0x0(%rip),%rax
vs
mov 0x0(%rip),%rax
Then, the linker modify those lines into these ones
Code: Select all
lea -0x16(%rip),%rax
vs
mov $0x40103b,%rax
Which makes sense after objdump-ing the .elf
However, if I set --oformat=binary the linker produces this code
Code: Select all
lea -0x16(%rip),%rax
vs
mov 0xb(%rip),%rax
This MOV stores
the content of 0xb(%rip) into RAX while LEA stores -0x16(%rip) into RAX which makes no sense at all.
The question is why the linker doesn't replace 0x0(%rip) with a constant (just like with the .elf), o replaces the MOV with LEA.
If I add -pie to the linker, the .elf version replaces the MOV with LEA and fixes the 0x0(%rip) with 0xb(%rip) but the flat binary doesn't.
Below you can find a minimal example, instructions to reproduce as well as the results I got.
c_code.c
Code: Select all
#include <stdint.h>
void take_func(uint64_t offset) {
}
int c_func() {
return 0x101010;
}
extern int extern_func();
void _start() {
take_func((uint64_t)&c_func);
take_func((uint64_t)&extern_func);
}
extern_code.c
Code: Select all
int extern_func() {
return 0x111111;
}
compile
Code: Select all
x86_64-linux-gnu-gcc -c c_code.c -o c_code.o
x86_64-linux-gnu-gcc -c extern_code.c -o extern_code.o
x86_64-linux-gnu-ld --oformat=binary *.o -o linked.bin
x86_64-linux-gnu-ld --oformat=elf64-x86-64 *.o -o linked.elf
I'm working with this Docker container: agodio/itba-so-multi-platform:3.0
objdump -D c_code.o
Code: Select all
000000000000000b <c_func>:
b: 55 push %rbp
c: 48 89 e5 mov %rsp,%rbp
f: b8 10 10 10 00 mov $0x101010,%eax
14: 5d pop %rbp
15: c3 ret
0000000000000016 <_start>:
16: 55 push %rbp
17: 48 89 e5 mov %rsp,%rbp
1a: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # 21 <_start+0xb>
21: 48 89 c7 mov %rax,%rdi
24: e8 00 00 00 00 call 29 <_start+0x13>
29: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # 30 <_start+0x1a>
30: 48 89 c7 mov %rax,%rdi
33: e8 00 00 00 00 call 38 <_start+0x22>
38: 90 nop
39: 5d pop %rbp
3a: c3 ret
objdump -b binary -D -m i386:x86-64 linked.bin
Code: Select all
b: 55 push %rbp
c: 48 89 e5 mov %rsp,%rbp
f: b8 10 10 10 00 mov $0x101010,%eax
14: 5d pop %rbp
15: c3 ret
16: 55 push %rbp
17: 48 89 e5 mov %rsp,%rbp
1a: 48 8d 05 ea ff ff ff lea -0x16(%rip),%rax # 0xb
21: 48 89 c7 mov %rax,%rdi
24: e8 d7 ff ff ff call 0x0
29: 48 8b 05 0b 00 00 00 mov 0xb(%rip),%rax # 0x3b
30: 48 89 c7 mov %rax,%rdi
33: e8 c8 ff ff ff call 0x0
38: 90 nop
39: 5d pop %rbp
3a: c3 ret
3b: 55 push %rbp
3c: 48 89 e5 mov %rsp,%rbp
3f: b8 11 11 11 00 mov $0x111111,%eax
44: 5d pop %rbp
45: c3 ret
objdump -D linked.elf
Code: Select all
000000000040100b <c_func>:
40100b: 55 push %rbp
40100c: 48 89 e5 mov %rsp,%rbp
40100f: b8 10 10 10 00 mov $0x101010,%eax
401014: 5d pop %rbp
401015: c3 ret
0000000000401016 <_start>:
401016: 55 push %rbp
401017: 48 89 e5 mov %rsp,%rbp
40101a: 48 8d 05 ea ff ff ff lea -0x16(%rip),%rax # 40100b <c_func>
401021: 48 89 c7 mov %rax,%rdi
401024: e8 d7 ff ff ff call 401000 <take_func>
401029: 48 c7 c0 3b 10 40 00 mov $0x40103b,%rax
401030: 48 89 c7 mov %rax,%rdi
401033: e8 c8 ff ff ff call 401000 <take_func>
401038: 90 nop
401039: 5d pop %rbp
40103a: c3 ret
000000000040103b <extern_func>:
40103b: 55 push %rbp
40103c: 48 89 e5 mov %rsp,%rbp
40103f: b8 11 11 11 00 mov $0x111111,%eax
401044: 5d pop %rbp
401045: c3 ret