函数调用约定:是对函数调用时如何传递参数的一种约定。
调用函数前要先把参数压入栈然后再传递给函数,栈就是定义在进程中的一段内存空间, 其大小被记录在PE头中,进程运行时确定栈内存的大小(与malloc/new动态分配内存不同)
函数执行完成后,栈中的参数不用处理
因为只是临时存储在栈中的值,清除会浪费CPU资源,直接下一次向栈中存入其他值自然覆盖就行了,而且栈的内存是固定的,所以不能也不用释放内存。
函数执行完毕之后,ESP值如何变化?
ESP的值要恢复到函数调用之前,这样可引用的栈大小才不会被缩减。如何处理ESP,就要用到函数调用约定。
调用者:调用函数的一方
被调用者:被调用的函数
例如,main函数中调用printf()函数,调用者为main(),被调用者为printf()。
主要函数调用约定
cdecl
调用者直接清理其压入栈的函数参数。主要在C语言中使用。
优点:可以向被调用函数传递长度可变的参数。这种长度可变的参数在其它调用约定中很难实现。
stdcall
常用于Win32 API,该方式由被调用者清理栈,C语言默认的函数调用方式为cdecl,若想要使用stdcall方式编译源码,只要使用_stdcall关键字就可以
示例代码:
#include<stdio.h>
int _stdcall add(int a,int b)
{
return (a+b);
}
int main(int argc,char* argv[])
{
return add(1,2);
}
优点:通过被调用者清理栈,和cdecl相比代码尺寸要小。
fastcall
与stdcall方式基本类似,但该方式通常会使用寄存器(而非栈内存)去传递需要传递给函数的部分参数(前2个),若某函数有4个参数,则前两个参数分别使用ECX、EDX寄存器传递
优点:速度快,实现对函数的快速调用
缺点:可能会增加系统开销,还可能需要备份ECX和EDX中的数据。