Bryant and O'Hallaron Chapter 3 Section 3.7.1 The Stack Frame ------------------------------------------------------------------------------------ stack ------------------------------------------------------------------------------------ 0xffffffff +--------------------------------+ | | | Kernel virtual memory | | | 0xc0000000 +--------------------------------+ | User stack | | (created at run time) | +----------------|---------------+ <- %esp (stack pointer) | | | | v | | | | | | ^ | | | | +----------------|---------------+ | Memory mapped region for | | shared libraries | 0x40000000 +--------------------------------+ | | | ^ | | | | +----------------|---------------+ <- brk | Run-time heap | |(created at run time by malloc) | +--------------------------------+ | Read/write segment | | (.data, .bss) | +--------------------------------+ | Read-only segment | | (.init, .text, .rodata) | 0x08048000 +--------------------------------+ | unused | 0x00000000 +--------------------------------+ ------------------------------------------------------------------------------------ Stack Frame ------------------------------------------------------------------------------------ Assume the function one() calls function two(int a, int b, int c) and that function two in tern calles function three(int x, int y). The three functions will use three contiguous but non-overlapping sections of the stack called stack frames. Since the stack grows downward (from 0xbffffffc toward 0x00000000, function one's stack frame occupies higher addresses than function two, and function two's stack fram occupies higher address than function three. Every function uses the 32-bit %ebp (Extended Base Pointer) register to point to the first item it pushes on the stack and the 32-bit %esp (Extended Stack Pointer) register to point to the last item pushed. The stack frame for a function generally consists of four areas, each of which may be null. 1. Register save area. If a function modifies registers %ebx, %esi, %edi, %ebp and $esp, it must save and restore the registers. (Registers %eax, %ecx, and %edx do not need to be restored). 2. Space for local function variables (any variables declared without a "static" modifier. 3. Space for arguments when lower-level functions are called. 4. Space for the return address when lower-level functions are called. When function one(a, b, c) calls function two, function one's stack frame will be as follows: +-----------------------------+ | | <---------- (%ebp) +-----------------------------+ ... +-----------------------------+ | copy of c | <---------- 12(%esp) +-----------------------------+ | copy of b | <---------- 8(%ebp) +-----------------------------+ | copy of a | <---------- 4(%esp) +-----------------------------+ | return address to one | <---------- (%esp) +-----------------------------+ After the call to two, function two generally executes the instructions: push %ebp movl %esp,%ebp to save the callers %ebp and %esp registers and tcreate define function two's stack frame. The arguments can now be accessed using register %ebp. +-----------------------------+ | copy of c | <---------- 16(%esp) +-----------------------------+ | copy of b | <---------- 12(%ebp) +-----------------------------+ | copy of a | <---------- 8(%esp) +-----------------------------+ | return address to one | <---------- 4(%ebp) +-----------------------------+ | one's saved %ebp | <---------- (%ebp) and (%esp) +-----------------------------+ With the new value in %ebp, function two can access the arguments a, b, and c with the operands 8(%ebp), 12(%ebp), and 16(%ebp). If function two needs to reserve space for two integer local variables i and j, it simply adds 8 to %esp with the instruction "addl $8,%esp" to produce the following stack frame. +-----------------------------+ | copy of c | <---------- 16(%esp) +-----------------------------+ | copy of b | <---------- 12(%ebp) +-----------------------------+ | copy of a | <---------- 8(%esp) +-----------------------------+ | return address to one | <---------- 4(%ebp) +-----------------------------+ | one's saved %ebp | <---------- (%ebp) +-----------------------------+ | local variable i | <---------- -4(%ebp) +-----------------------------+ | local variable j | <---------- -8(%ebp) and (%esp) +-----------------------------+ In order to call function three(x, y, z) function two pushes the values of x, y, and z and then pushes z, y, and x (in that order) and calls function three. As the call instruction is completed, the stack appears as follows: +-----------------------------+ | copy of c | <---------- 16(%esp) +-----------------------------+ | copy of b | <---------- 12(%ebp) +-----------------------------+ | copy of a | <---------- 8(%esp) +-----------------------------+ | return address to one | <---------- 4(%ebp) +-----------------------------+ | one's saved %ebp | <---------- (%ebp) +-----------------------------+ | local variable i | <---------- -4(%ebp) +-----------------------------+ | local variable j | <---------- -8(%ebp) +-----------------------------+ | argument z | <---------- +-----------------------------+ | argument y | <---------- +-----------------------------+ | argument x | +-----------------------------+ | return addrss to two | <---------- (%esp) +-----------------------------+ After function three returns to function two, function two can add 12 to %esp to "remove" the arguments x, y, and z from the stack so that those stack locations can be used by function two to call other functions. When it is functions two's turn to return to function one. it executes the instructions: movl %ebp,%esp # restore stack pointer to original value -4 popl %ebp # restore one's original %ebp and %esp ret Funciton main then resumes execution with the following stack frame. +-----------------------------+ | | <---------- (%ebp) +-----------------------------+ ... +-----------------------------+ | copy of c | <---------- 8(%esp) +-----------------------------+ | copy of b | <---------- 4(%esp) +-----------------------------+ | copy of a | <---------- (%esp) +-----------------------------+ Notice that the ret instruction has popped the return address off the stack, so %esp points to the last argument pushed on the stack (a). If function one wants to reuse the stack space for a, b, and c, it should add 12 to %esp.