#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
:
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.
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.
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.
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.
gcc
, when configured with --enable-default-pie
1 (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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With