C Function Call
- 翻译
- 2018-02-03 16:59:16
- Bigshot, Renee
- 1376
- 来源:
Parsing the C Function call from the view of compiling
Look at the function call below,
1 int Add(int x,int y) 2 { 3 int sum = 0; 4 sum = x + y; 5 return sum; 6 } 7 8 int main () 9 { 10 int a = 10; 11 int b = 12; 12 int ret = 0; 13 ret = Add(a,b); 14 return 0; 15 }
Assembly will be used to explain the C Function call, so let's see some registers and assembly instructions.
Registers
- esp : extended stack pointer, which holds a pointer that always points to the top of the stack frame at the top of the system stack.
- ebp : extended base pointer, which holds a pointer that always points to the bottom of the stack frame at the top of the system stack.
- eax : accumulator, which is the default register of add and multiply instructions.
- ebx : base, which holds base address in memory addressing.
- ecx : counter, which is the default counter for REP and LOOP instructions.
- edx : holds remainders generated by integer division.
- esi/edi : source/destination index. In string operations, DS:ES points to source strings and ES:EDI points to target strings.
On the 32 bit platform, ESP is reduced by 4 bytes at a time.
Assembly Instruction
- mov : data movement instruction, which is the very basic programming instruction. It is to move data from the source address to the - target address, which is basically the same as the nature of data movement between registers.
- sub : subtract instruction
- lea:take offset address
- push:push instruction
- pop:pop instruction
- call:save the next instruction of the current instruction and jump to the target function.
It can help you understand Function call, if you could understant those intrcutions. If not, you can read my explanation.
Before parsing it, let's see the distribution of the memory address space below.
=============== Highest Address (e.g. 0xFFFF) | | | KERNEL ADDR | <- kernel address space | | |-------------| | | | ENV VAR | <- environmentvariable |-------------| | | | PARAMETER | <- command line parameter | | |-------------| | | | STACK | | | |-------------| | | | | <- shared lib and mapped memory | | |-------------| | | | HEAP | | | |-------------| | | | Data SEGMENT| | | |-------------| | | | CODE SEGMENT| | | =============== Lowest Address
The stack space grows towards decreasing memory addrss, and it is for storing frames of functions. Its size is limited, just a few MB.
Assembler Code
- main
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 = 12; 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
- add
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
The image below described the change of address in call. All addresses in the image is from debugging in VS Code on 32-bit Windows.
STEPS
Call
1. Copy parameters.
2. Save the next instruction of the current instruction, and jump to the called function.
The 2 steps are done in main functions.
Call Add function and do the followings,
1. Move ebp and esp to create the new structure of frames.
2 Push and generate temporary variables and so the related.
2. Return a value.
The 3 step are done in Add function.
By now, call Add function in main function has been finished. Generally speaking, it includes three steps,
1. Find the entry to the function by the function name called.
2. Apply to call the parameters of the function and memory space of variables defined within the function in the stack.
3. After the function is executed, release the parameters and memory space that were applied by the function in the stack, and reture a values if any.
If you know the Principle of Microcomputer, you would think of CPU interrupt now. Yes, function call is the same as processing CPU interrup.
Function Calling Conventions
_stdcall
All parameters are pusheded into the stack from right to left. The called subprogram will clear the stack.
_cdecl(The C default calling convention)
All parameters are pusheded into the stack from right to left. The caller will clear the stack.
_fastcall
It is to call the function fast. It mainly relies on registers to pass parameters, and the rest parameter are pushed into the stack from right to left. The called subprogram will clear the stack.
In this blog, function is called according to _stdcall conventions.