C Function Call

2018-02-05 14:53:00
Bigshot, Renee
Original 1480

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 }
 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.


- 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 understand those instructions. 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 address, 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.


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


All parameters are pushed into the stack from right to left. The called subprogram will clear the stack.

_cdecl(The C default calling convention)

All parameters are pushed into the stack from right to left. The caller will clear the stack.


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.

Write a Comment
Comment will be posted after it is reviewed.