Calling Conventions Demystified (Visual C++ calling conventions explained)
来源:互联网 发布:数据分析统计基础 编辑:程序博客网 时间:2024/06/06 09:43
- # lea edi,[ebp-0C0h]
- # mov ecx,30h
- # mov eax,0CCCCCCCCh
- # rep stos dword ptr [edi]
Calling Conventions Demystified
Introduction
During the long, hard, but yet beautiful process of learning C++programming for Windows, you have probably been curious about thestrange specifiers that sometime appear in front of functiondeclarations, like __cdecl
, __stdcall
, __fastcall
, WINAPI
, etc. After looking through MSDN, or some other reference, you probably found out that these specifiers specify the calling conventionsfor functions. In this article, I will try to explain different callingconventions used by Visual C++ (and probably other Windows C/C++compilers). I emphasize that above mentioned specifiers areMicrosoft-specific, and that you should not use them if you want towrite portable code.
So, what are the calling conventions? When a function is called, thearguments are typically passed to it, and the return value isretrieved. A calling convention describes how the argumentsare passed and values returned by functions. It also specifies how thefunction names are decorated. Is it really necessary to understand thecalling conventions to write good C/C++ programs? Not at all. However,it may be helpful with debugging. Also, it is necessary for linkingC/C++ with assembly code.
To understand this article, you will need to have some very basic knowledge of assembly programming.
No matter which calling convention is used, the following things will happen:
- All arguments are widened to 4 bytes (on Win32, of course), and putinto appropriate memory locations. These locations are typically on thestack, but may also be in registers; this is specified by callingconventions.
- Program execution jumps to the address of the called function.
- Inside the function, registers ESI, EDI, EBX, and EBP are saved onthe stack. The part of code that performs these operations is called function prolog and usually is generated by the compiler.
- The function-specific code is executed, and the return value is placed into the EAX register.
- Registers ESI, EDI, EBX, and EBP are restored from the stack. The piece of code that does this is called function epilog, and as with the function prolog, in most cases the compiler generates it.
- Arguments are removed from the stack. This operation is called stack cleanup and may be performed either inside the called function or by the caller, depending on the calling convention used.
As an example for the calling conventions (except for this), we are going to use a simple function:
- int sumExample (int a, int b)
- {
- return a + b;
- }
- int c = sum (2, 3);
For __cdecl, __stdcall, and __fastcall callingconventions, I compiled the example code as C (not C++). The functionname decorations, mentioned later in the article, apply to the Cdecoration schema. C++ name decorations are beyond the scope of thisarticle.
C calling convention (__cdecl)
This convention is the default for C/C++ programs (compiler option/Gd). If a project is set to use some other calling convention, we canstill declare a function to use __cdecl:
- int __cdecl sumExample (int a, int b);
The main characteristics of __cdecl calling convention are:
- Arguments are passed from right to left, and placed on the stack.
- Stack cleanup is performed by the caller.
- Function name is decorated by prefixing it with an underscore character '_' .
- ; // push arguments to the stack, from right to left
- push 3
- push 2
- ; // call the function
- call _sumExample
- ; // cleanup the stack by adding the size of the arguments to ESP register
- add esp,8
- ; // copy the return value from EAX to a local variable (int c)
- mov dword ptr [c],eax
- ; // function prolog
- push ebp
- mov ebp,esp
- sub esp,0C0h
- push ebx
- push esi
- push edi
- lea edi,[ebp-0C0h]
- mov ecx,30h
- mov eax,0CCCCCCCCh
- rep stos dword ptr [edi]
- ; // return a + b;
- mov eax,dword ptr [a]
- add eax,dword ptr [b]
- ; // function epilog
- pop edi
- pop esi
- pop ebx
- mov esp,ebp
- pop ebp
- ret
Standard calling convention (__stdcall)
This convention is usually used to call Win32 API functions. In fact, WINAPI
is nothing but another name for __stdcall
:
- #define WINAPI __stdcall
__stdcall
convention:- int __stdcall sumExample (int a, int b);
Also, we can use the compiler option /Gz to specify __stdcall
for all functions not explicitly declared with some other calling convention.
The main characteristics of __stdcall
calling convention are:
- Arguments are passed from right to left, and placed on the stack.
- Stack cleanup is performed by the called function.
- Function name is decorated by prepending an underscore characterand appending a '@' character and the number of bytes of stack spacerequired.
The example follows:
- ; // push arguments to the stack, from right to left
- push 3
- push 2
- ; // call the function
- call _sumExample@8
- ; // copy the return value from EAX to a local variable (int c)
- mov dword ptr [c],eax
- ; // function prolog goes here (the same code as in the __cdecl example)
- ; // return a + b;
- mov eax,dword ptr [a]
- add eax,dword ptr [b]
- ; // function epilog goes here (the same code as in the __cdecl example)
- ; // cleanup the stack and return
- ret 8
Because the stack is cleaned by the called function, the __stdcall
calling convention creates smaller executables than __cdecl
,in which the code for stack cleanup must be generated for each functioncall. On the other hand, functions with the variable number ofarguments (like printf()
) must use __cdecl
,because only the caller knows the number of arguments in each functioncall; therefore only the caller can perform the stack cleanup.
Fast calling convention (__fastcall)
Fast calling convention indicates that the arguments should beplaced in registers, rather than on the stack, whenever possible. Thisreduces the cost of a function call, because operations with registersare faster than with the stack.
We can explicitly declare a function to use the __fastcall
convention as shown:
- int __fastcall sumExample (int a, int b);
We can also use the compiler option /Gr to specify __fastcall
for all functions not explicitly declared with some other calling convention.
The main characteristics of __fastcall
calling convention are:
- The first two function arguments that require 32 bits or less areplaced into registers ECX and EDX. The rest of them are pushed on thestack from right to left.
- Arguments are popped from the stack by the called function.
- Function name is decorated by by prepending a '@' character andappending a '@' and the number of bytes (decimal) of space required bythe arguments.
Note: Microsoft have reserved the right to change the registers for passing the arguments in future compiler versions.
Here goes an example:
- ; // put the arguments in the registers EDX and ECX
- mov edx,3
- mov ecx,2
- ; // call the function
- call @fastcallSum@8
- ; // copy the return value from EAX to a local variable (int c)
- mov dword ptr [c],eax
- ; // function prolog
- push ebp
- mov ebp,esp
- sub esp,0D8h
- push ebx
- push esi
- push edi
- push ecx
- lea edi,[ebp-0D8h]
- mov ecx,36h
- mov eax,0CCCCCCCCh
- rep stos dword ptr [edi]
- pop ecx
- mov dword ptr [ebp-14h],edx
- mov dword ptr [ebp-8],ecx
- ; // return a + b;
- mov eax,dword ptr [a]
- add eax,dword ptr [b]
- ;// function epilog
- pop edi
- pop esi
- pop ebx
- mov esp,ebp
- pop ebp
- ret
How fast is this calling convention, comparing to __cdecl
and __stdcall
? Find out for yourselves. Set the compiler option /Gr, and compare the execution time. I didn't find __fastcall
to be any faster than other calling conventons, but you may come to different conclusions.
Thiscall
Thiscall
is the default calling convention for callingmember functions of C++ classes (except for those with a variablenumber of arguments).
The main characteristics of thiscall
calling convention are:
- Arguments are passed from right to left, and placed on the stack.
this
is placed in ECX. - Stack cleanup is performed by the called function.
The example for this calling convention had to be a littledifferent. First, the code is compiled as C++, and not C. Second, wehave a struct with a member function, instead of a global function.
- struct CSum
- {
- int sum ( int a, int b) {return a+b;}
- };
- push 3
- push 2
- lea ecx,[sumObj]
- call ?sum@CSum@@QAEHHH@Z ; CSum::sum
- mov dword ptr [s4],eax
- push ebp
- mov ebp,esp
- sub esp,0CCh
- push ebx
- push esi
- push edi
- push ecx
- lea edi,[ebp-0CCh]
- mov ecx,33h
- mov eax,0CCCCCCCCh
- rep stos dword ptr [edi]
- pop ecx
- mov dword ptr [ebp-8],ecx
- mov eax,dword ptr [a]
- add eax,dword ptr [b]
- pop edi
- pop esi
- pop ebx
- mov esp,ebp
- pop ebp
- ret 8
__cdecl
is used, and this
is pushed onto the stack last.Conclusion
To cut a long story short, we'll outline the main differences between the calling conventions:
__cdecl
is thedefault calling convention for C and C++ programs. The advantage ofthis calling convetion is that it allows functions with a variablenumber of arguments to be used. The disadvantage is that it createslarger executables.__stdcall
is used to call Win32 API functions. It does not allow functions to have a variable number of arguments.__fastcall
attempts to put arguments in registers, rather than on the stack, thus making function calls faster.Thiscall
calling convention is the default calling convention used by C++ member functions that do not use variable arguments.
In most cases, this is all you'll ever need to know about the calling conventions.
About the Author
Nemanja TrifunovicBorn in Kragujevac, Serbia, and lived there until 2000. Spent fourwonderful years in San Diego, California, one year in Boston, one inNew York and now lives again in Boston area with his wife and twolittle daughters.
Wrotehis first program in 1984, became a professional developer after hegraduated in 1994. After all these years still very passionate aboutprogramming and software development in general.
Occupation: Software DeveloperLocation: United States
- Calling Conventions Demystified (Visual C++ calling conventions explained)
- 函数调用规范解惑 Calling Conventions Demystified
- Calling conventions
- Calling conventions(调用规则)
- calling conventions:amd64
- x86 calling conventions
- Talk:X86 calling conventions
- calling conventions:amd64
- x86 calling conventions
- x86 calling conventions
- IA-32 Function Calling Conventions
- Calling conventions 函数调用约定
- calling conventions on x86 platform --- 转载
- Function Calling Conventions and Name Decoration
- TI DSP Function Structure and Calling Conventions
- MS Visual Studio VC++: Calling Conventions - __cdecl, __stdcall, __fastcall, __thiscall, __clrcall,
- Nasm Assembly Intro - Understanding Calling Conventions (64-bit)
- Conventions
- .Net中Math.Round与四舍五入
- delphi2009技术总览
- DirectShow概述
- 我答辩幻灯片部分内容
- Operating System 文章链接
- Calling Conventions Demystified (Visual C++ calling conventions explained)
- VC6下使用API实现自带缓存的写文件类
- 日语颜色词汇
- SPAM状态重置以及查询用户在系统中做的动作
- 在access中采用sql和absoluteposition两种方式产生随机记录的速度比较
- 基于ExtJs框架的B/S高级查询界面
- C#事件解析
- Java正则表达式初学者指南(转自BLOGJAVA)
- 中日对照人体部位