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.

 

Â