源代碼
package main
func main() {
s := "hello world"
s += " go\n"
print(s)
}
Go版本
jagitch@34c4dd4d4a3e:str-demo$ go version
go version go1.22.2 linux/amd64
運行
jagitch@34c4dd4d4a3e:str-demo$ go run main.go
hello world go
編譯
jagitch@34c4dd4d4a3e:str-demo$ go build main.go
反匯編
jagitch@34c4dd4d4a3e:str-demo$ go tool objdump -S -s '^main.main' main
TEXT main.main(SB) /home/coder/workspace/own/jagitch-code/gitee/go-study/go-asm/str-demo/main.go
func main() {
0x45d120 493b6610 CMPQ SP, 0x10(R14)
0x45d124 7650 JBE 0x45d176
0x45d126 55 PUSHQ BP
0x45d127 4889e5 MOVQ SP, BP
0x45d12a 4883ec38 SUBQ $0x38, SP
s += " go\n"
0x45d12e 31c0 XORL AX, AX
0x45d130 488d1d15140100 LEAQ 0x11415(IP), BX
0x45d137 b90b000000 MOVL $0xb, CX
0x45d13c 488d3da70a0100 LEAQ 0x10aa7(IP), DI
0x45d143 be04000000 MOVL $0x4, SI
0x45d148 e813c7feff CALL runtime.concatstring2(SB)
0x45d14d 4889442430 MOVQ AX, 0x30(SP)
0x45d152 48895c2428 MOVQ BX, 0x28(SP)
print(s)
0x45d157 e8e436fdff CALL runtime.printlock(SB)
0x45d15c 488b442430 MOVQ 0x30(SP), AX
0x45d161 488b5c2428 MOVQ 0x28(SP), BX
0x45d166 e8553ffdff CALL runtime.printstring(SB)
0x45d16b e83037fdff CALL runtime.printunlock(SB)
}
0x45d170 4883c438 ADDQ $0x38, SP
0x45d174 5d POPQ BP
0x45d175 c3 RET
func main() {
0x45d176 e885cdffff CALL runtime.morestack_noctxt.abi0(SB)
0x45d17b eba3 JMP main.main(SB)
解析
CMPQ SP, 0x10(R14)
SP減去0x10(R14)
的值JBE 0x45d176
如果上一步的結(jié)果小于等于,則跳轉(zhuǎn)到0x45d176處PUSHQ BP
壓入上一個函數(shù)的棧幀基址MOVQ SP, BP
將當(dāng)前棧頂保存到BP寄存器SUBQ $0x38, SP
SP減去0x38褐奴,分配0x38個字節(jié)的棸唇牛空間XORL AX, AX
清空AXLEAQ 0x11415(IP), BX
將"hello world"字符串常量的地址加載到BXMOVL $0xb, CX
將"hello world"字符串的長度加載到CXLEAQ 0x10aa7(IP), DI
將" go\n"字符串的地址加載到DIMOVL $0x4, SI
將" go\n"的長度加載到SICALL runtime.concatstring2(SB)
調(diào)用concatstring2函數(shù)拼接字符串MOVQ AX, 0x30(SP)
AX是concatstring2的第一個返回值,是拼接后的字符串的地址敦冬,將其保存到0x30(SP)MOVQ BX, 0x28(SP)
BX是第二個返回值辅搬,是拼接后的字符串的長度,保存到0x28(SP)CALL runtime.printlock(SB)
打印加鎖MOVQ 0x30(SP), AX
將字符串的地址加載到AXMOVQ 0x28(SP), BX
將字符串的長度加載到BXCALL runtime.printstring(SB)
打印字符串CALL runtime.printunlock(SB)
解鎖打印ADDQ $0x38, SP
SP加上0x38脖旱,回收之前分配的椏八欤空間POPQ BP
彈出上個函數(shù)的BPRET
返回CALL runtime.morestack_noctxt.abi0(SB)
增加棧空間JMP main.main(SB)
跳轉(zhuǎn)到main包的main函數(shù)
結(jié)論
字符串常量會保存到一塊內(nèi)存中萌庆,使用0x11415(IP)等方式可以找到它的地址
字符串拼接會調(diào)用runtime.concatstring2函數(shù)進行拼接