获取Go程序汇编代码的3种方法

本文概述

  • 方法1:go tool编译
  • 方法2:go tool objdump
  • 方法3:go build -gcflags -S
有几种获取Go程序的汇编代码的方法。尽管它们的输出格式可能有所不同, 但是它们都是汇编代码, 易于阅读, 可以帮助我们更好地理解程序的基本操作模式。
让我们看一下下面的代码, 这是sync.Once的实现。在这里, 我删除了不必要的注释, 只复制了一小部分。
type Once struct { msync.Mutex done uint32 } func (o *Once) Do(f func()) { if atomic.LoadUint32(& o.done) == 1 { return } o.m.Lock() defer o.m.Unlock() if o.done == 0 { defer atomic.StoreUint32(& o.done, 1) f() } }

方法1:go tool编译使用go tool compile -N -l -S Once.go生成汇编代码。
"".(*Once).Do STEXT size=239 args=0x10 locals=0x28 0x0000 00000 (once.go:13) TEXT "".(*Once).Do(SB), $40-16 0x0000 00000 (once.go:13) MOVQ (TLS), CX 0x0009 00009 (once.go:13) CMPQ SP, 16(CX) 0x000d 00013 (once.go:13) JLS 229 0x0013 00019 (once.go:13) SUBQ $40, SP 0x0017 00023 (once.go:13) MOVQ BP, 32(SP) 0x001c 00028 (once.go:13) LEAQ 32(SP), BP 0x0021 00033 (once.go:13) FUNCDATA $0, gclocals·fdbf1f5761f6d17e8ae3f0aaecb6a3c5(SB) 0x0021 00033 (once.go:13) FUNCDATA $1, gclocals·7d2d5fca80364273fb07d5820a76fef4(SB) 0x0021 00033 (once.go:13) FUNCDATA $3, gclocals·96839595c383af6ae8227769d90a999e(SB) 0x0021 00033 (once.go:14) PCDATA $2, $1 0x0021 00033 (once.go:14) PCDATA $0, $0 0x0021 00033 (once.go:14) MOVQ "".o+48(SP), AX 0x0026 00038 (once.go:14) MOVL 8(AX), CX 0x0029 00041 (once.go:14) CMPL CX, $1 0x002c 00044 (once.go:14) JEQ 213 0x0032 00050 (once.go:18) PCDATA $2, $0 0x0032 00050 (once.go:18) MOVQ AX, (SP) 0x0036 00054 (once.go:18) CALL sync.(*Mutex).Lock(SB) 0x003b 00059 (once.go:19) PCDATA $2, $1 0x003b 00059 (once.go:19) MOVQ "".o+48(SP), AX ……

方法2:go tool objdump首先编译程序:
go tool compile -N -l once.go

使用go工具objdump Once.o来反汇编代码(或使用go工具objdump -s来执行一次o.o来反汇编特定的函数):
TEXT %22%22.(*Once).Do(SB) gofile../Users/……/once.go once.go:130x7cd65488b0c2500000000 MOVQ GS:0, CX[5:9]R_TLS_LE once.go:130x7d6483b6110CMPQ 0x10(CX), SP once.go:130x7da0f86d2000000JBE 0x8b2 once.go:130x7e04883ec28SUBQ $0x28, SP once.go:130x7e448896c2420MOVQ BP, 0x20(SP) once.go:130x7e9488d6c2420LEAQ 0x20(SP), BP once.go:140x7ee488b442430MOVQ 0x30(SP), AX once.go:140x7f38b4808MOVL 0x8(AX), CX once.go:140x7f683f901CMPL $0x1, CX once.go:140x7f90f84a3000000JE 0x8a2 once.go:180x7ff48890424MOVQ AX, 0(SP) once.go:180x803e800000000CALL 0x808[1:5]R_CALL:sync.(*Mutex).Lock once.go:190x808488b442430MOVQ 0x30(SP), AX once.go:190x80d4889442410MOVQ AX, 0x10(SP) once.go:190x812c7042408000000MOVL $0x8, 0(SP) ……

方法3:go build -gcflags -S【获取Go程序汇编代码的3种方法】你还可以使用go build -gcflags -S Once.go获取汇编代码:
"".(*Once).Do STEXT size=239 args=0x10 locals=0x28 0x0000 00000 (/Users/……/once.go:13) TEXT "".(*Once).Do(SB), $40-16 0x0000 00000 (/Users/……/once.go:13) MOVQ (TLS), CX 0x0009 00009 (/Users/……/once.go:13) CMPQ SP, 16(CX) 0x000d 00013 (/Users/……/once.go:13) JLS 229 0x0013 00019 (/Users/……/once.go:13) SUBQ $40, SP 0x0017 00023 (/Users/……/once.go:13) MOVQ BP, 32(SP) 0x001c 00028 (/Users/……/once.go:13) LEAQ 32(SP), BP 0x0021 00033 (/Users/……/once.go:13) FUNCDATA $0, gclocals·fdbf1f5761f6d17e8ae3f0aaecb6a3c5(SB) 0x0021 00033 (/Users/……/once.go:13) FUNCDATA $1, gclocals·7d2d5fca80364273fb07d5820a76fef4(SB) 0x0021 00033 (/Users/……/once.go:13) FUNCDATA $3, gclocals·96839595c383af6ae8227769d90a999e(SB) 0x0021 00033 (/Users/……/once.go:14) PCDATA $2, $1 0x0021 00033 (/Users/……/once.go:14) PCDATA $0, $0 0x0021 00033 (/Users/……/once.go:14) MOVQ "".o+48(SP), AX 0x0026 00038 (/Users/……/once.go:14) MOVL 8(AX), CX 0x0029 00041 (/Users/……/once.go:14) CMPL CX, $1 0x002c 00044 (/Users/……/once.go:14) JEQ 213

go工具编译和go build -gcflags -S用于生成正在处理的汇编代码, 而go工具objdump用于生成最终机器代码的汇编代码。

    推荐阅读