前言

函数调用和被调用之间肯定要规定,如何传递参数,如何恢复栈平衡的问题。


正文

程序运行最开始,main函数肯定是第一个入栈的,其他的函数被调用时相继入栈。


_cdecl

1
2
3
4
5
6
7
8
9
10
#include<iostream>

int add(int a, int b);

int main(){

add(1, 2);

return 0;
}

编译自然报错,但是我们看报错信息

之前说到过C语言处理函数在.obj文件下都是加一个_
而c++因为有重载的功能所以还多了参数,除此之外就是_cdecl

_cdecl的参数入栈 从右到左

堆栈平衡:谁调用谁平衡

所以这种方式能够支持不定量参数。 不定量详情看function1吧,好像写在那里了。

虽然不定量,但是毕竟是从右边开始传递,所以不会出现丢三落四的情况。


_stdcall

因为一般都是_cdecl 所以这玩意比较少见,但是反正能指定。

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>

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

int main(){

add(1, 2);

return 0;
}

_stdcall的参数入栈顺序同为 从右往左
堆栈平衡:由函数自己恢复栈平衡

特色就是windows编程中WINAPI CALLBACK都是_stdcall的宏
并且生成的函数名会加下划线,后面跟@和参数尺寸


_fastcall

fast看着就想快速

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>

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

int main(){

add(1, 2);

return 0;
}

它的特点就是第一个参数由ecx寄存器传递,第二个参数由dex寄存器传递
剩余参数仍然按照入栈顺序 从右到左依次入栈

可以看到俩参数没有通过push指令压入栈中,而是mov给寄存器。

堆栈平衡:由函数自己恢复栈平衡

因为有俩寄存器调用了,所以相对而言会比较快。

当多个形参,比如三个时,add(1,2,3);
3先被push入栈,2和1分别交给寄存器
恢复栈平衡的时候ret 4。 就是只压入了一个3,所以要释放掉。


其他调用

_thiscall 是用于c++中类的访问,用到类的底层时再看
naked call是一个常用的约定,一般也就是实验模式驱动开发


结语

有特殊需求的时候自然会指定函数的调用方式。