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

本文概述

有几种获取Go程序的汇编代码的方法。尽管它们的输出格式可能有所不同, 但是它们都是汇编代码, 易于阅读, 可以帮助我们更好地理解程序的基本操作模式。

让我们看一下下面的代码, 这是sync.Once的实现。在这里, 我删除了不必要的注释, 只复制了一小部分。


type Once struct {
	m    sync.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:13		0x7cd			65488b0c2500000000	MOVQ GS:0, CX			[5:9]R_TLS_LE
  once.go:13		0x7d6			483b6110		CMPQ 0x10(CX), SP
  once.go:13		0x7da			0f86d2000000		JBE 0x8b2
  once.go:13		0x7e0			4883ec28		SUBQ $0x28, SP
  once.go:13		0x7e4			48896c2420		MOVQ BP, 0x20(SP)
  once.go:13		0x7e9			488d6c2420		LEAQ 0x20(SP), BP
  once.go:14		0x7ee			488b442430		MOVQ 0x30(SP), AX
  once.go:14		0x7f3			8b4808			MOVL 0x8(AX), CX
  once.go:14		0x7f6			83f901			CMPL $0x1, CX
  once.go:14		0x7f9			0f84a3000000		JE 0x8a2
  once.go:18		0x7ff			48890424		MOVQ AX, 0(SP)
  once.go:18		0x803			e800000000		CALL 0x808			[1:5]R_CALL:sync.(*Mutex).Lock
  once.go:19		0x808			488b442430		MOVQ 0x30(SP), AX
  once.go:19		0x80d			4889442410		MOVQ AX, 0x10(SP)
  once.go:19		0x812			c7042408000000		MOVL $0x8, 0(SP)
  ……

方法3:go build -gcflags -S

你还可以使用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用于生成最终机器代码的汇编代码。

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?