Memory layout
Memory Layout Refresher
• How is program data laid out in memory?
• What does the stack look like?
• What effect does calling (and returning from) a
function have on memory?
• We are focusing on the Linux process model
• Similar to other operating systems
All programs are stored in memory
4G 0xffffffff
The process’s view In reality, these are
of memory is that virtual addresses;
it owns all of it the OS/CPU map
them to physical
addresses
0 0x00000000
The instructions themselves are in memory
4G 0xffffffff
...
0x4c2 sub $0x224,%esp
0x4c1 push %ecx
0x4bf mov %esp,%ebp
0x4be push %ebp
...
Text
0 0x00000000
Location of data areas
4G 0xffffffff
Set when
cmdline & env
process starts int f() {
Stack int x;
…
Runtime
Heap malloc(sizeof(long));
Uninit’d data static int x;
Known at
Init’d data static const int y=10;
compile time
Text
0 0x00000000
Memory allocation
Stack and heap grow in opposite directions
Compiler emits instructions
adjust the size of the stack at run-time
0x00000000 0xffffffff
Heap 3 2 1 Stack
{
apportioned by the OS; Stack push 1
managed in-process pointer
push 2
push 3
by malloc return
Focusing on the stack for now
Stack and function calls
• What happens when we call a function?
• What data needs to be stored?
• Where does it go?
• What happens when we return from a function?
• What data needs to be restored?
• Where does it come from?
Basic stack layout
void func(char *arg1, int arg2, int arg3)
{
char loc1[4]
int loc2;
...
}
0xffffffff
… loc2 loc1 ??? ??? arg1 arg2 arg3 caller’s data
Local variables Arguments
pushed in the pushed in
same order as reverse order
they appear of code
in the code
The local variable allocation is ultimately up to the compiler: Variables could be allocated in any order,
or not allocated at all and stored only in registers, depending on the optimization level used.
Accessing variables
void func(char *arg1, int arg2, int arg3)
{
...
loc2++; Q: Where is (this) loc2?
...
} A: -8(%ebp)
0xffffffff
… loc2 loc1 ??? ??? arg1 arg2 arg3 caller’s data
Stack frame
0xbffff323 %ebp for func
Can’t Frame pointer
know absolute But can know the relative address
address at compile time • loc2 is always 8B before ???s
Returning from functions
int main()
{
...
func(“Hey”, 10, -3);
...
}
Q: How do we restore %ebp?
%esp 0xffffffff
… loc2 loc1 %ebp
??? ??? arg1 arg2 arg3 caller’s data
Stack frame
%ebp for func %ebp
Push %ebp before locals
Set %ebp to current (%esp)
Set %ebp to(%ebp) at return
Returning from functions
int main()
{
...
func(“Hey”, 10, -3);
...
}
Q: How do we resume here?
0xffffffff
… loc2 loc1 %ebp ??? arg1 arg2 arg3 caller’s data
Stack frame
%ebp for func %ebp
Instructions in memory
4G 0xffffffff
...
0x5bf mov %esp,%ebp
0x5be push %ebp
...
...
0x4a7 mov $0x0,%eax
0x4a2 call <func>
0x49b movl $0x804..,(%esp)
0x493 movl $0xa,0x4(%esp) %eip
...
Text
0 0x00000000
Returning from functions
int main()
{
...
func(“Hey”, 10, -3);
...
}
Q: How do we resume here?
0xffffffff
… loc2 loc1 %ebp %eip
??? arg1 arg2 arg3 caller’s data
Stack frame
%ebp for func %ebp
Set %eip to 4(%ebp) Push next %eip
at return before call
Stack and functions: Summary
Calling function:
[Link] arguments onto the stack (in reverse)
[Link] the return address, i.e., the address of the instruction you
want run after control returns to you
[Link] to the function’s address
Called function:
[Link] the old frame pointer onto the stack (%ebp)
[Link] frame pointer (%ebp) to where the end of the stack is right now
(%esp)
[Link] local variables onto the stack
Returning function:
[Link] the previous stack frame: %esp = %ebp, %ebp = (%ebp)
[Link] back to return address: %eip = 4(%esp)