What is the difference between cdecl and stdcall C function calling protocols?
To fully understand the differences between these two conventions consider the sequence of events that occur when a function is called.
First, the function parameters are pushed onto the stack from right to left.
Next, the address of the next instruction (after the function call) is pushed on the stack.
At this point, the function is now in control and can use the stack to allocate local variables. If the function requires the use of the CPU registers, it saves the register values onto the stack before using them.
After the function has completed its task, it restores the original register state by popping the appropriate values from the stack.
/* 1. calling function in C++ */
i = Function(x, y, z);
/* 2. callee function body in C++ */
int Function(int a, int b, int c) { return a + b + c; }
A calling protocol is a contract between the caller and the callee which contains instructions for cleaning up the stack. In the cdecl
calling protocol, the calling function cleans the stack whereas with the stdcall
convention the callee function cleans the stack after executing.
CDECL
/* 1. calling CDECL 'Function' in pseudo-assembler (similar to what the compiler outputs) */
push on the stack a copy of 'z', then a copy of 'y', then a copy of 'x'
call (jump to function body, after function is finished it will jump back here, the address where to jump back is in registers)
move contents of register A to 'i' variable
pop all from the stack that we have pushed (copy of x, y and z)
/* 2. CDECL 'Function' body in pseudo-assembler */
/* Now copies of 'a', 'b' and 'c' variables are pushed onto the stack */
copy 'a' (from stack) to register A
copy 'b' (from stack) to register B
add A and B, store result in A
copy 'c' (from stack) to register B
add A and B, store result in A
jump back to caller code (a, b and c still on the stack, the result is in register A)
Note line 5 in the calling function cleans the stack
STDCALL
/* 1. calling STDCALL in pseudo-assembler (similar to what the compiler outputs) */
push on the stack a copy of 'z', then a copy of 'y', then a copy of 'x'
call
move contents of register A to 'i' variable
/* 2. STDCALL 'Function' body in pseaudo-assembler */
pop 'a' from stack to register A
pop 'b' from stack to register B
add A and B, store result in A
pop 'c' from stack to register B
add A and B, store result in A
jump back to caller code (a, b and c are no more on the stack, result in register A)
Note line 7,8,10 where the callee function cleans the stack
In Summary
 | __cdecl | __stdcall |
Move from stack to program counter | Next instruction address is being pushed from stack to program counter without removing the function parameters from the stack. | Clears the function from the stack before moving the next instruction address from the stack to the program counter |
Responsibility for cleaning the stack | The Caller is responsible | The Callee is responsible |
Number of function parameters | Can vary, the convention supports 'variadic' functions | Has to be fixed so that the convention can clear the stack |
Performance | Every __cdecl call requires additional code from the caller to clear the stack parameters | Additional code is unnecessary since Callee is responsible for clearing stack parameters, thus has a marginal increase in performance |
Uses | default for C and C++ programs | Chameleon uses and WinAPIs |
Naming conventions | Function names are decorated with a leading underscore | Function names are decorated by a leading underscore and a trailing @-sign followed by the number of bytes of parameters taken by the function. |
Â
Â