Understanding cdecl and fastcall Calling Conventions
Calling conventions are an essential part of computer programming, especially when dealing with functions and subroutines. They define the rules for how arguments are passed to functions, how the function receives those arguments, and how the return value is handled. Two common calling conventions are cdecl and fastcall, and understanding the difference between them is crucial for efficient and correct code execution.
cdecl: The Standard C Calling Convention
The cdecl (or __cdecl) calling convention is the default calling convention for C and C++ programs on most platforms, including Windows and Linux. It follows a specific set of rules:
Argument Passing: Arguments are pushed onto the stack from right to left, meaning the last argument is pushed first, and the first argument is pushed last.
Caller Responsibility: The caller is responsible for cleaning up (removing) the arguments from the stack after the function returns.
Return Value: The return value from the function is stored in a specific register, typically the EAX register for 32-bit x86 architectures or the RAX register for 64-bit x86 architectures.
Here’s an example of a cdecl function call in C:
int add(int a, int b) {
return a + b;
}
int main() {
int result = add(2, 3);
// result is now 5
return 0;
}
In this example, when add(2, 3)
is called, the value 3
is pushed onto the stack first, followed by 2
. The add
function retrieves these values from the stack, performs the addition, and stores the result in the EAX register. After the function returns, the caller is responsible for cleaning up the stack by removing the arguments (2
and 3
) from it.
fastcall: The Fast Calling Convention
The fastcall (or __fastcall) calling convention is a Microsoft-specific convention designed to improve performance by reducing the overhead of calling functions. It follows a different set of rules:
Argument Passing: The first two arguments (or three arguments on 64-bit systems) are passed in registers (ECX and EDX on 32-bit systems, RCX, RDX, and R8 on 64-bit systems). Any remaining arguments are pushed onto the stack from right to left, just like in cdecl.
Callee Responsibility: The callee (the function being called) is responsible for cleaning up the stack and any registers used for argument passing.
Return Value: The return value is stored in the same register as cdecl (EAX or RAX).
Here’s an example of a fastcall function call in C++:
__fastcall int add(int a, int b) {
return a + b;
}
int main() {
int result = add(2, 3);
// result is now 5
return 0;
}
In this example, when add(2, 3)
is called, the value 2
is passed in the ECX register, and 3
is passed in the EDX register. The add
function retrieves these values from the registers, performs the addition, and stores the result in the EAX register. After the function returns, the add
function is responsible for cleaning up any registers or stack space used for argument passing.
The fastcall convention is generally faster than cdecl because it reduces the number of memory accesses required to pass arguments, especially for functions with a small number of arguments. However, it is not portable across different platforms and compilers, and it may not provide significant performance improvements for functions with many arguments or complex logic.
In conclusion, cdecl and fastcall are two different calling conventions that define how arguments are passed to functions and how return values are handled. cdecl is the standard C calling convention and is widely portable, while fastcall is a Microsoft-specific convention designed for performance optimization but with limited portability. Understanding these conventions is essential for writing efficient and correct code, especially when working with low-level programming languages like C and C++.