Calling Conventions

x86 C Convention (cdecl)

  • Arguments to the function are put on the stack (in reverse order) prior to the call of the function.

 

  • Local variables are given space after the function is called

 

  • Caller must preserve EAX, ECX, EDX

 

  • Callee must preserve EBX, EDI, ESI

 

  • Stack must be cleaned* to return

stdcall (x86 Windows)

  • Exactly the same as cdecl except callee cleans up the stack
; int __cdecl func(int x, int y)
func:
   mov eax, [esp+4] ; x
   add eax, [esp+8] ; x += y
   ret
; int __stdcall func(int x, int y)
func:
   mov eax, [esp+4] ; x
   add eax, [esp+8] ; x += y
   ret 8

Uses special ret instruction that removes n bytes off the stack AFTER it pops EIP off the stack

Do not confuse this with C style returns, this has nothing to do with the return value

fastcall (x86 Windows)

  • Exactly the same as stdcall except first two arguments from the LEFT go into ECX and EDX
; int __fastcall func(int a, int b, int c, int d, unsigned char e)
func:
   mov eax, [esp+4] ; eax = c
   add eax, [esp+8] ; eax += d
   and eax, [esp+12]; eax &= e
   add eax, ecx ; eax += a
   add eax, edx ; eax += b
   ret 12 ; why is it 12 even though e is a char?
; int __stdcall func(int a, int b, int c, int d, unsigned char e)
func:
   mov eax, [esp+4] ; eax = a
   add eax, [esp+8] ; eax += b
   and eax, [esp+12]; eax &= c
   add eax, [esp+16]; eax += d
   add eax, [esp+20]; eax += e
   ret 20 

ECX and EDX do not need to be cleaned off the stack

x64 C Convention (SYS V)

  • Arguments are passed in through registers, then on the stack. First argument in RDI, then RSI, RDX, RCX, R8, R9, then stack


  • Locals are same as x86 (on stack after function call)


  • Caller must preserve RAX, RDX, RCX, RSI, RDI, R8-11




  • Stack must be cleaned* to return

Notice the offsets to each argument are now multiples of 8 instead of 4 like in x86

  • Callee must preserve RBX, RSP, RBP, R12-15

x64 C Convention (Windows)

  • Arguments are passed in through registers, then on the stack. First argument in RCX, then RDX, R8, R9, then stack
  • Formally: Windows x64 ABI 
  • Same as System V AMD64 ABI except only 4 registers used for arguments 
  • No more stdcall, fastcall, cdecl, etc.

Linker Name Mangling

  • How does Windows know which calling convention a function is using?  

_func

_func@8

@func@8

  • No mangling in x64
     
  • Names only need to be mangled for linking
    • What does this mean for us?
int __cdecl func(int x, int y)
int __stdcall func(int x, int y)
int __fastcall func(int x, int y)

Other calling conventions

The type of calling convention can vary from compiler to compiler.

  • Object oriented compilers like g++ need to mangle names and pass the calling object in a register (source)

 

  • And many others, but they all share persisting notions that are recognizable!

 

  • Calling conventions can be changed to make reversing difficult :(

x86 Calling Conventions

By Drake P

x86 Calling Conventions

  • 301