文档开发者中心
我的

探究Go函数调用栈

本文简单地对Go的函数调用栈进行了探究。

需要声明的一点是,根据Go语言文档《A Quick Guide to Go's Assembler》的说明,这里反编译得到Go的汇编程序不是底层机器执行代码的直接表示。 只有其中一部分是和底层机器码一一对应的,另外一部分则没有。

函数


反编译及代码分析

执行下面的语句得到汇编文件

shell go tool compile -S -N -l main.go > main.s

去除掉跟Go语言垃圾回收有关的FUNCDATA、PCDATA后,main函数、myFunction1函数、myFunction2函数的部分汇编代码分别如图1、图2和图3所示。这里所提到的SP寄存器并不是真正的寄存器,是工具链维护的虚拟寄存器。主要部分指令的解释如图1、图2和图3中的注释所示,不再赘述。

图1. main函数汇编代码(部分)

1fb2626457c003c530c0_932x368.png@900-0-90-f.png

图2. myFunction1函数汇编代码(部分)

图3. myFuntion2函数汇编代码(部分)

函数调用栈分析

图4~8展示了不同情况下的函数调用栈示意图,图的上边是高地址,下边是低地址,栈是向下生长的。

在执行CALL ''.myFunction1(SB)调用myFunction1函数前,main函数调用栈如图4的蓝色部分所示。从main函数的汇编代码可以看出,main函数分别在(SP)、8(SP)存放立即数77、66,也即要传递给myFuntion1函数的参数a、参数b。

图4. 调用myFuntion1前main函数调用栈示意图

在要退出myFunction1函数前,main函数和myFunction1函数调用栈分别如图5的蓝色、红色部分所示。从myFunction1的汇编代码可以看出,myFunction1函数分别从24(SP)、32(sp)(对应于图4中main函数调用栈的(SP)、8(SP))处获取参数a、参数b,将返回值放在40(SP)、48(sp)(对应于图4中main函数调用栈的16(SP)、24(SP)),局部变量c则放在(SP)(位于myFunction2函数自己的栈中)。

图5. main函数和myFunction1函数调用栈示意图

在退出myFunction1函数之后,并且执行CALL ''.myFunction2(SB)调用myFunction2函数前,main函数调用栈如图6的蓝色部分所示。从main函数的汇编代码可以看出,main函数分别在64(SP)、56(SP)、48(SP)存放变量x、y、z,并且分别将它们拷贝至(SP)、8(SP)、16(SP),也即要传递给myFuntion2函数的参数a、参数b、参数c。注意,24(SP)处保存的值没有被覆盖/擦除,仍然保留了myFunction1函数的第二个返回值。

图6. 调用myFuntion2前main函数调用栈示意图

在要退出myFunction2函数前,main函数和myFunction2函数调用栈分别如图7中的蓝色、红色部分所示。从myFunction2的汇编代码可以看出,myFunction2函数分别从24(SP)、32(SP)、40(SP)处(对应于 main函数调用栈的(SP)、8(SP)、16(SP))获取参数a、参数b、参数c,将返回值放在48(SP)处(对应于main函数调用栈的24(SP)),局部变量d则放在(SP)处(位于myFunction2函数自己的栈中)。

图7. main函数和myFunction2函数调用栈示意图

从上述情况可见,Go中的函数调用栈和C/C++有一定的区别。区别在于,Go中的函数调用中会把传递给被调用函数的参数和返回值保存在自己的栈中,而被调用函数则需要从调用函数的栈中去获取参数变量,并且返回值要写入到被调用函数栈中。Go中局部变量和C/C++一样,都是保存在所属函数的栈中。因此,Go的函数调用栈形式如图8所示。

图8. Go函数调用栈示意图

参考资料



——————————————————


BY:HW-YZQ

点赞
收藏
回复
3
分享
举报
浏览871 发布于2019-10-16 02:06未知归属地
全部评论
最多点赞
最新发布
最早发布

一起学习

3楼回复于2019-10-16 02:09 未知归属地

欢迎大家分享啊

2楼回复于2019-10-16 02:08 未知归属地

一些关于go函数调用栈的探究,值得一读!

1楼回复于2019-10-16 02:08 未知归属地
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

目录 收起
函数
反编译及代码分析
函数调用栈分析
参考资料
了解社区公约,与您携手共创和谐专业的开发者社区。