1. _ cdecl
_ Cdecl is the abbreviation of C Declaration (declaration), which indicates the default function call method of C language: All parameters are pushed to the stack from right to left, and the caller is responsible for pushing parameters to the stack, finally, the caller is responsible for clearing the stack content, in general, this is the C/C ++ default call function rules, the ms vc compiler uses the rules is this rule 2. _ stdcall
_ Stdcall is the abbreviation of StandardCall. It is the standard call method of c ++. All parameters are pushed to the stack from right to left, and the caller is responsible for pushing the parameters to the stack, finally, the caller is responsible for clearing the stack content. The function calling rules used by Windows APIs are such rules.
In addition, the modifier names generated by functions with different rules of _ cdecl and _ stdcall are also different. The same point is that the prefix of the generated function modifier names is underlined, the difference is the suffix. Of course, the biggest difference between the two is that the stack recovery method is different, and this is also the most important.
_ Cdecl rules require the caller to be responsible for Stack restoration. From the Assembly perspective, the position of stack restoration is within the calling function, consider such a piece of C ++ code (Debug under VC)
Copy codeThe Code is as follows: # include <cstdio>
Void _ cdecl func (int param1, int param2, int param3 ){
Int var1 = param1;
Int var2 = param2;
Int var3 = param3;
Printf ("% ld \ n", long (& param1 ));
Printf ("% ld \ n", long (& param2 ));
Printf ("% ld \ n", long (& param3 ));
Printf ("---------------- \ n ");
Printf ("% ld \ n", long (& var1 ));
Printf ("% ld \ n", long (& var2 ));
Printf ("% ld \ n", long (& var3 ));
Return;
}
Int main (){
Func (1, 2, 3 );
Return 0;
}
Note that the func function uses _ cdecl for modification (in fact, this is not required, because the default _ cdecl rule in VC is used, which is to be clearer here). The compilation code is as follows:
Copy codeThe Code is as follows: 3: void _ cdecl func (int param1, int param2, int param3 ){
00401020 push ebp
00401021 mov ebp, esp
00401023 sub esp, 4Ch
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi, [ebp-4Ch]
0040102C mov ecx, 13 h
00401031 mov eax, 0 CCCCCCCCh
00401036 rep stos dword ptr [edi]
4: int var1 = param1;
00401038 mov eax, dword ptr [ebp + 8]
0040103B mov dword ptr [ebp-4], eax; Note the order var1, var2, var3 press onto the stack!
5: int var2 = param2;
0040103E mov ecx, dword ptr [ebp + 0Ch]
00401041 mov dword ptr [ebp-8], ecx
6: int var3 = param3;
00401044 mov edx, dword ptr [ebp + 10 h]
00401047 mov dword ptr [ebp-0Ch], edx
........................................ .......; The printf code is omitted.
15: return;
16 :}
004010BD pop edi
004010BE pop esi
004010BF pop ebx
004010C0 add esp, 4Ch
004010C3 cmp ebp, esp
004010C5 call _ chkesp (004011d0)
004010CA mov esp, ebp
004010CC pop ebp
004010CD ret; here is ret, Which is restored by the caller (main), but if it is _ stdcall,
Resume the stack.
**************************************** **************************************** ***********************************
18: int main (){
........................................ .......; The stack creation code is omitted.
19: func (1, 2, 3 );
00401118 push 3; push param3 to stack
0040111A push 2; push param2 to stack
0040111C push 1; push param1 to stack
0040111E call @ ILT + 5 (func) (0040100a); @ ILT + 5 (func) is the modifier of function func, and 0040100a is his address.
00401123 add esp, 0Ch; stack restoration ,__ the cdecl rule is restored by the caller (here it is main ).
20: return 0;
00401126 xor eax, eax
21 :}
00401128 pop edi
00401129 pop esi
0040112A pop ebx
0040112B add esp, 40 h
0040da-e cmp ebp, esp
00401130 call _ chkesp (004011d0)
00401135 mov esp, ebp
00401137 pop ebp
00401138 ret
Result
The stack structure in the program is shown as follows:
_ Stdcall rules are adjusted by the caller. From the Assembly perspective, stack restoration occurs in the caller's function. Consider the following code (Debug in VC ):
Copy codeThe Code is as follows: # include <cstdio>
Void _ stdcall func (int param1, int param2, int param3 ){
Int var1 = param1;
Int var2 = param2;
Int var3 = param3;
Printf ("% ld \ n", long (& param1 ));
Printf ("% ld \ n", long (& param2 ));
Printf ("% ld \ n", long (& param3 ));
Printf ("---------------- \ n ");
Printf ("% ld \ n", long (& var1 ));
Printf ("% ld \ n", long (& var2 ));
Printf ("% ld \ n", long (& var3 ));
Return;
}
Int main (){
Func (1, 2, 3 );
Return 0;
}
Note that the func function uses _ cdecl for modification (in fact, this is not required, because the default _ cdecl rule in VC is used, which is to be clearer here). The compilation code is as follows:
Copy codeThe Code is as follows: 1: # include <cstdio>
2:
3: void _ stdcall func (int param1, int param2, int param3 ){
00401020 push ebp
00401021 mov ebp, esp
00401023 sub esp, 4Ch
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi, [ebp-4Ch]
0040102C mov ecx, 13 h
00401031 mov eax, 0 CCCCCCCCh
00401036 rep stos dword ptr [edi]
4: int var1 = param1;
00401038 mov eax, dword ptr [ebp + 8]
0040103B mov dword ptr [ebp-4], eax
5: int var2 = param2;
0040103E mov ecx, dword ptr [ebp + 0Ch]
00401041 mov dword ptr [ebp-8], ecx
6: int var3 = param3;
00401044 mov edx, dword ptr [ebp + 10 h]
00401047 mov dword ptr [ebp-0Ch], edx
........................................ ......; Omitting the printf code
15: return;
16 :}
004010BD pop edi
004010BE pop esi
004010BF pop ebx
004010C0 add esp, 4Ch
004010C3 cmp ebp, esp
004010C5 call _ chkesp (004011d0)
004010CA mov esp, ebp
004010CC pop ebp
004010CD ret 0Ch; _ stdcall here (called function) to restore the stack, but if it is _ cdecl, It is ret,
; The caller (main here) is responsible for Stack recovery.
**************************************** **************************************** ***********************************
18: int main (){
........................................ ...; Omitting stack creation code
19: func (1, 2, 3 );
00401118 push 3; param3 press into Stack
0040111A push 2; param2 press into Stack
0040111C push 1; param1 is pushed to the stack
0040111E call @ ILT + 0 (func) (00401005); @ ILT + 0 (func) is the modified name of the function, and 00401005 is the address for calling the function func.
20: return 0;
00401123 xor eax, eax
21 :}
00401125 pop edi
00401126 pop esi
00401127 pop ebx
00401128 add esp, 40 h
0040112B cmp ebp, esp
0040112D call _ chkesp (004011d0)
00401132 mov esp, ebp
00401134 pop ebp
00401135 ret
The running result is the same as that using the _ cdecl rule. The stack structure of the two is basically the same. The only difference is that the position of the stack (restoring stack) and the modifier of the function generation are different, these differences are the most important differences between _ stdcall and _ cdecl.