Search code examples
clinux64-bit

Why are instructions addresses on the top of the memory user space contrary to the linux process memory layout?


#include <stdio.h>
void func() {}

int main() {
    printf("%p", &func);

    return 0;
}

This program outputted 0x55c4cda9464a Supposing that func will be stored in the .text section, and according to this figure, from CS:APP: enter image description here I suppose that the address of func would be somewhere near the starting address of the .text section, but this address is somewhere in the middle. Why is this the case? Local variables stored on the stack have addresses near 2^48 - 1, but I tried to disassemble different C codes and the instructions were always located somewhere around that 0x55... address.


Solution

  • gcc, when configured with --enable-default-pie1 (which is the default), produces Position Independent Executables(PIE). Which means the load address isn't same as what linker specified at compile-time (0x400000 for x86_64). This is a security mechanism so that Address Space Layout Randomization (ASLR) 2 can be enabled. That is, gcc compiles with -pie option by default.

    If you compile with -no-pie option (gcc -no-pie file.c), then you can see the address of func is closer to 0x400000.

    On my system, I get:

    $ gcc -no-pie t.c
    $ ./a.out 
    0x401132
    

    You can also check the load address with readelf:

    $ readelf -Wl a.out | grep LOAD
     LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x000478 0x000478 R   0x1000
     LOAD           0x001000 0x0000000000401000 0x0000000000401000 0x0001f5 0x0001f5 R E 0x1000
     LOAD           0x002000 0x0000000000402000 0x0000000000402000 0x000158 0x000158 R   0x1000
     LOAD           0x002e10 0x0000000000403e10 0x0000000000403e10 0x000228 0x000230 RW  0x1000
    

    1 you can check this with gcc --verbose.

    2 You may also notice that address printed by your program is different in each run. That's because of ASLR. You can disable it with:

    $ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
    

    ASLR is enabled on Linux by default.