文章插图
2.main.main CALL main.test2之后的栈帧
也就是0x45daf2执行之后的寄存器和栈的情况. 这个时候SP的值-=8,里面存放main.test2执行完成之后返回main.main的执行指令的地址,也就是CALL下面那条指令的地址.由于RIP的值被CALL指令修改了,CPU执行的下一条指令就是main.test2的第一条指令了.
文章插图
main.test2(以及其他函数)本身的执行流程如下.
首先是栈帧的准备,然后是返回值的初始值设置.然后是核心的计算逻辑代码,然后是根据计算的结果设置返回值.最后销毁栈帧并返回.
文章插图
3.main.test2准备栈帧
通过将RSP的值调整小(栈帧向下生长),扩展好main.test2函数的栈帧,然后设置和RBP的值来标记栈帧的开始,同时让各个栈帧的RBP本身可以形成一个链表,方便调试器查找.
文章插图
4.初始化返回值,完成计算逻辑,保存返回值.
golang的一个函数返回值默认值需要为0,因为我们可以直接使用不带参数的return语句.这儿将返回值设置为0值.
在通过相应的指令完成计算逻辑之后,把返回值保持到main.main的栈帧里面,注意这整个过程中RSP和RBP都不会变化的,局部变量,入参,出参都是通过对RSP进行偏移得到的(入参,出参会偏移到main.main的栈帧里面,局部变量偏移到自己的栈帧里面),具体的偏移值编译器在编译过程中是可以计算出来的. 注意全f的表示值-1.
文章插图
【golang函数调用流程详解】5.销毁栈帧,返回main.main
在恢复了BP和SP之后,SP处值为main.main中CALL语句压入的下一条语句的地址.
main.test2的最后一条RET语句执行完成之后,RIP的值值变成SP处的值,SP+=8.栈帧完全恢复到CALL语句之前,唯一变的是main.main栈帧中返回值的两个地址里面变成了经过main.test2执行的值.然后SP-0X28这部分的内存就无效了,虽然里面的内容并没有被清空为全0.
文章插图
推荐阅读
- C++的函数重载和函数重写
- 相同逻辑的php与golang代码效率对比,最好语言落谁家…
- 数学证明深度学习激活函数从Softmax到Sparsemax
- 三分钟搞懂SQL的Case函数
- 六个鲜为人知的数据库函数,简单又好用
- Hook 函数与 CAM 算法
- Excel中基于四舍五入功能的CEILING函数
- 5个好用的 CSS 函数
- 它是Excel最短的一个函数:N,你知道怎么使用吗
- Golang超好用的支付宝支付类库