What is the object oriented way of getting rich? - Inheritance

the brown-dragon blog

Calling Conventions in Windows (x86)

2009-04-30

When debugging with WinDbg you may notice that all functions are not called in the same way. The "traditional" way would be to push arguments on the stack, call the function and check the return value. However, in many places this may not happen. This is because the x86 architecture has several different calling conventions which I will describe below.

__stdcall
  Function parameters are passed on the stack, pushed right to left, and the callee cleans the stack.

__fastcall
  The first two DWORD-or-smaller arguments are passed in the ecx and edx registers. The remaining parameters are passed on the stack, pushed right to left. The callee cleans the stack.

__cdecl
  Function parameters are passed on the stack, pushed right to left, and the caller cleans the stack. The __cdecl calling convention is used for all functions with variable-length parameters.

Native C++ method call (also known as thiscall)
  Function parameters are passed on the stack, pushed right to left, the "this" pointer is passed in the ecx register, and the callee cleans the stack.

COM (__stdcall for C++ method calls)
  Function parameters are passed on the stack, pushed right to left, then the "this" pointer is pushed on the stack, and then the function is called. The callee cleans the stack.

Notes:

The following code gives an example of each convention. The C++ code below includes all the above calling conventions:

callconv.cpp

int __stdcall f_std (int i, long long j, char k, long z)
{
    return i + j + k + z;
}

int __fastcall f_fast (int i, long long j, char k, long z)
{
    return i + j + k + z;
}

int __cdecl f_cdecl (int i, long long j, char k, long z)
{
    return i + j + k + z;
}

class CallConv {
public:
    int m_native (int i, long long j, char k, long z)
    {
        return i + j + k + z;
    }

    int __stdcall m_std (int i, long long j, char k, long z)
    {
        return i + j + k + z;
    }

    int __fastcall m_fast (int i, long long j, char k, long z)
    {
        return i + j + k + z;
    }

    int __cdecl m_cdecl (int i, long long j, char k, long z)
    {
        return i + j + k + z;
    }
};

int main (void)
{
        CallConv    cc;

    /* Functions */
    f_std (1, 2, 3, 4); /* __stdcall */
    f_fast (1, 2, 3, 4); /* __fastcall */
    f_cdecl (1, 2, 3, 4); /* __cdecl */

    /* Methods */
    cc.m_native (1, 2, 3, 4); /* native method */
    cc.m_std (1, 2, 3, 4); /* __stdcall method */
    cc.m_fast (1, 2, 3, 4); /* __fast method */
    cc.m_cdecl (1, 2, 3, 4); /* __cdecl method */
}

And it translates to this in assembly:

callconv.asm

   40 00401100 55              push    ebp        ;
   40 00401101 8bec            mov     ebp,esp    ;- main prolog
   40 00401103 51              push    ecx        ;

   44 00401104 6a04            push    4    ;
   44 00401106 6a03            push    3    ;
   44 00401108 6a00            push    0    ;- stdcall
   44 0040110a 6a02            push    2    ;
   44 0040110c 6a01            push    1    ;
   44 0040110e e8f7feffff      call    f_std(0040102d)

   45 00401113 6a04            push    4    ;
   45 00401115 6a00            push    0    ;- fastcall
   45 00401117 6a02            push    2    ;<--note that large
   45 00401119 b203            mov     dl,3 ; param is skipped over
   45 0040111b b901000000      mov     ecx,1; and two smaller are
   45 00401120 e803ffffff      call    f_fast(00401028); put in regs

   46 00401125 6a04            push    4    ;
   46 00401127 6a03            push    3    ;
   46 00401129 6a00            push    0    ;- cdecl
   46 0040112b 6a02            push    2    ;
   46 0040112d 6a01            push    1    ;
   46 0040112f e8e0feffff      call    f_cdecl(00401014)
   46 00401134 83c414          add     esp,14h ;<--note cleanup

   49 00401137 6a04            push    4            ;
   49 00401139 6a03            push    3            ;- native
   49 0040113b 6a00            push    0            ;
   49 0040113d 6a02            push    2            ;
   49 0040113f 6a01            push    1            ;
   49 00401141 8d4dff          lea     ecx,[ebp-1]  ;<--note the "this"
   49 00401144 e8d5feffff      call    m_nativeCallConv(0040101e);pointer

   50 00401149 6a04            push    4            ;
   50 0040114b 6a03            push    3            ;
   50 0040114d 6a00            push    0            ;- COM
   50 0040114f 6a02            push    2            ;
   50 00401151 6a01            push    1            ;
   50 00401153 8d45ff          lea     eax,[ebp-1]  ;<--note the "this"
   50 00401156 50              push    eax          ; pointer on stack
   50 00401157 e8a9feffff      call    m_stdCallConv(00401005)

   51 0040115c 6a04            push    4            ;
   51 0040115e 6a03            push    3            ;- fastcall
   51 00401160 6a00            push    0            ;
   51 00401162 6a02            push    2            ;
   51 00401164 ba01000000      mov     edx,1        ;<--note that "this"
   51 00401169 8d4dff          lea     ecx,[ebp-1]  ; is treated as first
   51 0040116c e8b2feffff      call    m_fastCallConv(00401023); param

   52 00401171 6a04            push    4            ;
   52 00401173 6a03            push    3            ;
   52 00401175 6a00            push    0            ;- cdecl
   52 00401177 6a02            push    2            ;
   52 00401179 6a01            push    1            ;
   52 0040117b 8d4dff          lea     ecx,[ebp-1]  ;
   52 0040117e 51              push    ecx          ;
   52 0040117f e88bfeffff      call    m_cdeclCallConv(0040100f)
   52 00401184 83c418          add     esp,18h      ;<--note cleanup

   53 00401187 33c0            xor     eax,eax ; return 0

   53 00401189 8be5            mov     esp,ebp  ;
   53 0040118b 5d              pop     ebp      ;- main epilog
   53 0040118c c3              ret              ;<-- is __cdecl

As a side-note that we can easily see that main itself is a __cdecl function as it does not clean up the stack!

UPDATE: 2009-05-01
Wikipedia has list of calling conventions which includes other OS's here: http://en.wikipedia.org/wiki/X86_calling_conventions

Other Posts

(ordered by Tags then Date)