Intel IA-32 / Intel 64 指令架構 之 指令解碼

引言:
-------------------------------------
IA-32 到 Intel 64 架構中每一條匯編指令也由特定的格式給CPU的指令解碼器,或調試器的反匯編器(disassembler)解析,因而我們可以直觀地知道這些指令,第一層人類有能力看得懂的語言,其中每條指令由以下組件組成:


1. Instruction prefixes(指令前輟):
-------------------------------------

指令前輟分為4組:

Group 1 :
- Lock/repeat prefix :
F0h : LOCK prefix
F2h : REPNE/REPNZ
F3h : REP or REPE/REPZ , F3h prefix 更預設用在POPCNT,LZCNT,ADOX指令上

- Bound prefix :


Group 2:
- Segment override prefix:
2Eh - CS segment override
36h - SS segment override
3Eh - DS segment override
26h - ES segment override
64h - FS segment override
65h - GS segment override

- Branch hints(分支)
2Eh - 分支沒效,只有jcc指令使用
3Eh - 分支有效,只有jcc指令使用

Group 3 :
66h - Operand-size override


Group 4 :
67h - address-size override


LOCK prefix - 強制向cpu發送LOCK#信號,確保原子操作
Repeat prefix - 重覆執行指定指令 比如movs, cmps, scas, lods, stos, ins, outs
Branch hint prefix - 用於提醒CPU,最有可能的執行路徑(分支)
Operand/address-size override prefix - 用於尋址時,operand/內存的16bit / 32bit大小切換


2. Opcode (操作碼):
-------------------------------------

Opcode 亦即操作碼,即該指令實際要執行的動作;其大小最大為1~3 byte , 如果操作需要,另外會有3-bit opcode信息被加到ModR/M field

2-byte opcode: 一般由 0F 填充 + 任意byte組成 , prefix 分別可以是66H, F2H, F3H
如: CVTDQ2PD指令: F3 0F E6
3-byte opcode: 一般由 0F 填充 + 住意2byte組成 ,prefix 分別可以是66H,F2H ,F3H
如: XMM指令集中的PHADDW : 66 0F 38 01


ModR/M and SIB bytes:
它們只占2byte, 各占1byte, 很多指令一般需要使用操作數operand,處理器在解析指令其間需要進行解碼,才知道指令的"參數"

ModR/M - 1byte :
mod[7:6]: 與r/m位組成32種可能性,(指的是8個通用寄存器/24種尋址模式)
reg/opcode[5:3] : 指通用寄存器號碼 / 3bit外加opcode信息 (被寫入的寄存器)
R/M[2:0]: 可以指的是register 或與 mod位組成一個尋址模式 並定義出主要寄存器

即mod位 + REG位 + r/m位

ModR/M 取參數的基本組成原理,以32bit為例:

Reg映射表格:
####################################
           AL       CL           DL          BL         AH          BH        DH           CH
           AX      CX           DX         BX           SP          BP          SI             DI
        EAX    ECX         EDX       EBX        ESP       EBP        ESI          EDI
       MM0     MM1       MM2      MM3     MM4     MM5     MM6        MM7
      XMM0 XMM1    XMM2   XMM3  XMM4  XMM5  XMM6     XMM7
REG: 000b     001b       010b      011b       100b      101b       110b         111b
#####################################


32位尋址模式映射表格:
#####################################
mod: 00b     R/M

[EAX] :        000b
[ECX] :        001b
[EDX] :        010b
[EBX] :        011b
[--][--] :       100b
disp32 :       101b
[ESI]   :       110b
[EDI]  :       111b

mod: 01b            R/M

[EAX]+disp8 :     000b
[ECX]+disp8 :     001b
[EDX]+disp8 :     010b
[EBX]+disp8 :     011b
[--][--]+disp8 :     100b
[EBP]+disp8  :     101b
[ESI]+disp8   :     110b
[EDI]+disp8   :     111b

mod: 10b             R/M

[EAX]+disp32 :    000b
[ECX]+disp32 :    001b
[EDX]+disp32 :    010b
[EBX]+disp32 :    011b
[--][--]+disp32 :    100b
[EBP]+disp32 :     101b
[ESI]+disp32 :      110b
[EDI]+disp32 :      111b

mod: 11b                                        R/M
EAX/AX/AL/MM0/XMM0 :         000b
ECX/CX/CL/MM1/XMM1 :          001b
EDX/DX/DL/MM2/XMM2 :         010b
EBX/BX/BL/MM3/XMM3 :          011b
ESP/SP/AH/MM4/XMM4 :           100b
EBP/BP/CH/MM5/XMM5 :          101b
ESI/SI/DH/MM6/XMM6 :             110b
EDI/DI/BH/MM7/XMM7 :            111b
#####################################

如:mov eax, [EBP + displacement8 /r8] = 8b 45 08

這裡的45h 表示的其實是
mod = 1 ;
r/m = [ebp+disp8] = 101 ; 此模式表示緊隨其後的是SIB byte就是8
reg = 000 ; 是否選用eax/ax/al/xmm0/mm0 是基于opcode的原因 

mod + reg + r/m = 01000101 = 45h

因而產生出參數是 45 08

而操作數是: 8b 則採用rax/eax/ax 或 可能是r8寄存器(Intel 64架構), 這取決於cpu結構

因此IA-32架構下最終指令為 : 8b 45 08 | mov eax, [ebp+0x8]

假如我們想把參數[ebp+0x8h] 改為ebx, 即mov eax, ebx指令, 把尋址模式改變即可(即改變mod位 跟r/m 位)
mod = 11h
r/m = 011

11000011 = C3h

指令則變成: 8b C3 p.s. 由於沒有displacement 08h 自動去掉

3. SIB byte:
-------------------------------------
SIB byte = Scale + Index + base

ModR/M byte需要下一級的2級參數的解析,base-plus-index / scale-plus-index
Scale[7:6]: 指的是scale factor
Index[5:3]: 指的是寄存器索引
Base [2:0]: 指的是基礎寄存器索引

首先也來一張解碼表:

Base 映射表格:
#####################################
        EAX ECX EDX EBX ESP [*] ESI EDI
Base: 000    001   010   011 100  101 110 111
#####################################

scale 映射表格:
#####################################Scaled Index             | SS | Index |
EAX                00     000
ECX                         001
EDX                         010
EBX                         011
non                           100
EBP                         101
ESI                           110
EDI                          111

Scaled Index | SS | Index |
EAX*2            01    000
ECX*2                    001
EDX*2                    010
EBX*2                     011
non                          100
EBP*2                     101
ESI*2                      110
EDI*2                      111
#####################################

p.s. 避免篇幅太長 *4 / *8 只是改變了ss

SS + Index + Base : 如 : 00 001 001 則代表是 [ecx+ecx]

如: 8b 04 09     |    mov eax, dword ptr[ecx+ecx] ; 8Bh表示opcode操作碼及目的地寄存器為mov eax,
                                                                                 ; 04h則表示參數的尋址模式為[--][--],即來源為寄存器並需要非固定displacement
                                                                                 ;  09h則決定哪兩個寄存器成為參數如: ecx+ecx


SIB byte生效的前提是:
當ModR/M尋址模式是[--][--] / [--][--]+disp時: SIB byte則取替其功效
而[--][--]+disp模式就必須在SIB byte後,緊接著displacement

如: 8b 44 40 08      |        mov eax, dword ptr [eax+eax*2+8h]




4. IA-32e 
----------------------------------
IA-32e模式 即64位下,唯一不同是增加了REX prefix

對以下3項作出了64位的兼容

  • GPRs and SSE.
  • 64-bit operand大小.
  • extended 控制寄存器. 

----------------------------------

Comments

Popular posts from this blog

How does Nested-Virtualization works?

Understanding ACPI and Device Tree

Android Kernel Development - Kernel compilation and Hello World