Golang原始碼探索(一) 編譯和除錯原始碼
原文來自部落格園 作者: q303248153
GO可以說是近幾年最熱門的新興語言之一了, 一般人看到 分散式 和 大資料 就會想到GO,
這個系列的文章會通過研究golang的原始碼來分析內部的實現原理,
和CoreCLR不同的是, golang的原始碼已經被很多人研究過了, 我將會著重研究他們未提到過的部分.
另一點和CoreCLR不同的是, golang的原始碼 非常易懂 , 註釋也 非常的豐富 ,
很明顯Google的工程師在寫程式碼的時候有考慮其他人會去看這份程式碼.
儘管程式碼非常易懂, 研究它們還是需要實際執行和除錯才能得到更好的理解,
這個系列分析的golang原始碼是Google官方的實現的1.9.2版本, 不適用於其他版本和gccgo等其他實現,
執行環境是Ubuntu 16.04 LTS 64bit.
編譯golang原始碼
go的原始碼是用go寫的, 編譯也需要一個可執行的go.
首先我們從官網下載原始碼和二進位制檔案.
注意兩個壓縮包解壓出來資料夾名稱都是go, 我們解壓到以下目錄:
原始碼: ~/git_go/go_src 二進位制: ~/git_go/go_bin
image
編譯go之前需要設定環境變數,
GOROOT_BOOTSTRAP
是go二進位制資料夾的所在目錄,
GO_GCFLAGS
是編譯go時使用的引數.
export GOROOT_BOOTSTRAP=~/git_go/go_bin export GO_GCFLAGS="-N -l"
這裡的 -N
引數代表禁止優化, -l
引數代表禁止內聯, go在編譯目標程式的時候會嵌入執行時(runtime)的二進位制,
禁止優化和內聯可以讓執行時(runtime)中的函式變得更容易除錯.
都準備好以後就可以進入go的原始碼資料夾執行 all.bash
編譯了:
image
編譯的結果在 ~/git_go/go_src/bin
下:
image
除錯golang原始碼
之前CoreCLR的系列中我使用了lldb, 在這個系列中我繼續沿用這個偵錯程式.
這個系列中使用的是lldb 4.0.
以以下原始碼(hello.go)為例:
package main import ( "fmt" "time" ) func printNumber(from, to int, c chan int) { for x := from; x <= to; x++ { fmt.Printf("%d\n", x) time.Sleep(1 * time.Millisecond) } c <- 0 } func main() { c := make(chan int, 3) go printNumber(1, 3, c) go printNumber(4, 6, c) _, _ = <- c, <- c }
編譯原始碼使用以下命令, 這裡的 -l
引數的意思和上面一樣, 如果有需要還可以加 -N
引數:
~/git_go/go_src/bin/go build -gcflags "-l" hello.go
編譯後使用lldb執行:
lldb ./hello
image
go裡面的函式符號名稱的命名規則是 包名稱.函式名稱
, 例如主函式的符號名稱是 main.main
, 執行時中的 newobject
的符號名稱是 runtime.newobject
.
首先給主函式下一個斷點然後執行:
image
可以看到成功的進入了主函式, 並且有原始碼提示.
接下來給按檔名和行數來下斷點:
image
然後檢視函式的彙編程式碼:
image
關於lldb的命令可以檢視 這篇文件 .
在我使用的環境中lldb可以正常的下斷點, 步進和步過go程式碼或者彙編指令,
但 列印變數輸出的值有可能是錯的 , 即使不開啟優化.
雖然列印變數這個功能不好用, 我們仍然可以直接讓go輸出我們想要的值,
例如修改 runtime/malloc.go
輸出當前環境下arena|spans|bitmap區的大小:
image
修改後進入 src
並執行 ./make.bash
, 然後重新編譯目標程式, 執行:
image
可以看到當前環境下arena是512G, spans是512M, bitmap是16G.
這個方法雖然比較笨, 但是可以在任何情況下輸出我們想要的值.
此外, go執行時(runtime)的原始碼會包括在目標檔案中,
例如你對 runtime.newobject
下斷點可以對go自身的原始碼進行除錯.
參考連結
https://golang.org/doc/install/source
http://lldb.llvm.org/tutorial.html
http://legendtkl.com/archives接下來我將分析golang的任務排程機制和三色GC的具體實現, 敬請期待.