上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
8.1 call convention
Go 底层调用约定(low-level calling convention)。
当函数调用时,调用函数(caller)会将参数(arg)传递给被调用函数(callee),并接收其返回值(ret)。而所谓调用约定是指如何传递参数(栈内存或寄存器,参数入栈次序),谁来为参数和返回值提供内存,并维持栈平衡。
go 1.15 linux/amd64
参数,返回值
函数返回值通过堆栈内存传递,而非寄存器。
C 等语言习惯使用寄存器传递参数和返回值。
RDI、RSI、RDX、RCX、R8、R9 传参,RAX 返回。
超出的参数入栈,或使用其他寄存器,看具体的编译器。
有个提案 《[define register-based calling convention]》,建议 Go 使用寄存器。
不过似乎没被接受。
由调用者(caller)准备参数和返回值存储空间。
被调用者(callee)负责将返回值复制到调用者内存。
自 0(SP) 开始,向后依次存放调用参数,最后是返回值。
调用者栈帧分上下两部分,分别用于函数调用和局部变量。
编译器在调用前总是将必要的寄存器数据保存到栈。
被调用者可自由使用寄存器,无需提前保存(callee-save registers)。
栈帧(stack frame)用 SP 指向栈顶(低地址),BP 指向栈低。
栈帧包括存储调用者 BP 的空间。
调用结束,恢复 SP、BP,指向调用者栈帧。
package main func add(x, y int) int { z := x + y return z } func main() { x, y := 17, 34 z := add(x, y) _ = z }
$ go build -gcflags "-N -l -S" "".add STEXT nosplit size=52 args=0x18 locals=0x10 0x0000 TEXT "".add(SB), $16-24 SP +---------+------------- 0x0000 SUBQ $16, SP | z | 0x0004 MOVQ BP, 8(SP) BP +---------+ add 0x0009 LEAQ 8(SP), BP | main.BP | 16 +---------+------------- 0x000e MOVQ $0, "".~r2+40(SP) | main.PC | 0x0017 MOVQ "".x+24(SP), AX 24 +---------+------------- 0x001c ADDQ "".y+32(SP), AX | arg x | 0x0021 MOVQ AX, "".z(SP) 32 +---------+ 0x0025 MOVQ AX, "".~r2+40(SP) | arg y | main 40 +---------+ 0x002a MOVQ 8(SP), BP | ret | 0x002f ADDQ $16, SP 48 +---------+ 0x0033 RET | ... | "".main STEXT size=97 args=0x0 locals=0x38 0x000f SUBQ $56, SP SP +---------+------------- 0x0013 MOVQ BP, 48(SP) | arg x | 0x0018 LEAQ 48(SP), BP 8 +---------+ | arg y | <call> 0x001d MOVQ $17, "".x+40(SP) 16 +---------+ 0x0026 MOVQ $34, "".y+32(SP) | ret | 0x002f MOVQ "".x+40(SP), AX 24 +---------+ . . . . . . . 0x0034 MOVQ AX, (SP) | z = ret | 0x0038 MOVQ $34, 8(SP) 32 +---------+ 0x0041 CALL "".add(SB) | y = 34 | <local> 0x0046 MOVQ 16(SP), AX 40 +---------+ 0x004b MOVQ AX, "".z+24(SP) | x = 17 | BP +---------+ 0x0050 MOVQ 48(SP), BP | ... | 0x0055 ADDQ $56, SP 56 +---------+-------------- 0x0059 RET
注:汇编指令及示意图使用十进制。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论