三种常用的函数调用约定

1、函数调用在汇编中,有关于参数传递与栈平衡的问题,可参照函数调用在汇编中的基本实现,主要有三种方式__cdecl、__stdcall、__fastcall;
2、在C++代码中,可以在函数名前加这三个关键字来设定编译方式,先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// VCTest.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
 
int __cdecl sum1(int a, int b)
{
	return a + b;
}
int __stdcall sum2(int a, int b)
{
	return a + b;
}
int __fastcall sum3(int a, int b)
{
	return a + b;
}
int main(int argc, char* argv[])
{
	sum1(2, 3);
	sum2(2, 3);
	sum3(2, 3);
	return 0;
}

3、断点反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
20:       sum1(2, 3);
;参数从右至左传递,外平栈,修改esp值
0040D7A8   push        3
0040D7AA   push        2
0040D7AC   call        @ILT+20(print) (00401019)
0040D7B1   add         esp,8
21:       sum2(2, 3);
;参数从右至左传递,内平栈,后面再贴出函数内部实现
0040D7B4   push        3
0040D7B6   push        2
0040D7B8   call        @ILT+30(sum2) (00401023)
22:       sum3(2, 3);
;参数从右至左,直接使用寄存器,不需要平栈
0040D7BD   mov         edx,3
0040D7C2   mov         ecx,2
0040D7C7   call        @ILT+25(sum3) (0040101e)

3.1、__stdcall sum3()内部反汇编,最后一句ret 8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
10:   int __stdcall sum2(int a, int b)
11:   {
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]
12:       return a + b;
00401068   mov         eax,dword ptr [ebp+8]
0040106B   add         eax,dword ptr [ebp+0Ch]
13:   }
0040106E   pop         edi
0040106F   pop         esi
00401070   pop         ebx
00401071   mov         esp,ebp
00401073   pop         ebp
00401074   ret         8  ;内平栈!

Leave a Reply