Plan 9匯編
寄存器:
數據寄存器:R0-R7,地址寄存器:A0-A7,浮點寄存器:F0-F7。
偽棧寄存器:FP, SP, TOS。
FP是frame pointer,0(FP)是第一個參數,4(FP)是第二個。
SP是local stack pointer,保存自動變量。0(SP)是第一個。
TOS是top of stack寄存器,用來保存過程的參數,保存局部變量。
匯編器可以有一個變量名,比如p+0(FP),表示p是第一個參數,這個變量保存在符號表內,但是對程序運行沒有影響。
數據:
所有的外部引用都需通過偽寄存器: PC(virtual Program Counter)/SB(Static Base register)。
PC用來控制程序執行,SB用來引用全局變量。比如:
把全局數組的地址壓棧:MOVL $array(SB), TOS。
把全局數組的第二個元素壓棧:MOVL array+4(SB), TOS
local<>+4(SB)是本地變量,只在本文件可見。
定義流程:
TEXT sum(SB), $0
TEXT是一個偽指令,用來定義入口點。后面的參數是函數名,然后是棧大小,通常為0。
中間可以有一個指定loader的選項,設置為1暫停函數的profiling。
設置為2允許一個程序中有多個TEXT符號。
子流程把運算結果放到R0中。浮點的結果放在F0中。
子流程負責保存自己的寄存器,為caller saves模式。
Go語言匯編
Go語言的匯編基於Plan 9的匯編,但是有一些不同。最主要的一個區別是,Go語言的匯編指令不一定直接對應機器表示。有一些直接對應,有一些則不是。
編譯器產生的是一些中間碼,具體的機器指令是在匯編生成之后才定下來的(Linker的工作)。
FUNCDATA和PCDATA是編譯器產生的,用於保存一些給垃圾收集的信息。
Go語言的匯編和Plan 9的另一個不同是操作符的優先級。比如3&1<<2被解釋成(3&1)<<2。
符號:
Go語言有4個偽寄存器,實際是對內存位置的一個引用。
FP: 幀指針,保存參數和本地變量
PC:程序指針,負責跳轉和流程控制
SB: 靜態基指針,全局變量
SP:棧指針,棧頂
所有的符號全部攜程FP和SB的偏移的形式:
SB偽寄存器用來表示全局的變量或者函數,不如foo(SB)用來表示foo的地址。加<>表示符號本文件內可見。
FP是用來保存參數的。(0)FP是第一個參數(8)FP是第二個(如果是64位機器)。
SP指向本地棧頂,分別用x-8(SP), y-4(SP)表示變量。
直接的jmp或者call指令,只能指向text符號,不能是符號的偏移。
指令:
TEXT指令定義一個符號,后面緊跟函數體。
DATA指令定義一個section的內存,這段內存並不會被初始化。
DATA symbol+offset(SB)/width, value
GLOBAL指令定義一個符號是全局的
GLOBL divtab<>(SB), RODATA, $64 GLOBL runtime·tlsoffset(SB), NOPTR, $4
divtab是制度的64byte的表格,保存4個byte的整形。tlsoffset是,4byte的no pointers
指令修飾符:
DUPOK:允許一個二進制文件里有多個實例
NOSPLIT: FOR TEXT,routine或者routine的子函數,必須把棧的空間的頭填滿,用來保護棧分隔
RODATA:FOR DATA/GLOBL,把數據放在只讀段
NOPTR: FOR DATA/GLOBL,數據沒有指針,不需要被垃圾收集掃描
WRAPPER: FOR TEXT,wrapper function,不需要被以禁用recover計數
NEEDCTXT:FOR TEXT,閉包
Runtime協作:
NOPTR和RODATA的數據不需要被垃圾收集。比指針還要小的數據也被當做NOPTR。不要在go匯編里寫非只讀數據。
語法:
plan9函數調用協議中采用的是caller-save的模式,也就是由調用者負責保存寄存器。
TEXT !$Add(SB),$0 MOVQ x+0(FP), BX MOVQ y+8(FP), BP ADDQ BP, BX MOVQ BX, ret+16(FP) RET
a+8(FP)
變量名+偏移(寄存器)。FP其實就是BP(棧基址寄存器上移一個機器字長位置的內存地址)。
TEXT ·add(SB),NOSPLIT,$0
00B7分隔了包名和變量名。NOSPLIT表示不用寫入參數的大小,$0表示參數的大小,因為制定了NOSPLIT所以寫0
匯編文件的名字甚至變量名稱並不重要。
MOVQ $0, DX //put 0 into DX register. Q means quadword which is 8 bytes. L for 4 bytes. (src, destination) order
¥24-8表示24字節的幀,和8個字節的參數
Go Array有不是指向第一個元素的指針,而是代表整個數組。賦值或者傳遞的時候是有一個copy的。
Go slice有三個部分, 一個指針,一個長度,一個容量,指針8個字節,長度和容量4個字節
一個slice沒有固定的長度。slice不能指定長度。一個slice如果要增加capacity必須創建一個新的容量更大的slice,並copy內容過去。
Examples: