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的組成格式:
- Prefixes
- code
- ModR/M
- SIB
- Displacement
- Immediate
請注意第三項:ModR/M,它佔一個字節,其格式爲:
7 6 5 3 2 0
Mod Reg/Opcode R/M
可見,ModR/M是由Mod、Reg/Opcode和R/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。(在這裏也沒有SIB、Displacement和Immediate)
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)
羅聰 www.LuoCong.com |
(注:如果出現鏈接打不開的情況,請去掉IE瀏覽器的“工具->Internet選項->高級->總是以UTF-8發送URL”前面的勾。謝謝!) |