您的位置:首页 > 其它

__stdcall、__cdecl、__fastcall三种函数调用方式

2012-12-03 20:20 411 查看
前些天在cnblogs看到《win32 api 函数参数传递过程》这篇文章,其中只举了push入栈传参的例子,索性又在VC的Debug模式下把几种函数调用方式又看了一遍,这里权当做补充,复习一下函数调用方式。其实原文中说的也没有错,毕竟win32 api是微软的函数,使用__stdcall的方式,传参都是push指令也没有什么问题。

__stdcall是Pascal程序的缺省调用方式,通常Win32API,函数采用从右到左的压栈方式,自己在退出时清空栈。

__cdecl是C/C++程序的缺省的调用方式,按从右至左的顺序压参数入栈,由调用者把参数弹出栈,对于栈由调用者进行维护(可以达到参数可变)。

__fastcall的特点就是快,所以称之为fastcall,关键是通过寄存器来传递参数的(实际上,这种调用方式是采用ecx,edx传送参数的),依旧是自右向左压栈传送,被调用的函数在返回前清理栈。



在VC的编译器中可以通过修改Calling convention来修改函数调用方式。

#include <printf.h>

int add(int a, int b)
{
return a+b;
}

void main()
{
int x = 10, y=16;
printf("%d", add(x, y));
}


这样子的代码太简单了,没有任何含义这里就不解释了,主要看一下add()函数被在不同调用方式下,会有如何的变化。

__cdecl方式

mov     dword ptr [ebp-4], 0A
mov     dword ptr [ebp-8], 10
mov     eax, dword ptr [ebp-8]   ;将16传递给eax
push    eax                      ;16入栈
mov     ecx, dword ptr [ebp-4]   ;将10传递给ecx
push    ecx                      ;10入栈
call    00401005                 ;调用子函数
add     esp, 8                   ;调用者修正栈空间大小


;子程序
mov     eax, dword ptr [ebp+8]  ;在栈内操作数据
add     eax, dword ptr [ebp+C]  ;相加
pop     edi                     ;现场恢复


__stdcall方式

其他跟__cdcel方式差别不大,只是又子程序来清空堆栈。

retn    8                   ;子程序自己修正栈空间


__fastcall方式

mov     dword ptr [ebp-4], 0A
mov     dword ptr [ebp-8], 10
mov     edx, dword ptr [ebp-8]
mov     ecx, dword ptr [ebp-4]
call    00401005                         ;调用子函数

mov     dword ptr [ebp-8], edx           ;现在才是开始对栈进行送数据
mov     dword ptr [ebp-4], ecx           ;不使用push而用mov速度快
mov     eax, dword ptr [ebp-4]
add     eax, dword ptr [ebp-8]           ;进行加法操作


可以看出__fastcall没有一句push指令,但是依然能够将a和b进行相加,这里就是使用mov传参。除了这三种传参方式,还有很多方式,以后有需要再深入学习吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: