When you call a function in C, you need to ensure mainly 5 things:
In C, first 4 features are implemented using stack.
Salient Features of Stack:
1. It grows downwards in memory. That is the top of the stack moves down with each push to the stack.
_______________ <---- Bottom of the stack (fixed) | | Higher memory address | | | | |_______________|<---- Top of the stack (moving down) | Lower memory address | V Grows downwards in memory
2. Top of stack (pointer to the last pushed vlaue) is stored in the register ESP
3. Only operations allowed are push and pop.
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.
1. Push the parameters in the reverse order (right to left).
2. "Call" function now. It implicitly pushes the return address into STACK.
[[ call func ]] ------ Now enters the called procedure ------
3. Push the current EBP ie. Frame Pointer (FP) of calling function into stack. We need to do this to continue with the execution of calling function after return from the called function.
[[ pushl %ebp ]]
4. Copy the ESP to EBP. (yes, this location will be new FRAME POINTER)
[[ movl %esp, %ebp ]]
5. Allocate space on stack for local variables. It's done by decrementing ESP.
[[ subl $4, %esp ]] ------ Do some processing ------
6. Put the value to be returned in EAX.
----- Start unwinding STACK ------
7. Copy current EBP to ESP, it will reduce stack's size. Now we have old FP at the top of the stack.
[[ movl %ebp, %esp]]
8. Pop a 32 bit value (which is old frame pointer) and stuff it into EBP. (undoing Step 3)
[[ popl %ebp ]]
9. The "ret" instruction pops a 32 bit value from the stack and stuffs into the program counter.
[[ ret ]]
** steps 7 and 8 are combined in single instruction "leave".
Example C Code:
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);
}
Corresponding Assembly Code (Only relevant part shown):
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.
Author: Manu Garg
http://www.manugarg.com
manugarg at gmail dot com
Online URL of article - http://manugarg.googlepages.com/stack.txt
Other articles of mine published on aplawrence.com:
http://aplawrence.com/Unixart/backup_rsync.html
http://aplawrence.com/Unixart/socket-programming.html
More Articles by Manu Garg
Have you tried Searching this site?
Unix/Linux/Mac OS X support by phone, email or on-site: Support Rates
This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more. We appreciate comments and article submissions.
Many of the products and books I review are things I purchased for my own use. Some were given to me specifically for the purpose of reviewing them. I resell or can earn commissions from the sale of some of these items. Links within these pages may be affiliate links that pay me for referring you to them. That's mostly insignificant amounts of money; whenever it is not I have made my relationship plain. I also may own stock in companies mentioned here. If you have any question, please do feel free to contact me.
Specific links that take you to pages that allow you to purchase the item I reviewed are very likely to pay me a commission. Many of the books I review were given to me by the publishers specifically for the purpose of writing a review. These gifts and referral fees do not affect my opinions; I often give bad reviews anyway.
We use Google third-party advertising companies to serve ads when you visit our website. These companies may use information (not including your name, address, email address, or telephone number) about your visits to this and other websites in order to provide advertisements about goods and services of interest to you. If you would like more information about this practice and to know your choices about not having this information used by these companies, click here.
Click here to add your comments
Sat Jun 25 09:47:31 2011: venkat
Missing information
how parameters that are pushed on to the stack are removed ?
Sat Jun 25 09:58:42 2011: TonyLawrence
When you return from a function, the stack is popped.
Sun Jun 26 00:55:50 2011: BigDumbDinosaur
http://bcstechnology.net
Something that may not have been clear in this article is that, as a rule, the stack acrobatics performed as part of executing a C language function and returning from it are not something the average programmer needs to be concerned about. The whole purpose of using C instead of assembly language is to avoid having to micromanage the system and worry about where each byte is going. However, it's useful to know something about how this stuff works, if for no other reason that to try to figure out why a function call returns garbage or generates a core dump, or the machine itself goes wacko on a function call (rare with modern operating systems, but possible on an embedded design running a real time operating system).
Something else to note: the register references in this article are specific to the x86 architecture. For example, if you're compiling on an HP PA-RISC box don't bother looking for the ESP register -- it ain't there (look at R30).
Don't miss responses! Subscribe to Comments by RSS or by Email
Click here to add your comments
If you want a picture to show with your comment, go get a Gravatar