函数的底层原理
发布时间:2022-04-02 17:29:02 415
相关标签:
每个函数都有一个属于自己的栈空间,用来记录函数的必要信息
1、按调用约定传参
- 参数的传递方向(是从右向左还是从左向右传参)
- 参数的存储媒介(参数放寄存器还是栈区或者其他)
- 谁负责释放(平衡)参数空间
- 返回值的处理
__cdecl | __stdcall | __fastcall | |
解释 | C调用约定,美国国标标准,默认调用约定 | 标准约定,微软的规定,微软操作系统使用的调用规定,Windows API的标准调用约定 | 快速约定,只有微软某一系列编译器独有的,未标准化,不同编译器可能没有或者实现不一致 |
参数传递方式 | 从右往左,通过栈传递 | 从右往左,通过栈传递 | 左数前两个参数放在ecx、edx寄存器中,其余从右往左通过栈传递 |
谁清理栈上参数 | 调用者(caller) | 被调者(callee) | 被调者(callee) |
编译器参数 | /Gd | /Gz | /Gr |
可变参 | 支持 | 不支持 | 不支持 |
2、在栈顶保存返回地址
3、保存调用方的栈信息(调用方的栈底位置)
4、更新栈位置(在处理器里)到被调用方的栈底处
5、在栈内开辟局部变量的空间
- 编译器此时会统计局部变量的大小(占多大空间),然后以此开辟足够空间
- 调试版开辟的空间大于等于实际局部变量的大小,发行版(优化版)开辟的空间小于等于实际局部变量的大小
使用`/O1`和`/O2`编译选项会根据变量使用情况,会分配小于等于变量大小的空间,例:
// 第一种优化情况
// 如果开了优化,编译器不会给局部变量nNum开辟空间
// 而是直接使用 printf("%d",3);
int nNum = 3;
printf("%d",nNum)
// 第二种优化情况
// 根据情况使用寄存器存储变量
编译选项有/Zi+/Od(调试版且不优化),则填充局部变量空间为0xcc
6、保存寄存器环境
7、执行函数体
8、恢复寄存器环境
9、释放局部变量空间
10、恢复栈信息到调用方
11、如果是 __cdecl,先取出返回地址,并按此返回地址作流程更新,抵达新地址后,由调用方清理参数;
- 如果是 __fastcall,__stdcall,先取出返回地址,并清理参数,然后按返回地址作流程更新
特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报