源代碼
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
運(yùn)行
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壓入上一個(gè)函數(shù)的棧幀基址MOVQ SP, BP將當(dāng)前棧頂保存到BP寄存器SUBQ $0x38, SPSP減去0x38,分配0x38個(gè)字節(jié)的??臻gXORL AX, AX清空AXLEAQ 0x11415(IP), BX將"hello world"字符串常量的地址加載到BXMOVL $0xb, CX將"hello world"字符串的長(zhǎng)度加載到CXLEAQ 0x10aa7(IP), DI將" go\n"字符串的地址加載到DIMOVL $0x4, SI將" go\n"的長(zhǎng)度加載到SICALL runtime.concatstring2(SB)調(diào)用concatstring2函數(shù)拼接字符串MOVQ AX, 0x30(SP)AX是concatstring2的第一個(gè)返回值,是拼接后的字符串的地址,將其保存到0x30(SP)MOVQ BX, 0x28(SP)BX是第二個(gè)返回值,是拼接后的字符串的長(zhǎng)度,保存到0x28(SP)CALL runtime.printlock(SB)打印加鎖MOVQ 0x30(SP), AX將字符串的地址加載到AXMOVQ 0x28(SP), BX將字符串的長(zhǎng)度加載到BXCALL runtime.printstring(SB)打印字符串CALL runtime.printunlock(SB)解鎖打印ADDQ $0x38, SPSP加上0x38,回收之前分配的??臻gPOPQ BP彈出上個(gè)函數(shù)的BPRET返回CALL runtime.morestack_noctxt.abi0(SB)增加棧空間JMP main.main(SB)跳轉(zhuǎn)到main包的main函數(shù)
結(jié)論
字符串常量會(huì)保存到一塊內(nèi)存中,使用0x11415(IP)等方式可以找到它的地址
字符串拼接會(huì)調(diào)用runtime.concatstring2函數(shù)進(jìn)行拼接