函数调用约定
参数传递过程中,二个问题:
1 当参数多于1个时,按照什么顺序把参数入栈
2 函数调用后 ,由谁把栈恢复原貌
函数调用时,函数调用者依次把参数压栈,然后调用函数,函数调用后,在栈中取得数据,并进行计算。函数调用结束后,
或者调用者或者函数本身修改栈,使栈恢复原貌。
stdcall
stdcall调用约定声明函数的格式:
int __stdcall func(int x, int y)
stdcall的调用约定规则:
参数入栈规则: 参数从右向左入栈
堆栈平衡:被调用函数自身修改栈
函数名自动加前导的下划线,后面紧跟一个@符合,其后紧跟着参数的尺寸。
cdecl调用约定
C语言缺省的调用约定,它声明函数的格式:
int func(int x, int y) 或 int __cdecl func(int x, int y)都可以
cdecl的调用约定规则:
参数入栈顺序: 从右到左
堆栈平衡:调用者修改栈
函数名:前加下划线
由于每次函数调用都要由编译器产生还原栈的代码,所以使用__cdecl方式编译的程序比使用__stdcall编译的程序大很多。
但是__cdecl调用方式是由函数调用者负责清除栈中的函数参数,所以这种方式支持可变参数,比如printf()和Windows API的wsprintf
fastcall调用约定
fastcall调用约定声明函数的格式:
int fastcall func(int x, int y)
fastcall调用约定规则:
参数入栈顺序:函数的第一个和第二个参数通过ecx和edx传递,剩余参数从右到左入栈
堆栈平衡:被调用者修改栈
函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸
以fastcall声明执行的函数,具有较快的执行速度,因为函数的前二个参数通过寄存器来传递的。
thiscall调用约定
thiscall是C++类成员函数缺省的调用约定,但它没有显示的声明形式。在C++类中,成员函数调用还有一个this指针参数,因此必须特殊处理,thiscall意味着:
参数入栈:参数从右向左入栈
this指针入栈:如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入栈。
栈恢复:对参数个数不定的,调用者清理栈,否则函数自己清理栈。
函数调用约定:
调用函数时使用的是绝对地址
c语言:
X86:_cdecl _stdcall _fastcall
X64:_fastcall
C++ thiscall: 将类的this指针的地址给寄存器 不压参
X86
_cdecl:回收参数列表由主调函数完成
stdcall:回收参数列表由被调函数完成 ret的作用—— 先pop eip 然后 esp 加(add) 一个值(回收参数列表)
fastcall:第一第二参数不压参,直接传递给寄存器 ecx edx 回收参数列表由被调函数完成
X64
fastcall: 多了r8 r9 两个寄存器 可以直接将前四个参数传递给寄存器(rcx rdx r8 r9)