Calling Convetions in Microsoft Visual C++
The calling conventions used in Visual C++ are documented. The main reason for having this document here is so that I can reference it from elsewhere for the benefit of those who do not have access to the documentation while they are an article which requires knowledge of the conventions. While I’m here though I might as well try to do as good a job as I can at explaining the different conventions.
What Are Calling Conventions?
C++ provides a way of defining a function and a way of calling that function with arguments that soon become second nature to use. When the function and calls to it are compiled there are quite a few different ways in which the process of getting those arguments to where the function’s code can “see” them before executing the code can be performed. There are pros and cons to each, and some compilers have extensions which allow you do choose which is used.
Most of the time there is no need to do anything other than use the defaults or, in a few cases where you are required to match a binary specification, do what you are told. But you might want to make use of this in some cases, or simply understand what it is going on with calling conventions used by code you interface with.
Calling Conventions and “Pure C++”
The C++ Standard [ISO/IEC 14882] has very little to say about calling conventions. It has a bit to say about language linkage and linkage specifications, and it notes that a particular language linkage may be associated with a particular calling convention. Everything else related to calling conventions is implementation specific. Everything else in this article is Microsoft Visual C++ specific, indeed VC++6 or VC++.NET specific (some other calling conventions that have since been obsoleted are not mentioned here, and what is detailed here may change with later versions of VC++).
Since Visual C++ gives you the same ability to alter the calling conventions used with C code as with C++ code the effects of this are slight.
A few features of the thiscall convention and the choice of the __cdecl convention as the default convention follow naturally from how C++ is defined outside of a purely Microsoft-orientated view of the language. These shall be noted as we come to them.
Name Decoration
Overloading of functions is resolved at compile time, which means that by to
the linker int doubleIt(int);
and float
doubleIt(float)
are completely different functions. As a means to
implement this the function names are internally “decorated”
with extra characters that describe the parameters, namespace and/or class
membership and return type of the function.
This mechanism is compatible with C, a C function or a function declared to have C linkage is not decorated in this manner. This obviously doesn’t allow you to overload a function with C linkage, and also means that namespaces are ignored and you can have only one function with C linkage with any given name, even if they are declared in different namespaces. Notably these rules are also imposed on functions with C linkage by the Standard Standard [ISO/IEC 14882].
Because otherwise identical functions with different calling conventions would not be compatible it is also necessary to ensure that the linker does not consider two such functions to be one and the same. If they occur in the same compilation unit (.cpp file) then it’s a simple bug for the compiler to catch. However to if a function is declared and used in one compilation unit, and defined in another compilation unit (or an already compiled library) with a different calling convention it isn’t as clear an error. To prevent such a case from being linked both C and C++ functions will be decorated so as to identify the calling convention used. This means that the linker will consider the two uses of the function name to differ, and compilation will stop with a linker error.
You’ve no doubt seen these decorated names when debugging or dealing with linker errors. It can be particularly common when two pieces of code use the same header file, but differ in the default calling convention set. Apart from that name decoration impacts on calling conventions only in so far as different calling conventions means different name decoration.
Inlining and Optimisation
There is one rule in both the standard and the way Visual C++ works that overrides everything mentioned here, the “as-if” rule. Formally:
The semantic descriptions in this International Standard
define a parameterized nondeterministic abstract machine.
This International Standard places no requirement on the
structure of conforming implementations. In particular,
they need not copy or emulate the structure of the abstract
machine. Rather, conforming implementations are required to
emulate (only) the observable behavior of the abstract
machine as explained below.
This is an amazingly long-winded, if admirably precise, way of saying that a C++ implementaton can do whatever it wants, as long as the final result is the same as if it followed the standard to the letter. In fairness to the Standard’s authors there is a note explaining the above in more vernacular language.
This isn’t just a concession to the compiler writers, it is the basis of almost all optimisation techniques beyond explicit inlining, and given that much of the design of the Standard Library (in particular the STL) assumes aggressive optimisation on the part of the compiler, compilers are really expected to do this.
The effects on our current topic of discussion is that what I am about to explain may not actually be what happens in the case of a “release” build. Inline function calls don’t involve any of this, and there is the potential that other features may change. This is of little practical importance, but could explain apparant weirdness if you are trying to debug a release build.
Most often when calling conventions become an issue it is with the linking of seperately compiled code. In these cases the scope for optimisation of how the functions are called is limited anyway, so what follows is pretty reliable in debugging such situations.
How Functions are Called
No matter what the calling convention the following takes place for all function calls:
- All arguments are widened to the natural machine size if they are smaller. In 32-bit Windows this means 32-bits.
- The parameters are placed on the stack and/or in registers.
- Execution jumps to the start of the function.
- If the ESI, EDI, EBX, and EBP registers are used by the function they are saved on the stack. This means that the calling code can assume that they are not changed by the call. In debug builds they are pushed on the stack whether they are used or not. Also debug builds give the EAX register (which will be used for the return value) the value 0xCCCCCCCC, as part of the way debug builds fill easily recognisable values into uninitialised variables to help you spot them.
- The function is executed.
-
The return value is saved depending on its size:
- 32-bit or smaller values
- Widened to 32 bits and stored in the EAX register
- 64-bit values
- Stored in the EDX:EAX register-pair
- Values larger than 64 bits
- Stored in memory, which EAX then points to.
- The ESI, EDI, EBX and EBP registers are given their initial values if necessary.
- Depending on the calling convention, either the function cleans the arguments from the stack and then returns, or it returns and the calling code cleans the stack.
The Conventions
__cdecl
The __cdecl calling convention is used for functions marked with the
__cdecl
keyword, or for unmarked functions when the /Gd
compiler option is set. Since /Gd is the default this is then the default
calling convention.
All arguments are stored on the stack, in right to left order. The code that called the function will have to remove these arguments when the function returns.
Because the calling code cleans the stack this convention can be used with
functions with a variable number of arguments such as
printf(const char*, ...)
. Since C++ must allow such functions,
as advisable as it is to avoid them when you can, it makes sense that this
is the default calling convention.
__stdcall
The __stdcall calling convention is used for functions marked with the
__stdcall
keyword, or for unmarked functions when the /Gz
compiler option is set.
All arguments are stored on the stack, in right to left order. The function itself will clean the stack. This results in slightly smaller executables but cannot be used with functions that take a variable number of arguments.
COM methods, and the Windows API functions are generally __stdcall
functions. The macros WINAPI
and CALLBACK
and a
few others used in Windows API declarations expand to __stdcall
.
__fastcall
The __fastcall calling convention is used for functions marked with the
__fastcall
keyword, or for unmarked functions when the /Gr
compiler option is set (/Gr will not affect main()
).
The first two arguments (left to right) which are 32bit or smaller are placed into two registers (currently ECX and EDX, though Microsoft have no commitment to keep using those two with later compilers). All other arguments are stored on the stack, in right to left order. The function itself will clean the stack.
If you attempt to take the address of an argument stored in a register it will be copied to a temporary location.
While reasons this would giva an advantage in speed are clear, with modern machines it tends to be negligible.
thiscall
The thiscall calling convention cannot be explicitly used. It is used for member functions of classes which are not explicitly set to use a different convention, and which do not take a variable number of arguments (in which case __cdecl is used).
The convention operates much like __stdcall except
that the this
pointer (which is effectively a hidden argument)
is stored in the ECX register. This neatly matches with the C++ rule that
one cannot take the address of the this
pointer.
In the case where a variable number of arguments requires __cdecl to be used the this pointer is considered the left-most argument, and hence pushed on the stack last.
References
- ISO/IEC 14882
- ISO (International Organization for Standardization), ISO/IEC 14882:1998. Programming Languages — C++, (Bound under the title The C++ Standard), International Organization for Standardization