x86机器指令(machine instruction) - 图2

机器指令

任何一种微处理器(CPU)在设计时,就已规定好自己特定的指令系统,x86处理器的指令系统被称x86指令集。这种指令系统的功能也就决定了由该微处理器构成的计算机系统及其基本功能。指令系统中所设计的每条指令都对应着微处理器要完成的一种规定功能操作,即这些指令功能的实现都是由微处理器中的物理器件完成的。要使计算机完成一个完整的任务,就需要执行一组指令,这组指令通常称为程序。计算机能够执行的各种不同指令的集合就称为处理器(CPU)的指令系统。
一台计算机只能识别由二进制编码表示的指令,称之为机器指令。一条机器指令应包括两部分内容:一部分给出该指令应完成何种操作,称为指令操作码部分;另一部分给出参与操作的操作数的值,或指出操作数存放在何处、操作的结果应送往何处等,这一部分称为指令的操作数部分。处理器可根据指令中给出的地址信息求出存放操作数的地址称为有效地址EA(Effective Address),然后对存放在有效地址中的操作数进行存取操作。指令中关于如何求岀存放操作数有效地址的方法称为操作数的寻址方式。计算机按照指令给出的寻址方式求出操作数有效地址进行存取操作数的过程,称为指令的寻址操作。

x86指令码格式由四个部分组成。

  1. 可选的指令前缀(instruction prefix)。
  2. 操作码(opcode)
  3. 可选的修饰符(modR/M字段,SIB字段,偏移(disaplacement))
  4. 可选的数据

image.png

寄存器编号

寄存器类型 寄存器名称 二进制码编号 十进制编码
通用寄存器 EAX 000 0
AX 000 0
AL 000 0
AH 100 4
EBX 011 3
BX 011 3
BL 011 3
BH 111 7
ECX 100 1
CX 100 1
CL 100 1
CH 101 5
EDX 010 2
DX 010 2
DL 010 2
DH 110 6
ESP 100 4
SP 100 4
EBP 101 5
BP 101 5
EDI 111 7
DI 111 7
ESI 110 6
SI 110 6
段寄存器 CS 001 1
DS 011 3
ES 000 0
SS 010 2
FS 100 4
GS 101 5

指令前缀

指令前缀一般用于增强指令的功能,调整内存操作数的访问属性。
指令前缀可以分为6类。

  1. 操作数大小重写。
  2. 地址大小重写前缀
  3. 段重写前缀
  4. 重复指令指向前缀
  5. lock指令前缀
  6. 分支提示前缀

    操作数大小重写

    二进制编码为0x66,操作数大小重写发生在指令操作数太小与当前汇编上下文默认操作数大小不一致的情况。

    32为nasm汇编指令

  1. mov eax,1

机器码

b8 01 00 00 00

在16位汇编中不能访问

操作码

指令的操作码表达了指令的基本功能,是指令必不可少的字段,其长度为1-3字节不等,

  1. 1字节操作码与指令前缀共享指令第一个字节的空间(0x00~0xff),因为指令的前缀是可选的,cpu的解码器能根据指令的第一个字节的值确定该字节是指令的前缀还是操作码。
  2. 2字节操作码总是以0x0fxx开始,紧接另一个字节。其中0xff字节称为操作码转移前缀或转义操作码。
  3. 3字节操作码也是使用转义前缀的方式进行扩展,3字节操作码的转义前缀包含 0x0f38xx和0x0f3a两种。转义前缀后紧跟着另一个字节共同表示操作码。

根据操作码表达的指令功能的不同方式,可以把常见指令分为四类。

  1. 操作码独立表示指令功能

    操作码独立表示指令功能

    对于1个字节长度的指令。其操作码表达了指令的所以含义。
指令 2进制指令 16进制指令
ret 11001011 cb
nop 10010000 90
leave 11001001 c9
int imm8 11001101 cd
int3 11001100 cc
jmp rel32 11101001 e9

仅仅使用操作码就表达功能的指令,其操作数形式都比较简单,当操作数访问模式负复杂的时候,需要使用 ModR/M和SIB字段 补充指令的功能,intel指令系统将操作数寻址模式相同的一类指令组成一组。使用共同的操作码表示,这样的操作码称为组属性的操作码。

组属性操作码。ModR/M和SIB字段仅仅指定操作数访问模式

这类的操作码仅定义了指令的的基本框架,并没有明确具体的操作数,具体的操作数由ModR/M和SIB字段输出。

指令 2进制指令 16进制指令
mov r32, r32/m32 10001011 8b
mov r32/m32, m32 10001001 89
add r32, r32/m32 00000011 03
add r32/m32, r32 00000001 01
sub r32, r32/m32 00101011 2b
sub r32/m32, r32 00101001 29
cmp r32, r32/m32 00111011 3b
cmp r32/m32, r32 00111001 39

mov r32, r32/m32,8b表示从32位寄存器或者32位内存的值移动到32位寄存器上,但没有多余的信息说明具体是那个寄存器和地址,所以在此,需要ModR/M和SIB提供可信息。

组属性操作码。ModR/M的reg字段对操作码的补充

上面中MoR/M字段仅提供了指令的操作数访问模式信息,除此之外,ModR/M的reg字段还具有对组属性操作码的补充的功能,用于反作用于操作码。

指令 2进制指令 16进制指令
add r32, imm32 10000001/00000000 81/00
sub r32, imm32 10000001 00000101 81/05
cmp r32, imm32 10000001 00000111 81/07
imul r32/m32 11110111 00000101 f7/05
idiv r32/m32 11110111 00000111 f7/05
inc r8/m8 11111110 00000000 fe/0
dec r8/m8 11111110 00000001 fe/1

ModR/M字节的3~5位表示reg字段,取值为0~7,改字段可以对组属性的操作码进行补充,add r32, imm32,和sub r32, imm32指令的操作码都是81,当reg为0的时候表示add r32, imm32指令,当reg为5的时候表示sub r32, imm32指令。

组属性操作,寄存器编号补充操作数

除了ModR/M的reg字段可以对操作码进行补充,寄存器本身的编号也可以对操作码进行补充

指令 说明
inc r32 0x40 + reg
dec r32 0x48+reg
push r32 0x50+reg
pop r32 0x58+reg
mov r32, imm32 x0b8+reg

inc指令的组属性操作码为0x40,当指定具体的寄存器后,需要将寄存器的编号累加到操作码中。

ModR/M字段

image.png
ModM/R字段长度为1个字节分为分段。
0~2:r/m段r/m段表示另一个操作数,也保存寄存器编号,改编号知道的寄存器中肯能是操作数本身,也能是是存放和操作数的内存地址相关信息。3~5:reg字段。reg字段保存了寄存器编号和操作码的补充信息。6~7: mod字段mod字段为r/m字段指定具体的操作数模式,r/m字段内保存寄存器编号,根据不同的mod的值确定了该寄存器是寄存器操作数还是需要寻址的内存操作数。

mod r/m寻址模式 说明
00 寄存器间接地址 [eax]
01 寄存器基址 + 8位偏移值 [eax + 0x00]
10 寄存器基址 + 32位偏移值 [eax+ 0x00000000]
11 寄存器操作数 eax

SIB字段

SIB地址字段为ModR/M字段的补充值。通用寻址模式为寄存器基址 + 寄存器变址 + 偏移的寻址,也解决了寄存器编号冲突导致的部分指令无法由ModR/M字段表示。
SIB字段长度为一个字节,其中0~2位为base字段,3~5为index字段,6~7为scale字段,base字段保存基址寄存器编号,index字段保存变址的寄存器的编号,scale字段保存以2为底数的指数,表示变址寄存器的因子。因此SIB字段定义的寻址模式格式为:
[base + index*2]

立即数

x86指令中的立即数分别为3类,8位立即数,16位立即数和32位立即数,不同长度的立即数操作码也不一样。例如指令:

mov r8/r16/r32, imm8/imm16/imm32
立即数 指令前缀 操作码 说明
8位 b0+reg mov cl,0x00
16位 0x66 b8+reg mov cx,0x0000
32位 b8+reg mox ecx,0x000000