内容简介:golang中的函数调用底层是靠栈帧实现的,翻看了好多文章发现很少有从最终机器码层面进行解释的,我跟踪发现要比golang汇编复杂一些,具体为什么要有这个命令为啥这么扩容,扩容多少这都是编译器算出来的,我们不需要知道。这篇文章的目的是对函数调用的一个更深层次的认识,当然如果要学好golang中的汇编还需要去看golang汇编相关的知识讲解。从实际开发中需要明白golang汇编就好。以下代码环境:1,Linux version 3.10.0-957.12.2.el7.x86_64
golang中的函数调用底层是靠栈帧实现的,翻看了好多文章发现很少有从最终机器码层面进行解释的,我跟踪发现要比golang汇编复杂一些,具体为什么要有这个命令为啥这么扩容,扩容多少这都是编译器算出来的,我们不需要知道。这篇文章的目的是对函数调用的一个更深层次的认识,当然如果要学好golang中的汇编还需要去看golang汇编相关的知识讲解。从实际开发中需要明白golang汇编就好。
以下代码环境:
1,Linux version 3.10.0-957.12.2.el7.x86_64
2,go version go1.12.5 linux/amd64
以下是我做实验的代码两个数相加的一个函数。
package main import "fmt" func main() { d := jia(1,2) fmt.Println(d) } func jia(a, b int) int { c := a + b return c }
然后编译成可执行文件。
go build -gcflags "-N -l" -o run
这里gcflags参数是去掉编译优化,方便调试。
然后用gdb工具进行查看相应的汇编代码,如下:
图1
sub rbp,0x70(%rsp) //将rbp的值存入到old rbp处见图2。
lea 0x70(%rsp),%rbp //将old rbp位置的地址存入到rbp作为main的栈底。
movq $0x1, (%rsp) //将函数参数1放入栈中。
movq $0x2, 0x8(%rsp) //将函数参数2放入栈中。
执行完绿框处代码栈的赋值情况见下图2。(其中蓝色的框是第一次扩容的main函数栈空间。绿色的表示调用调用 call jia时候call内部又扩容了8个byte(我猜是函数返回值占8个字节)。粉色是jia函数扩容16个字节。绿色加蓝色的空间是就是jia的栈空间)
图2
刚扩容完之后栈中的数据见图3:
图3
执行到call jia指令,参数赋值到栈中,栈顶向低地址移动8byte,见下图4:
图4
去0x4872d0<main.jia>地址处查看汇编码,见图5:
图5
然后执行到图6位置:
图6
从图中可以看出将计算结果放到了rax中且赋值到了栈顶处。然后在看一下栈的整体流程图见图7:
图7
从图7可以看出函数的参数,返回值都放到了栈中,然后继续执行见下图8:
图8
调用完jia(int,int)的retq时,rsp又缩容到初次扩容的地方0xc000032718处,这样栈顶的前3个位置分别为参数和返回值。
在继续执行我发现0xc000032718处的数据依然存在,我猜这些数据不会被删除,如果再用到此空间直接覆盖就好,因为如果用完删除的话会影响性能。
以上就是函数调用的大概流程,直观感受一下就好,但是函数调用如何传参,如何获取返回,大致思路都是一样的都是借助类似栈结构及栈的收缩来实现的。
以上所述就是小编给大家介绍的《golang函数调用的执行逻辑》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Python 函数调用&定义函数&函数参数
- Linux内核如何替换内核函数并调用原始函数
- gdb 如何调用函数?
- 汇编层面分析函数调用
- 理解 Golang 的函数调用
- Wasm 介绍(六):间接函数调用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
程序员面试宝典(第5版)
欧立奇、刘洋、段韬 / 电子工业出版社 / 2015-10 / 55.00
容提要 《程序员面试宝典(第5版)》是《程序员面试宝典》的第5 版,在保留第4 版的数据结构、面向对象、程序设计等主干的基础上,修正了前4 版近40 处错误,解释清楚一些读者提出的问题,并使用各大IT 公司及相关企业最新面试题(2014-2015)替换和补充原内容,以反映自第4 版以来两年多的时间内所发生的变化。 《程序员面试宝典(第5版)》取材于各大公司面试真题(笔试、口试、电话面试......一起来看看 《程序员面试宝典(第5版)》 这本书的介绍吧!