函数调用约定

通过名字来分析:压栈就是往栈内添加东东,因为栈是先进先出的,所以叫做压栈。

-------------------------------------------

下面是搜索到的内容,很好:

函数压栈的本质是参数传递 
这又跟汇编语言连系起来了.汇编语言的过程即proc可以理解成函数 
比如一个最简单的计算两数之和函数 
如果用汇编来写估计是这样的 

sub proc 
pop ax ;从stack取a 并放在AX寄存器中 
pop bx ;从stack取b 并放在BX寄存器中 
add ax,bx ; 计算a+b 
ret //返回 
sub endp 

显然要调用这个函数,你应当先把b值push进stack,然后再push a 
因为stack是先进后出的 
所以调用汇编像这样 
比如计算4+5 
push 5; 
push 4; 
call sub; //返回值在AX中 
在这个例子中先压5或先压4得到的结果没有变化 
但大多数程序,如果参数的顺序错误将是灾难性的 


因为不管什么高级语言最终都要编译成汇编语言,然后是机器语言 
同样下面这个C程序,计算a+b值,必然会编译成上面的汇编代码 
int sub(int a ,int b) {return a+b;} 
所以C在调用这个函数sub时,必须要压栈(即传入参数)但这些工作,在C语言里,并不需要你来完成.你只要写出 
sub(7,9); 
编译器在编译成汇编时就会自动完成相关的压栈工作. 

根据函数调用方式和参数压入顺序目前存在三种约定: 

stdcall 
cdecl 
fastcall 
这都相关压栈顺序和栈的清理工作约定 
他们的细节都不相同,但有一点是肯定的,参数比须从右向左压入栈中 
stdcall中 函数必须自已清理栈 
cdecall 由调用者清除堆栈 C的默认函数调用方式 所以这样C支持可变参数 
fastcall 是把函数参数列表的前三个参数放入寄存器eax,edx,ecx,其他参数压栈 

源代码: 
int function(int a, int b) 

return a + b; 


void main() 

function(10, 20); 


1.__cdecl 

_function 
push ebp 
mov ebp, esp 
mov eax, [ebp+8] ;参数1 
add eax, [ebp+C] ;加上参数2 
pop ebp 
retn 
_main 
push ebp 
mov ebp, esp 
push 14h ;参数 2入栈 
push 0Ah ;参数 1入栈 
call _function ;调用函数 
add esp, 8 ;修正栈 
xor eax, eax 
pop ebp 
retn 

2.__fastcall 

@function@8 
push ebp 
mov ebp, esp ;保存栈指针 
sub esp, 8 ;多了两个局部变量 
mov [ebp-8], edx ;保存参数 2 
mov [ebp-4], ecx ;保存参数 1 
mov eax, [ebp-4] ;参数 1 
add eax, [ebp-8] ;加上参数 2 
mov esp, ebp ;修正栈 
pop ebp 
retn 
_main 
push ebp 
mov ebp, esp 
mov edx, 14h ;参数 2给EDX 
mov ecx, 0Ah ;参数 1给ECX 
call @function@8 ;调用函数 
xor eax, eax 
pop ebp 
retn 

3.__stdcall 

_function@8 
push ebp 
mov ebp, esp 
mov eax, [ebp] ;参数 1 
add eax, [ebp+C] ;加上参数 2 
pop ebp 
retn 8 ;修复栈 
_main 
push ebp 
mov ebp, esp 
push 14h ;参数 2入栈 
push 0Ah ;参数 1入栈 
call _function@8 ;函数调用 
xor eax, eax 
pop ebp 
retn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值