Golang中string类型作为函数参数进行传递的时候背后是怎么实现的呢?本文通过查看Golang汇编结果进行一些insight。
编译Golang汇编命令:
GOOS=linux GOARCH=amd64 go tool compile -S -N xxx.go > xxx.s
第一个案例——简单的函数参数传递
Go代码:
package main
//go:noinline
func foo(s string) {
s = "this is a change"
}
func main() {
s := "hello world"
foo(s)
}
注意为了防止函数在编译过程中被内联优化,使用了go:noinline
。汇编结果(简明考虑删去了一些不重要的内容):
"".foo STEXT nosplit size=22 args=0x10 locals=0x0
0x0000 00000 (func_string.go:5) LEAQ go.string."this is a change"(SB), AX # C
0x0007 00007 (func_string.go:5) MOVQ AX, "".s+8(SP) # C
0x000c 00012 (func_string.go:5) MOVQ $16, "".s+16(SP) # C
0x0015 00021 (func_string.go:6) RET
"".main STEXT size=85 args=0x0 locals=0x28
0x0000 00000 (func_string.go:8) MOVQ (TLS), CX
0x0009 00009 (func_string.go:8) CMPQ SP, 16(CX)
0x000d 00013 (func_string.go:8) JLS 78
0x000f 00015 (func_string.go:8) SUBQ $40, SP
0x0013 00019 (func_string.go:8) MOVQ BP, 32(SP)
0x0018 00024 (func_string.go:8) LEAQ 32(SP), BP
0x001d 00029 (func_string.go:9) LEAQ go.string."hello world"(SB), AX # A
0x0024 00036 (func_string.go:9) MOVQ AX, "".s+16(SP) # A
0x0029 00041 (func_string.go:9) MOVQ $11, "".s+24(SP) # A
0x0032 00050 (func_string.go:10) MOVQ AX, (SP) # B
0x0036 00054 (func_string.go:10) MOVQ $11, 8(SP) # B
0x003f 00063 (func_string.go:10) CALL "".foo(SB)
0x0044 00068 (func_string.go:11) MOVQ 32(SP), BP
0x0049 00073 (func_string.go:11) ADDQ $40, SP
0x004d 00077 (func_string.go:11) RET
0x004e 00078 (func_string.go:11) NOP
0x004e 00078 (func_string.go:8) CALL runtime.morestack_noctxt(SB)
0x0053 00083 (func_string.go:8) JMP 0
go.string."this is a change" SRODATA dupok size=16
0x0000 74 68 69 73 20 69 73 20 61 20 63 68 61 6e 67 65 this is a change
go.string."hello world" SRODATA dupok size=11
0x0000 68 65 6c 6c 6f 20 77 6f 72 6c 64 hello world
在main
函数中,A处将hello world
字符串的地址保存在了SP&