When you call a function in C, you need to ensure mainly 5 things:
________________ <---- Bottom of the stack (fixed)
| | Higher memory address
| |
| |
|________________|<---- Top of the stack (moving down)
| Lower memory address
|
V Grows downwards in memory
Thus, **ESP alone represents the current status of the stack.
By convention, procedures will take their parameters from stack. If a procedure returns a value that will fit in a register, it will be returned in AL, AX, EAX, depending on its size. A procedure will in general have local variables on stack as well.
A standard method of accessing both local variables and parameters is to "mark" a place on the stack, and then address both parameters and local variables by their offsets from the "mark". This mark or reference point is called "FRAME POINTER" , because all the information that is pushed into the stack at the time of procedure call is called a frame for that procedure.
Frame Pointer (FP) for the running procedure is always stored in EBP.
[[ call func ]]
[[ pushl %ebp ]]
[[ movl %esp, %ebp ]]
[[ subl $4, %esp ]]
[[ movl %ebp, %esp]]
[[ popl %ebp ]]
[[ ret ]]
static int a = 8; /*Static Storage*/
extern c;
static int func1 (int x)
{
int t = 8; /* Local Variable */
return (x+t); /* Return */
}
int main()
{
int b = 0;
b = func1(a);
c = b;
return(0);
}
a:
.long 8 &<-- Static variable a
func1:
pushl %ebp <-- Step 3, Push EBP
movl %esp, %ebp <-- Step 4, Copy ESP -> EBP
subl $4, %esp <-- Step 5, Create space on stack for t
movl $8, -4(%ebp) <-- Initialize "t" to 8
movl -4(%ebp), %eax <-- Step 6, Copy "t" to EAX
addl 8(%ebp), %eax <-- Step 6, Add "c" to EAX
leave <-- Step 7 and 8:
7: Restore ESP (EBP -> ESP)
8: Restore EBP (Pop STACK -> EBP)
ret <-- Step 9, (Pop STACK -> Program Counter)
main:
.........
pushl a <-- Step 1, push parameters
call func1 <-- Step 2, call func1
addl $16, %esp
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
movl %eax, c
.........
During execution of func1, STACK looks like:
_______________ <---- Bottom of the stack (fixed)
| |
| main |
|_______________|
func1 frame --> | a |<---- Parameters pushed
starts here |_______________|
| RET Addr |<---- Return address pushed by "call"
|_______________|
Frame Pointer-->| EBP |<---- FP for main pushed by func1
for func1 |_______________| Copy ESP to EBP
| t |<---- Local variable "t"
|_______________|
|
V
From the figure, you can make out that , to refer to parameters, we have to add 8 offset to EBP ie. 8(%ebp). And to refer to local variable, we'll say -4(%ebp).
**Remember, ESP points to the last item pushed, so 0(%ebp) will give us FP of main.
Copyright 2006-2022 Manu
Garg.