跳到內容

認識組合語言 - 暫存器

常規使用的暫存器
RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, R8, R9, R10, R11, R12, R12, R13, R14, R15
其中RSP始終指向stack頂部的位址,在C編譯風格的程式RBP指向區域變數頂部的位置
還有一個特殊的暫存器RIP始終指向下一條要執行的指令,也就是我們學過的程式計數器
RIP在使用者端不可寫(read only)

64 32 16 8 8
RAX, EAX, AX, AH, AL

AL是最右邊8位,AH是接著8位,AH和AL合起來是AX
在nasm語法中,取用暫存器大小直接依照上述寫法即可
後面的暫存器如下:

rsi, esi, si, sil
rdi, edi, di, dil
rsp, esp, sp, spl
r8, r8d, r8w, r8b

列舉了一些通用暫存器的常見用途

  • rax: 存放函數的返回值
  • rcx: 迴圈的疊代變數 (while i--)i
  • rdx: 當兩個暫存器合併使用成16位時,左邊8位的內容
  • rsi: 來源內容
  • rdi: 目的內容
  • rbp: 區域變數頂部
  • rsp: stack頂部 (規定)

呼叫函數時需要將參數內容放入對應的暫存器
linux使用的順序為:
rdi, rsi, rdx, rcx, r8, r9, rsp(堆疊)
windows使用的順序為:
rcx, rdx, r8, r9, rsp(堆疊)

rdi rsi rdx
f(arg1, arg2, arg3)

假設要呼叫一個函數f,參數需要先放入對應的地方,函數進入後會當作已經將參數放好了直接使用
超過的長度則全部放入堆疊中

用於平行處理的暫存器(可處理浮點與整數)

XMM0 ~ XMM15 128 bits
YMM0 ~ YMM15 256 bits
ZMM0 ~ ZMM31 512 bits

包含特定的狀態旗標,有些指令執行過程會使用並依照情況亮燈
比如常用的ZF,當ZF亮了表示值為0,像是加減法和cmp都會觸發
舉個例子:

while(n--) {}

我們只要一直執行dec遞減1,使用jz 當ZF觸發則跳轉到另一個地方
但不是所有指令出現0都會ZF,常用的xor就不會觸發,這部份請查找網路資料和Intel x86_64指令集文檔
還有CF(進位)、SF(符號)、OF(溢位)、DF(方向)等

CS、DS、SS、ES、FS、GS
現在只剩FS和GS在多線程使用到,平時不會出現

以下是補充說明:
記憶體位址可以用 [segment:offset] 來描述,segment 就是這幾個暫存器
比如bootloader以及早期的16 bits環境中,常用 [ds:si][es:di] 來表示記憶體位址
實際位址是 es × 16 + di,比如 es = 0x1000, di = 0x20,表示 0x10020 這個位址
當今x86_64使用的 fsgs 是一般加法 [fs:0x12]fs + 0x12