Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c

linux

64-bit

#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.

like image 793
Tortellini Teusday Avatar asked Aug 18 '20 09:08

Tortellini Teusday


People also ask

What is the memory layout of a process?

Memory Layout of a Process Lets explain each component of the above layout one by one : The command line arguments and the environment variables are stored at the top of the process memory layout at the higher addresses. Then comes the stack segment.

How kernel uses the address space?

The kernel address space is statically mapped into the address space. The top 1 GB of the user's space is reserved for system elements while the bottom 1 GB holds the user code, data, stack, and heap.

How does the memory layout differ between a Windows and Linux OS?

Yes, windows and linux lay out their memory differently. Some examples are here. For example, windows typically splits your memory evenly (in 32-bit) between kernel and user space, while linux is 3/1 user/kernel. The compiler can also lay out the memory as it sees fit, within the limits of the spec.


1 Answers

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.

like image 85
P.P Avatar answered Oct 17 '22 17:10

P.P