Environment: VC++
Effect:
A function is a unit of independent program code that performs a specific task
1. Creating and using functions
- Function prototype: declare the type of the function, indicating the return value of the function and the parameter type received by the function. There are many types of functions and variables, and any program must declare the type of the function before using the function
- Function call: it indicates that when the function is executed here and the statement of function call is executed, the program will find the definition of the function and execute its contents. After execution, return to the calling function and continue to execute the next line
- Function definition: specify what the function does
#include "stdio.h" int add(int a,int b); //Function prototype int main(void) { int a=1,b=1,sum=0; sum=add(a,b); //function call printf("sum=%d\n",sum); return 0; } //Function definition int add(int a,int b) { return a+b; }
Let's look at disassembly:
Function prototype:
We can see that the function prototype does not generate machine code here. This is for the compiler to see. It tells the compiler the return value of this function and the parameter type received by the function, and looks at the function type elsewhere. The machine code is for the CPU to execute, so the CPU will not do anything here
Function call:
8: sum=add(a,b); //function call 0040104D 8B 45 F8 mov eax,dword ptr [ebp-8] 00401050 50 push eax 00401051 8B 4D FC mov ecx,dword ptr [ebp-4] 00401054 51 push ecx 00401055 E8 AB FF FF FF call @ILT+0(add) (00401005) 0040105A 83 C4 08 add esp,8 0040105D 89 45 F4 mov dword ptr [ebp-0Ch],eax
Before the function is called, we can see that the parameters will be stored in the stack, that is, the values of a and b, and then executed at 00401005 address. There is a jmp statement at this address, which will jump to the function definition for execution
Function definition:
13: //Function definition 14: int add(int a,int b) 15: { 004010A0 55 push ebp 004010A1 8B EC mov ebp,esp 004010A3 83 EC 40 sub esp,40h 004010A6 53 push ebx 004010A7 56 push esi 004010A8 57 push edi 004010A9 8D 7D C0 lea edi,[ebp-40h] 004010AC B9 10 00 00 00 mov ecx,10h 004010B1 B8 CC CC CC CC mov eax,0CCCCCCCCh 004010B6 F3 AB rep stos dword ptr [edi] 16: return a+b; 004010B8 8B 45 08 mov eax,dword ptr [ebp+8] 004010BB 03 45 0C add eax,dword ptr [ebp+0Ch] 17: } 004010BE 5F pop edi 004010BF 5E pop esi 004010C0 5B pop ebx 004010C1 8B E5 mov esp,ebp 004010C3 5D pop ebp 004010C4 C3 ret
From the above program, we can see that the function definition will first store the esp in the stack, then give the value of esp to ebp, then open a 40h stack, then store ebx, esi, edi in the stack, and then store 0cccccccccccccccch in some consecutive addresses, and execute the statements in the function definition after these are done.
16: return a+b; 004010B8 8B 45 08 mov eax,dword ptr [ebp+8] 004010BB 03 45 0C add eax,dword ptr [ebp+0Ch]
Let's look at the end of the function
004010BE 5F pop edi 004010BF 5E pop esi 004010C0 5B pop ebx 004010C1 8B E5 mov esp,ebp 004010C3 5D pop ebp 004010C4 C3 ret
At the end of the function, the contents of these registers are given to them. The value of ebp is given to esp. ebp recovers the ebp before the function, and then returns. The function is the same as function call
The function only completes specific tasks, and nothing else changes. From function call to function definition, and finally return, it seems that it only operates on the values of a and b, and nothing else changes
Conclusion:
The function prototype didn't generate machine code. It told the compiler what my parameters were and what the return value was. The function call would first push the parameters into the stack, and then execute the call to an address where there is a jmp command, and then execute the function definition. The function definition would first push some registers into the stack, and then assign values to some memory, and finally put these registers in the stack The function returns to the original value, executes the ret command, and returns the calling function to continue to execute the next line.
2. Difference between value and address
First of all, we need to know some little knowledge
- &Operator: take the storage address of the variable
- *Indirect operator: takes the value stored on the pointer point address, and can also be used to declare the pointer
- Declare pointer variable: type * variable name, declare pointer variable must specify the type of variable the pointer points to, because different variable types occupy different storage space
#include "stdio.h" int add1(int a,int b); //Function prototype int add2(int *a,int *b); //Function prototype int main(void) { int a=1,b=1,sum1,sum2; sum1=add1(a,b); //function call printf("sum1=%d\n",sum1); sum2=add2(&a,&b); //function call printf("sum2=%d\n",sum2); return 0; } //Function definition int add1(int a,int b) { return a+b; } int add2(int *a,int *b) { return *a+*b; }
Passing value:
8: sum1=add1(a,b); //function call 0040D786 8B 45 F8 mov eax,dword ptr [ebp-8] 0040D789 50 push eax 0040D78A 8B 4D FC mov ecx,dword ptr [ebp-4] 0040D78D 51 push ecx 0040D78E E8 7C 38 FF FF call @ILT+10(add) (0040100f) 0040D793 83 C4 08 add esp,8 0040D796 89 45 F4 mov dword ptr [ebp-0Ch],eax
Value is passed to eax register, and then it is pushed into stack
Address:
10: sum2=add2(&a,&b); //function call 0040D7AA 8D 45 F8 lea eax,[ebp-8] 0040D7AD 50 push eax 0040D7AE 8D 4D FC lea ecx,[ebp-4] 0040D7B1 51 push ecx 0040D7B2 E8 5D 38 FF FF call @ILT+15(add2) (00401014) 0040D7B7 83 C4 08 add esp,8 0040D7BA 89 45 F0 mov dword ptr [ebp-10h],eax
Send the address to eax and stack it
We know that the value of a variable can't be modified by its address, but it can. From the perspective of assembly, we can understand more clearly that the value of a variable is just passed by. The function call is executed at the function definition, and we don't know where the variable is, so we can't modify it. When the address is passed to the function definition, we know where the variable's address is, so we can modify the content of the variable