本文翻译自 https://github.com/teh-cmc/go-internals/tree/master/chapter1_assembly_primer
先看一个简单的 code
// go tool compile -N -l -S once.go // go build -gcflags -S once.go package main //go:noinline func add(a, b int32) (int32, bool) { return a + b, true } func main() { add(10, 32) } 生成汇编
GOOS=linux GOARCH=amd64 go tool compile -S x.go 在我的机器 Ubuntu kernel 5.4.0, Go version go1.18.3 amd64 上出来的结果与原文中还是有些差异的,但为了文章通顺,下面还是用的原文的结果。
0x0000 TEXT "".add(SB), NOSPLIT, $0-16 0x0000 FUNCDATA $0, gclocals·f207267fbf96a0178e8758c6e3e0ce28(SB) 0x0000 FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 MOVL "".b+12(SP), AX 0x0004 MOVL "".a+8(SP), CX 0x0008 ADDL CX, AX 0x000a MOVL AX, "".~r2+16(SP) 0x000e MOVB $1, "".~r3+20(SP) 0x0013 RET 0x0000 TEXT "".main(SB), $24-0 ;; ...omitted stack-split prologue... 0x000f SUBQ $24, SP 0x0013 MOVQ BP, 16(SP) 0x0018 LEAQ 16(SP), BP 0x001d FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x001d MOVQ $137438953482, AX 0x0027 MOVQ AX, (SP) 0x002b PCDATA $0, $0 0x002b CALL "".add(SB) 0x0030 MOVQ 16(SP), BP 0x0035 ADDQ $24, SP 0x0039 RET ;; ...omitted stack-split epilogue... Add 函数 0x0000 TEXT "".add(SB), NOSPLIT, $0-16 0x0000 : 表示当前指令相对于函数的偏移量 TEXT “”.add : 定义函数,在链接阶段会被链接器替换为 main.add (SB): SB 是 static base pointer,代表程序地址空间的起始地址。"".add(SB) 代表 add 在程序地址空间的一个固定 offset。比如像下面这样 $ objdump -j .text -t binary | grep 'main.add' 000000000044d980 g F .text 000000000000000f main.add FP 和 SB 的作用可以参见 《Go 语言汇编 一》
...