Go Assembly 學習筆記

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

最近升級 go1.9,發現一個擷取 goroutine id 的依賴沒有支援1.9,於是手動寫了一個,順便學習一下 go assembly。希望你看完這篇文章後,對go彙編有一定的瞭解。

Go Assembly

首先安利一個擷取當前goroutine id 的library, gid,支援 go1.7 - go1.9, 可能是目前最小的庫了,使用也很簡單: id := gid.Get()

Go彙編文法類似 Plan 9,它不是對機器語言的直接表達,擁有半抽象的指令集。總體來說, machine-specific 操作一般就是它們的本意,其他概念例如 memory move, subroutine call, return 是抽象的表達。

常量

evaluation 優先順序和 C 不同,例如 3&1<<2 == 4, 解釋為 (3&1) << 2。
常量被認為是 unsigned 64-bit int, 因此 -2 不是負數,而是被作為 uint64 解讀。

符號

4個預定義的符號,表示 pseudo-registers, 偽寄存器(虛擬寄存器?)。

  • FP: frame pointer, 參數和本地變數
  • PC: program counter: 跳轉,分支
  • SB: static base pointer: 全域符號
  • SP: stack pointer: 棧頂

使用者定義的符號都是通過位移(offset)來表示的。

SB寄存器表示全域記憶體起點,foo(SB) 表示 符號foo作為記憶體位址使用。這種形式用於命名 全域函數,資料。<>限制符號只能在當前源檔案使用,類似 C 中的 static。foo+4(SB)表示foo 往後 4位元組的地址。

FP寄存器指向函數參數。0(FP)是第一個參數,8(FP)是第二個參數(64-bit machine). first_arg+0(FP)表示把第一個參數地址綁定到符號 first_arg, 這個與SB的含義不同。

SP寄存器表示棧指標,指向 top of local stack frame, 所以 offset 都是負數,範圍在 [ -framesize, 0 ), 例如 x-8(SP). 對於硬體寄存器名稱為SP的架構,x-8(SP) 表示虛擬棧指標寄存器, -8(SP) 表示硬體 SP 寄存器.

跳轉和分支是針對PC的offset,或者 label, 例如:

label:    MOVW $0, R1    JMP label

label 範圍是函數層級的,不同函數可以定義相同名稱的label。

指令

例如:

TEXT runtime·profileloop(SB),NOSPLIT,$8    MOVQ    $runtime·profileloop1(SB), CX    MOVQ    CX, 0(SP)    CALL    runtime·externalthreadhandler(SB)    RET

TEXT 指令定義符號 runtime·profileloop, RET 表示結尾,如果沒聲明,linker會添加 jump-to-self 指令。
$8 表示 frame size,一般後面需要加上參數大小。這裡因為有 NOSPLIT,可以不加。

全域資料符號用 DATA 聲明,方式為 DATA symbol+offset(SB)/width, value
GLOBL 定義資料為全域。例如:

DATA divtab<>+0x00(SB)/4, $0xf4f8fcffDATA divtab<>+0x04(SB)/4, $0xe6eaedf0...DATA divtab<>+0x3c(SB)/4, $0x81828384GLOBL divtab<>(SB), RODATA, $64GLOBL runtime·tlsoffset(SB), NOPTR, $4

定義並初始化了 divtab<>, 一個 唯讀 64位元組 表,每一項4位元組。定義了 runtime·tlsoffset, 4位元組空值,非指標。

指令有一個或兩個參數。如果有兩個,第一個是 bit mask, 可以為數字運算式。值的定義如下:

  • NOPROF = 1 ; (For TEXT items.) Don't profile the marked function. This flag is deprecated. 廢棄
  • DUPOK = 2 ; It is legal to have multiple instances of this symbol in a single binary. The linker will choose one of the duplicates to use. 此符號允許存在多個,連結器選擇其一使用。
  • NOSPLIT = 4 ; (For TEXT items.) Don't insert the preamble to check if the stack must be split. The frame for the routine, plus anything it calls, must fit in the spare space at the top of the stack segment. Used to protect routines such as the stack splitting code itself. 不插入代碼,不檢查是否需要 stack split. (疑問,高版本go使用連續棧,這個指令還有作用嗎?)
  • RODATA = 8 ; (For DATA and GLOBL items.) Put this data in a read-only section. 資料存入唯讀區
  • NOPTR = 16 ; (For DATA and GLOBL items.) This data contains no pointers and therefore does not need to be scanned by the garbage collector. 表示非指標,不需要 GC。
  • WRAPPER = 32 ; (For TEXT items.) This is a wrapper function and should not count as disabling recover.
  • NEEDCTXT = 64 ; (For TEXT items.) This function is a closure so it uses its incoming context register.

Example: Add

//main.gopackage mainimport "fmt"func add(x, y int64) int64func main() {    fmt.Println(add(2, 3))}
// add.sTEXT ·add(SB),$0-24    MOVQ x+0(FP), BX    MOVQ y+8(FP), BP    ADDQ BP, BX    MOVQ BX, ret+16(FP)    RET

定義一個函數的方式為: TEXT package_name·function_name(SB),$frame_size-arguments_size
例子中 package_name 是空,表示當前package。 之後是一個 middle point(U+00B7) 和 函數名稱。
frame_size 是 $0, 表示了需要 stack 的空間大小,這裡是0, 表示不需要stack,只使用 寄存器。函數的參數和傳回值的大小為 3 * 8 = 24 bytes。

MOVQ 表示移動一個 64bit 的值(Q 代表 quadword)。這裡是從 FP(frame pointer, 指向 函數參數的起始位置) 移動到 BXBP. 文法 symbol+offset(register) 中的 offset, 代表了從 register 為起點,移動 offset後的地址。這裡的 x, y 是在函數定義中的參數符號。

ADDQ 那一行指令 表示把兩個 64bit register的值相加,存到 BX。

最後的 MOVQ 把 BX 中的值,移動到 FP+16的位置, 這裡的 ret 符號是編譯器預設的傳回值符號。

Example: Hello

package mainimport _ "fmt"func hello()func main(){    hello()}
#include "textflag.h"DATA world<>+0(SB)/8, $"hello wo"DATA world<>+8(SB)/4, $"rld "GLOBL world<>+0(SB), RODATA, $12// 需要 stack空間 88位元組,沒有參數和傳回值TEXT ·hello(SB),$88-0    SUBQ    $88, SP    MOVQ    BP, 80(SP)    LEAQ    80(SP), BP    // 建立字元,存在 my_string    LEAQ    world<>+0(SB), AX     MOVQ    AX, my_string+48(SP)            MOVQ    $11, my_string+56(SP)    MOVQ    $0, autotmp_0+64(SP)    MOVQ    $0, autotmp_0+72(SP)    LEAQ    type·string(SB), AX    MOVQ    AX, (SP)    LEAQ    my_string+48(SP), AX            MOVQ    AX, 8(SP)    // 建立一個 interface    CALL    runtime·convT2E(SB)               MOVQ    24(SP), AX    MOVQ    16(SP), CX                        MOVQ    CX, autotmp_0+64(SP)            MOVQ    AX, autotmp_0+72(SP)    LEAQ    autotmp_0+64(SP), AX            MOVQ    AX, (SP)                          MOVQ    $1, 8(SP)                          MOVQ    $1, 16(SP)    // 調用 fmt.Println    CALL    fmt·Println(SB)    MOVQ 80(SP), BP    ADDQ $88, SP    RET

第一行的 #include 載入一些常量,這裡我們將用到 RODATA.

DATA 用於在記憶體中儲存字串,一次可以儲存 1,2,4或8 位元組。在符號後的<>作用是限制資料在當前檔案使用。

GLOBL 將資料設為全域,唯讀,相對位置12.

Example: gid

gid 庫中用到的函數

#include "go_asm.h"#include "go_tls.h"#include "textflag.h"// 傳回值 8 bytes, 符號為 getgTEXT ·getg(SB), NOSPLIT, $0-8    // get_tls 的宏為: #define    get_tls(r)    MOVQ TLS, r    // 等價於 MOVQ TLS, CX    // 從 TLS(Thread Local Storage) 起始移動 8 byte 值 到 CX 寄存器    get_tls(CX)    // g的宏為: g(r)    0(r)(TLS*1)    // 等價於 0(CX)(TLS*1), AX    // 查到意義為 indexed with offset, 這裡 offset=0, 索引是什麼意思不清楚    MOVQ    g(CX), AX    // 從AX起始移動 8 byte 值,到ret符號的位置    MOVQ    AX, ret+0(FP)    RET

Example: SwapInt32

一個原子交換 int32 的函數

package atomicimport (    "unsafe")func SwapInt32(addr *int32, new int32) (old int32)
#include "textflag.h"// 參數大小 = 8 + 4 + 4 , + 4 (預設的 ret符號?)TEXT ·SwapInt32(SB),NOSPLIT,$0-20    JMP    ·SwapUint32(SB)TEXT ·SwapUint32(SB),NOSPLIT,$0-20    // 第一個參數 移動 8 byte 到 BP    MOVQ    addr+0(FP), BP    // 第二個參數 移動 4 byte 到 AX    MOVL    new+8(FP), AX    // 原子操作, write-after-read, 把 (AX, offset=0) 與 (BP, offset=0) 交換 4 byte 資料    XCHGL    AX, 0(BP)    // 移動 AX 到 old 符號    MOVL    AX, old+16(FP)    RET
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.