1. c调用约定 _cdecl
调用方将参数从右面到左压栈,被调用函数完成后,调用方负责从栈中清除参数。
// c代码
void sum(int a, int b);
int main() {
sum(10, 20);
}
// 汇编代码
push 20
push 10
call sum
add esp 8
// 或者 编译器预先在栈顶分配了存储空间
mov [esp + 4], 20
mov [esp], 10
call sum
这种方式调用sum之后 不需要调整栈指针,GUN(g++和gcc)采用这个技巧。
2. stdcall 调用约定
参数压栈顺序跟cdel一样,只是恢复esp是在被调用者内进行,被调用这采用ret指令。
这种方式的有点是:生成的程序体积稍小 速度稍快, 但是缺点是:对于可变参数的方法不能采用这种方式,只能使用cdecl。
3. fastcall 调用约定
mov edx 20
mov ecx 10
call sum
fastcall是stdcall的变体, 区别是fastcall会使用ecx和edx保存前两个参数。fastcall负责清理esp, 返回的大小减去ecx和edx的大小。
4. c++调用约定
c++静态成员函数就不需要写了,因为他跟普通函数没有区别。
非静态成员函数调用约定,因为需要一个this指针,这个各家编译器有自己的实现,vs系列把this放到ecx里,GUN系列把this作为第一个隐藏参数,this被放到栈顶。
网友评论