讀懂X86的OpCode碼錶(機翻)

Intel 64和IA-32架構軟件開發者手冊2021年6月版合訂本2647頁至2652頁,附錄A:操作碼映射表(OpCode Map)。AMD64架構開發者手冊2021年3月合訂本1205頁開始也是相似內容。

使用本章中的操作碼錶解釋IA-32和Intel 64體系結構目標代碼。指令分爲編碼組:
1字節、2字節和3字節操作碼編碼用於編碼整數、系統、MMX技術、SSE/SSE2/SSE3/SSE3/SSE4和VMX指令。表A-2至表A-6給出了這些指令的映射。
轉義操作碼(格式:ESC字符、操作碼、ModR/M字節)用於浮點指令。表A-7至表A-22中提供了這些指令的映射。
注意:操作碼映射中的所有空白都是保留的,不得使用。不要依賴於未定義或空白操作碼的操作。

A.1 使用操作碼錶
本附錄中的表格列出了指令的操作碼(包括所需的指令前綴、相關ModR/M字節中的操作碼擴展)。表中的空白單元格表示保留或未定義的操作碼。標記爲“Reserved-NOP”的單元格也是保留的,但在某些處理器上可能表現爲NOP。軟件不應使用操作碼對應的空白單元格或標記爲“Reserved-NOP”的單元格,也不應依賴於這些操作碼的當前行爲。
操作碼映射表由操作碼字節高低4位的十六進制值組織。對於1字節編碼(表A-2),使用操作碼的高4位來索引操作碼錶的一行;使用低4位對錶中的一列進行索引。對於以0FH開頭的2字節操作碼(表A-3),跳過任何指令前綴、0FH字節(0FH前面可能有66H、F2H或F3H),並使用下一個操作碼字節的上下4位值來索引錶行和列。類似地,對於以0F38H或0F3AH開頭的3字節操作碼(表A-4),跳過任何指令前綴0F38H或0F3AH,並使用第三個操作碼字節的上下4位值索引錶行和列。參見第A.2.4節“操作碼查找單字節、雙字節和三字節操作碼示例”。
當ModR/M字節提供操作碼擴展時,此信息限定操作碼執行。有關ModR/M字節中的操作碼擴展如何修改表A-2和表A-3中的操作碼映射的信息,請參見第A.4節。
浮點指令的轉義(ESC)操作碼錶在每一頁的頂部識別操作碼的八個高位。見A.5節。如果伴隨的ModR/M字節在00H-BFH範圍內,則位3-5(每頁第三個表的頂行)以及ModR/M的reg位確定操作碼。00H-BFH範圍之外的ModR/M字節由該節每頁的底部兩個表映射。

A.2 縮略語的關鍵
操作數由Zz形式的兩字符代碼標識。第一個字符(大寫字母)指定尋址方法;第二個字符(小寫字母)指定操作數的類型。

A.2.1 尋址方法代碼
以下縮寫用於記錄尋址方法:
A:直接尋址:指令沒有ModR/M字節;操作數的地址在指令中編碼。不能應用基址寄存器、索引寄存器或比例因子(例如,far JMP(EA))。
B: VEX前綴的VEX.vvvv字段選擇通用寄存器。
C: ModR/M字節的reg字段選擇一個控制寄存器(例如,MOV(0F20,0F22))。
D: ModR/M字節的reg字段選擇調試寄存器(例如,MOV(0F21,0F23))。
E: ModR/M字節跟隨操作碼並指定操作數。操作數是通用寄存器或內存地址。如果是內存地址,則根據段寄存器和以下任意值計算地址:基址寄存器、索引寄存器、比例因子、位移。
F: EFLAGS/RFLAGS寄存器。
G: ModR/M字節的reg字段選擇一個通用寄存器(例如,AX(000))。
H: VEX前綴的VEX.VVV字段選擇由操作數類型確定的128位XMM寄存器或256位YMM寄存器。對於傳統SSE編碼,此操作數不存在,將指令更改爲破壞性形式。
I: 即時數據:操作數值在指令的後續字節中編碼。
J: 指令包含要添加到指令指針寄存器的相對偏移量(例如,JMP(0E9),LOOP)。
L: 8位立即數的高4位選擇128位XMM寄存器或256位YMM寄存器,由操作數類型決定(在32位模式下忽略MSB,即最高有效位)。
M: ModR/M字節可能僅指內存(例如,BOUND、LES、LDS、LSS、LFS、LGS、CMPXCHG8B)。
N: ModR/M字節的R/M字段選擇壓縮四字MMX技術寄存器。
O: 指令沒有ModR/M字節。操作數的偏移量在指令中編碼爲一個字或雙字(取決於地址大小屬性)。不能應用基址寄存器、索引寄存器或比例因子(例如,MOV(A0–A3))。
P: ModR/M字節的reg字段選擇壓縮四字MMX技術寄存器。
Q: ModR/M字節跟隨操作碼並指定操作數。操作數是MMX技術寄存器或內存地址。如果是內存地址,則根據段寄存器和以下任意值計算地址:基址寄存器、索引寄存器、比例因子和位移。
R: ModR/M字節的R/M字段可能僅指通用寄存器(例如,MOV(0F20-0F23))。
S: ModR/M字節的reg字段選擇一個段寄存器(例如,MOV(8C,8E))。
U: ModR/M字節的R/M字段選擇由操作數類型確定的128位XMM寄存器或256位YMM寄存器。
V: ModR/M字節的reg字段選擇由操作數類型確定的128位XMM寄存器或256位YMM寄存器。
W: ModR/M字節跟隨操作碼並指定操作數。操作數是128位XMM寄存器、256位YMM寄存器(由操作數類型確定)或內存地址。如果是內存地址,則根據段寄存器和以下任意值計算地址:基址寄存器、索引寄存器、比例因子和位移。
X: 由DS:rSI寄存器對尋址的內存(例如,MOVS、CMPS、OUTS或LODS)。
Y: 由ES:rDI寄存器對尋址的內存(例如,MOVS、CMPS、INS、STOS或SCAS)。

A.2.2 操作數類型碼
以下縮寫用於記錄操作數類型:
a:內存中的兩個單字操作數或內存中的兩個雙字操作數,具體取決於操作數大小屬性(僅由BOUND指令使用)。
b:字節,與操作數大小屬性無關。
c:字節或字,取決於操作數大小屬性。
d:雙字,與操作數大小屬性無關。
dq: 雙四字,與操作數大小屬性無關。
p: 32位、48位或80位指針,具體取決於操作數大小屬性。
pd: 128位或256位壓縮雙精度浮點數據。
pi: 四字MMX技術寄存器(例如:mm0)。
ps: 128位或256位壓縮單精度浮點數據。
q: 四字,與操作數大小屬性無關。
qq: 四元四字(256位),與操作數大小屬性無關。
s: 6字節或10字節僞描述符。
sd: 128位雙精度浮點數據的標量元素。
ss: 128位單精度浮點數據的標量元素。
si: 雙字整數寄存器(例如:eax)。
v: 字、雙字或四字(在64位模式下),具體取決於操作數大小屬性。
w: 字,與操作數大小屬性無關。
x: 基於操作數大小屬性的dq或qq。
y: 雙字或四字(在64位模式下),具體取決於操作數大小屬性。
z: 字表示16位操作數大小,雙字表示32位或64位操作數大小。

A.2.3 寄存器碼
當一個操作碼需要一個特定的寄存器作爲操作數時,該寄存器由名稱標識(例如,AX、CL或ESI)。該名稱指示寄存器是64、32、16還是8位寬。
當寄存器寬度取決於操作數大小屬性時,使用eXX或rXX形式的寄存器標識符。eXX用於16位或32位大小的情況;rXX用於16、32或64位大小的情況。例如:eAX表示在操作數大小屬性爲16時使用AX寄存器,在操作數大小屬性爲32時使用eAX寄存器。rAX可以表示AX、EAX或rAX。
當REX.B位用於修改操作碼reg字段中指定的寄存器時,可通過在寄存器名稱中添加“/x”來表示這一事實,以表示其他可能性。例如,rCX/r9用於指示寄存器可以是rCX或r9。請注意,在這種情況下,r9的大小由操作數大小屬性決定(與rCX一樣)。

A.2.4 操作碼查找單字節、雙字節和三字節操作碼示例
本節提供了演示如何使用操作碼映射的示例。

A.2.4.1 單字節操作碼指令
1字節操作碼的操作碼映射如表A-2所示。1字節操作碼的操作碼映射按行(十六進制值的最低有效4位)和列(十六進制值的最高有效4位)排列。表中的每個條目都列出了以下操作碼類型之一:
使用第A.2節中列出的符號的指令助記符和操作數類型
用作指令前綴的操作碼
對於操作碼映射中與指令對應的每個條目,解釋主操作碼後字節的規則屬於以下情況之一:
需要ModR/M字節,並根據《Intel 64和IA-32架構軟件開發人員手冊》第2A卷第A.1節和第2章“指令格式”中列出的縮寫進行解釋。操作數類型根據第A.2節中列出的符號列出。
需要ModR/M字節,並在ModR/M字節的reg字段中包含操作碼擴展。解釋ModR/M字節時使用表A-6。
ModR/M字節的使用是保留的或未定義的。這適用於表示指令前綴的條目或不帶使用ModR/M操作數的指令的條目(例如:60H,PUSHA;06H,PUSH ES)。

例A-1. 查找1字節操作碼示例
ADD指令的操作碼030500000000H使用1字節操作碼映射(表A-2)解釋如下:
操作碼的第一位數字(0)表示錶行,第二位數字(3)表示表列。這將查找帶有兩個操作數的加法操作碼。
第一個操作數(Gv類型)表示一個通用寄存器,它是一個字或雙字,具體取決於操作數大小屬性。第二個操作數(Ev類型)表示後面的ModR/M字節,指定操作數是字還是雙字通用寄存器或內存地址。
此指令的ModR/M字節爲05H,表示隨後出現32位位移(00000000 h)。ModR/M字節(位3-5)的reg/opcode部分爲000,表示EAX寄存器。
此操作碼的指令爲ADD EAX、mem_op,mem_op的偏移量爲00000000 h。
一些1字節和2字節的操作碼指向組號(操作碼映射表中的陰影項)。組號表示指令使用ModR/M字節中的reg/opcode位作爲操作碼擴展(參考A.4節)。

A.2.4.2 雙字節操作碼指令
表A-3中所示的雙字節操作碼映射包括長度爲兩字節或三字節的主操作碼。長度爲2字節的主操作碼以轉義操作碼0FH開頭。第二個操作碼字節的上下四位用於索引表a-3中的特定行和列。
長度爲3字節的兩字節操作碼以一個強制前綴(66H、F2H或F3H)和轉義操作碼(0FH)開頭。第三個字節的上下四位用於索引表a-3中的特定行和列(第二個操作碼字節爲3字節轉義操作碼38H或3AH時除外;在這種情況下,請參閱第a.2.4.3節)。
對於操作碼映射中的每個條目,解釋主操作碼後面字節的規則屬於以下情況之一:
需要ModR/M字節,並根據《英特爾64和IA-32體系結構軟件開發人員手冊》第2A卷第A.1節和第2章“指令格式”中列出的縮寫進行解釋。操作數類型根據第A.2節中列出的符號列出。
需要ModR/M字節,並在ModR/M字節的reg字段中包含操作碼擴展。解釋ModR/M字節時使用表A-6。
ModR/M字節的使用是保留的或未定義的。這適用於表示沒有使用ModR/M編碼的操作數的指令的條目(例如:0F77H,EMMS)。

例A-2. 查找2字節操作碼示例
使用表a-3查找SHLD指令的操作碼0FA4050000000003H。
操作碼位於A行第4列。該位置指示具有操作數Ev、Gv和Ib的SHLD指令。請按如下方式解釋操作數:
-Ev: ModR/M字節跟在操作碼後面,用於指定一個字或雙字操作數。
-Gv: ModR/M字節的reg字段選擇通用寄存器。
-Ib: 是後續指令的編碼字節。
第三個字節是ModR/M字節(05H)。ModR/M的mod和opcode/reg字段表示32位位移用於定位內存中的第一個操作數,eAX作爲第二個操作數。
操作碼的下一部分是目標內存操作數(00000000 h)的32位位移。最後一個字節存儲提供移位計數(03H)的立即字節。

通過這個分解,可以看出這個操作碼代表指令:SHLD DS:00000000 h,EAX,3。

A.2.4.3三字節操作碼指令
表A-4和表A-5中所示的三字節操作碼映射包括長度爲3或4字節的主操作碼。長度爲3字節的主操作碼以兩個轉義字節0F38H或0F3A開頭。第三個操作碼字節的上下四位用於索引表a-4或表a-5中的特定行和列。
長度爲4字節的三字節操作碼以強制前綴(66H、F2H或F3H)和兩個轉義字節(0F38H或0F3AH)開頭。第四字節的上下四位用於索引表a-4或表a-5中的特定行和列。
對於操作碼映射中的每個條目,解釋主操作碼後字節的規則分爲以下幾種情況:
需要ModR/M字節,並根據《英特爾64和IA-32體系結構軟件開發人員手冊》第2A卷A.1和第2章“指令格式”中列出的縮寫進行解釋。操作數類型根據第A.2節中列出的符號列出。

例A-3. 查找3字節操作碼示例
使用表a-5查找操作碼660F3A0FC108H的PALIGNR指令。
66H爲前綴,0F3AH表示使用表a-5。操作碼位於第0行第F列,表示使用操作數Vdq、Wdq和Ib的PALIGNR指令。操作數解釋如下:
-Vdq: ModR/M字節的reg字段選擇128位XMM寄存器。
-Wdq: ModR/M字節的R/M字段選擇128位XMM寄存器或內存位置。
-Ib: 是後續指令的編碼字節。
下一個字節是ModR/M字節(C1H)。reg字段指示第一個操作數爲XMM0。mod顯示R/M字段指定一個寄存器,R/M表示第二個操作數是XMM1。
最後一個字節是立即字節(08H)。
通過這一細分,可以看出這個操作碼代表指令:PALIGNR XMM0,XMM1,8。

A.2.4.4 VEX前綴說明
包含VEX前綴的指令分別基於隱含的0F、0F38H和0F3AH的VEX.mmmmm字段編碼,相對於2字節和3字節操作碼映射進行組織。VEX編碼指令的操作碼映射中的每個條目都基於操作碼字節的值,類似於非VEX編碼指令。
VEX前綴包括幾個位字段,這些位字段編碼隱含的66H、F2H、F3H前綴功能(VEX.pp)和操作數大小/操作碼信息(VEX.L)。詳見第4章。
操作碼錶A2-A6包括帶VEX前綴的指令和不帶VEX前綴的指令。許多條目只生成一次,但同時表示指令的凸形式和非凸形式。如果存在VEX前綴,則所有操作數都有效,助記符的前綴通常爲“v”。如果VEX前綴不存在,則VEX.VV操作數不可用,並且從助記符中刪除前綴“v”。
少數指令僅以VEX形式存在,並標有上標“v”。
VEX前綴指令的操作數大小可由操作數類型代碼確定。128位向量由“dq”表示,256位向量由“qq”表示,操作數支持128位或256位的指令由VEX.L確定,由“x”表示。例如,條目“VMOVUPD Vx,Wx”表示支持VEX.L=0和VEX.L=1。

A.2.5 操作碼錶中使用的上標
表A-1包含關於特定編碼的註釋。這些註釋在以下操作碼圖中用上標表示。灰色單元格表示指令分組。

表A-1. 操作碼錶中使用的上標

上標符號 符號含義
1A 用作操作碼擴展的ModR/M字節的第5、4和3位(請參閱第A.4節“單字節和雙字節操作碼的操作碼擴展”)。
1B 有意嘗試生成無效操作碼異常(#UD)時,請使用0F0B操作碼(UD2指令)、0FB9H操作碼(UD1指令)或0FFFH操作碼(UD0指令)。
1C 有些指令使用相同的雙字節操作碼。如果指令有變化,或操作碼代表不同的指令,則ModR/M字節將用於區分指令。有關解碼指令所需的ModR/M字節值,請參見表A-6。
i64 指令無效或在64位模式下不可編碼。在64位模式下,40到4F(單字節INC和DEC)是REX前綴組合(使用FE/FF Grp 4和5表示INC和DEC)。
o64 指令僅在64位模式下可用。
d64 在64位模式下,指令默認爲64位操作數大小,不能對32位操作數大小進行編碼。
f64 在64位模式下,操作數大小強制爲64位操作數大小(在64位模式下,此指令忽略更改操作數大小的前綴)。
v 只存在VEX形式。該指令沒有遺留的SSE形式。對於整數GPR指令,它意味着需要VEX前綴。
v1 當無法從數據大小推斷時,VEX128和SSE表格僅存在(無VEX256)。

A.3 單字節、雙字節和三字節操作碼映射
見下表A-2至表A-5。這些表格是多頁的演示文稿。具有順序關係的行和列被放置在面對面的頁面上,以使查找任務更容易。請注意,並非每頁都有表格腳註。各表的腳註見表的最後一頁。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章