美文网首页
Go字符串及字符串拼接的反汇编代码解读

Go字符串及字符串拼接的反汇编代码解读

作者: jagitch | 来源:发表于2024-05-25 16:27 被阅读0次

    源代码

    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)
    

    解析

    1. CMPQ SP, 0x10(R14) SP减去0x10(R14)的值
    2. JBE 0x45d176 如果上一步的结果小于等于,则跳转到0x45d176处
    3. PUSHQ BP 压入上一个函数的栈帧基址
    4. MOVQ SP, BP 将当前栈顶保存到BP寄存器
    5. SUBQ $0x38, SP SP减去0x38,分配0x38个字节的栈空间
    6. XORL AX, AX 清空AX
    7. LEAQ 0x11415(IP), BX 将"hello world"字符串常量的地址加载到BX
    8. MOVL $0xb, CX 将"hello world"字符串的长度加载到CX
    9. LEAQ 0x10aa7(IP), DI 将" go\n"字符串的地址加载到DI
    10. MOVL $0x4, SI 将" go\n"的长度加载到SI
    11. CALL runtime.concatstring2(SB) 调用concatstring2函数拼接字符串
    12. MOVQ AX, 0x30(SP) AX是concatstring2的第一个返回值,是拼接后的字符串的地址,将其保存到0x30(SP)
    13. MOVQ BX, 0x28(SP) BX是第二个返回值,是拼接后的字符串的长度,保存到0x28(SP)
    14. CALL runtime.printlock(SB) 打印加锁
    15. MOVQ 0x30(SP), AX 将字符串的地址加载到AX
    16. MOVQ 0x28(SP), BX 将字符串的长度加载到BX
    17. CALL runtime.printstring(SB) 打印字符串
    18. CALL runtime.printunlock(SB) 解锁打印
    19. ADDQ $0x38, SP SP加上0x38,回收之前分配的栈空间
    20. POPQ BP 弹出上个函数的BP
    21. RET 返回
    22. CALL runtime.morestack_noctxt.abi0(SB) 增加栈空间
    23. JMP main.main(SB) 跳转到main包的main函数

    结论

    1. 字符串常量会保存到一块内存中,使用0x11415(IP)等方式可以找到它的地址

    2. 字符串拼接会调用runtime.concatstring2函数进行拼接

    推荐阅读

    1. 使用VS Code调试Go程序

    2. 使用树梅派搭建Golang、Python、NodeJs的开发服务器

    3. Go语言中局部变量的逃逸分析(从汇编的角度)

    相关文章

      网友评论

          本文标题:Go字符串及字符串拼接的反汇编代码解读

          本文链接:https://www.haomeiwen.com/subject/uhzhjctx.html