Calling Conventions Demystified (2024)

Introduction

During the long, hard, but yet beautiful process of learning C++ programming for Windows, you have probably been curious about the strange specifiers that sometime appear in front of function declarations, like __cdecl, __stdcall, __fastcall, WINAPI, etc. After looking through MSDN, or some other reference, you probably found out that these specifiers specify the calling conventions for functions. In this article, I will try to explain different calling conventions used by Visual C++ (and probably other Windows C/C++ compilers). I emphasize that above mentioned specifiers are Microsoft-specific, and that you should not use them if you want to write portable code.

So, what are the calling conventions? When a function is called, the arguments are typically passed to it, and the return value is retrieved. A calling convention describes how the arguments are passed and values returned by functions. It also specifies how the function names are decorated. Is it really necessary to understand the calling conventions to write good C/C++ programs? Not at all. However, it may be helpful with debugging. Also, it is necessary for linking C/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:

  1. All arguments are widened to 4 bytes (on Win32, of course), and put into appropriate memory locations. These locations are typically on the stack, but may also be in registers; this is specified by calling conventions.
  2. Program execution jumps to the address of the called function.
  3. Inside the function, registers ESI, EDI, EBX, and EBP are saved on the stack. The part of code that performs these operations is called function prolog and usually is generated by the compiler.
  4. The function-specific code is executed, and the return value is placed into the EAX register.
  5. 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.
  6. 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;}

The call to this function will look like this:

int c = sum (2, 3);

For __cdecl, __stdcall, and __fastcall calling conventions, I compiled the example code as C (not C++). The function name decorations, mentioned later in the article, apply to the C decoration schema. C++ name decorations are beyond the scope of this article.

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 can still declare a function to use __cdecl:

int __cdecl sumExample (int a, int b);

The main characteristics of __cdecl calling convention are:

  1. Arguments are passed from right to left, and placed on the stack.
  2. Stack cleanup is performed by the caller.
  3. Function name is decorated by prefixing it with an underscore character '_' .

Now, take a look at an example of a __cdecl call:

; // push arguments to the stack, from right to leftpush 3 push 2 ; // call the functioncall _sumExample ; // cleanup the stack by adding the size of the arguments to ESP registeradd esp,8 ; // copy the return value from EAX to a local variable (int c)mov dword ptr [c],eax

The called function is shown below:

; // 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

We can explicitly declare a function to use the __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:

  1. Arguments are passed from right to left, and placed on the stack.
  2. Stack cleanup is performed by the called function.
  3. Function name is decorated by prepending an underscore character and appending a '@' character and the number of bytes of stack space required.

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

The function code is shown below:

; // 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 function call. On the other hand, functions with the variable number of arguments (like printf()) must use __cdecl, because only the caller knows the number of arguments in each function call; therefore only the caller can perform the stack cleanup.

Fast calling convention (__fastcall)

Fast calling convention indicates that the arguments should be placed in registers, rather than on the stack, whenever possible. This reduces the cost of a function call, because operations with registers are 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:

  1. The first two function arguments that require 32 bits or less are placed into registers ECX and EDX. The rest of them are pushed on the stack from right to left.
  2. Arguments are popped from the stack by the called function.
  3. Function name is decorated by by prepending a '@' character and appending a '@' and the number of bytes (decimal) of space required by the 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 code:

; // 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 calling member functions of C++ classes (except for those with a variable number of arguments).

The main characteristics of thiscall calling convention are:

  1. Arguments are passed from right to left, and placed on the stack. this is placed in ECX.
  2. Stack cleanup is performed by the called function.

The example for this calling convention had to be a little different. First, the code is compiled as C++, and not C. Second, we have a struct with a member function, instead of a global function.

struct CSum{ int sum ( int a, int b) {return a+b;}};

The assembly code for the function call looks like this:

push 3push 2lea ecx,[sumObj]call ?sum@CSum@@QAEHHH@Z ; CSum::summov dword ptr [s4],eax

The function itself is given below:

push ebpmov ebp,espsub esp,0CChpush ebxpush esipush edipush ecxlea edi,[ebp-0CCh]mov ecx,33hmov eax,0CCCCCCCChrep stos dword ptr [edi]pop ecxmov dword ptr [ebp-8],ecxmov eax,dword ptr [a]add eax,dword ptr [b]pop edipop esipop ebxmov esp,ebppop ebpret 8

Now, what happens if we have a member function with a variable number of arguments? In that case, __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 the default calling convention for C and C++ programs. The advantage of this calling convetion is that it allows functions with a variable number of arguments to be used. The disadvantage is that it creates larger 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.

Calling Conventions Demystified (2024)

FAQs

What does the so called calling convention determines? ›

A calling convention governs how functions on a particular architecture and operating system interact. This includes rules about includes how function arguments are placed, where return values go, what registers functions may use, how they may allocate local variables, and so forth.

What are calling conventions in C++? ›

Calling conventions are used to ensure that functions are called correctly and consistently across different platforms and compilers.

Is calling convention part of ABI? ›

Calling conventions are usually considered part of the application binary interface (ABI). They may be considered a contract between the caller and the called function.

Is C calling convention from right to left? ›

In the C calling convention subprogram parameters are pushed on the stack by the caller from right to left. The caller itself is in charge of cleaning up the stack after the call. In addition, the name of a routine with C calling convention is mangled by adding a leading underscore.

What is the calling convention in assembly language? ›

Function calls in assembly are governed by the calling convention of the architecture and operating system used: it determines which registers hold specific values such as arguments and return values, which registers a function may modify, and where on the stack certain information (such as the return address) is ...

What is the ARM64 calling convention? ›

The ARM64 calling convention specifies that the first eight parameters to a function are passed in registers x0 through x7 . Additional parameters are passed on the stack. The return value is passed back in register x0 , or in x1 as well if its 128 bits long.

What is the default calling convention in Windows? ›

The default convention — shown above — is known as __cdecl. The other most popular convention is __stdcall. In it the parameters are again pushed by the caller, but the stack is cleaned up by the callee. It is the standard convention for Win32 API functions (as defined by the WINAPI macro in <windows.

What is an example of a naming convention in C++? ›

Common C++ Naming Conventions

Types start with upper case: MyClass . Functions and variables start with lower case: myMethod . Constants are all upper case: const double PI=3.14159265358979323; .

What is the calling convention of a DLL? ›

The __stdcall calling convention is used by default when calling DLL functions. This calling convention is used by all Windows API DLL functions. You can change the calling convention for a DLL function by using the CallingConvention property of the DllFunctionOptions annotation.

What is the difference between calling convention in Pascal and C? ›

The STDCALL calling convention of C pushes the parameters on the stack in right-to-left order. Pascal-style procedure call is made with : caller pushing parameters into the stack in left-to-right order (opposite of __cdecl) calling the function.

What is Pascal calling convention? ›

CC_PASCAL uses the Pascal calling convention. The caller pushes the parameters onto the stack in left-to-right order. The called function cleans the stack before returning. CC_STDCALL is the standard calling convention for Win32 functions.

Which registers are volatile? ›

Volatile registers are scratch registers presumed by the caller to be destroyed across a call. Nonvolatile registers are required to retain their values across a function call and must be saved by the callee if used.

Which calling convention does C follow? ›

__cdecl is the default calling convention for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions. The __cdecl calling convention creates larger executables than __stdcall, because it requires each function call to include stack cleanup code.

Why bother with the C calling convention when writing assembly? ›

Understanding this convention will allow you to write assembly language subroutines that are safely callable from C and C++ code, and will also enable you to call C library functions from your assembly language code. The C calling convention is based heavily on the use of the hardware-supported stack.

What calling convention does Rust use? ›

In practice, Rust lowers to LLVM's built-in C calling convention, which LLVM's prologue/epilogue codegen generates calls for. Rust is fairly conservative: it tries to generate LLVM function signatures that Clang could have plausibly generated.

What is the significance of function calling convention in C? ›

Calling conventions specify how arguments are passed to a function, how return values are passed back out of a function, how the function is called, and how the function manages the stack and its stack frame. In short, the calling convention specifies how a function call in C or C++ is converted into assembly language.

Does a language's calling convention does not include the order in which parameters are passed? ›

False - A language's calling convention often includes the order in which parameters are passed. For example, the C calling convention passes arguments from left to right.

What is the calling convention of MIPS O32? ›

O32: This is the default calling convention for the MIPS architecture. It is used for functions written in C or C++. In this convention, arguments are passed to the function in registers, and any additional arguments are passed on the stack. The return value is stored in the $v0 and $v1 registers.

References

Top Articles
Latest Posts
Article information

Author: Arielle Torp

Last Updated:

Views: 6027

Rating: 4 / 5 (61 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Arielle Torp

Birthday: 1997-09-20

Address: 87313 Erdman Vista, North Dustinborough, WA 37563

Phone: +97216742823598

Job: Central Technology Officer

Hobby: Taekwondo, Macrame, Foreign language learning, Kite flying, Cooking, Skiing, Computer programming

Introduction: My name is Arielle Torp, I am a comfortable, kind, zealous, lovely, jolly, colorful, adventurous person who loves writing and wants to share my knowledge and understanding with you.