go语言如何使用rbp, rsp, 参数如何传递, 为什么go的返回值写在后面

简介: # 为什么go的返回值写在后面 go一直被鼓吹语法比java好, 性能跟c一样. 让我们来看一看go语言各部分对应的二进制指令, 是如何实现的 现在的想法是写个一系列文章, 把go的所有语法的实现方式都分析一遍, 不知道会不会半途而废 ### 本文所有的分析方法, 结论都是本人猜测的, 查各种文档太费时间了, 当然不是乱猜, 都是有依据的 先看栈回溯最基本的方法, rbp, r

为什么go的返回值写在后面

go一直被鼓吹语法比java好, 性能跟c一样. 让我们来看一看go语言各部分对应的二进制指令, 是如何实现的

现在的想法是写个一系列文章, 把go的所有语法的实现方式都分析一遍, 不知道会不会半途而废

本文所有的分析方法, 结论都是本人猜测的, 查各种文档太费时间了, 当然不是乱猜, 都是有依据的

先看栈回溯最基本的方法, rbp, rsp的使用情况, 现在的实验都是加了-N -l的, 简单化

rbp, rsp

随便写了go语言

package main

func boo(a int, b int) int {
    return a + b
}
func aoo(a int, b int) int {
    c := 10
    return a + b + c + boo(1, 2)
}
func main() {
    aoo(1, 2)
}
81094 000000000044dfc0 <main.aoo>:
81095   44dfc0:>------64 48 8b 0c 25 f8 ff >--mov    %fs:0xfffffffffffffff8,%rcx
81096   44dfc7:>------ff ff-
81097   44dfc9:>------48 3b 61 10          >--cmp    0x10(%rcx),%rsp
81098   44dfcd:>------76 61                >--jbe    44e030 <main.aoo+0x70>
81099   44dfcf:>------48 83 ec 30          >--sub    $0x30,%rsp
81100   44dfd3:>------48 89 6c 24 28       >--mov    %rbp,0x28(%rsp)
81101   44dfd8:>------48 8d 6c 24 28       >--lea    0x28(%rsp),%rbp
81102   44dfdd:>------48 c7 44 24 48 00 00 >--movq   $0x0,0x48(%rsp)
81103   44dfe4:>------00 00-
81104   44dfe6:>------48 c7 44 24 18 0a 00 >--movq   $0xa,0x18(%rsp)
81105   44dfed:>------00 00-
81106   44dfef:>------48 c7 04 24 01 00 00 >--movq   $0x1,(%rsp)
81107   44dff6:>------00-
81108   44dff7:>------48 c7 44 24 08 02 00 >--movq   $0x2,0x8(%rsp)
81109   44dffe:>------00 00-
81110   44e000:>------e8 9b ff ff ff       >--callq  44dfa0 <main.boo>
81111   44e005:>------48 8b 44 24 10       >--mov    0x10(%rsp),%rax

拿出上面的rsp rbp部分的代码

81099   44dfcf:>------48 83 ec 30          >--sub    $0x30,%rsp
81100   44dfd3:>------48 89 6c 24 28       >--mov    %rbp,0x28(%rsp) 
81101   44dfd8:>------48 8d 6c 24 28       >--lea    0x28(%rsp),%rbp
其实就是push rbp; mov rsp rbp; rsp -= 0x28

一看就很简单, 先分配0x30空间, 保存之前的rbp到靠近ret ip的地方, 然后把这个地址保存到rbp寄存器里面
和c一样, 就是rbp一直循环指向来做栈回溯, ret ip就是这个栈帧的rbp, + 8 的地方
如果有些函数不需要栈, 就没有这些东西了

参数如何入


func aoo(a int, b int) int {
    c := 10
    return a + b + c + boo(1, 2)
}
81106   44dfef:>------48 c7 04 24 01 00 00 >--movq   $0x1,(%rsp)
81107   44dff6:>------00-    
81108   44dff7:>------48 c7 44 24 08 02 00 >--movq   $0x2,0x8(%rsp)
81109   44dffe:>------00 00- 
81110   44e000:>------e8 9b ff ff ff       >--callq  44dfa0 <main.boo>

和c语言一样, 从右到左, 只不过这里直接mov来写栈里面的内容了, 不需要push

从右到左是可变参数的必须要的条件

如何获取参数

func boo(a int, b int) int {
    return a + b
}
81079 000000000044dfa0 <main.boo>:
81080   44dfa0:>------48 c7 44 24 18 00 00 >--movq   $0x0,0x18(%rsp)
81081   44dfa7:>------00 00- 
81082   44dfa9:>------48 8b 44 24 08       >--mov    0x8(%rsp),%rax
81083   44dfae:>------48 03 44 24 10       >--add    0x10(%rsp),%rax
81084   44dfb3:>------48 89 44 24 18       >--mov    %rax,0x18(%rsp)

直接rsp加8, 来获取, 为什么多了一个8, 因为callq的时候push了一个ret ip

这里其实可以看到, 返回值的处理不是rax了, 而是直接操作父函数的第三个参数

mov %rax,0x18(%rsp), 这个语言设计就比c语言更加简化了, 可以理解为都是参数, 没有返回值这个概念, 所以多返回值也就很好操作了, 第四个参数, 第五个参数, 直接读写对应地址就可以了
这样就很好理解为什么go喜欢把返回值写在后面

func boo(a int, b int) int {
    return a + b
}

原来返回值就是第三个参数

这篇文章标题可以写成, 为什么go的返回值写在后面

目录
相关文章
|
3天前
|
安全 网络协议 Go
Go语言网络编程
【10月更文挑战第28天】Go语言网络编程
89 65
|
3天前
|
网络协议 安全 Go
Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
【10月更文挑战第28天】Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
23 13
|
3天前
|
网络协议 安全 Go
Go语言的网络编程基础
【10月更文挑战第28天】Go语言的网络编程基础
17 8
|
2天前
|
Go
go语言的复数常量
【10月更文挑战第21天】
13 6
|
2天前
|
Go
go语言的浮点型常量
【10月更文挑战第21天】
9 4
|
2天前
|
编译器 Go
go语言的整型常量
【10月更文挑战第21天】
8 3
|
3天前
|
Go
go语言编译时常量表达式
【10月更文挑战第20天】
11 3
|
2天前
|
Serverless Go
Go语言中的并发编程:从入门到精通
本文将深入探讨Go语言中并发编程的核心概念和实践,包括goroutine、channel以及sync包等。通过实例演示如何利用这些工具实现高效的并发处理,同时避免常见的陷阱和错误。
|
3天前
|
安全 Go 开发者
代码之美:Go语言并发编程的优雅实现与案例分析
【10月更文挑战第28天】Go语言自2009年发布以来,凭借简洁的语法、高效的性能和原生的并发支持,赢得了众多开发者的青睐。本文通过两个案例,分别展示了如何使用goroutine和channel实现并发下载网页和构建并发Web服务器,深入探讨了Go语言并发编程的优雅实现。
10 2
|
3天前
|
Go
go语言常量的类型
【10月更文挑战第20天】
9 2