返回

函数的底层原理

发布时间: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,先取出返回地址,并清理参数,然后按返回地址作流程更新
特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线