InnocentZero's Treasure Chest

HomeFeedAbout Me

20 Nov 2024

Memory layouts

Stack memory vs Heap memory

Whenever a program is run, it has two kinds of memories, stack and heap.

memory-organization.jpg

This describes the layout of memory when the program is run.

Higher memory address is read off first, then the data that was at the top of the stack is removed and the data below it is read.

Think of stack like a pile of dishes. To take a plate, sane people would pick up one from the top of the pile. Then the next one is picked, and so on.

Stack contains both function calls and local variables. Heap contains only variables.

BSS and data segments are not relevant, but they contain the global uninitialized and initialized data respectively.

Heap has a large amount of memory. More than stack. And most heap allocated things are freely resizable. However, the access to heap is significantly slower, and the elements may not be stored in a continuous fashion.

Stack Frames

Stack frames are the mechanism by which function calls are done. In x86 architecture

EBP1
main function local vars
next function arg1
next function arg2 / ESP1

Assume that this is the stack, and main has already loaded the args in the stack. The current EBP and current ESP demarcate the current stack frame

Now we do a call fun in assembly. What this implicitly does is pushes the return address (basically address of the next instruction) onto the stack. So now the stack looks something like this.

EBP1
main function local vars
next function arg1
next function arg2
return addr / ESP1

Next, the very first steps of fun would be to create its own stackframe.

The following instructions are executed in sequence:

push ebp
mov ebp, esp    
sub esp, 0x08 ; an example here

push and pop are basically fancy ways of saying add this value and move to next element and take this value and move to the previous element.

Now when we execute the first instruction:

old ebp / EBP1
main function local vars
next function arg1
next function arg2
return addr
EBP1 / ESP1

Next, a second value of ebp is created when we execute the second instruction.

old ebp / EBP1
main function local vars
next function arg1
next function arg2
return addr
EBP1 / ESP1 ; EBP2

Next, the sub creates the space for the local variables of fun.

old ebp / EBP1
main function local vars
next function arg1
next function arg2
return addr
EBP1 / ESP1 ; EBP2
fun function local vars
fun function local var / ESP2

Now, when we're done with the function, we destroy the stack frame. There are two methods to do it.

leave
ret

OR

mov rsp, rbp
pop rbp
ret

leave is effectively equivalent to the second one. So for simplicity and elaboration we'll go with the second form.

After the first instruction

old ebp / EBP1
main function local vars
next function arg1
next function arg2
return addr
EBP1 / ESP1 ; EBP2 ; ESP3
fun function local vars
fun function local var / ESP2

After the second instruction

old ebp / EBP1 ; EBP3
main function local vars
next function arg1
next function arg2
return addr / ESP3
EBP1 / ESP1 ; EBP2
fun function local vars
fun function local var / ESP2

After the third instruction

old ebp / EBP1 ; EBP3
main function local vars
next function arg1
next function arg2 / ESP3
return addr
EBP1 / ESP1 ; EBP2
fun function local vars
fun function local var / ESP2
Tags: programming hardware C

Other posts
Creative Commons License
This website by Md Isfarul Haque is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.