Analysis of C + + function call agreement
Visual C / C + + compiler offers several function calling convention, agreed understanding of these function calls the meaning and the difference between them can help us better debugging procedures. In this article, and I will explore some common agreement on the content of function call.
Visual C / C + + compiler for the function calling convention is as follows:
Keyword
Stack cleared
Ruzhan sequence parameters
Modified function name (C)
__cdecl
Call functions
Left Right Ã
_ Function names
__stdcall
Function is called
Left Right Ã
_ Function names @ Figures
__fastcall
Function is called
Left Right Ã
@ @ Function of the number
Thiscall (non-keyword)
Function is called
Left Right Ã
/
Above this table simply lists each function call features of the agreement, since the topic of the article before the word "analysis" How could so easily get away! ? Below the top four of the agreed-by-function call "analysis":
1 __ cdecl function calling convention
This is C and C + + function call default procedures agreed parameters according to the order from right to left into the stack pressure by calling function responsible for clearing the stack, stack up the parameters. It is exactly because of the parameters used to send call stack by the maintenance function, a function of achieving variable parameters can only use this function calling convention. Because each one calls it a function of stack clean-up to contain the code, the compiler executable file size than __ stdcall call the function. The use of this function call agreement, modified only after the function name in the original function with a former _ (underlined), and do not change the function of the case. For __ cdecl, we generally do not specifically pointed out that because it is C and C + + function call default procedures agreed that the only option will be set to compiler / Gz (stdcall) or / Gr (fastcall), we only need to function former explicit that the use of this function calling convention. Below cite an example:
Int __cdecl Sumcdecl (int a, int b, int c)
(
Int i = 1000;
Short j = 2000;
Int k = 3000;
Int rEBP = 0;
Int value = 0;
/ / …
Return (a + b + c);
)
Call: Sumcdecl (10, 20, 30);
The function body and called statements, as indicated above, a function called modified _ Sumcdecl, stack and register state as follows (and his entourage 4 bytes):
0
Value
0
REBP
3000
K
2000
J
1000
I
<——— EBP
10
A
20
B
30
C
[Unused]
ECX
[Unused]
EDX
I say that with no code can explain all, the following procedures are Win32 console application (. Exe) is also:
# Include "iostream.h"
# Include "stdio.h"
Extern "C" __declspec (dllexport) int __cdecl Sumcdecl (int a, int b, int c)
(
/ / Local variables statement
Int i = 1000;
Short j = 2000;
Int k = 3000;
Int rEBP = 0;
Int value = 0;
/ / Show the address of local variables
Cout << "local variables Address:" <<endl;
Cout <<& value << "<———– value" <<endl;
Cout <<& rEBP << "<———– rEBP" <<endl;
Cout <<& k << "<———– k" <<endl;
Cout <<& j << "<———– j" <<endl;
Cout <<& i << "<———– i" <<endl;
/ / Show the value of register
Cout << "register:" <<endl;
__asm Mov rEBP, ebp;
Printf ( "<———– EBP 0x% 08X \ n", rEBP);
/ / Show the address of function parameters
Cout << "function parameters Address:" <<endl;
Cout <<& a << "<———– a" <<endl;
Cout <<& b << "<———– b" <<endl;
Cout <<& c << "<———– c" <<endl;
/ / EBP register through access to the data in the stack and display
Cout << "EBP access through the data in the stack:" <<endl;
__asm Mov eax, [ebp - 4];
__asm Mov value, eax;
Cout << "i:" <<value <<endl;
__asm Mov eax, [ebp - 8];
__asm Mov value, eax;
Cout << "j:" <<(short) value <<endl;
__asm Mov eax, [ebp - 12];
__asm Mov value, eax;
Cout << "k:" <<value <<endl;
__asm Mov eax, [ebp + 8];
__asm Mov value, eax;
Cout << "a:" <<value <<endl;
__asm Mov eax, [ebp + 12];
__asm Mov value, eax;
Cout << "b:" <<value <<endl;
__asm Mov eax, [ebp + 16];
__asm Mov value, eax;
Cout << "c:" <<value <<endl;
/ /
Return (a + b + c);
)
/ / Main function
Int main (int argc, char * argv [])
(
Sumcdecl (10, 20, 30);
Return 0;
)
In my machines, operating results were as follows:
Local variables Address:
0×0012FF0C <———– value
0×0012FF10 <———– rEBP
0×0012FF14 <———– k
0×0012FF18 <———– j
0×0012FF1C <———– i
Register:
0×0012FF20 <———– EBP
Function parameters Address:
<———– A 0×0012FF28
0×0012FF2C <———– b
0×0012FF30 <———– c
EBP through access to the data in the stack:
I: 1000
J: 2000
K: 3000
A: 10
B: 20
C: 30
Part of the function statement extern "C" said that linking norms (Linkage Specification) using C, rather than C + +, not extern "C" in the back I will discuss reunification. __declspec (Dllexport) that the function is derived, will generate. Lib documents, so that we verify function of how modified. On the modification of the function, we can use the VC98 \ bin directory under the dumpbin tools to verify:
Dumpbin / exports <lib文件å>
Output results are as follows:
File Type: LIBRARY
Exports
Ordinal name
_Sumcdecl
Summary
C9. Debug $ S
14. Idata $ 2
14. Idata $ 3
4. Idata $ 4
4. Idata $ 5
E. Idata $ 6
Second, the function calling convention __ stdcall
__stdcall Function calling convention is used Win32 API function, parameter according to the order from right to left into the stack pressure, was responsible for clearing the function call stack, stack up the parameters. In windows.h includes windef.h, and the definition of a windef.h WINAPI macro: # define WINAPI __stdcall, Oh, it should be well aware of. The use of this function call agreement, modified the function name in the original function with a former _ (underlined), and in the original function name with "@ Digital", of course, does not change the function of the case, behind the @ Figures number of bytes of parameters, we should pay attention to this point, less than 32-bit (4-byte) in the parameters of transmission parameters were expanded to 32. Below cite an example:
Int __stdcall Sumstdcall (int a, int b, int c)
(
Int i = 1000;
Short j = 2000;
Int k = 3000;
Int rEBP = 0;
Int value = 0;
/ / …
Return (a + b + c);
)
Call: Sumstdcall (10, 20, 30);
The function body and called statements, as indicated above, a function called modified _ Sumstdcall @ 12, int is 32, accounting for 4 bytes, three of the 32 variables total of 12 bytes. Stack and register state as follows (and his entourage 4 bytes):
0
Value
0
REBP
3000
K
2000
J
1000
I
<——— EBP
10
A
20
B
30
C
[Unused]
ECX
[Unused]
EDX
Still code:
# Include "iostream.h"
# Include "stdio.h"
Extern "C" __declspec (dllexport) int __stdcall Sumstdcall (int a, int b, int c)
(
/ / Local variables statement
Int i = 1000;
Short j = 2000;
Int k = 3000;
Int rEBP = 0;
Int value = 0;
/ / Show the address of local variables
Cout << "local variables Address:" <<endl;
Cout <<& value << "<———– value" <<endl;
Cout <<& rEBP << "<———– rEBP" <<endl;
Cout <<& k << "<———– k" <<endl;
Cout <<& j << "<———– j" <<endl;
Cout <<& i << "<———– i" <<endl;
/ / Show the value of register
Cout << "register:" <<endl;
__asm Mov rEBP, ebp;
Printf ( "<———– EBP 0x% 08X \ n", rEBP);
/ / Show the address of function parameters
Cout << "function parameters Address:" <<endl;
Cout <<& a << "<———– a" <<endl;
Cout <<& b << "<———– b" <<endl;
Cout <<& c << "<———– c" <<endl;
/ / EBP register through access to the data in the stack and display
Cout << "EBP access through the data in the stack:" <<endl;
__asm Mov eax, [ebp - 4];
__asm Mov value, eax;
Cout << "i:" <<value <<endl;
__asm Mov eax, [ebp - 8];
__asm Mov value, eax;
Cout << "j:" <<(short) value <<endl;
__asm Mov eax, [ebp - 12];
__asm Mov value, eax;
Cout << "k:" <<value <<endl;
__asm Mov eax, [ebp + 8];
__asm Mov value, eax;
Cout << "a:" <<value <<endl;
__asm Mov eax, [ebp + 12];
__asm Mov value, eax;
Cout << "b:" <<value <<endl;
__asm Mov eax, [ebp + 16];
__asm Mov value, eax;
Cout << "c:" <<value <<endl;
/ /
Return (a + b + c);
)
/ / Main function
Int main (int argc, char * argv [])
(
Sumstdcall (10, 20, 30);
Return 0;
)
In my machines, operating results were as follows:
Local variables Address:
0×0012FF0C <———– value
0×0012FF10 <———– rEBP
0×0012FF14 <———– k
0×0012FF18 <———– j
0×0012FF1C <———– i
Register:
0×0012FF20 <———– EBP
Function parameters Address:
<———– A 0×0012FF28
0×0012FF2C <———– b
0×0012FF30 <———– c
EBP through access to the data in the stack:
I: 1000
J: 2000
K: 3000
A: 10
B: 20
C: 30
In fact, and the almost __ cdecl, only __ __ stdcall cdecl changed, and changed a function name. Analysis by dumpbin. Lib document the results are as follows:
File Type: LIBRARY
Exports
Ordinal name
_Sumstdcall @ 12
Summary
C9. Debug $ S
14. Idata $ 2
14. Idata $ 3
4. Idata $ 4
4. Idata $ 5
E. Idata $ 6
Third, function calling convention __ fastcall
__fastcall, By definition, characteristic is fast, because it is on the register transfer parameters. Transmission parameters, the most left two less than or equal to 32 (4 bytes) of the parameters will be deposited in the respective registers ECX EDX and the other parameters remain on the order from right to left into the stack pressure, was responsible for the clean-up call functions stack, stack up the parameters. Here are some that would like to emphasize: the two deposited register also credited to the actual parameters of the stack in the back of examples and code will prove this point. The use of this function call agreement, modified the function name in the original function with a former @, and in the original function name with "@ figures," but do not change the function of the case, said that the figures behind the @ parameter of number of bytes, and in fact almost stdcall __, _ only to the top of the (underlined) by the Government. Below cite an example, and in front of two slightly different:
Int __fastcall Sumfastcall (int a, double x, int b, int c)
(
Int i = 1000;
Short j = 2000;
Int k = 3000;
Int rEBP = 0;
Int rECX = 0;
Int rEDX = 0;
Int value = 0;
/ / …
Return (a + b + c);
)
Call: Sumfastcall (10, 8.8, 20, 30);
The function body and called statements, as indicated above, a function called modified Sumfastcall @ @ 20, int is 32, accounting for 4 bytes, double that of 64, accounting for eight bytes, three of the 32 variables plus 1 of 64 variables, a total of 20 bytes. Stack and register state as follows (and his entourage 4 bytes):
0
Value
0
REDX
0
RECX
0
REBP
3000
K
2000
J
1000
I
20
B
10
A
<——— EBP
8.8
X (8 bytes)
30
C
10
ECX
20
EDX
__ Fastcall and because of the two previous function calling convention is not the same, local variables, function parameters stored in the stack and register (and mainly ECX EDX), the value has changed, and we have to verify these, the code not, but substantially the same, they will be requested by the following:
# Include "iostream.h"
# Include "stdio.h"
Extern "C" __declspec (dllexport) int __fastcall Sumfastcall (int a, double x, int b, int c)
(
/ / Local variables statement
Int i = 1000;
Short j = 2000;
Int k = 3000;
Int rEBP = 0;
Int rECX = 0;
Int rEDX = 0;
Int value = 0;
/ / Display ECX EDX register and the value of
__asm Mov rECX, ecx;
__asm Mov rEDX, edx;
Cout << "ECX EDX register and the value:" <<endl;
Cout << "ECX:" <<rECX <<endl;
Cout << "EDX:" <<rEDX <<endl;
/ / Show the address of local variables
Cout << "local variables Address:" <<endl;
Cout <<& value << "<———– value" <<endl;
Cout <<& rEDX << "<———– rEDX" <<endl;
Cout <<& rECX << "<———– rECX" <<endl;
Cout <<& rEBP << "<———– rEBP" <<endl;
Cout <<& k << "<———– k" <<endl;
Cout <<& j << "<———– j" <<endl;
Cout <<& i << "<———– i" <<endl;
/ / Display deposited register the address of the parameters, although deposited in the register variables, but also in the stack
Cout << "show that the parameters of the deposit register address:" <<endl;
Cout <<& b << "<———– b" <<endl;
Cout <<& a << "<———– a" <<endl;
/ / Show the value of register
Cout << "register:" <<endl;
__asm Mov rEBP, ebp;
Printf ( "<———– EBP 0x% 08X \ n", rEBP);
/ / Show the address of function parameters
Cout << "function parameters Address:" <<endl;
Cout <<& x << "<———– x" <<endl;
Cout <<& c << "<———– c" <<endl;
/ / EBP register through access to the data in the stack and display
Cout << "EBP access through the data in the stack:" <<endl;
__asm Mov eax, [ebp - 12];
__asm Mov value, eax;
Cout << "i:" <<value <<endl;
__asm Mov eax, [ebp - 16];
__asm Mov value, eax;
Cout << "j:" <<(short) value <<endl;
__asm Mov eax, [ebp - 20];
__asm Mov value, eax;
Cout << "k:" <<value <<endl;
__asm Mov eax, [ebp - 4];
__asm Mov value, eax;
Cout << "a:" <<value <<endl;
__asm Mov eax, [ebp - 8];
__asm Mov value, eax;
Cout << "b:" <<value <<endl;
__asm Mov eax, [ebp + 16];
__asm Mov value, eax;
Cout << "c:" <<value <<endl;
/ /
Return (a + b + c);
)
/ / Main function
Int main (int argc, char * argv [])
(
Sumfastcall (10, 8.8, 20, 30);
Return 0;
)
In my machines, operating results were as follows:
ECX EDX register and the value of:
ECX: 10
EDX: 20
Local variables Address:
0×0012FEFC <———– value
0×0012FF00 <———– rEDX
0×0012FF04 <———– rECX
0×0012FF08 <———– rEBP
0×0012FF0C <———– k
0×0012FF10 <———– j
0×0012FF14 <———– i
Show that the parameters of the deposit register Address:
0×0012FF18 <———– b
<———– A 0×0012FF1C
Register:
0×0012FF20 <———– EBP
Function parameters Address:
0×0012FF28 <———– x
0×0012FF30 <———– c
EBP through access to the data in the stack:
I: 1000
J: 2000
K: 3000
A: 10
B: 20
C: 30
Use the same dumpbin / exports after the results were as follows:
File Type: LIBRARY
Exports
Ordinal name
@ @ 20 Sumfastcall
Summary
C9. Debug $ S
14. Idata $ 2
14. Idata $ 3
4. Idata $ 4
4. Idata $ 5
E. Idata $ 6
4. Thiscall function calling convention
Yi? Thiscall front did not underscore how, huh. In fact, thiscall not C + + keywords, therefore, we can not explicit in the proceedings that such function calling convention. Some people may ask, how in the end that these things? In fact, we often used, because it is a C + + member function of the default function calling convention, the parameters according to the order from right to left into the stack pressure, was responsible for clearing the function call stack, stack up the parameters. In the secret transfer this pointer, members of this function will not only guide credited to the ECX register, but also deposited to the stack, but it is pressed into the final stack, location and use __ fastcall function calling convention of the most left two less than or equal to 32 (4 bytes) of the location of the same parameters. Below cite an example:
Class Test
(
Public:
Int Sumthiscall (int a, int b, int c)
(
Int i = 1000;
Short j = 2000;
Int k = 3000;
Int rEBP = 0;
Int value = 0;
/ / …
Return (a + b + c);
)
);
Call:
Test test;
Test.Sumthiscall (10, 20, 30);
Members of the definition of function calls and statements, as indicated above, stack and register state as follows (and his entourage 4 bytes):
0
Value
0
REBP
3000
K
2000
J
1000
I
Address Object
This
<——— EBP
10
A
20
B
30
C
Address Object
ECX
[Unused]
EDX
Below we let the code speak, I believe it:
# Include "iostream.h"
# Include "stdio.h"
Class Test
(
Public:
Int Sumthiscall (int a, int b, int c)
(
/ / Local variables statement
Int i = 1000;
Short j = 2000;
Int k = 3000;
Int rEBP = 0;
Int value = 0;
/ / ECX register through access to this guideline
__asm Mov value, ecx;
Printf ( "ECX register through access to this guideline: 0x% 08X \ n", value);
/ / Output this direct object referred to the address of
Printf ( "direct output of the object referred to this address: 0x% 08X \ n", this);
/ / Show the address of local variables
Cout << "local variables Address:" <<endl;
Cout <<& value << "<———– value" <<endl;
Cout <<& rEBP << "<———– rEBP" <<endl;
Cout <<& k << "<———– k" <<endl;
Cout <<& j << "<———– j" <<endl;
Cout <<& i << "<———– i" <<endl;
/ / Show the value of register
Cout << "register:" <<endl;
__asm Mov rEBP, ebp;
Printf ( "<———– EBP 0x% 08X \ n", rEBP);
/ / Show the address of function parameters
Cout << "function parameters Address:" <<endl;
Cout <<& a << "<———– a" <<endl;
Cout <<& b << "<———– b" <<endl;
Cout <<& c << "<———– c" <<endl;
/ / EBP register through access to the data in the stack and display
Cout << "EBP access through the data in the stack:" <<endl;
__asm Mov eax, [ebp - 4];
__asm Mov value, eax;
Printf ( "this: 0x% 08X \ n", value);
__asm Mov eax, [ebp - 8];
__asm Mov value, eax;
Cout << "i:" <<value <<endl;
__asm Mov eax, [ebp - 12];
__asm Mov value, eax;
Cout << "j:" <<(short) value <<endl;
__asm Mov eax, [ebp - 16];
__asm Mov value, eax;
Cout << "k:" <<value <<endl;
__asm Mov eax, [ebp + 8];
__asm Mov value, eax;
Cout << "a:" <<value <<endl;
__asm Mov eax, [ebp + 12];
__asm Mov value, eax;
Cout << "b:" <<value <<endl;
__asm Mov eax, [ebp + 16];
__asm Mov value, eax;
Cout << "c:" <<value <<endl;
/ /
Return (a + b + c);
)
);
/ / Main function
Int main (int argc, char * argv [])
(
Test test;
Test.Sumthiscall (10, 20, 30);
Return 0;
)
In my machines, operating results were as follows:
ECX register through access to this guideline: 0×0012FF7C
Referred to directly output target this address: 0×0012FF7C
Local variables Address:
0×0012FF04 <———– value
0×0012FF08 <———– rEBP
0×0012FF0C <———– k
0×0012FF10 <———– j
0×0012FF14 <———– i
Register:
0×0012FF1C <———– EBP
Function parameters Address:
<———– A 0×0012FF24
0×0012FF28 <———– b
0×0012FF2C <———– c
EBP through access to the data in the stack:
This: 0×0012FF7C
I: 1000
J: 2000
K: 3000
A: 10
B: 20
C: 30
Code did not pass the output variable of this guideline addresses (there & this?) To verify whether it was placed in the stack, but it was through the EBP register correctly referred to the object of this address, and the ECX register in the value of the same . Because thiscall function calling convention only applied to the C + + class member functions, so there is no C language function name modification mechanism, so I did not discuss it, nor will members of function is derived.
Sumcdecl, Sumstdcall function and Sumfastcall three months ago have extern "C", said linking norms (Linkage Specification) using C, rather than C + +, if we do not write it using the default C + +, of course, can be written in extern "C + +." These three functions into one document, and to remove the front of each function extern "C", compiled by dumpbin analysis. Lib documents, results are as follows (and I only take a key part):
? Sumcdecl YAHHHH @ @ @ Z (int __cdecl Sumcdecl (int, int, int))
? Sumfastcall YIHHNHH @ @ @ Z (int __fastcall Sumfastcall (int, double, int, int))
? Sumstdcall YGHHHH @ @ @ Z (int __stdcall Sumstdcall (int, int, int))
Wow! ? This is what things ah, what looked like a mess, slowly Find Road to the next:
1, each function of the "?" The beginning, followed by a function, do not change the case.
2, __ cdecl, function name followed by YA @ @ For __ stdcall, function name followed by YG @ @ For __ fastcall, function follows @ @ YI.
3, again followed by the function's return value type is the type of code and parameters of the code, the rules are as follows:
Code
Type
X
Void
D
Char
E
Unsigned char
F
Short
H
Int
I
Unsigned int
J
Long
K
Unsigned long
M
Float
N
Double
_N
Bool
O
Long double
PA
Guidelines prefix
AA
Quoted prefix
V class name @ @
Class
If the parameter is a pointer, then type in the code before the PA If it is used, in addition of AA type code. If the same type of indicators for a case of "0" to replace each "0" represents a duplication; if the same type of successive cited the case of "1" instead of each "1" represents a duplication.
4, followed by the code List @ Z or Z to identify the function of the end: If there are parameters of the function, while @ Z logo function of the end, if not the function parameters, while Z logo function of the end.
5, function name symbol followed by the end of a space, after the space is bracketed function prototype. Generation in the final document (. Exe or. Dll), the function of the back end there will be no signs function prototype.
Cite a simple example, suppose the following function prototype (Test since definition):
Void abc (int a, long b, c char *, char * d, bool & e, Test f, short g)
Then, after the modified function called:
? YAXHJPAD0AA_NVTest abc @ @ @ @ @ Z F
In fact, we can be in VC + + 6.0 IDE settings in the current environment projects using the default function calling convention. In the main interface opened by pressing Alt + F7] [Project Settings dialog box, choose [C / C + +] tab, and then [Category] in the drop-down list box, select the "Code Gernation" can [in] Call convetion drop-down list box, select the function calling convention. As for the command line switches, / Gd said cdecl __, / __ fastcall Gr said, / __ fastcall Gz said.
Finally, there is a small episode, the theme of the article and not too much, but people will be careful discovered the problem. All the above-mentioned function (including the Test of the members of functions), local variables are short-j, it should be only two bytes from the memory accounts for the distribution of four bytes, why? Because the memory allocation is the smallest unit of four bytes. Do not believe that can char s [10], and then use a similar method above analysis, we believe that accounted for 10 bytes perfectly justified, but the fact is, 12 bytes are assigned to it.
Well, at the end of this journey and I hope you voyage. Finally, before sending a small gift: I above and the rest of the Test of three functions to be placed in a document, the case will be integrated into all together:
Http://csdngoodname008.51.net/CallTest.zip
* Reprint please notify the author and indicate the source of CSDN Welcomes You! *
* Author: Leipeipei (goodname008) *
* E-mail: goodname008@163.com *
* Column: http://blog.csdn.net/goodname008 *
*——————————————-*
Tags: function








0 Comments to “Analysis of C + + function call agreement”
No Comments. Send your comment.
Leave a Reply
You must be logged in to post a comment.