您的位置:首页 > 其它

函数调用约定

2013-03-20 16:33 351 查看
通过名字来分析:压栈就是往栈内添加东东,因为栈是先进先出的,所以叫做压栈。

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

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

函数压栈的本质是参数传递 

这又跟汇编语言连系起来了.汇编语言的过程即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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: