-
-
[原创]深入理解C语言二-函数调用约定
-
2021-7-5 23:26 4288
-
函数调用约定
调用者和被调用者关于栈上参数传递和清理栈空间的一种约定,用来清理参数占用的栈空间,恢复栈平衡。栈平衡是编译器在汇编时完成的,不需要手动完成。
调用约定的类型
- cdecl(C语言默认,变参函数)
- stdcall(Windows API,内核驱动)
- fastcall(x64平台)
cdecl调用约定
- 参数入栈顺序:从右向左
- 调用者修改栈,恢复栈平衡,所以可以支持变参函数
stdcall调用约定
- 参数入栈顺序:从右向左
- 被调用者自身修改栈,恢复栈平衡
fastcall调用约定
- 参数入栈顺序:函数的第一、第二个参数通过ecx、edx寄存器传递,剩余参数从右向左入栈
- 被调用者自身修改栈,恢复栈平衡
EIP
系统中的寄存器,存储CPU要读取的指令地址,CPU通过eip寄存器读取即将要执行的指令,每次CPU执行完相应的汇编指令后,eip的值就会增加。栈中的返回地址存放在eip中,供当前函数执行完后,CPU执行程序的下一条语句。
ESP
栈指针寄存器,一直指向系统栈最上面一个栈帧的栈顶,是CPU机制决定的,push、pop指令会自动调整esp的值。
EBP
基址指针寄存器,一直指向系统栈最上面一个栈帧的栈底,ebp只存取某时刻的esp,这个时刻是指进入一个函数内部后,CPU会将esp的值赋值给ebp,此时就可以通过ebp对栈进行操作,比如获取函数参数、局部变量等。
esp在函数运行时会不断变化,所以保存一个进入某个函数的esp到ebp,方便访问参数和局部变量,还方便调试器分析函数调用过程中的堆栈情况。
x86和x64的fastcall的区别
- x64传递参数时比x86多了两个寄存器r8、r9
- x64参数入栈对齐到8个字节,x86是4个字节
- x64函数的前4个参数通过rcx、rdx、r8、r9四个寄存器传递
- x64会在栈上预留4个字节的内存空间
- x64调用者恢复栈平衡,支持变参函数
- x64栈整体大小要能被16整除
- x64局部变量空间的分配和初始化由调用者完成
github:https://github.com/0I00II000I00I0I0
bilibili:https://space.bilibili.com/284022506
赞赏
他的文章
[分享]C++基础十七-异常机制
7849
[分享]C++基础十六-模板
8210
[分享]C++基础十五-运算符重载
8255
[分享]C++基础十四-抽象类
7967
[分享]C++基础十三-多态
7701
看原图