Parsing function call conventions
Http://www.allaboutprogram.com/index.php? Option = content & task = view & id = 29 & Itemid = 31
HouSisong@263.net 2004.11.07 Finishing
The article comes from a post in the ABC Forum: http://bbs.allaboutprogram.com/viewtopic.php? T = 1245
(The original article was written in 2003.12.01, and the description of the Transfer Method of the function return value is provided here)
Preface:
This article describes the function call conventions in several major programming languages. The detailed descriptions mainly refer to the function call conventions in vc6, the interpretation method is mainly based on the Compilation code obtained after the C ++ program is compiled;
The compiler and platform I use: WindowsXP + Sai Yang 1G + vc6 (main tool)/DELPHI6/C ++ Builder6;
I. function call conventions;
The function call convention is a convention between the function caller and the called function body regarding parameter transfer, return value transfer, stack clearing, and register use;
It is a strong Convention that requires binary compatibility. If different call conventions are used by function callers and function bodies, program execution errors may occur and must be considered as part of the function declaration;
Ii. Common function call conventions;
Function call conventions in vc6;
Call Convention stack clearing parameter passing
_ Cdecl the caller passes the stack from right to left
_ Stdcall function is passed through Stack from right to left
_ Fastcall: Use register (ECx, EDX) first, and then use Stack
The thiscall function body this pointer is passed through ECx by default, and other parameters are passed from right to left.
_ Cdecl is the default call Convention of C/C ++. The keyword thiscall is not found in the call Convention of VC. It is the default call Convention of class member functions;
The calling conventions of the main (or wmain) function in C/C ++ must be _ cdecl and cannot be changed;
The default call conventions can be changed through the compiler settings. If your code depends on the call conventions, specify the call conventions to be used;
The function call convention in DELPHI6;
Call Convention stack clearing parameter passing
The register function uses registers (eax, EDX, ECx) first from left to right, and then stacks
Pascal functions are transferred from left to right through Stack
Cdecl callers pass through stacks from right to left (compatible with C/C ++ default call conventions)
Stdcall function from right to left, passed through stack (compatible with _ stdcall in VC)
The safecall function is passed through Stack from right to left (same as stdcall)
The default call convention in Delphi is register, which is also the most efficient method in my opinion, and cdecl is the one with the worst overall efficiency;
The _ fastcall call convention in VC is generally less efficient than register;
Function call conventions in C ++ Builder6;
Call Convention stack clearing parameter passing
_ Fastcall function bodies are left-to-right. Registers (eax, EDX, and ECx) are preferentially used, and stacks (Delphi-compatible register) are used)
(Register is equivalent to _ fastcall)
_ Pascal function from left to right, passed through Stack
_ Cdecl callers pass through stacks from right to left (compatible with C/C ++ default call conventions)
The _ stdcall function is passed through the stack from right to left (compatible with _ stdcall in VC)
_ Msfastcall: use registers (ECx, EDX) first, and use stacks (_ fastcall compatible with VC)
In common function call conventions, only cdecl conventions require callers to clear stacks;
Functions in C/C ++ support a list of parameters with an indefinite number, such as the printf function. Because the function body does not know how many parameters the caller has added to the stack,
Therefore, the function body cannot easily know how to clear the stack, so the best way is to hand over the responsibility for clearing the stack to the caller;
This should be the reason why the cdecl call convention exists;
VB generally uses the stdcall call convention; (PS: Is there a stronger guarantee)
In Windows APIs, stdcall conventions are generally used. (PS: Is there a stronger guarantee)
We recommend that you use the stdcall call convention in different languages (such as DLL), because it provides the best compatibility between languages;
Iii. Transfer Method of function return values
In fact, the transfer of return values can also be considered as an out-form parameter for function calls. The transfer of function return values is also part of the function call conventions;
When a function with a return value is returned: Generally, 32-bit data values (including 32-bit data values) such as int and pointer are transmitted through eax, (bool and Char are passed through Al, and short is passed through Ax ), the special 64-bit structure (struct) such as _ int64 is passed through the edX and eax registers (likewise, the 32bit integer is passed through Dx and ax in the 16bit environment ); returns an eax address for a structure of other sizes (struct). (when the return value type is not 1, 2, 4, or 8 bytes, the efficiency may be poor)
During parameter and return value transfer, the type of the reference method can be seen as the same as that of the pass pointer method;
Float/double (including extended in Delphi) are all returned through the floating point register ST (0;
4. Use the C ++ example in VC and the compiled assembly list to describe the function call conventions;
(PS: although many compilations are listed later, I have made detailed comments. I hope those who are "afraid" of compilation
It can also be smoothly read, and provide some help for those who want to use the Assembly in VC
A:
Test code:
Int X;
Int _ cdecl add (int A, int B) {return a + B;} // call convention using _ cdecl
Int main (INT argc, char * argv [])
{
X = add (1, 2 );
Return 0;
}
Compiled assembly code in debug mode
Public? X @ 3ha; x
_ BSS segment
? X @ 3ha dd 01 h dup (?) ; X variable
_ BSS ends
Public? Add @ yahhh @ Z; add
Public _ main
Extrn _ chkesp: near
; Comdat _ main
_ Text Segment
_ Main proc near; comdat // main function body
Push EBP; // Save the EBP value to the stack, and use Pop EBP to restore it before exiting the function.
MoV EBP, esp; // EBP points to the current stack; function can be accessed through EBP Stack
Sub ESP, 64; // open up 64byte local space in the stack
; // Note: these three assembly commands are the first common use of many function bodies;
; // Use EBP to point to the stack (which will not be changed); and use EBP to access parameters and local variables;
Push EBX; // generally, according to the Inter-function call conventions, eax, ECx, and EDX can be freely used in functions;
Push ESI; // if other registers need to be used, they need to be saved and restored when used up; that is, the register usage Convention; this also makes part of the function call Convention;
Push EDI; // that is, after other functions are called in the function, eax, ECx, and EDX may have changed,
; // Other registers (EBX, ESI, EDI, EBP) can be used with confidence (except ESP)
Lea EDI, dword ptr [ebp-64]
MoV ECx, 16; 00000010 H
MoV eax,-858993460; cccccccch
Rep stosd; // all the previously opened (16*4) byte local space is filled with 0xcc
; // Note: 0xcc is the instruction code for debugging interruption (_ asm int 3). As you can imagine, when
; // Debugging interruption occurs when a program jumps to this region for execution due to a program error
Push 2; // code: x = add (1, 2 );
Push 1; // stack inbound from right to left (_ cdecl call convention !!!)
Call? Add @ yahhh @ Z; call the Add function. The call command pushes the address (return address) of the next command to the stack.
Add ESP, 8; after the Add function is called, the caller is responsible for clearing the stack (_ cdecl call convention !!!)
Two int-type parameters use a stack of 8 bytes space.
MoV dword ptr? X @ 3ha, eax; Save the return value of the add function to the X variable. You can see that the return value of the add function is placed in eax.
XOR eax, eax; // original code: Return 0; execute eax clearing, and put the return value of main function 0 in eax
Pop EDI
Pop ESI
Pop EBX; // restores EDI, ESI, and EBX registers.
Add ESP, 64; // restore 64byte local space
Cmp ebp, ESP
Call _ chkesp; // EBP = ESP and debug should be used here for confirmation. If not, an exception is thrown.
MoV ESP, EBP
Pop EBP; // restores the EBP register.
RET 0
_ Main endp
_ Text ends
; // The following is the code of the add function, so you don't need to explain it as detailed as above
; Comdat? Add @ yahhh @ Z
_ Text Segment
_ A $ = 8; // parameter A for Stack offset 8
_ B $ = 12; // parameter B offset from Stack 12
? Add @ yahhh @ Z proc near; add, comdat // Add function body
Push EBP
MoV EBP, ESP
Sub ESP, 64; 00000040 H
Push EBX
Push ESI
Push EDI
Lea EDI, dword ptr [ebp-64]
MoV ECx, 16; 00000010 H
MoV eax,-858993460; cccccccch
Rep stosd
MoV eax, dword ptr _ A $ [EBP]; move the value of parameter A to eax
Add eax, dword ptr _ B $ [EBP]; Add the value of parameter B to eax; it can be seen that the returned value is returned through eax
Pop EDI
Pop ESI
Pop EBX
MoV ESP, EBP
Pop EBP
RET 0; the function body is cleared regardless of the stack parameters (_ cdecl call convention !!!)
The RET command will take out the return address pushed by the call command, and jump to the past to continue the execution
? Add @ yahhh @ Z endp; add
_ Text ends
End
; Let's take a look at the compilation code after the release mode is compiled.
As you can see, this is much less than the debug mode of assembly instructions, of course, the speed may be faster; no more details, please refer to the above explanation
Public? X @ 3ha; x
_ BSS segment
? X @ 3ha dd 01 h dup (?) ; X
_ BSS ends
Public? Add @ yahhh @ Z; add
Public _ main
; Comdat _ main
_ Text Segment
_ Main proc near; comdat // main function body
Push 2
Push 1; // stack inbound from right to left (_ cdecl call convention !!!)
Call? Add @ yahhh @ Z; // call the Add function;
MoV dword ptr? X @ 3ha, eax; x
Add ESP, 8; // the caller is responsible for clearing the stack (_ cdecl call convention !!!)
XOR eax, eax
RET 0
_ Main endp
_ Text ends
; Comdat? Add @ yahhh @ Z
_ Text Segment
_ A $ = 8
_ B $ = 12
? Add @ yahhh @ Z proc near; add, comdat // Add function body
MoV eax, dword ptr _ B $ [esp-4]; move the value of parameter B to eax
MoV ECx, dword ptr _ A $ [esp-4]; move the value of parameter A to ECx
Add eax and ECx; accumulate the value of ECx to eax; pass the returned value through eax
RET 0; the function body is cleared regardless of the stack parameters (_ cdecl call convention !!!)
? Add @ yahhh @ Z endp; add
_ Text ends
End
The following analysis will only show the compiled assembly code in the release mode.
B:
Declare the Add function as the _ stdcall call Convention
Int X;
Int _ stdcall add (int A, int B) {return a + B ;}
Int main (INT argc, char * argv [])
{
X = add (1, 2 );
Return 0;
}
; To see the resulting assembly code:
; // Main function body
Push 2
Push 1; // stack inbound from right to left
Call? Add @ yghhh @ Z; add
MoV dword ptr? X @ 3ha, eax; x
XOR eax, eax
RET 0
; // Add function body
MoV eax, dword ptr _ B $ [esp-4]
MoV ECx, dword ptr _ A $ [esp-4]
Add eax, ECx
RET 8; // The function body is responsible for clearing the stack. Two int-type parameters use a stack of 8 bytes of space.
C:
Declare the Add function as the _ fastcall call Convention
Int X;
Int _ fastcall add (int A, int B) {return a + B ;}
Int main (INT argc, char * argv [])
{
X = add (1, 2 );
Return 0;
}
; To see the resulting assembly code:
; // Main function body
MoV edX, 2; B is passed through the Register edX
MoV ECx, 1; A is passed through the Register ECx
Call? Add @ yihhh @ Z; add
MoV dword ptr? X @ 3ha, eax; x
XOR eax, eax
RET 0
; // Add function body
Lea eax, dword ptr [ECx + EDX]; // The value of A and B is already in ECx and EDX. Put the sum of the two values into eax as the return value;
RET 0; // The function body should be responsible for clearing the stack, but because the two parameters have been passed through the Register
; //, No stack is used, so RET 0;
D:
Let's take a look at the call of the member functions of the class:
Struct t
{
Int start0;
T (): start0 (1 ){}
Int add (int A, int B); // class member functions; thiscall is used by default as long as the call Conventions are not explicitly declared;
};
Int T: add (int A, int B) {return (* This). start0 + A + B ;}
Int X;
Int main (INT argc, char * argv [])
{
T;
X = T. Add (1, 2 );
Return 0;
}
Let's look at the generated assembly code:
; // Main function body
Push ECx; // save ECx
Push 2
Push 1; // The parameter is pushed from right to left.
Lea ECx, dword ptr _ T $ [esp + 12]; // Save the address of t to ECx
MoV dword ptr _ T $ [esp + 12], 1; // execute T: start0 = 1;
Call? Add @ t @ qaehhh @ Z; // call the T: Add function. In this case, the address of T (this pointer) is stored in ECx );
MoV dword ptr? X @ 3ha, eax; x
XOR eax, eax
Pop ECx
RET 0
; // T: Add function body
MoV eax, dword ptr [ECx]; // move the start0 value to eax through the this pointer (saved in ECx)
MoV ECx, dword ptr _ A $ [esp-4]; // move the value of a to ECx; the value of this will be lost, but no longer needed in the function body
Add eax, ECx; // Add the value of a to eax
MoV ECx, dword ptr _ B $ [esp-4]; // move the value of B to ECx;
Add eax, ECx; // Add the value of B to eax
RET 8; // The function body is responsible for clearing the stack;
V. Others
1. When implementing a function body in VC, you can use the _ declspec (naked) Declaration, which tells the compiler not to automatically generate the start and end codes for the function body;
2. In vc6, to get the assembly code list, set the method:
Reference: [project]-> [setting...] -> [C ++]-> [Category:]-> [Listing files]-> [listing file type:]-> [assembily,...]
3. The method for embedding assembly code in vc6 is as follows:
_ ASM {<Assembly Statement S>}
Or _ ASM <an Assembly Statement>
4. The default call conventions for resetting functions in vc6 are as follows:
Reference:
Add the compilation settings in [project]-> [setting...]-> [C ++]-> [project options :].
For example,/GD stands for _ cdecl;/GR stands for _ fastcall;/GZ stands for _ stdcall
References:
Msdn: calling conventions;
DELPHI6/C ++ Builder6 help;
Use www.google.com and www.baidu.com to search for "Call conventions" or "calling conventions ";