X86架構解析及指令模擬流程


前言:

要進行指令模擬,我們先需要了解X86架構下的指令是長什么樣子的。根據intel的編程手冊我們找到了如下信息。

Intel CPU的機器指令格式如下圖所示:

 

e.g.:圖片位於intel開發手冊第二卷第二章的2.1

根據開發手冊,一條指令由 指令前綴(Instruction Prefixes) + 操作碼(Opcode) + ModR/M + SIB + 偏移(displacement) + 立即數(Immediate data)幾部分組成,一條指令至少需要有Opcode,其它幾部分,在不同指令中可能存在可能不存在。今天我們主要來看Opcode、Instruction Prefixes、Immediate data三部分在不同指令中的使用。

一:x86指令解析

1.1  指令前綴

指令前綴分為四組,每組都有一組允許的前綴代碼。對於每條指令,它僅在包含來自四個組(組 1、2、3、4)中的每一組的最多一個前綴代碼時有用。第 1 組至第 4 組可以以任何相對於彼此的順序放置。
第一組:封鎖和重復執行前綴

    F0H: LOCK前綴,封鎖總線。在有數的指令(如ADD,ADC)前方時,使指令變為原子操作,並與被修飾的指令一起提供內存屏障效果。
    F2H:REPNE/REPNZ前綴(只位於字符串指令前)
    F3H:REP前綴(只位於字符串指令前)
    F3H:(與REP前綴同碼)

第二組:段前綴

    在32位匯編中,有8個段寄存器:ES、CS、SS、DS、FS、GS、LDTR、TR(順序固定),不再用段寄存器尋址而只做權限控制。前綴和寄存器對應如下:

2E - CS
36 - SS
3E - DS
26 - ES
64 - FS
65 - GS

    使用前綴修飾后,指令(opcode)的默認段寄存器會被修改,如默認的MOV操作從DS段拿數據,加上36前綴后會基於SS段地址取數據。

第三組:修改操作數默認長度

     66H,用來“反轉”默認的16位或32位操作數寬度。例如,當默認的操作數寬度是32位時,可以用這個前綴選擇16位寬度的操作數,或者反之。如下指令碼和匯編對照:

50:  PUSH EAX
6650: PUSH AX
第四組:修改默認地址長度

    67H,用來“反轉”默認的16位或32位地址寬度。例如,當默認的地址寬度是32位時,可以用這個前綴選擇16位寬度的地址,或者反之。如下指令碼和匯編對照:

8801:   MOV DS:[ECX],AL
678801: MOV DS:[BX+DI], AL

2.  指令碼(opcode)

    主操作碼的長度可以是 1、2 或 3 個字節。如果主操作碼不能確定指令則會有額外的字段編輯倒ModR/M中。如果主操作碼是0x0f開頭則需要取第二字節,如果主操作碼開頭是0x0f38,0x0f3a開頭則再取第三字節。

    從intel編程手冊中截取一字節指令碼格式如下圖(附錄A,第三章):

    

    部分釋義:

  G:通用寄存器
  E:寄存器/內存
  b:字節
  v:word\double word\quadword(16/32/64位,取決於CPU模式)

      opcode查看方法:

        如指令碼0x48,查看第4行第0列,屬於dec eax(REX是為64位指令集使用的,可自行搜索研究),此時指令為定長指令。

        再比如0x28(表示sub Eb, Gb),這里Gb表示通用寄存器,Eb表示還需要其他字段來確定這個參數,這就是下面要講的ModR/M字段。此時指令為不定長指令。

3.  ModR/m

     字段名稱解析:

  Mod: 指明操作碼中的E表示寄存器還是內存,11表示內存,其余表示寄存器
  Reg/Opcode:標記通用寄存器
  R/M:配合Mod字段標明取址方式,若為內存尋址則需要SIB字段輔助

    ModR/m格式表格:

 指令解析示例:88 01
  ①"88"我們知道其同通式是“mov Eb,Gb”,因此88是不定長指令,所以其后的一個字節**"01"即為ModR/M;
  ②我們將“01”按照ModR/M的格式拆分成三部分:01== 00 000 001三部分 ==> Mod=00=0,Eb即為byte ptr的內存;Reg/Opcode=000=0,即為eax/ax/al寄存器(Eb即byte則為al);R/M=001=1,即為ecx
  ③確定出“8801”的匯編指令為:mov byte ptr [ecx],al ==>mov byte ptr ds:[ecx],al(沒有指令前綴則DS是默認的)

3.  SIB

   SIB字段 引出:
          SIB是緊接着ModR/M的一個字節。不定長指令后必有ModR/M,而ModR/M的Mod不為"11"且R/M值為"100"(ESP)時則ModR/M后就有SIB。

    解析方式:

  SIB字段分三部分,如上圖所示。
  該三部分均存在於[]的括號中,格式為:Base + Index*2^(Scale),Base為寄存器編號索引的寄存器,Index也是寄存器編號索引的寄存器,Scale為00~11,因此格式又為:Base + Index * 1/2/4/8所以格式形如:ds:[eax+ecx*4]。

 解析示例:"88 84 48 12 34 56 78":
  ①Opcode = 88 --> 指令格式:mov Eb,Gb
  ②ModR/M = 84 --> 10 000 100 -->[reg+disp32](普通格式), al,esp
  ③由於Mod為10,且R/M為100,則屬於特殊情況,不遵循普通格式,所以下一個字節為SIB(可確定匯編指令為:mov byte ptr [–][–][disp32],al)
  ④[–][–]解析:SIB = 48H --> 01 001 000;Scale=1,Index=1(ECX),Base=0(EAX)
  ⑤得到匯編指令為:mov byte ptr [eax][ecx*2][78563412],al ==> **mov byte ptr [eax+ecx*2+78563412],al**

 二:指令模擬

    本文不對虛擬化的基礎知識再進行展開,如需理解下面的內容須先 了解硬件輔助虛擬化的基礎知識,如 KVM/GVM/HAXM的實現流程,網上講基礎的帖子很多,此處就不再展開。

    如下內容基於HAXM進行流程分析,假設大家都知道了一些基礎知識(如VM_EXIT,VM_ENTRY,VMX)

    2.1 功能定位

        指令模擬在硬件輔助虛擬化環境下,所處的執行流程如下圖:

    

 

     2.2 功能描述

  功能描述部分屬於上圖藍色部分的展開,便於后續對代碼的理解

    

 

     2.3 代碼流程

 

     

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM