function calling process
When a function is called in C language, it will jump to execute the function until it is completed and then execute the next instruction.
This is accomplished by forming a stack frame during the execution of the calling function. A stack frame is a data structure used by the compiler to implement the function calling process.
Take the Add() function as an example to analyze the calling process:
#include<stdio.h>
#include<stdlib.h>
int Add(int x, int y){
int sum = 0;
sum = x + y;
return sum;
}
int main(){
int a = 10;
int b = 20;
int ret = 0;
ret = Add(a, b);
return 0;
}
- The stack frame requires two registers, ebp and esp. During the function call, these two registers store the bottom and top pointers of the stack that maintain the stack.
Note: ebp points to the bottom of the stack frame currently located at the top of the system stack , not the bottom of the system stack. Strictly speaking, "bottom of stack frame" and "bottom of stack" are different concepts; the top of the stack frame referred to by ESP and the top of the system stack are the same position .
esp: Stack pointer register (extended stack pointer), which stores a pointer that always points to the top of the stack frame at the top of the system stack; on a 32-bit platform, ESP decreases by 4 bytes each time ebp: base
address The pointer register (extended base pointer) stores a pointer, which always points to the bottom of the top stack frame of the system stack.
eax is the "accumulator", which is the default register for many addition and multiplication instructions.
ebx is The "base address" (base) register stores the base address when addressing memory.
ecx is a counter, which is the default counter of the repeat (REP) prefix instruction and the LOOP instruction.
edx is always used to store the remainder generated by integer division.
esi/edi are called "source/destination index" respectively, because in many string operation instructions, DS:ESI points to the source string, and ES:EDI points to the destination string. Assembly instruction: mov: data
transfer
instruction , is also the most basic programming instruction, used to transfer a data from the source address to the target address (the data transfer between registers is essentially the same) sub: subtraction instruction lea:
take
the offset address
push: the instruction to implement the push operation It is the PUSH instruction
pop: the instruction that implements the pop operation
call: used to save the next instruction of the current instruction and jump to the target function
Distribution of memory address space:
The stack space grows toward lower addresses and is mainly used to save function stack frames. The size of the stack space is very limited, only a few MB in size (so the high address in the picture below is at the bottom)
Assembly code implementation:
int main ()
{
011B26E0 push ebp
011B26E1 mov ebp,esp
011B26E3 sub esp,0E4h
011B26E9 push ebx
011B26EA push esi
011B26EB push edi
011B26EC lea edi,[ebp-0E4h]
011B26F2 mov ecx,39h
011B26F7 mov eax,0CCCCCCCCh
011B26FC rep stos dword ptr es:[edi]
int a = 10;
011B26FE mov dword ptr [a],0Ah
int b = 20;
011B2705 mov dword ptr [b],0Ch
int ret = 0;
011B270C mov dword ptr [ret],0
ret = Add(a,b);
011B2713 mov eax,dword ptr [b]
011B2716 push eax
011B2717 mov ecx,dword ptr [a]
011B271A push ecx
011B271B call @ILT+640(_Add) (11B1285h)
011B2720 add esp,8
011B2723 mov dword ptr [ret],eax
return 0;
011B2726 xor eax,eax
}
011B2728 pop edi
011B2729 pop esi
011B272A pop ebx
011B272B add esp,0E4h
011B2731 cmp ebp,esp
011B2733 call @ILT+450(__RTC_CheckEsp) (11B11C7h)
011B2738 mov esp,ebp
011B273A pop ebp
011B273B ret
int Add(int x,int y)
{
011B26A0 push ebp
011B26A1 mov ebp,esp
011B26A3 sub esp,0CCh
011B26A9 push ebx
011B26AA push esi
011B26AB push edi
011B26AC lea edi,[ebp-0CCh]
011B26B2 mov ecx,33h
011B26B7 mov eax,0CCCCCCCCh
011B26BC rep stos dword ptr es:[edi]
int sum = 0;
011B26BE mov dword ptr [sum],0
sum = x + y;
011B26C5 mov eax,dword ptr [x]
011B26C8 add eax,dword ptr [y]
011B26CB mov dword ptr [sum],eax
return sum;
011B26CE mov eax,dword ptr [sum]
}
011B26D1 pop edi
011B26D2 pop esi
011B26D3 pop ebx
011B26D4 mov esp,ebp
011B26D6 pop ebp
011B26D7 ret
1. Call the main() function:
1. push on the stack, put ebp on the top of the stack, and esp always points to the top of the stack
2. mov , pass the esp value to ebp, that is, move esp and ebp together
3. sub (meaning to decrease), that is, esp -0E4h is assigned to esp, and the function call allocation increases from high address to low address , so esp moves upward, which opens up a new space, that is, it opens up space for the main function
4. The next three pushes will ebx, esi, and edi respectively. Push the top of the stack in order, and esp will also point to the top of the stack
5.lea instruction to load the effective address; put the address of ebp-0E4h into edi, that is, edi points to ebp-0E4h (1. Put 39h into ecx ;2. Put 0cccccccch into eax; 3. Start copying from the address pointed by edi to the high address. The number of copies is the ecx content, and the copied content is within eax) 6. Create variables a and b, and initialize
10 and 20
2. Call of Add() function
Put b into eax, and then push eax onto the stack (formal parameter a).
Put a into eax, and then push eax onto the stack (formal parameter b).
Call: Push the address of the next instruction onto the stack, and then enter the add() function. in
Note: The call statement pushes the address of the next instruction. In order to know where to continue execution when the function returns,
enter the add() function:
A. First push the main function ebp onto the stack and save the address of the ebp pointing to the bottom of the main() function stack frame. The purpose is to find the bottom of the main function stack when returning. At this time, esp points to the new top of the stack and changes the ebp of the main function
. Pushing the stack is also to find the bottom of the main function stack when returning.
B. Assign the value of esp to ebp to generate a new ebp, that is, the ebp of the Add() function stack frame;
C. Subtract a hexadecimal number 0CCh from esp ( Pre-open space for the Add() function);
D. push ebx, esi, edi;
E. lea instruction, load the effective address;
F. Initialize the pre-opened space to 0xcccccccc;
G. Create variable z and assign it a value
H. Put Put the formal parameter a into eax, that is, put 10 into eax, add the formal parameter b into eax, that is, add 20 to eax, and then put eax at the position of z, that is, put the sum of the two numbers into z
I .Put the value of z into the register eax and return. Because z is a variable space temporarily opened by the function and will be destroyed after the function is executed, so put it in the register and return K. Next, perform the
pop operation from the stack, and edi esi ebx in sequence from top to bottom When popping the stack, esp will move downward. The characteristics of the stack are: first in last out, last in first out
L. Assign the ebp value to esp, that is, esp moves downward to point to the ebp position. At this time, the stack space opened by add has been destroyed
M .pop pops the element at the top of the stack into ebp, that is to say, puts the ebp of the main function into ebp, that is, ebp now points to the main function ebp
N. After executing ret, the address of the previous push will be popped out, so It will return to the main function, which is why this address was pushed before, so that the call instruction is completed.
Next, continue executing O from that call instruction.
Move esp+8, that is, move esp downwards, and destroy the formal parameters.
P. Finally, the main() function stack frame is destroyed, the method is the same as above
Summary: The stack is a necessary space for recording the calling path and parameters when a C language program is running:
function calling frame;
passing parameters;
saving return address;
providing local variable space;