Go 語言 plan 9 彙編

本文將簡單介紹一下 go 語言的彙編。
主要的內容如下:

  • plan 9 是什麼?爲什麼學習 plan9?

  • plan9 的常見指令

  • go 程序如何轉換爲 plan9 ?
    下面就開始簡單介紹一下。

plan 9 是什麼?爲什麼學習 plan9?

plan9, Go 一套自己的彙編。按照官方文檔的說法,其設計初衷是解決跨平臺的問題,但是沒有做好。並且它不同於傳統的彙編,也就是說要想學習 go 彙編,你需要重新學習一套語法。社區在爭論這個問題,有人說是因爲 go 的幾個大佬,原來是用 plan9 的。這個問題咱們這兒不討論。
那作爲普通人,我們學彙編幹啥呢?
裝逼!這是第一生產力!我一直有一個不成熟的想法,希望自己能夠像機器一樣看穿代碼的運行。有時想想,也挺可笑的。
除了裝逼,真的一點用處都沒有了嗎?
當然不是!!!
說下我能想到的幾個點:

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