Go字符串及字符串拼接的反匯編代碼解讀

源代碼

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)

解析

  1. CMPQ SP, 0x10(R14) SP減去0x10(R14)的值
  2. JBE 0x45d176 如果上一步的結(jié)果小于等于,則跳轉(zhuǎn)到0x45d176處
  3. PUSHQ BP 壓入上一個(gè)函數(shù)的棧幀基址
  4. MOVQ SP, BP 將當(dāng)前棧頂保存到BP寄存器
  5. SUBQ $0x38, SP SP減去0x38,分配0x38個(gè)字節(jié)的??臻g
  6. XORL AX, AX 清空AX
  7. LEAQ 0x11415(IP), BX 將"hello world"字符串常量的地址加載到BX
  8. MOVL $0xb, CX 將"hello world"字符串的長(zhǎng)度加載到CX
  9. LEAQ 0x10aa7(IP), DI 將" go\n"字符串的地址加載到DI
  10. MOVL $0x4, SI 將" go\n"的長(zhǎng)度加載到SI
  11. CALL runtime.concatstring2(SB) 調(diào)用concatstring2函數(shù)拼接字符串
  12. MOVQ AX, 0x30(SP) AX是concatstring2的第一個(gè)返回值,是拼接后的字符串的地址,將其保存到0x30(SP)
  13. MOVQ BX, 0x28(SP) BX是第二個(gè)返回值,是拼接后的字符串的長(zhǎng)度,保存到0x28(SP)
  14. CALL runtime.printlock(SB) 打印加鎖
  15. MOVQ 0x30(SP), AX 將字符串的地址加載到AX
  16. MOVQ 0x28(SP), BX 將字符串的長(zhǎng)度加載到BX
  17. CALL runtime.printstring(SB) 打印字符串
  18. CALL runtime.printunlock(SB) 解鎖打印
  19. ADDQ $0x38, SP SP加上0x38,回收之前分配的??臻g
  20. POPQ BP 彈出上個(gè)函數(shù)的BP
  21. RET 返回
  22. CALL runtime.morestack_noctxt.abi0(SB) 增加棧空間
  23. JMP main.main(SB) 跳轉(zhuǎn)到main包的main函數(shù)

結(jié)論

  1. 字符串常量會(huì)保存到一塊內(nèi)存中,使用0x11415(IP)等方式可以找到它的地址

  2. 字符串拼接會(huì)調(diào)用runtime.concatstring2函數(shù)進(jìn)行拼接

推薦閱讀

1. 使用VS Code調(diào)試Go程序

2. 使用樹梅派搭建Golang、Python、NodeJs的開發(fā)服務(wù)器

3. Go語(yǔ)言中局部變量的逃逸分析(從匯編的角度)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容