I try to compile a non-PIC code with gcc and I noticed that the assembly code generated by GCC does not use a pure function address to call but adds to it a weird offset.
I use GCC 9.3.0 as gcc test.c -o test-nopic -mcmodel=large -no-pie -O0
with the following code. I left out -fPIC
.
#include <stdio.h>int var1 = 1;int var2 = 2;void putstr(int* ptr) { printf("val: %d\n", *ptr);}int main() { putstr(&var1); putstr(&var2);}
Here is listing with the code of main()
from objdump -wdrC -M intel test-nopic
.
000000000040117e <main>: 40117e: 55 push rbp 40117f: 48 89 e5 mov rbp,rsp 401182: 53 push rbx 401183: 48 83 ec 08 sub rsp,0x8 401187: 48 8d 1d f9 ff ff ff lea rbx,[rip+0xfffffffffffffff9] # 401187 <main+0x9> 40118e: 49 bb 79 2e 00 00 00 00 00 00 movabs r11,0x2e79 401198: 4c 01 db add rbx,r11 40119b: 48 b8 30 00 00 00 00 00 00 00 movabs rax,0x30 4011a5: 48 8d 3c 03 lea rdi,[rbx+rax*1] 4011a9: 48 b8 26 d1 ff ff ff ff ff ff movabs rax,0xffffffffffffd126 4011b3: 48 8d 04 03 lea rax,[rbx+rax*1] 4011b7: ff d0 call rax 4011b9: 48 b8 34 00 00 00 00 00 00 00 movabs rax,0x34 4011c3: 48 8d 3c 03 lea rdi,[rbx+rax*1] 4011c7: 48 b8 26 d1 ff ff ff ff ff ff movabs rax,0xffffffffffffd126 4011d1: 48 8d 04 03 lea rax,[rbx+rax*1] 4011d5: ff d0 call rax 4011d7: b8 00 00 00 00 mov eax,0x0 4011dc: 48 83 c4 08 add rsp,0x8 4011e0: 5b pop rbx 4011e1: 5d pop rbp 4011e2: c3 ret
The address of pustr(int*) is 0x401126
. readelf -l test-nopic
shows the file type is EXEC and the following headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x0000000000000268 0x0000000000000268 R 0x8 INTERP 0x00000000000002a8 0x00000000004002a8 0x00000000004002a8 0x000000000000001c 0x000000000000001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x00000000000004d8 0x00000000000004d8 R 0x1000 LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000 0x0000000000000275 0x0000000000000275 R E 0x1000 LOAD 0x0000000000002000 0x0000000000402000 0x0000000000402000 0x0000000000000168 0x0000000000000168 R 0x1000 LOAD 0x0000000000002e00 0x0000000000403e00 0x0000000000403e00 0x0000000000000238 0x0000000000000240 RW 0x1000 DYNAMIC 0x0000000000002e10 0x0000000000403e10 0x0000000000403e10 0x00000000000001d0 0x00000000000001d0 RW 0x8 NOTE 0x00000000000002c4 0x00000000004002c4 0x00000000004002c4 0x0000000000000044 0x0000000000000044 R 0x4 GNU_EH_FRAME 0x0000000000002010 0x0000000000402010 0x0000000000402010 0x0000000000000044 0x0000000000000044 R 0x4 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 GNU_RELRO 0x0000000000002e00 0x0000000000403e00 0x0000000000403e00 0x0000000000000200 0x0000000000000200 R 0x1
- Why gcc does not use just
movabs rax, 0x401126
before the calls? - Why the address(?) used at 4011a9 is filled with all these 0xFFs?
- Why gcc uses the rip register with added the weird offset and then use the magic value 0x2e79 which does not fit to any of the segments listed above.