C language function call process

content

Function call process in C language

The previous piece of code

#include<stdio.h>
int Add(int x, int y)
{
    int z = 0;
    z = x + y;
    return z;
}
#include <stdio.h>
int main()
{
    int a = 10;
    int b = 20;
    int c = Add(a, b);
    return 0;
}

This function computes the value of two numbers. Next, let's take a look at the process after the function is disassembled.

disassembled code

#include <stdio.h>
int main()
{
01151720  push        ebp  
01151721  mov         ebp,esp  
01151723  sub         esp,0E4h  
01151729  push        ebx  
0115172A  push        esi  
0115172B  push        edi  
0115172C  lea         edi,[ebp-0E4h]  
01151732  mov         ecx,39h  
01151737  mov         eax,0CCCCCCCCh  
0115173C  rep stos    dword ptr es:[edi]  
    int a = 10;
0115173E  mov         dword ptr [a],0Ah  
    int b = 20;
01151745  mov         dword ptr [b],14h  
    int c = Add(a, b);
0115174C  mov         eax,dword ptr [b]  
0115174F  push        eax  
01151750  mov         ecx,dword ptr [a]  
01151753  push        ecx  
01151754  call        _Add (01151104h)  
01151759  add         esp,8  
0115175C  mov         dword ptr [c],eax  
    return 0;
0115175F  xor         eax,eax  
}
01151761  pop         edi  
01151762  pop         esi  
01151763  pop         ebx  
01151764  add         esp,0E4h  
0115176A  cmp         ebp,esp  
0115176C  call        __RTC_CheckEsp (01151122h)  
01151771  mov         esp,ebp  
01151773  pop         ebp  
}
//Add()
#include<stdio.h>
int Add(int x, int y)
{
001016D0  push        ebp  
001016D1  mov         ebp,esp  
001016D3  sub         esp,0CCh  
001016D9  push        ebx  
001016DA  push        esi  
001016DB  push        edi  
001016DC  lea         edi,[ebp-0CCh]  
001016E2  mov         ecx,33h  
001016E7  mov         eax,0CCCCCCCCh  
001016EC  rep stos    dword ptr es:[edi]  
    int z = 0;
001016EE  mov         dword ptr [z],0  
    z = x + y;
001016F5  mov         eax,dword ptr [x]  
001016F8  add         eax,dword ptr [y]  
001016FB  mov         dword ptr [z],eax  
    return z;
001016FE  mov         eax,dword ptr [z]  
}
00101701  pop         edi  
00101702  pop         esi  
00101703  pop         ebx  
00101704  mov         esp,ebp  
00101706  pop         ebp  
00101707  ret  

The above is the disassembled code. Now let's interpret it piece by piece to see how the whole program is executed.

Creation of main() function

01.15172 million Push EBP
01,151,721 MOV EBP, ESP
01,151,723 Sub ESP, 0E4h
01,151,729 Push EBX
0115172A Push ESI
0115172B Push EDI
0115172C LEA EDI, [EBP-0E4h]
01,151,732 MOV ECX, 39h
01,151,737 MOV EAX, 0CCCCCCCCh
0115173C REP STOS DWORD PTR ES: [EDI ]
//Separation line…………………….
int a = 10;
0115173E mov dword ptr [a],0Ah
int b = 20;
01151745 mov dword ptr [b],14h
"`
This is for readers and friends Briefly talk about the meaning of variables. ebp and esp are two general-purpose registers. They can store immediate data and memory addresses. esi is the source index register. edi is the destination index register.
They can be used to store addresses.

Before the main() function, there is a function CRTStartUp, ebp is the bottom of the stack of this function, and esp is the top of the stack of this function.
write picture description here
Next, through the first two sentences of code mov assignment move, their state becomes as follows:
write picture description here
In the third sentence, sub is a subtraction instruction, which makes esp move backward by 0E4h units.
The next three sentences are to push ebx, esi, and edi into the stack.
write picture description here
In the seventh sentence, lea means load effective address, that is, the address of [ebp - 0E4h] is taken out and assigned to edi.
Eighth sentence, move the 39h assignment to ecx. In the ninth sentence, move the content assignment to eax.
The tenth sentence, rep stos is to copy the data repeatedly.
Note:
The ecx register is used to save the number of copy-pastes, and ecx is the counter.
The eax register is used to transfer information, and eax is an accumulator, usually used to store data.
rep is to repeat the above instruction.
stos is the storage unit that moves the value of eax to the address of es:[edi].
write picture description here
Now the blanks in it are filled with cc cc cc cc. Here cc cc is often encountered "hot".
The split line
The next operation is well understood, its purpose is to create a and b and push them onto the stack.
write picture description here

The calling process of the Add() function

    int c = Add(a, b);
0115174C  mov         eax,dword ptr [b]  
0115174F  push        eax  
01151750  mov         ecx,dword ptr [a]  
01151753  push        ecx  
01151754  call        _Add (01151104h)  
01151759  add         esp,8  
0115175C  mov         dword ptr [c],eax  

In the first four sentences, it finds a register for a and b to store, and at the same time, pushes it into the stack in a reversed way of the function parameter list.
write picture description here
For convenience, only the top half of the diagram will be taken.

Next, the call instruction is used, which moves the instruction to the next sentence first, and then manipulates the content after the call . Pressing F11 at the call will jump to the Add() function.
write picture description here
Add() function


#include<stdio.h>
int Add(int x, int y)
{
001016D0  push        ebp  
001016D1  mov         ebp,esp  
001016D3  sub         esp,0CCh  
001016D9  push        ebx  
001016DA  push        esi  
001016DB  push        edi  
001016DC  lea         edi,[ebp-0CCh]  
001016E2  mov         ecx,33h  
001016E7  mov         eax,0CCCCCCCCh  
001016EC  rep stos    dword ptr es:[edi]  

This part is very similar to the main function creation process. So it is represented by two pictures.
write picture description here
write picture description here

    int z = 0;
001016EE  mov         dword ptr [z],0  
    z = x + y;
001016F5  mov         eax,dword ptr [x]  
001016F8  add         eax,dword ptr [y]  
001016FB  mov         dword ptr [z],eax  
    return z;
001016FE  mov         eax,dword ptr [z]  
}
00101701  pop         edi  
00101702  pop         esi  
00101703  pop         ebx  
00101704  mov         esp,ebp  
00101706  pop         ebp  
00101707  ret  

This code is very interesting, please readers and friends must pay attention.
First, we create the variable ptr[z]. Then, put the value of ptr[x] in eax, add the value of ptr[y] to eax and put it in eax, and move the value of eax to ptr[z]. Finally, we need to return z. This is where the compiler moves the value assignment of ptr[z] to eax again. The reason for this is: ptr[x], ptr[y], ptr[z] will be destroyed after the function completes, but the register eax will not be destroyed, so the value in eax is very safe.

The fourth sentence outside the brackets is very important. It will destroy all data for that function.
write picture description here
After popping ebp, there is only one pointer esp at that point. Next, execute ret, that is, return returns. Go back to where we just called below.

Destruction of main() function

01151759  add         esp,8  
0115175C  mov         dword ptr [c],eax  
    return 0;
0115175F  xor         eax,eax  
}
01151761  pop         edi  
01151762  pop         esi  
01151763  pop         ebx  
01151764  add         esp,0E4h  
0115176A  cmp         ebp,esp  
0115176C  call        __RTC_CheckEsp (01151122h)  
01151771  mov         esp,ebp  
01151773  pop         ebp  
}

Now we jump back to the first sentence of the paragraph, and now esp+8 is headed for the high address. Its purpose is to eliminate the a, b of the parameter instantiation. In the second sentence, we moved the data assignment saved in eax to c. Finally, xor XOR, self and self XOR or its value becomes 0.

write picture description here
After that, we popped edi, esi, ebx. Now esp points to our red arrow ebp - 0E4h at the beginning .
Then, thanks to the add operation, we continue to the high address, to where we started.
write picture description here
write picture description here
Now, we come to the cmp instruction, cmp is the comparison instruction. Its operation is to take the first number and subtract the second number. If the subtraction is ZF=0, it means equal. But cmp doesn't really decrease. At this point, the main() function is really executed, and then esp, ebp. back to its original position. As for the subsequent function calls, there is no need to delve into it. So far we have seen how the function is implemented in assembly

Thank you for reading, and if you have any questions, please let me know.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324733463&siteId=291194637