5. OpCode:ModRM - Part I

  5. ModRM - Part I

轉自老羅

道,可道,非常道。

-- 老子,《道德經》

基本概念

讓我們從最經常用到的域開始學起——ModR/M

在開始之前,先來講一些最基礎的概念,掃掃盲。

一個字節如果被轉換成二進制,則是由8位(bit)來表示(不足8位的話則高位用0來補足),例如:

16進制      2進制
B7          1011 0111
3A          0011 1010

示例中的B7的二進制是1011 0111,這是典型的4:4表示格式——1011表示的是B,0111表示的是7,這樣,1011 0111表示的就是B7了。

很容易理解吧?呵呵,那麼我們可不可以用另外一種方式來表示一個字節呢?

答案是肯定的:

16進制      2進制的4:4格式      2進制的2:3:3格式
B7          1011 0111           10 110 111
3A          0011 1010           00 111 010

請看,我們在這裏引進了一種新的表示格式:2:3:3

它的特點是把一個字節的8位二進制分成3個部分:最高的2位表示的是一個東西,接下來的3位表示的是另外一個東西,以及最後的3位表示的是另另外一個東西。

好了,明白了這一點後,我們來開始吧!

首先回憶一下OpCode的組成格式:

  1. Prefixes
  2. code
  3. ModR/M
  4. SIB
  5. Displacement
  6. Immediate

請注意第三項:ModR/M,它佔一個字節,其格式爲:

7 6  5        3  2 0
Mod  Reg/Opcode  R/M

可見,ModR/M是由ModReg/OpcodeR/M三個部分組成的。每個部分所佔的bit大小爲:

       Mod: 佔最高位的6~7共2個bit
Reg/Opcode: 佔中間位的3~5共3個bit
       R/M: 佔最低位的0~2共3個bit

呵呵,正好是2:3:3的格式!

ModR/M的具體描述如下面兩個表,第一個是16位的,第二個是32位的:
(截圖自《IA-32 Intel Architecture Software Developer's Manual Volume 2: Instruction Set Reference》,頁碼2-5,2-6,希望Intel不要因爲版權問題找我的麻煩)

- 16位 -

- 32位 -

哇,這兩個圖好複雜呀!你是不是已經有了這個感慨了呢?

呵呵不要緊,讓我們來舉個例子看看ModR/M到底是怎麼來看的:

mov edi, ecx	8B F9
sub edi, ecx	2B F9

注意這兩個OpCode的第二個字節——都是F9,再來看看OpCode的格式:

Prefixes  Code  ModR/M  SIB  Displacement  Immediate

我們在前面說過,在OpCode的格式中,只有Code是必須有的,別的都是可選的。所以,在8B F9和2B F9這兩組OpCode中,8B和2B就是Code,(這裏沒有Prefixes,因爲Prefixes只有在前面的章節中所介紹過的那幾個:66、67、F2、F3、2E、36、3E、26、64、65、F0)。

緊接着在Code後面的就是ModR/M了,所以在這兩組OpCode中的F9就是ModR/M。(在這裏也沒有SIBDisplacementImmediate

F9的4:4格式的二進制是1111 1001,我們把它分解成2:3:3的二進制看看:

16進制      2進制的2:3:3格式
F9          11 111 001

也就是:

       Mod: 11
Reg/Opcode: 111
       R/M: 001

暈頭轉向了?呵呵,讓我們來對其分而治之吧!

假設是在32位模式下。從上面的第二個圖中可以看到,Mod總共分爲00、01、10、11四種情況,每種情況又分別有8種情況。現在Mod是11,所以我們應該看Mod爲11的那一欄。

OK,現在來討論第二個:Reg/Opcode

Reg/Opcode中間的那個“/”表示“或”,意思就是,這個地方可以表示爲Reg或者Opcode——至於到底什麼時候表示Reg,什麼時候表示Opcode,這就要由Code來決定了。目前我們不必去深究它,後面會講明白的,我們只要知道,如果它是表示Opcode,則這個指令必定是2個字節的。

Reg由3個bit的二進制組成,因此,它可以表示:

2 ^ 3 = 8

一共8種可能的值。我們知道,常用的通用寄存器恰好也有8個,因此,根據組合數學的常識,可以得到:

REG && Register
REG Register
000 EAX
001 ECX
010 EDX
011 EBX
100 ESP
101 EBP
110 ESI
111 EDI

這是在32位的模式下得到的。

在16位的模式下,Reg則是表示另外一種“局部”的格式,它的低4位表示寄存器的低地址,高4位表示寄存器的高地址,如下表:

REG && Register
REG Register
000 AL
001 CL
010 DL
011 BL
100 AH
101 CH
110 DH
111 BH

好了,把目光返回到上面的32位ModR/M圖,看看最上面,在r32(/r)那一欄中,REG=111表示的就是寄存器EDI

到目前爲止,最後剩下還沒討論的就是R/M。這一欄要與Mod結合起來。我們來看Mod爲11的那一欄——R/M爲001對應的寄存器是ECX

好了!大功告成!整理如下:

       Mod: 11  表示應該查看Mod爲11的那一欄
Reg/Opcode: 111 表示的是寄存器EDI
       R/M: 001 表示的是ECX

因此,通過OpCode:

8B F9
2B F9

不難得到:

mov edi, ecx	8B F9
sub edi, ecx	2B F9

(注:8B是助記符“MOV”的Code,2B是助記符“SUB”的Code



(注:如果出現鏈接打不開的情況,請去掉IE瀏覽器的“工具->Internet選項->高級->總是以UTF-8發送URL”前面的勾。謝謝!)
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章