I am a bit confused on how a program looks like in memory , my professors told me that the stack and heap grow towards each other with the stack being at a lower memory address.
First thing that bothered me with that image is that if the heap grew from high to low then if I allocated an array on the heap shouldn't a pointer to the second element be smaller in int value than a pointer to the first element ? which would be confusing
I did a little research and I came upon this figure (note my question is focused on linux)
(source: cyberplusindia.com)
Ok, so Data and un-initialized data comes after the Text segment and are in the beginning of the program's memory then the heap followed by the stack and finally the command line arguments and environment.
But if the stack grows from high addresses to low then how come if I have an array allocated on the stack a pointer to the first element will also be lower in value than a pointer to the second element ? doesn't that mean the stack would grow from low to high also ?
So my question is what is the correct memory layout for a process in Linux? And also where does the memory for a shared library come from (in the process' address space)
Simple code with pointer examples :
#include <iostream>
int data[5];
int main()
{
using std::cout;
using std::endl;
int stack = 0;
short *sptr = reinterpret_cast<short *> ( &stack );
int *iptr = new int[5];
cout << "Starting static tests"
<< "\nPointer to first element " << data
<< "\nPointer to second element " << &data[1]
<< "\nstarting stack test " << sptr
<< "\nsecond short " << &sptr[1]
<< "\nStarting heap test " << iptr
<< "\nsecond int " << &iptr[1];
delete[] iptr;
return 0;
}
Output:
Starting static tests
Pointer to first element 0x6013e0
Pointer to second element 0x6013e4
starting stack test 0x7fffdf864dbc
second short 0x7fffdf864dbe
Starting heap test 0x1829010
second int 0x1829014
The 4 GB address space in 32 bit x86 Linux is usually split into different sections for every process on the system: 0GB-1GB User space - Used for text, code and brk / sbrk allocations. malloc uses brk for small chunks. 1GB-3GB User space - Used for shared libraries, shared memory, and the stack.
The computer memory is built to store bit patterns. Not only data but also instructions are bit patterns and these can be stored in memory. In systems software, they are stored in separate segment of memory. And the segments are also divided by data and program type.
Memory is laid out in sequential order basically from 0 on up (one byte at a time). Each position in memory has a number (called its address!). The compiler (or interpreter) associates your variable names with memory addresses.
the dec column gives the total size of the program code and data: the sum of text, data and bss. This does not include memory allocated at startup time, stack space, nor data allocated dynamically from the heap or using other OS specific methods. hex is the hexadecimal representation of dec.
if I have an array allocated on the stack a pointer to the first element will also be lower > in value than a pointer to the second element ?
It is not important "how" you allocate the array, you can increase or decrease the stack pointer, but as result you have address space reserved for the array.
You can work with them in normal way, since the lowest adress is reserved for element 0.
so my question is what is the correct memory layout for a process in Linux ?
You can check it yourself. Insert somewhere into you program something
like std::cin.get()
to pause your program.
Then run in a separate shell:
ps aux | grep your_program_name
cat /proc/<pid show by grep>/maps
This prints the memory mappings of your process, where you can see where the heap, the stack and other things are placed in memory.
About the stack: let's assume that you have ordinary machine with Linux and Intel or AMD 64 bit CPU. Then write the following code:
extern void f(int);
void g(int param)
{
f(param);
}
compile it and disassemble:
g++ -ggdb -c test_my_stack.cc && objdump -S test_my_stack.o
you can see (unimportant details removed):
void g(int param)
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 89 7d fc mov %edi,-0x4(%rbp)
f(param);
b: 8b 45 fc mov -0x4(%rbp),%eax
as you can see in sub $0x10,%rsp
we reserved space in the stack by decreasing (moving down) the stack pointer.
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