深入Go底層原理,重寫Redis中介軟體實戰
download: 百度網盤
什麼是plan9彙編
我們知道,CPU是隻認二進位制指令的,也就是一串的0101;人類無法記住這些二進位制碼,於是發明了組合語言。組合語言實際上是二進位制指令的文字形式,它與指令可以一一對應。
每一種CPU指令都是不一樣的,因此對應的組合語言也就不一樣。人類寫完組合語言後,把它轉換成二進位制碼,就可以被機器執行了。轉換的動作由編譯器完成。
Go語言的編譯器和彙編器都帶了一個-S引數,可以檢視生成的最終目的碼。通過對比目的碼和原始的Go語言或Go組合語言程式碼的差異可以加深對底層實現的理解。
Go組合語言實際上來源於plan9組合語言,而plan9組合語言最初來源於Go語言作者之一的Ken Thompson為plan9系統所寫的C語言編譯器輸出的彙編虛擬碼。這裡強烈推薦一下春暉大神的新書《Go語言高階程式設計》,即將上市,電子版的點選閱讀原文可以看到地址,書中有一整個章節講Go的組合語言,非常精彩!
理解Go的組合語言,哪怕只是一點點,都能對Go的執行機制有更深入的理解。比如我們以前講的defer,如果從Go原始碼編譯後的彙編程式碼來看,就能深刻地掌握它的底層原理。再比如,很多文章都會分析Go的函式引數傳遞都是值傳遞,如果把彙編程式碼秀出來,很容易就能得出結論。
彙編角度看函式呼叫及返回過程
假設我們有一個這樣年幼無知的例子,求兩個int的和,Go原始碼如下:
package main func main() { _ = add(3,5) } func add(a, b int) int { return a+b }
使用如下命令得到彙編程式碼:
go tool compile -S main.go
go tool compile
命令用於呼叫Go語言提供的底層命令工具,其中 -S
引數表示輸出彙編格式。
我們現在只關心add函式的彙編程式碼:
"".add STEXT nosplit size=19 args=0x18 locals=0x0 0x0000 00000 (main.go:7) TEXT "".add(SB), NOSPLIT, $0-24 0x0000 00000 (main.go:7) FUNCDATA $0, gclocals·54241e171da8af6ae173d69da0236748(SB) 0x0000 00000 (main.go:7) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (main.go:7) MOVQ "".b+16(SP), AX 0x0005 00005 (main.go:7) MOVQ "".a+8(SP), CX 0x000a 00010 (main.go:8) ADDQ CX, AX 0x000d 00013 (main.go:8) MOVQ AX, "".~r2+24(SP) 0x0012 00018 (main.go:8) RET
看不懂沒關係,我目前也不是全部都懂,但是對於理解一個函式呼叫的整體過程而言,足夠了。
0x0000 00000 (main.go:7) TEXT "".add(SB), NOSPLIT, $0-24
這一行表示定義 add
這個函式,最後的數字 $0-24
,其中 0
表示函式棧幀大小為0; 24
表示引數及返回值的大小:引數是2個int型變數,返回值是1個int型變數,共24位元組。
再看中間這四行:
0x0000 00000 (main.go:7) MOVQ "".b+16(SP), AX 0x0005 00005 (main.go:7) MOVQ "".a+8(SP), CX 0x000a 00010 (main.go:8) ADDQ CX, AX 0x000d 00013 (main.go:8) MOVQ AX, "".~r2+24(SP)
程式碼片段中的第1行,將第2個引數 b
搬到 AX
暫存器;第2行將1個引數 a
搬到暫存器 CX
;第3行將 a
和 b
相加,相加的結果搬到 AX
;最後一行,將結果搬到返回引數的地址,這段彙編程式碼非常簡單,來看一下函式呼叫者和被調者的棧幀圖:
(SP)指棧頂,b+16(SP)表示裸騎1的位置,從SP往上增加16個位元組,注意,前面的b僅表示一個標號;同樣,a+8(SP)表示實參0;~r2+24(SP)則表示返回值的位置。
有疑問加站長微信聯絡(非本文作者)

- 用位運算為你的程式加速
- 如何用Golang來手擼一個Blog - Milu.blog 開發總結
- 十七年運維老兵萬字長文講透優維低程式碼~
- 一文讀懂 Kubernetes的四種服務型別!
- 優維低程式碼:Use Resolves
- 優維低程式碼:Brick Life Cycle 構件生命週期
- 優維低程式碼:Best Practice
- 終於有人把雲原生架構講明白了
- 優維低程式碼:構件渲染子構件
- 優維低程式碼:構件 slot 說明
- Go語言愛好者週刊:第 149 期 — 正確率只有 22%
- 優維低程式碼:構件引數傳遞
- 教育業IT運維怎麼做?這家機構給出了他們的答案
- 優維低程式碼:構件基本說明
- GO專案實戰—開發上傳圖片功能
- 熬夜運維必看!監控觀測夠有效,你就可以睡好覺
- 用 Golang 跑「佇列任務」,也可以像 Laravel 一樣簡單
- GitHub 倉庫對比工具 —— github-compare
- 優維低程式碼:編排詳解選單配置
- GoBatch簡介 —— 一款基於go語言的企業級批處理框架(Golang下的SpringBatch)