X64指令基本格式

X64指令基本格式

  • 1 REX Prefix结构
  • 2 REX prefix扩展位
    • 2.1 第一种,无SIB字节的内存寻址(mod !=11 )
    • 2.2 第二种,寄存器到寄存器的寻址(无内存操作数,mod=11)
    • 2.3 第三种,带SIB字节的内存寻址(mod!=11 & r/m=100)
    • 2.4 第四种,寄存器操作数编码于操作码字节中
  • 3 RIP寻址

本文属于《 X86指令基础系列教程》之一,欢迎查看其它文章。

X64指令与X86指令兼容,因此不再对X86指令结构重复描述,主要以讲解X64上新特性为主。

1 REX Prefix结构

x64指令机器码,在原来X86 32位基础上,增加了Rex Prefix,如下所示:
X64指令基本格式_第1张图片
AMD推出 x86 扩展 64 位技术时,增加了一个用于访问扩展的 64 位数据 prefix,它是:REX prefix,而 x86 原有的 prefix 则变为了指令格式中的:Legacy prefix

REX prefix 仅存在于 x64 的 64-bit 模式中,在 legacy x86 模式下,REX prefix 是无效的。 Legacy prefix在 x86 和x64下,均是有效的。

REX prefix 的取值范围是:40H - 4FH。在非 64 位模式下,它们是 inc 与 dec 指令;也就是说这些指令在 64 位模式下被重定义为 REX prefix,关于Prefix的介绍真的是少之又少,不过可以在x86/x64 指令编码内幕(适用于 AMD/Intel)学到很多。

这里就简单说一下吧,一个Legacy prefix还有一个REX prefix。这些修饰符是为了改变缺省的寄存器,比如说在32位下mov ax,bx。那么就要有Legacy prefix 0x66修饰,前者还有个作用就是改变当前段寄存器,不多这在目前已经显得不怎么重要了。

到了x64的时候,由于通用寄存器的扩展(主要原因),原本的8个通用寄存器只要3个位来标识,但是现在多了r8~r15,16个通用寄存器怎么办呢,很明显加上一位就能完全标识了。

那么就是REX prefix的作用,看一下这个家伙的结构:
X64指令基本格式_第2张图片
各个位的含义,如下:
X64指令基本格式_第3张图片
他有取值范围,前4位一定是4,后四位可选,W,R,X,B。

  • W位,标识改变默认操作数大小,比如现在x64有个汇编代码mov r8,r10。一般很多指令都是默认32位操作数的,只有在CS.L1&&CS.D0的时候才会是64位操作数(我没见过)。
    所以一般都要去改变默认操作数大小,那REX prefix就是0x48 (Inter手册上常说是 REX.W);
  • R位,用来扩展 ModRM.reg 域,000 ~ 111 —> 0 000 ~ 1 111 ,于是现在寄存器的情况变成了如下:
    X64指令基本格式_第4张图片
  • X位,用来扩展 SIB.index 域;
  • B位,用来扩展 SIB.base, ModRM.r/m 以及 Opcode.reg。

2 REX prefix扩展位

REX prefix=0100WRXB,扩展位WRXB的使用场景,有以下4种。

2.1 第一种,无SIB字节的内存寻址(mod !=11 )

X64指令基本格式_第5张图片
比如:mov rcx,[r8],机器码:49 8B 0B

  • 扩展ModRM.reg
    在X86 32位架构下,ModRM字节中reg有3位,可以表示eax、ebx、ecx、edx、esi、edi、ebp、esp共8个寄存器。
    但是,在X64架构下,有rax、rbx、rcx、rdx、rsi、rdi、rbp、rsp、r8、r9、r10、r11、r12、r13、r14、r15共16个寄存器,reg原有的3位不够用了,因此,需要与REX prefix中R位合并扩展为4位Rrrr,表示X64架构下这16个寄存器编号,具体编号如下:
r8(/r)
r16(/r)
r32(/r)
r64(/r)
mm(/r)
AL
AX
EAX
RAX
MM0
CL
CX
ECX
RCX
MM1
DL
DX
EDX
RDX
MM2
BL
BX
EBX
RBX
MM3
AH
SP
ESP
RSP
MM4
CH
BP
EBP
RBP
MM5
DH
SI
ESI
RSI
MM6
BH
DI
EDI
RDI
MM7
r8b
r8w
r8d
r8
r9b
r9w
r9d
r9
r10b
r10w
r10d
r10
r11b
r11w
r11d
r11
r12b
r12w
r12d
r12
r13b
r13w
r13d
r13
r14b
r14w
r14d
r14
r15b
r15w
r15d
r15
Rrrr 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
  • 扩展ModRM.r/m
    在X86 32位架构下,ModRM字节中r/m有3位,可以表示8种内存寻址方式。
    但是,在X64架构下,由于寄存器数量翻倍,原来的3位不足以表示所有寄存器的寻址方式,因此,需要与REX prefix中B位合并扩展为4位Bbbb,并且与X86 32位架构下一样,再次与ModRM.mod组合,表示64种内存寻址方式,如下所示:
    X64指令基本格式_第6张图片
    X64指令基本格式_第7张图片

2.2 第二种,寄存器到寄存器的寻址(无内存操作数,mod=11)

X64指令基本格式_第8张图片
比如:mov r9,r8,机器码:4D 8B C8
ModRM.reg与ModRM.r/m的扩展与上文描述完全一致,不再赘述。

2.3 第三种,带SIB字节的内存寻址(mod!=11 & r/m=100)

X64指令基本格式_第9张图片
比如:mov rax,[rbx+rcx*2],机器码:48 8B 04 4B

  • 扩展ModRM.reg
    ModRM.reg的扩展与上文描述完全一致,不再赘述。
  • 扩展SIB.index
    以下为32位时,SIB的寻址地址计算。
    X64指令基本格式_第10张图片
    也是由于X64下,寄存器数量增加,index只有3位,只能表示8个寄存器。因此需要将REX.X与index合并为4位Xxxx,可以表示16个寄存器。Xxxx为X64架构下寄存器的编号。
  • 扩展SIB.base
    X64下,寄存器数量增加,base只有3位,只能表示8个寄存器。因此需要将REX.B与base合并为4位Bbbb,可以表示16个寄存器。Bbbb为X64架构下寄存器的编号。

2.4 第四种,寄存器操作数编码于操作码字节中

X64指令基本格式_第11张图片
比如:mov rax,4,机器码:48 C7 C0 04 00 00 00
需要将REX.B与reg合并为4位Bbbb,可以表示16个寄存器。Bbbb为X64架构下寄存器的编号。

3 RIP寻址

X64架构的寻址模式与X86类似,但不完全等同,X64架构提供了一种新的rip相对寻址模式(RIP-Relative),引用单常量地址的指令,被编码为基于rip的偏移量(offsets)。
例如:

mov rax, [addr] 		;指令移动以addr+rip为起始地址的8字节内容到rax寄存器。

在64位模式下,RIP-Relative寻址,实现了一种新的寻址形式,rip相对(相对指令指针)寻址。有效的地址,是通过在下一条指令的64位RIP上增加位移来形成的。在IA-32体系结构和兼容模式下,相对于指令指针的寻址只适用于控制转移指令。

在64位模式下,使用ModR/M寻址的指令可以使用rip相对寻址。没有rip相对寻址,所有ModR/M指令模式都相对于零寻址内存。

RIP相对寻址允许特定的ModR/M模式使用带符号的32位位移来寻址相对于64位RIP的内存。这提供了与RIP的±2GB的偏移范围。rip相对寻址的ModR/M和SIB编码如下表所示。在当前的ModR/M和SIB编码中存在32位位移寻址的冗余形式。有一种ModR/M编码和几种SIB编码。rip相关寻址使用冗余形式进行编码。在64位模式下,ModR/M Disp32(32位位移)编码被重新定义为RIP+ Disp32,而不仅是位移。
X64指令基本格式_第12张图片
rip相对寻址的ModR/M编码不依赖于使用前缀。具体来说,101B的r/m位域编码(用于选择rip相对寻址)不受REX前缀的影响。例如,选择“R13”(REX.B = 1, r/m = 101B)时,只要mod = 00B仍然会导致rip相对寻址。REX.B结合ModR/ m的4位r/m字段没有被完全解码。为了处理没有位移的R13,软件必须使用1字节的位移0对R13 + 0进行编码。

rip相对寻址由64位模式启用,而不是64位的address-size。使用address-size前缀不会禁用rip相对寻址。地址大小前缀的作用是截断并零扩展计算出的有效地址为32位。

你可能感兴趣的:(X86指令集,X86指令,CPU指令集,机器码,汇编,寻址)