1. 程式人生 > >X86指令編碼內幕 --- 指令格式

X86指令編碼內幕 --- 指令格式

在序言裡的例子裡:

mov dword ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678

這裡稍作修改:將記憶體運算元 operand size 的指示符 word ptr 改回 dword ptr,使得指令的 operand size 是 32 位。

這是個具有典型指令編碼意義的指令,它的 encodes(機器編碼)是:26 c7 84 c8 44 33 22 11 78 56 34 12 (共12個位元組)。

go ahead~

1. 編碼序列

instruction_format

如上圖所示:這是 x86/x64 體系的 General-Pupose Instruction(通用體系指令)的編碼格式,記住這個編碼序列很重要,這是解析指令編碼的基石

這個編碼序列組成部分分為:

  • Legacy Prefix
  • REX prefix
  • Opcode
  • ModRM
  • SIB
  • Displacement
  • Immediate

按功能組別,可以將這個指令序列分為 4 大部分:PrefixOpcodeModRM/SIB 以及 Displace/Immediate

1.1 Prefix(字首)

AMD推出 x86 擴充套件 64 位技術時,增加了一個用於訪問擴充套件的 64 位資料的 REX prefix,而 x86 的 prefix 則變為了指令格式中的 Legacy prefix

1.1.1 Legacy prefix

在 legacy 的 x86 模式下 REX prefix 是無效的,但是在 x64 的 64 位下 Legacy prefix 是有效的。

1.1.2 REX prefix

在 64 位模式下,由於絕大多數指令的 default operand size(預設運算元大小)是 32 位,為了可以訪問擴充套件的 64 位資料和 64 位地址,x64 指令體系引入了 REX prefix 來實現這一目的。

1.2 Opcode(操作碼)

大多數通用指令的 Opcode 是單位元組,最多是 2 位元組,但是對有些 Float 指令和 SSEx 等 midea 指令來說是 3 個位元組的。opcode 是指令的核心部分,代表指令是用來幹什麼的?怎樣幹?

1.3 ModRM/SIB

ModRM 和 SIB 是用來提供 operands 的定址模式。

1.3.1 ModRM

ModRM 位元組,意為:mod-reg-r/m2-3-3 比例劃分位元組。

ModRM.mod 是提供定址模式, ModRM.reg 用來提供暫存器 ID,ModRM.r/m 提供 register 或 memory 的 ID

1.3.2 SIB

SIB 意即:Sacle-Index-Base 也是按 2-3-3 比例劃分位元組。

這兩個位元組用來為 memory 運算元提供 base, index 以及 scale

1.4 Disp/Imme

displacement 與 immediate 直接嵌在指令編碼中。

1.4.1 displacement

displacemnt 需要 ModRM 甚至 SIB 提供定址, displacement 最大為 4 個位元組 32 位。

1.4.2 immediate

immediate 部分大多數情況下不需要 ModRM 位元組提供定址,在一些指令還是需要 ModRM 進行定址。

immediate 最大可為 8 個位元組,在 x64 的 64 位下的某些情況才會有的。

注意:
displacement 和 immediate 的兩種情況:

★ 符號數(signed)

  在這種情形下:進行運算時,是符號數。
   當小於目標 operands 位數時,displacement 和 immediate 都有符號擴充套件的行為,擴充套件到目標運算元的位數。

實際上:
   operand size 具有 z 或 b 屬性的指令,才可能進行 sign-extended(符號擴充套件)行為。

(1)當指令的 operand size 是 z 屬性時,如果 immediate 是小於 effective operand size 的,immediate 會進行 sign-extended 行為。

(2)同樣 operand size 是 b 屬性的,如果  immediate 是小於 effective operand size 的,immediate 也會進行 sign-extended 行為。

(3)當指令的 displacement size 小於 address size  的,displacement 會進行 sign-extended 行為。

★ 無符號數(unsigned)

  在這種情況下,displacement 是一個絕對地址值,immediate 是一個無符號立即數值。

如:mov eax, dword ptr [0x11223344]mov eax, 0x12345678

本質上:
   所有 displacement 都是 signed(符號數),displacement 是基於 base 地址的一個 offset(偏移量)。

★ 當地址形式中無 base 暫存器時,雖然它是絕對值形式,實際上它仍是基於 segment base 地址。

因此,只有 immediate 才具有的 unsigned 的時候。


對照上面的 encode 來看:


26 c7 84 c8 44 33 22 11 78 56 34 12

(1) 26 是 legacy prefix,這是 segment-override prefix,指明是 ES 段選擇子
(2) c7 是 Opcode,表明這個指令是 mov reg/mem, imme
(3) 84 是 ModRm,即:10-000-100。
(4) c8 是 SIB,即:11-001-000
(5) 44332211 是 32 位 displacement 值
(6) 78563412 是 32 位 immediate 值


2、指令長度



上圖中顯示,指令長度最長是 15 個位元組,在什麼時候達到飽和的 15 個位元組呢?

2.1 什麼情況下達到飽和的 15 bytes

答案是如下類似指令:

lock add dword ptr es:[eax+ecx*8+0x11223344], 0x12345678

當在 16 位程式碼下,這條指令將達到飽和的 15 個位元組長度。

注意:僅在 16 位下,這條指令的編碼是:

26 66 67 F0 81 84 C8 44 33 22 11 78 56 34 12 (正好 15 個位元組)



這個編碼的具體含義:


26 66 67 F0: 這 4 個位元組是 prefix,這 4 個位元組達到了飽和的 prefix 狀態。

  • 26 是 ES segment register
  • 66 是 operand-size override
  • 67 是 address-size override
  • F0 是 Lock prefix

C7:Opcode

84:ModRM

C8:SIB

44 33 22 11:displacement

78 56 34 12:immediate

有沒有超過 15 個位元組的指令編碼,答案是:沒有! 那麼在 64 位下呢? 答案同樣是沒有!


2.2 為什麼指令長度最長是 15 位元組?

★ 4 個位元組的 prefix 已經達到飽和度了:

  • 1 個位元組用來調整 segment selector registers
  • 1 個位元組用來調整 Operand effective size
  • 1 個位元組用來調整 Address effective size
  • 還有 1 個位元組用來 lock 匯流排

已經無法再增加 prefix 了。

★ 若是採用 2 個位元組的 Opcode 碼,則定址模式上不會有 mem32, imm32 這種操作法。所以還是採用 1 個位元組的 Opcode,而得到 4 個位元組的立即數。

★ ModRM + SIB:2 個位元組。

★ 4 個位元組的 displacement 值。

★ 4 個位元組的 immediate 值。

這樣每個組成部分都呈飽和狀態,加起來總共 15 個位元組,而只有採用 mem32, imme32 這種定址模式可能會達到飽和狀態。

在 64 位下,若採用 mem, imme 的定址模式,這和 32 位是一致的,所以不會超越 15 個位元組,

2.3 prefix 的限制

prefix 的限制來自 legacy prefix (包括:operand size override、address size override、segment override、repeat prefix 以及 lock prefix)本身之間,

以及與 REX prefix 之間存在衝突:

  • 在 64 位下,operand size override

3、 encodes 的位元組序

x86/x64 指令的 encodes 在記憶體中是以 little endian 儲存的,這主要體現在 displacementimmediate 部分。

在 encode 序列裡,legacy prefix 在低端,依次往 immediate 部分在高階。

mov dword ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678

指令中的 displacement0x11223344,在記憶體的 little endian 序列是:44 33 22 11

immediate0x12345678 在記憶體的 lttle endian 序列是:78 56 34 12

相關推薦

X86指令編碼內幕 --- 指令格式

在序言裡的例子裡: mov dword ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678 這裡稍作修改:將記憶體運算元 operand size 的指示符 word ptr 改回 dword ptr,使得指令的 opera

X86指令編碼內幕 --- 指令 Opcode 碼

指令 Opcode 碼 x86 指令編碼的核心是:Opcode、ModRM 以及 SIB。Opcode 提供指令的操作碼,ModRM 及 SIB 提供運算元的定址模式。 指令編碼設計模式是:Opcode 的設計要考慮兼顧 ModRM。ModRM 要服務於 Opcode,S

X86指令編碼內幕 --- ModRM 定址模式

ModRM 定址模式 在 x86/x64 指令集的世界裡: Opcode 對指令提供操作碼,ModRM 最主要作用是對指令的 operands 提供定址,另一個作用是對 Opcode 進行補充,而 SIB 則是對 ModRM 進行補充定址 有兩種情況下是無需用 Mo

從編譯器源代碼中提取ARMv8的指令編碼

med constant ray 結構 any exce clas 標識 變量 2012年11月份的資料,之前ARMv8手冊還沒公布,我想辦法從編譯器的binutils中提取出了全部ARMv8指令的二進制編碼,之前不能隨便發,如今相當於解禁了^_^。

《深入理解計算機系統》練習題3.13-3.16 set指令 跳轉指令編碼

文章目錄 set指令訪問條件碼 3.13 跳轉指令編碼 3.15 cmp指令運算元順序 3.16 3.21 set指令訪問條件碼 SET指令根據條件碼或者條件碼的組合來將一個位元組設定為0或1(所以如果s

Atitit 計算機系統結構 計算機系統結構 Cpu 儲存 cache 指令系統 目錄 Line 56: 第2章指令系統設計 指令格式 定址方式 1 Line 64: 第3章CPU及其實現

Atitit 計算機系統結構  計算機系統結構   Cpu  儲存 cache   指令系統 目錄 Line 56: 第2章指令系統設計 指令格式  定址方式 1 Line 64: 第3章CPU及其實

【計組】-- 指令系統(1) : 指令格式

概緒 參考書目:《計算機組成原理》(第三版) 蔣本珊 編著   指令、指令系統是計算機中一個最基本的概念。指令是指示計算機執行某些操作的命令,一臺計算機的所有指令的集合構成該機

原子操作與 x86 上的 lock 指令字首

原子操作是不可分割的操作,在執行完畢時它不會被任何事件中斷。在單處理器系統(UniProcessor,簡稱 UP)中,能夠在單條指令中完成的操作都可以認為是原子操作,因為中斷只能發生在指令與指令之間。 在多處理器系統(Symmetric Multi-Processor,簡稱

jsp用靜態指令編碼問題

首先我們有時候儲存jsp會報錯說ISO-8859-1儲存失敗這是ISO-8859-1不能儲存中文的原因首先要去 Window-->General-->Content Types-->

python中關於編碼,json格式的中文輸出顯示

pri 整體 pytho src repr 接口 ensure 輸出 unicode 但我們用requests請求一個返回json的接口時候, 語法是 result=requests.post(url,data).content print type(result),re

JSP中的編譯指令和動作指令的差別

font class 編譯 執行 gb2 ron 消息 腳本 con JSP中的編譯指令和動作指令的差別 1、編譯指令是通知Servlet引擎的處理消息。而動作指令僅僅是執行時的腳本動作 2、編譯指令是在將JSP編譯成Servlet時起作用,而動作指令可替換成J

ARM指令集—SWP指令

而且 post margin {} 這樣的 有效 介紹 back swp ARM指令集—SWP指令 SWP和SWPB是ARM指令集中對存儲單元的原子操作。即對存儲單元的一次讀和一次不可被切割。SWP和SWPB分別完畢存儲器和寄存器之間 一個字(

Velocity(4)——引入指令和#Parse 指令

層次 必須 dep 屬性 mil das eight mar height #Include和#Parse都是用於將本地文件引入當前文件的指令,而且被引入的文件必須位於TEMPLATE_ROOT。這兩者之間有一些區別。 #Include 被#Include引入的文件,其

jsp筆記2(編譯指令與動作指令)

getpara html 丟失 另一個 value 默認 extend servlet encoding 一、jsp的編譯指令是通知jsp引擎的消息,不會生成輸出。 jsp的3個編譯指令: page:針對當前頁面的指令 include:包含另一個頁面的指令

字符編碼,時間格式轉換

encode codes decode 格式 unicode轉化 instr hello AI 普通 普通字符串可以用多種方式編碼成Unicode字符串,具體要看你究竟選擇了哪種編碼:unicodestring = u"Hello world" # 將Unicode轉

向量指令和標量指令

actor 基本 .get 對象 oid dom nod 文件的 imp 向量指令和標量指令:有些大型機和巨型機 設置功能齊全的向量運算指令系統。 向量指令的基本操作對象是向量,即有序排列的一組數。 若指令為向量操作,則由指令確定向量操作數的地址(主存儲器起始地址或向量寄

匯編語言指令是機器指令的符號化

lec 匯編 系統 close rac finall 缺點 stream port 匯編語言指令是機器指令的符號化 ,與機器指令存在著直接的對應關系,所以匯編語言同樣存在著難學難用、容易出錯、維護困難等缺點。 但是匯編語言也有自己的優點:可直接訪問系統接口,匯編程序翻譯成

CE的LVD指令,EMC指令都測試些什麽

保護套 震動 電氣 溢出 試驗 防火 封裝 天線 電路 歐盟CE認證的LVD指令、EMC指令檢測的具體項目: 一、安全實驗(LVD): 1.工作電壓 2.故障試驗 3.撞擊實驗 4.震動實驗 5.沖擊試驗 6.電氣間隙、爬電距離和絕緣穿透距離 7.插頭實驗 8.保護連接導體

《組合語言》實驗二——用機器指令和彙編指令程式設計

.title { background-color: #4682B4 } 實驗任務一:使用debug將下面的程式寫入記憶體,逐條執行,根據指令執行後的實際執行情況填空。 前提說明:為便於驗證實驗結果,對實驗任務一做了2點調整: ①在使用a命令輸入指令除錯前,使用e命令將記憶體單元0021:0~002

more指令和less指令使用的區別

more和less都是可以一頁一頁的翻動 more翻頁的時候,顯示有百分比在最下一行 less沒有 more可以用來查詢 空白鍵 (space):代表向下翻一頁;Enter :代表向下翻『一行』;/字串 :代表在這個顯示的內容當中,向下搜尋『字串』這個關鍵字;q :代表立刻離開 more ,不再顯示該