Go 語言 plan 9 彙編
本文將簡單介紹一下 go 語言的彙編。
主要的內容如下:
plan 9 是什麼?爲什麼學習 plan9?
plan9 的常見指令
go 程序如何轉換爲 plan9 ?
下面就開始簡單介紹一下。
plan 9 是什麼?爲什麼學習 plan9?
plan9, Go 一套自己的彙編。按照官方文檔的說法,其設計初衷是解決跨平臺的問題,但是沒有做好。並且它不同於傳統的彙編,也就是說要想學習 go 彙編,你需要重新學習一套語法。社區在爭論這個問題,有人說是因爲 go 的幾個大佬,原來是用 plan9 的。這個問題咱們這兒不討論。
那作爲普通人,我們學彙編幹啥呢?
裝逼!這是第一生產力!我一直有一個不成熟的想法,希望自己能夠像機器一樣看穿代碼的運行。有時想想,也挺可笑的。
除了裝逼,真的一點用處都沒有了嗎?
當然不是!!!
說下我能想到的幾個點:
-
確定一段代碼底層執行了什麼函數
-
查看基礎的數據結構的運行機制
-
查看內存的分配
-
查看 go 在函數頭和函數尾插入的相關的調度
...
難道這幾條還不夠嗎?
plan9 的常見指令
其實彙編跟 java, go 等語言 沒啥區別,無非也是變量、方法等。只是我們做應用層開發不常用而已。如果懂了基礎的語法,其實也就這樣。下面列幾個常用的指令,看不懂也沒事,多看幾遍就知道了,其實我也不是很熟,啥時候真用到,再回來看也行。
棧擴大、縮小
plan9 中棧操作並沒有使用 push,pop,而是採用 sub 跟 add SP。
SUBQ $0x18, SP // 對 SP 做減法,爲函數分配函數棧幀
ADDQ $0x18, SP // 對 SP 做加法,清除函數棧幀
數據 copy
MOVB $1, DI // 1 byte
MOVW $0x10, BX // 2 bytes
MOVD $1, DX // 4 bytes
MOVQ $-10, AX // 8 bytes
計算指令
ADDQ AX, BX // BX += AX
SUBQ AX, BX // BX -= AX
IMULQ AX, BX // BX *= AX
跳轉
// 無條件跳轉
JMP addr // 跳轉到地址,地址可爲代碼中的地址,不過實際上手寫不會出現這種東西
JMP label // 跳轉到標籤,可以跳轉到同一函數內的標籤位置
JMP 2(PC) // 以當前指令爲基礎,向前/後跳轉 x 行
JMP -2(PC) // 同上
// 有條件跳轉
JNZ target // 如果 zero flag 被 set 過,則跳轉
變量聲明
在彙編裏所謂的變量,一般是存儲在 .rodata 或者 .data 段中的只讀值。對應到應用層的話,就是已初始化過的全局的 const、var、static 變量 / 常量。
DATA symbol+offset(SB)/width, value
使用 DATA 結合 GLOBL 來定義一個變量
GLOBL 必須跟在 DATA 指令之後:
DATA age+0x00(SB)/4, $18 // forever 18
GLOBL age(SB), RODATA, $4
DATA pi+0(SB)/8, $3.1415926
GLOBL pi(SB), RODATA, $8
DATA birthYear+0(SB)/4, $1988
GLOBL birthYear(SB), RODATA, $4
函數聲明
先看一個定義:
// func add(a, b int) int
// => 該聲明定義在同一個 package 下的任意 .go 文件中
// => 只有函數頭,沒有實現
TEXT pkgname·add(SB), NOSPLIT, $0-8
MOVQ a+0(FP), AX
MOVQ a+8(FP), BX
ADDQ AX, BX
MOVQ BX, ret+16(FP)
RET
代碼存儲在 TEXT 段中。
pkgname 可以省略。
比如你的方法是 runtime·main,在編譯之後的程序裏的符號則是 runtime.main。
參數及返回值大小
|
TEXT pkgname·add(SB),NOSPLIT,$32-32
| | |
包名 函數名 棧幀大小(局部變量+可能需要的額外調用函數的參數空間的總大小,但不包括調用其它函數時的 ret address 的大小)
寄存器
有 4 個核心的僞寄存器,這 4 個寄存器是編譯器用來維護上下文、特殊標識等作用的:
FP(Frame pointer): arguments and locals
PC(Program counter): jumps and branches
SB(Static base pointer): global symbols
SP(Stack pointer): top of stack
還有很多其他的用法,就先不摘抄了,後面用到再去查吧。
go 程序如何轉換爲 plan9 ?
// 編譯
go build -gcflags="-S"
go tool compile -S hello.go
go tool compile -N -S hello.go // 禁止優化
// 反編譯
go tool objdump <binary>
總結與後記
本文簡單的講述了 plan9 是什麼?什麼用途?也羅列了幾個 plan9 常見的指令,增加自信。最後簡單的幾行指令,教你如何看某一段代碼的 plan9 指令。
如果時間允許,會結合前人的文章,針對 go 中常見的類型、api 操作、內存分配、channel 等進行彙編指令級的學習,給自己加油~
轉自:
jianshu.com/p/c4da2512117d
Go 開發大全
參與維護一個非常全面的 Go 開源技術資源庫。日常分享 Go, 雲原生、k8s、Docker 和微服務方面的技術文章和行業動態。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/D2avHczJMpi74wLQG5Ap8A