研究Go的內(nèi)部實(shí)現(xiàn),這里介紹一些基本的技巧。
Go語言的源代碼布局是有一些規(guī)律的。假定讀者在$GOROOT下:
- ./misc 一些工具
- ./src 源代碼
- ./src/cmd 命令工具,包括6c, 6l, 6g等等。最后打包成go命令。
- ./src/pkg 各個(gè)package的源代碼
- ./src/pkg/runtime Go的runtime包,本書分析的最主要的部分
- AUTHORS — 文件,官方 Go語言作者列表
|– CONTRIBUTORS — 文件,第三方貢獻(xiàn)者列表
|– LICENSE — 文件,Go語言發(fā)布授權(quán)協(xié)議
|– PATENTS — 文件,專利
|– README — 文件,README文件,大家懂的。提一下,經(jīng)常有人說:Go官網(wǎng)打不開啊,怎么辦?其實(shí),在README中說到了這個(gè)。該文件還提到,如果通過二進(jìn)制安裝,需要設(shè)置GOROOT環(huán)境變量;如果你將Go放在了/usr/local/go中,則可以不設(shè)置該環(huán)境變量(Windows下是C:\go)。當(dāng)然,建議不管什么時(shí)候都設(shè)置GOROOT。另外,確保$GOROOT/bin在PATH目錄中。
|– VERSION — 文件,當(dāng)前Go版本
|– api — 目錄,包含所有API列表,方便IDE使用
|– doc — 目錄,Go語言的各種文檔,官網(wǎng)上有的,這里基本會有,這也就是為什么說可以本地搭建”官網(wǎng)”。這里面有不少其他資源,比如gopher圖標(biāo)之類的。
|– favicon.ico — 文件,官網(wǎng)logo
|– include — 目錄,Go 基本工具依賴的庫的頭文件
|– lib — 目錄,文檔模板
|– misc — 目錄,其他的一些工具,相當(dāng)于大雜燴,大部分是各種編輯器的Go語言支持,還有cgo的例子等
|– robots.txt — 文件,搜索引擎robots文件
|– src — 目錄,Go語言源碼:基本工具(編譯器等)、標(biāo)準(zhǔn)庫
`– test — 目錄,包含很多測試程序(并非_test.go方式的單元測試,而是包含main包的測試),包括一些fixbug測試??梢酝ㄟ^這個(gè)學(xué)到一些特性的使用。
學(xué)習(xí)Go語言的內(nèi)部實(shí)現(xiàn),主要依靠對源代碼的分析,所以閱讀源代碼是很好的方式。linus談到如何學(xué)習(xí)Linux內(nèi)核時(shí)也說過"Read the F**ing Source code"。
通過gdb下斷點(diǎn),跟蹤程序的行為。調(diào)試跟代碼的方式是源代碼閱讀的一種輔助手段。
用戶代碼入口是在main.main,runtime庫中的函數(shù)可以通過runtime.XXX斷點(diǎn)捕獲。比如寫一個(gè)test.go:
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world!")
}
編譯,調(diào)試
go build test.go
gdb test
可以在main.main處下斷點(diǎn),單步執(zhí)行,你會發(fā)現(xiàn)進(jìn)入了一個(gè)runtime·convT2E的函數(shù)。這個(gè)就是由于fmt.Println接受的是一個(gè)interface,而傳入的是一個(gè)string,這里會做一個(gè)轉(zhuǎn)換。以這個(gè)為一個(gè)突破點(diǎn)去跟代碼,就可以研究Go語言中具體類型如何轉(zhuǎn)為interface抽象類型。
有時(shí)候分析會需要研究生成的匯編代碼,這里介紹生成匯編代碼的方法。
go tool 6g -S hello.go
-S參數(shù)表示打印出匯編代碼,更多參數(shù)可以通過-h參數(shù)查看。
go tool 6g -h
或者可以反匯編生成的可執(zhí)行文件:
go build test.go
go tool 6l -a test | less
本機(jī)是amd64的機(jī)器,如果是i386的機(jī)器,則命令是8g
需要注意的是用6g的-S生成的匯編代碼和6l -a生成的反匯編代碼是不太一樣的。前者是直接對源代碼進(jìn)行匯編,后者是對可執(zhí)行文件進(jìn)行反匯編。在6l進(jìn)行鏈接過程中,可能會在原匯編文件基礎(chǔ)上插入新的指令。所以6l反匯編出來的是最接近真實(shí)代碼的。
不過Go的匯編語法跟常用的有點(diǎn)不太一致,可能讀起來會不太習(xí)慣。還有另一種方式,就是在用gdb調(diào)試的過程中查看匯編。
gdb test
b main.main
disas
更多建議: