四、函数参数的传递规则

函数参数的传递规则

函数传递的规则现在一般有两种,一种是WINAPI方式,也就是_stdcall还有一种是_cdecl方式


_stdcall调用规则:


(1)参数从右到左进入堆栈
(2)被调用者在返回前自动清理堆栈


_cdecl C方式调用规则:


(1)参数从右到左进入堆栈
(2)由调用者负责清理堆栈
生成的程序代码一般会比_stdcall的大。


C编译器默认采用_cdecl方式,而windows API默认采用_stdcall。

在windows中,无论哪种方式,返回值都放在eax中,然后返回,外部从eax中得到返回值。


_cdecl使用的一般过程:
(1)保持ebp 。ebp总是被我们用来保存这个函数执行前esp的值,执行函数完毕后,用来恢复esp。当然,这个函数的上层函数也是这样做的,所以我们要先把ebp压入堆栈,避免ebp被我们改动。
(2)保存esp到ebp中
上面的两步的代码如下:
push ebp
mov ebp,esp
(3)为局部变量申请空间,一般是用sub esp,空间大小 来进行分配,相当于压入堆栈。完成后记得平衡堆栈
(4)保存其它寄存器的值。ebx、esi、edi压入堆栈,调用完后恢复。
sub esp,0cch
push ebp
push esi
push edi
(5)将局部变量区域初始化为0cccccccch,也就是int3指令的机器码。
lea edi,[ebp-0cch]
mov ecx,33h
mov eax,0cccccccch
rep stos dword ptr [edi]
(6)做函数要做的事
(7)恢复ebx、esi、edi、esp、ebp,然后返回
pop edi
pop esi
pop ebx
mov esp,ebp

pop ebp
ret

 


对应的c代码:

 1 #include "stdafx.h"
 2 
 3 
 4 int _tmain(int argc, _TCHAR* argv[])
 5 {
 6     void fun(int a,int b);
 7     fun(11,22);
 8     return 0;
 9 }
10 
11 void fun(int a,int b)
12 {
13     int c=a+b;
14 }

对应的函数汇编代码

 1 void fun(int a,int b)
 2 {
 3 00411780  push        ebp  
 4 00411781  mov         ebp,esp  
 5 00411783  sub         esp,0CCh  
 6 00411789  push        ebx  
 7 0041178A  push        esi  
 8 0041178B  push        edi  
 9 0041178C  lea         edi,[ebp-0CCh]  
10 00411792  mov         ecx,33h  
11 00411797  mov         eax,0CCCCCCCCh  
12 0041179C  rep stos    dword ptr es:[edi]  
13     int c=a+b;
14 0041179E  mov         eax,dword ptr [a]  
15 004117A1  add         eax,dword ptr [b]  
16 004117A4  mov         dword ptr [c],eax  
17 }
18 004117A7  pop         edi  
19 004117A8  pop         esi  
20 004117A9  pop         ebx  
21 004117AA  mov         esp,ebp  
22 004117AC  pop         ebp  
23 004117AD  ret  

..................................

posted @ 2012-04-26 19:49  r3call  阅读(367)  评论(0编辑  收藏  举报