有多種方式可以獲得Go程序的彙編代碼, 儘管輸出的格式有些不同,但是都是方便閱讀的彙編代碼,可以幫助我們更好的瞭解程序的底層運行方式。
我們看下面一段代碼, 它是sync.Once的實現,去掉了不必要的註釋,複製出來用來研究的一段小代碼:
once.go
1type Once struct {
2 m sync.Mutex
3 done uint32
4}
5func (o *Once) Do(f func()) {
6 if atomic.LoadUint32(&o.done) == 1 {
7 return
8 }
9 o.m.Lock()
10 defer o.m.Unlock()
11 if o.done == 0 {
12 defer atomic.StoreUint32(&o.done, 1)
13 f()
14 }
15}
方法一: go tool compile
使用go tool compile -N -l -S once.go生成彙編代碼:
1"".(*Once).Do STEXT size=239 args=0x10 locals=0x28
2 0x0000 00000 (once.go:13) TEXT "".(*Once).Do(SB), $40-16
3 0x0000 00000 (once.go:13) MOVQ (TLS), CX
4 0x0009 00009 (once.go:13) CMPQ SP, 16(CX)
5 0x000d 00013 (once.go:13) JLS 229
6 0x0013 00019 (once.go:13) SUBQ $40, SP
7 0x0017 00023 (once.go:13) MOVQ BP, 32(SP)
8 0x001c 00028 (once.go:13) LEAQ 32(SP), BP
9 0x0021 00033 (once.go:13) FUNCDATA $0, gclocals·fdbf1f5761f6d17e8ae3f0aaecb6a3c5(SB)
10 0x0021 00033 (once.go:13) FUNCDATA $1, gclocals·7d2d5fca80364273fb07d5820a76fef4(SB)
11 0x0021 00033 (once.go:13) FUNCDATA $3, gclocals·96839595c383af6ae8227769d90a999e(SB)
12 0x0021 00033 (once.go:14) PCDATA $2, $1
13 0x0021 00033 (once.go:14) PCDATA $0, $0
14 0x0021 00033 (once.go:14) MOVQ "".o+48(SP), AX
15 0x0026 00038 (once.go:14) MOVL 8(AX), CX
16 0x0029 00041 (once.go:14) CMPL CX, $1
17 0x002c 00044 (once.go:14) JEQ 213
18 0x0032 00050 (once.go:18) PCDATA $2, $0
19 0x0032 00050 (once.go:18) MOVQ AX, (SP)
20 0x0036 00054 (once.go:18) CALL sync.(*Mutex).Lock(SB)
21 0x003b 00059 (once.go:19) PCDATA $2, $1
22 0x003b 00059 (once.go:19) MOVQ "".o+48(SP), AX
23 ……
方法二: go tool objdump
首先先編譯程序: go tool compile -N -l once.go,
使用go tool objdump once.o反彙編出代碼 (或者使用go tool objdump -s Do once.o反彙編特定的函數:):
1TEXT %22%22.(*Once).Do(SB) gofile../Users/……/once.go
2 once.go:13 0x7cd 65488b0c2500000000 MOVQ GS:0, CX [5:9]R_TLS_LE
3 once.go:13 0x7d6 483b6110 CMPQ 0x10(CX), SP
4 once.go:13 0x7da 0f86d2000000 JBE 0x8b2
5 once.go:13 0x7e0 4883ec28 SUBQ $0x28, SP
6 once.go:13 0x7e4 48896c2420 MOVQ BP, 0x20(SP)
7 once.go:13 0x7e9 488d6c2420 LEAQ 0x20(SP), BP
8 once.go:14 0x7ee 488b442430 MOVQ 0x30(SP), AX
9 once.go:14 0x7f3 8b4808 MOVL 0x8(AX), CX
10 once.go:14 0x7f6 83f901 CMPL $0x1, CX
11 once.go:14 0x7f9 0f84a3000000 JE 0x8a2
12 once.go:18 0x7ff 48890424 MOVQ AX, 0(SP)
13 once.go:18 0x803 e800000000 CALL 0x808 [1:5]R_CALL:sync.(*Mutex).Lock
14 once.go:19 0x808 488b442430 MOVQ 0x30(SP), AX
15 once.go:19 0x80d 4889442410 MOVQ AX, 0x10(SP)
16 once.go:19 0x812 c7042408000000 MOVL $0x8, 0(SP)
17 ……
方法三: go build -gcflags -S
使用go build -gcflags -S once.go也可以得到彙編代碼:
1"".(*Once).Do STEXT size=239 args=0x10 locals=0x28
2 0x0000 00000 (/Users/……/once.go:13) TEXT "".(*Once).Do(SB), $40-16
3 0x0000 00000 (/Users/……/once.go:13) MOVQ (TLS), CX
4 0x0009 00009 (/Users/……/once.go:13) CMPQ SP, 16(CX)
5 0x000d 00013 (/Users/……/once.go:13) JLS 229
6 0x0013 00019 (/Users/……/once.go:13) SUBQ $40, SP
7 0x0017 00023 (/Users/……/once.go:13) MOVQ BP, 32(SP)
8 0x001c 00028 (/Users/……/once.go:13) LEAQ 32(SP), BP
9 0x0021 00033 (/Users/……/once.go:13) FUNCDATA $0, gclocals·fdbf1f5761f6d17e8ae3f0aaecb6a3c5(SB)
10 0x0021 00033 (/Users/……/once.go:13) FUNCDATA $1, gclocals·7d2d5fca80364273fb07d5820a76fef4(SB)
11 0x0021 00033 (/Users/……/once.go:13) FUNCDATA $3, gclocals·96839595c383af6ae8227769d90a999e(SB)
12 0x0021 00033 (/Users/……/once.go:14) PCDATA $2, $1
13 0x0021 00033 (/Users/……/once.go:14) PCDATA $0, $0
14 0x0021 00033 (/Users/……/once.go:14) MOVQ "".o+48(SP), AX
15 0x0026 00038 (/Users/……/once.go:14) MOVL 8(AX), CX
16 0x0029 00041 (/Users/……/once.go:14) CMPL CX, $1
17 0x002c 00044 (/Users/……/once.go:14) JEQ 213
go tool compile 和 go build -gcflags -S 生成的是過程中的彙編,和最終的機器碼的彙編可以通過go tool objdump生成。
原文發佈時間爲:2019-1-1
本文作者:Golang語言社區
本文來自雲棲社區合作伙伴“ Golang語言社區”,瞭解相關信息可以關注“Golangweb”微信公衆號