调用约定

Tutorial: C与汇编 Category: C语言 Published: 2026-04-07 13:58:26 Views: 20 Likes: 0 Comments: 0
1. 几种约定
调用约定                参数压栈顺序                         平衡堆栈
__cdecl                从右至左入栈                         调用者清理
__stdcall              从右至左入栈                         自身清理堆栈
__fastcall             ECX/EDX 传递前2个参数                自身清理堆栈
                       剩下的:从右至左入栈
2. 举例
#include <stdio.h>

int add(int x, int y)
{
    return x + y;
}

int main()
{
    int z = add(1, 2);
    return 0;
}

1:    #include <stdio.h>
2:
3:    int add(int x, int y)
4:    {
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]
5:        return x + y;
00401038   mov         eax,dword ptr [ebp+8]
0040103B   add         eax,dword ptr [ebp+0Ch]    // 返回值放在 eax
6:    }
0040103E   pop         edi
0040103F   pop         esi
00401040   pop         ebx
00401041   mov         esp,ebp
00401043   pop         ebp
00401044   ret
8:    int main()
9:    {
0040D400   push        ebp
0040D401   mov         ebp,esp
0040D403   sub         esp,44h
0040D406   push        ebx
0040D407   push        esi
0040D408   push        edi
0040D409   lea         edi,[ebp-44h]
0040D40C   mov         ecx,11h
0040D411   mov         eax,0CCCCCCCCh
0040D416   rep stos    dword ptr [edi]
10:       int z = add(1, 2);
0040D418   push        2                           // 从右至左入栈
0040D41A   push        1
0040D41C   call        @ILT+5(add) (0040100a)
0040D421   add         esp,8                       // 调用者清理
0040D424   mov         dword ptr [ebp-4],eax       // 获取返回值
11:       return 0;
0040D427   xor         eax,eax
12:   }
0040D429   pop         edi
0040D42A   pop         esi
0040D42B   pop         ebx
0040D42C   add         esp,44h
0040D42F   cmp         ebp,esp
0040D431   call        __chkesp (0040d680)
0040D436   mov         esp,ebp
0040D438   pop         ebp
0040D439   ret
3. 改变调用约定 __stdcall
#include <stdio.h>

int __stdcall add(int x, int y)
{
    return x + y;
}

int main()
{
    int z = add(1, 2);
    return 0;
}


3:    int __stdcall add(int x, int y)
4:    {
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]
5:        return x + y;
00401038   mov         eax,dword ptr [ebp+8]
0040103B   add         eax,dword ptr [ebp+0Ch]
6:    }
0040103E   pop         edi
0040103F   pop         esi
00401040   pop         ebx
00401041   mov         esp,ebp
00401043   pop         ebp
00401044   ret         8                      // 自身清理

7:
8:    int main()
9:    {
00401050   push        ebp
00401051   mov         ebp,esp
00401053   sub         esp,44h
00401056   push        ebx
00401057   push        esi
00401058   push        edi
00401059   lea         edi,[ebp-44h]
0040105C   mov         ecx,11h
00401061   mov         eax,0CCCCCCCCh
00401066   rep stos    dword ptr [edi]
10:       int z = add(1, 2);
00401068   push        2
0040106A   push        1
0040106C   call        @ILT+10(add) (0040100f)
00401071   mov         dword ptr [ebp-4],eax
11:       return 0;
00401074   xor         eax,eax
12:   }
00401076   pop         edi
00401077   pop         esi
00401078   pop         ebx
00401079   add         esp,44h
0040107C   cmp         ebp,esp
0040107E   call        __chkesp (004010a0)
00401083   mov         esp,ebp
00401085   pop         ebp
00401086   ret
4. 改变调用约定 __fastcall
#include <stdio.h>

int __fastcall add(int x, int y)
{
    return x + y;
}

int main()
{
    int z = add(1, 2);
    return 0;
}


3:    int __fastcall add(int x, int y)
4:    {
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
5:        return x + y;
00401040   mov         eax,dword ptr [ebp-4]
00401043   add         eax,dword ptr [ebp-8]
6:    }
00401046   pop         edi
00401047   pop         esi
00401048   pop         ebx
00401049   mov         esp,ebp
0040104B   pop         ebp
0040104C   ret
7:
8:    int main()
9:    {
00401050   push        ebp
00401051   mov         ebp,esp
00401053   sub         esp,44h
00401056   push        ebx
00401057   push        esi
00401058   push        edi
00401059   lea         edi,[ebp-44h]
0040105C   mov         ecx,11h
00401061   mov         eax,0CCCCCCCCh
00401066   rep stos    dword ptr [edi]
10:       int z = add(1, 2);
00401068   mov         edx,2                            // 这里,2个参数的话,就不需要堆栈
0040106D   mov         ecx,1                            // 寄存器在cpu中,所以从cpu读数据,比在内存中读数据更快
00401072   call        @ILT+15(add) (00401014)
00401077   mov         dword ptr [ebp-4],eax
11:       return 0;
0040107A   xor         eax,eax
12:   }
0040107C   pop         edi
0040107D   pop         esi
0040107E   pop         ebx
0040107F   add         esp,44h
00401082   cmp         ebp,esp
00401084   call        __chkesp (004010a0)
00401089   mov         esp,ebp
0040108B   pop         ebp
0040108C   ret