通过汇编看golang函数的多返回值问题

2020-06-22 12:27 来源:易采站长站 作者:于海丽 点击: 评论:

A-A+

原标题:通过汇编看golang函数的多返回值问题

golang这门语言,有个比较好的特性,就是支持函数的多返回值。想C,C++,Java等这些语言,是不支持函数多返回的。但是C,C++可以使用传递指针,实现函数多返回。但是,你有没有想过,golang是怎样实现函数多返回值的呢?

我们知道,C,C++是通过寄存器实现函数返回值的,也就是先把返回值写入到一个寄存器中,然后再从寄存器中,读到函数的返回值。golang也是这样实现的吗?

伟大的思想家孔子曾说过,在源码面前一切都如同裸奔。后来,鲁迅先生,总结了孔子的思想,说出了,在汇编面前,一切语法都是纸老虎。

下面我们通过golang的汇编指令,来看一下golang是怎样实现函数的多返回值的

在看汇编之前,我们先用go的 debug 函数看下函数的栈信息

代码很简单,不用解释了

package main
import (
 "fmt"
 "runtime/debug"
)

func main() {
 one(3)
}

func one(a int) (int, int) {
 fmt.Println(string(debug.Stack()))
 return a, a + 5
}

 

我标红的这一行,就是 one 函数的栈信息,第一个参数 0x3 很好理解,就是我们传入的参数 3

, 但是后面这两个是啥?还有,我明明只传了一个参数,为啥会传入三个参数?

到这里,我也就不卖关子了,直接说了,后面这两个参数,就是one函数返回值的地址,也就是说,one函数返回值地址不在one函数中,而是在调用one函数的mian函数中。golang的函数返回值,和C,C++的不同,golang的返回值是通过栈内地址实现的(返回值的地址是由函数调用者提供)。

package main

func main() {
 var b, c *int
 one(3, b, c)
}

func one(a int, b, c *int) {
}

也就是说,刚开始的那段代码,和这段在功能实现上,没有什么差别,只是golang编译器提供的一个语法糖。

下面通过汇编来看一下

这次我们不是对深入分析golang的汇编,只是从汇编层面,验证我们之前结论(golang函数多返回问题)

所以,不会死磕plan9汇编语法,说实话,plan9的很多知识我也不懂,大学没开过汇编的课程,这些东西都是因为兴趣自学的。

golang用的是plan9汇编,看plan9之前,先了解一下plan9的几个概念

go汇编中有4个伪寄存器

FP: Frame pointer,指向栈底位置,一般用来引用函数的输入参数,用来访问函数的参数 PC: Program counter: 程序计数器,用于分支和跳转 SB: Static base pointer: 一般用于声明函数或者全局变量 SP: Stack pointer:指向当前栈帧的局部变量的开始位置(栈顶位置),一般用来引用函数的局部变量

我们用这段代码进行汇编

package main

func main() {
 one(3)
}

func one(a int) (int, int) {
 return a, a + 5
}

【易采站长站编辑:秋军】