x86組合語言 - 第二章 | x86架構及暫存器解釋
這邊是對x86的架構和暫存器做一些了解,也是希望自己透過看這文章可以多吸收試圖了解。哪天碰到或是看到,或許會突然靈光乍現,看得懂能了解。知識就是這樣不嫌多,不知道哪天會用到。
x86架構
x86架構有8個通用暫存器(GPR)、6段暫存器、1個標誌暫存器和指令指標。 64位元的x86有附加的暫存器。
通用暫存器(GPR) - 32位元命名約定
8個GPR是:
- 累加器暫存器(AX)。用在算術運算。
- 基址暫存器(BX)。作為一個指向資料的指標(在分段模式下,位於段暫存器DS)。
- 計數器暫存器(CX)。用於移位/迴圈指令和迴圈。
- 資料暫存器(DX)。用在算術運算和I/O操作。
- 堆疊指標暫存器(SP)。用於指向堆疊的頂部。
- 棧基址指標暫存器(BP)。用於指向堆疊的底部。
- 源變址暫存器(SI)。在流操作中用作源的一個指標。
- 目標索引暫存器(DI)。用作在流操作中指向目標的指標。
將它們以這樣的順序列出是有原因的:這個順序和堆疊操作中推入棧中的次序相同,我們以後會講到。
所有暫存器都可以在16位元和32位元模式下被存取。在16位元模式下,通過上面的列表中兩個字母的縮寫來確定該暫存器。在32位元模式下,這兩個字母的縮寫名字前有「E」(extended,延伸)。例如,EAX
是累加器暫存器作為一個32位元的值。
類似地,在64位元的版本,「E」被替換為「R」,所以在64位元版本EAX
被稱為RAX
。
指標暫存器
區段暫存器
- 在真實模式或虛擬86模式時,『區段暫存器』用來擴展定址的範圍由 64 KByte 到 1 MByte 。
- 在保護模式時,『區段暫存器』將變成『選擇子暫存器』,用為對於程式與記憶體存取權限的控管的索引。
大多現代作業系統(如FreeBSD、Linux或Windows)的大多應用程式使用將幾乎所有段暫存器都指向同一位置(並使用頁面),從而便捷地停用這些暫存器。
EFLAGS暫存器
EFLAGS暫存器,在台灣也稱為「旗標暫存器」,是用一系列表示布林值的位來儲存操作的結果和處理器狀態的32位元暫存器。
這些位的名稱是:
- AF:輔助進位旗標
- CF:進位旗標
- OF:溢位旗標
- SF:符號(負號)旗標
- PF:奇偶旗標
- ZF:零值旗標
- DF:方向旗標
- IF:中斷旗標
- TF:單步旗標
指令指標
如果沒有建立過分支,EIP暫存器包含下一條將要執行的指令的位址。
EIP只能在一個call
指令後從堆疊讀出。
記憶體中字的儲存
x86架構是小端序的,即多位元組數值的最低位位元組首先寫入。(這隻針對位元組的排序,不對於位。)
所以x86上的32位元數值B3B2B1B016在記憶體中會表示為:
小端序表示法:
1 | B0 B1 B2 B3 |
例如,32位元的雙字0x1BA583D4 (0x表示十六進位)在記憶體中寫為:
1 | D4 83 A5 1B |
執行記憶體轉儲時會把其視為 0xD4 0x83 0xA5 0x1B
二進位二補數表示
二進位二補數是以二進位表示負整數的標準方式。符號是由對所有的位取反並加一來改變的。
二進位二補數 範例:(0001表示十進位的 1,1111表示十進位的-1)
說明 | 值 |
---|---|
開始 | 0001 |
取反 | 1110 |
加一 | 1111 |
尋址方式
尋址方式給出了運算元給出的方式。
暫存器尋址
(運算元位址R所在位址欄位)
1 | mov ax, bx ; // 將寄存器bx的內容移動到ax |
Immediate
(實際位址所在欄位)
1 | mov ax, 1 ; // 將值1移動到寄存器ax |
或
1 | mov ax, 010Ch ; // 將0x010C的值移入寄存器ax |
直接記憶體尋址
(運算元位址所在位址欄位)
1 | .data |
直接偏移尋址
(通過算數改變位址)
1 | byte_tbl db 12,15,16,22,..... ; Table of bytes |
暫存器間接尋址
(field points to a register that contains the operand address)
1 | mov ax,[di] |
基址
1 | mov ax,[bx + di] |
例如,如果我們是在討論一個陣列,BX包含陣列的起始位址和DI包含陣列的索引。
基址變址:
1 | mov ax,[bx + di + 10] |
棧
棧是一個後進先出(LIFO)的資料結構,資料被壓到棧頂並會以逆序出棧。
1 | mov ax, 006Ah |
你將AX中的數值壓入棧頂, 它現在的數值為$006A。
1 | push bx |
你對BX中的數值做相同的操作,現在棧中有$006A和$F79A。
1 | push cx |
如今棧中有$006A、$F79A和$1124。
1 | call do_stuff |
做一些事情。 該函數不會被強制保存它使用的寄存器,因此我們保存它們。
1 | pop cx |
取出最後一個壓入棧中的元素到CX,即$1124;現在棧中有$006A和$F79A.
1 | pop bx |
取出最後一個壓入棧中的元素到BX,即$F79A;現在棧中只有$006A。
1 | pop ax |
取出最後一個壓入棧中的元素到AX,即$006A;現在棧是空的。
棧通常用來向函式或過程傳遞參數,並用來記錄call指令使用時的控制流。棧的另一個常見的用途是臨時儲存暫存器。
CPU的工作模式
真實模式 (Real mode)
參照: 真實模式 (維基百科)
特性:
記憶體定址限制: 1 MByte (每一個記憶體區段限定 64 Kbyte, 使用區段暫存器擴展可存取的記憶體範圍到 1 MByte)
暫存器與資料操作寬度: 16 bits 與 8 bits
保護模式 (Protected Mode)
參照: 保護模式 (維基百科)
16位元保護模式 (16-bit protected mode)
特性:
記憶體定址限制: 16 MByte
暫存器與資料操作寬度: 16 bits 與 8 bits
32位元保護模式 (32-bit protected mode)
特性:
記憶體定址限制: 4 GByte
暫存器與資料操作寬度: 32 bits 與 16 bits 與 8 bits
註:以上參考了
X86組合語言/X86架構及暫存器解釋