经过上一篇的介绍,大家应该对调用约定有了一定的感性认识。下面通过几个实例加深一下对这五种调用约定的理解。不会查看汇编代码?很简单,在Debug模式下按Ctrl+F11就能看到汇编代码了~
1.__stdcall
源程序:
    int __stdcall add(int a, int b)
    {
        return a + b;
    }
    void main()
    {
        add(10, 20);
    }

汇编代码:
6:        void main()
7:        {
00401050   push        ebp
00401051   mov         ebp,esp
00401053   sub         esp,40h
00401056   push        ebx
00401057   push        esi
00401058   push        edi
00401059   lea         edi,[ebp-40h]
0040105C   mov         ecx,10h
00401061   mov         eax,0CCCCCCCCh
00401066   rep stos    dword ptr [edi]
8:            add(10, 20);
00401068   push        14h
0040106A   push        0Ah
0040106C   call        @ILT+0(_add@8) (00401005)
9:        }
00401071   pop         edi
00401072   pop         esi
00401073   pop         ebx
00401074   add         esp,40h
00401077   cmp         ebp,esp
00401079   call        __chkesp (00401090)
0040107E   mov         esp,ebp
00401080   pop         ebp
00401081   ret


1:        int __stdcall add(int a, int b)
2:        {
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,40h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-40h]
0040102C   mov         ecx,10h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
3:            return a + b;
00401038   mov         eax,dword ptr [ebp+8]
0040103B   add         eax,dword ptr [ebp+0Ch]
4:        }
0040103E   pop         edi
0040103F   pop         esi
00401040   pop         ebx
00401041   mov         esp,ebp
00401043   pop         ebp
00401044  
ret         8
注意汇编代码中红色的部分:参数自右向左入栈,函数名为_add@8,由被调用函数清理入栈参数

2.__cdecl
源程序:
    int __cdecl add(int a, int b)
    {
        return a + b;
    }
    void main()
    {
        add(10, 20);
    }

汇编代码:
6:        void main()
7:        {
00401060   push        ebp
00401061   mov         ebp,esp
00401063   sub         esp,40h
00401066   push        ebx
00401067   push        esi
00401068   push        edi
00401069   lea         edi,[ebp-40h]
0040106C   mov         ecx,10h
00401071   mov         eax,0CCCCCCCCh
00401076   rep stos    dword ptr [edi]
8:            add(10, 20);
00401078   push        14h
0040107A   push        0Ah
0040107C   call        @ILT+15(_add) (00401014)
00401081   add         esp,8
9:        }
00401084   pop         edi
00401085   pop         esi
00401086   pop         ebx
00401087   add         esp,40h
0040108A   cmp         ebp,esp
0040108C   call        __chkesp (004010b0)
00401091   mov         esp,ebp
00401093   pop         ebp
00401094   ret


1:        int __cdecl add(int a, int b)
2:        {
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,40h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-40h]
0040102C   mov         ecx,10h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
3:            return a + b;
00401038   mov         eax,dword ptr [ebp+8]
0040103B   add         eax,dword ptr [ebp+0Ch]
4:        }
0040103E   pop         edi
0040103F   pop         esi
00401040   pop         ebx
00401041   mov         esp,ebp
00401043   pop         ebp
00401044   ret
 注意汇编代码中红色的部分:参数自右向左入栈,函数名为
_add
,被调用函数不清理入栈参数,用ret直接返回;调用函数给esp加8清理入栈参数

3.__fastcall
源程序:
    int __fastcall add(int a, int b)
    {
        return a + b;
    }
    void main()
    {
        add(10, 20);
    }

汇编代码:
6:        void main()
7:        {
00401060   push        ebp
00401061   mov         ebp,esp
00401063   sub         esp,40h
00401066   push        ebx
00401067   push        esi
00401068   push        edi
00401069   lea         edi,[ebp-40h]
0040106C   mov         ecx,10h
00401071   mov         eax,0CCCCCCCCh
00401076   rep stos    dword ptr [edi]
8:            add(10, 20);
00401078   mov         edx,14h
0040107D   mov         ecx,0Ah
00401082   call        @ILT+5(@add@8) (0040100a)
9:        }
00401087   pop         edi
00401088   pop         esi
00401089   pop         ebx
0040108A   add         esp,40h
0040108D   cmp         ebp,esp
0040108F   call        __chkesp (004010b0)
00401094   mov         esp,ebp
00401096   pop         ebp
00401097   ret


1:        int __fastcall add(int a, int b)
2:        {
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,48h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   push        ecx
0040102A   lea         edi,[ebp-48h]
0040102D   mov         ecx,12h
00401032   mov         eax,0CCCCCCCCh
00401037   rep stos    dword ptr [edi]
00401039   pop         ecx
0040103A   mov         dword ptr [ebp-8],edx
0040103D   mov         dword ptr [ebp-4],ecx
3:            return a + b;
00401040   mov         eax,dword ptr [ebp-4]
00401043   add         eax,dword ptr [ebp-8]
4:        }
00401046   pop         edi
00401047   pop         esi
00401048   pop         ebx
00401049   mov         esp,ebp
0040104B   pop         ebp
0040104C  
ret
 注意汇编代码中红色的部分:前两个参数分别送往edx和ecx,在函数中函数名为@add@8,由于参数只有两个,不涉及入栈的问题,因此不需要清理栈,直接返回

4.thiscall
源程序:
#include <stdarg.h>

class A
{
    public:
       int add(int a, int b);
       int addMore(int a, ...);
};

int A::add(int a, int b)//固定参数
{
     return a + b;
}

int A::addMore(int cnt, ...)//可变参数
{
     va_list a;
     int i;
     int result = 0;
     va_start(a, cnt);
     for(i=0; i<cnt; i++)
     {
        result += va_arg(a, int);
     }
     return result;
}

void main()
{
     A *a = new A();
     a->add(1, 2);
     a->addMore(4, 1, 2, 3, 4);
}

汇编代码:(只看main函数)
31:   void main()
32:   {
004010A0   push        ebp
004010A1   mov         ebp,esp
004010A3   sub         esp,48h
004010A6   push        ebx
004010A7   push        esi
004010A8   push        edi
004010A9   lea         edi,[ebp-48h]
004010AC   mov         ecx,12h
004010B1   mov         eax,0CCCCCCCCh
004010B6   rep stos    dword ptr [edi]
33:       A *a = new A();
004010B8   push        1
004010BA   call        operator new (00401100)
004010BF   add         esp,4
004010C2   mov         dword ptr [ebp-8],eax
004010C5   mov         eax,dword ptr [ebp-8]
004010C8   mov         dword ptr [ebp-4],eax
34:       a->add(1, 2);
004010CB   push        2
004010CD   push        1
004010CF   mov         ecx,dword ptr [ebp-4]
004010D2   call        @ILT+10(A::add) (0040100f)
35:       a->addMore(4, 1, 2, 3, 4);
004010D7   push        4
004010D9   push        3
004010DB   push        2
004010DD   push        1
004010DF   push        4
004010E1   mov         ecx,dword ptr [ebp-4]
004010E4   push        ecx
004010E5   call        @ILT+0(A::addMore) (00401005)
004010EA   add         esp,18h
36:   }
004010ED   pop         edi
004010EE   pop         esi
004010EF   pop         ebx
004010F0   add         esp,48h
004010F3   cmp         ebp,esp
004010F5   call        __chkesp (00401120)
004010FA   mov         esp,ebp
004010FC   pop         ebp
004010FD   ret

 注意汇编代码中红色的部分:对于参数固定的函数,this指针放入ecx,由被调用函数清理入栈参数;对于参数不定的函数,this指针在所有参数入栈后压入堆栈,由调用者自己清理入栈参数

5.naked call
    __declspec(naked) int add(int a, int b)
    {
         __asm mov eax, a
         __asm add eax, b
         __asm ret
    }

    void main()
    {
        add(10, 20);
    }

汇编代码:
8:        void main()
9:        {
00401030   push        ebp
00401031   mov         ebp,esp
00401033   sub         esp,40h
00401036   push        ebx
00401037   push        esi
00401038   push        edi
00401039   lea         edi,[ebp-40h]
0040103C   mov         ecx,10h
00401041   mov         eax,0CCCCCCCCh
00401046   rep stos    dword ptr [edi]
10:           add(10, 20);
00401048   push        14h
0040104A   push        0Ah
0040104C   call        @ILT+0(_add) (00401005)
00401051   add         esp,8
11:       }
00401054   pop         edi
00401055   pop         esi
00401056   pop         ebx
00401057   add         esp,40h
0040105A   cmp         ebp,esp
0040105C   call        __chkesp (00401080)
00401061   mov         esp,ebp
00401063   pop         ebp
00401064   ret

1:        __declspec(naked) int add(int a, int b)
2:        {
00401020   mov         eax,dword ptr [ebp+8]
3:            __asm mov eax, a
4:            __asm add eax, b
00401023   add         eax,dword ptr [ebp+0Ch]
5:            __asm ret
00401026  
ret
 注意汇编代码中红色的部分:不产生对寄存器的保护代码,不能用return语句返回返回值,只能插入ret汇编语句返回,返回值存放在eax中