X64(64位)汇编指令与机器码转换原理

X64(64位)汇编指令与机器码转换原理

  • 1 64位寻址形式下的ModR/M字节
    • 1.1 寻址方式
    • 1.2 寄存器编号
  • 2 汇编指令转机器码
    • 2.1 mov rcx, 1122334455667788h
    • 2.2 mov rcx,[r8]与mov [r8],rcx
    • 2.3 mov rcx,[r8+r9*2]

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

1 64位寻址形式下的ModR/M字节

x64指令机器码组成:
在这里插入图片描述
REX prefix组成:
在这里插入图片描述
ModR/M组成:
在这里插入图片描述

1.1 寻址方式

ModR/M字节具体值,组成情况,如下图所示:X64(64位)汇编指令与机器码转换原理_第1张图片
X64(64位)汇编指令与机器码转换原理_第2张图片
ModRM.mod、ModRM.r/m和REX.B三者确定一种内存寻址方式,一共有64种内存寻址方式。

1.2 寄存器编号

ModRM.reg与REX.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

2 汇编指令转机器码

我们举几个立即数操作的例子:

mov cl, 12h
mov cx, 1234h
mov ecx, 12345678h
mov rcx, 1122334455667788h

然后,把表格中每一类寻址方式,都举一个例子,进行描述,如下:

序号 寻址方式 Mod R/M REX.B 汇编例子 含义
1 [r8] 00 000 1 mov rcx,[r8]与mov [r8],rcx (rcx)=((r8))与((r8))=(rcx)
2 [SIB] 00 100 任意 mov rcx,[r8+r9*2] (rcx)=((r8)+(r9)*2)
3 [disp32] / [rip+disp32] 00 101 任意 mov rcx,[00001000h] (rcx)=(00001000h) / (rcx)=((rip)+00001000h)
4 [r8+disp8] 01 000 1 mov rcx,[r8+10h] (rcx)=((r8)+10h)
5 [SIB+disp8] 01 100 任意 mov rcx,[r8+r9*2+10h] (rcx)=((r8)+(r9)*2+10h)
6 [r8+disp32] 10 000 1 mov rcx,[r8+00001000h] (rcx)=((r8)+00001000h)
7 [SIB+disp32] 10 100 任意 mov rcx,[r8+r9*2+00001000h] (rcx)=((r8)+(r9)*2+00001000h)
8 r8 11 000 1 mov r9,r8 (r9)=(r8)
9 r9 11 001 1 mov r8,r9 (r8)=(r9)

因此,一共有13个汇编指令转机器码的例子,接下来,依次来讲解。

2.1 mov rcx, 1122334455667788h

  • mov cl, 12h
    mov cl, 12h表示将立即数12h存储到8位寄存器cl中。
    查询指令手册,与MOV r8,imm8指令相符,其操作码为B0+ rb,rb表示目的操作数cl寄存器编号。
    在这里插入图片描述
    当前指令cl编号为1,因此操作码为B0+1=B1。
    因此指令的机器码组成,如下所示:
汇编指令 操作码 立即数 机器码
mov cl, 12h B1 12 B112
  • mov cx, 1234h
    mov cx, 1234h表示将立即数1234h存储到16位寄存器cx中。
    查询指令手册,与MOV r16,imm16指令相符,其操作码为B8+ rw,rw表示目的操作数cx寄存器编号。
    在这里插入图片描述
    当前指令cx编号为1,因此操作码为B8+1=B9。
    由于在X64下,默认操作数宽度是32位,需要添加指令前缀66H,“反转”选择16位宽度的操作数。
    因此指令的机器码组成,如下所示:
汇编指令 指令前缀 操作码 立即数 机器码
mov cx, 1234h 66 B9 1234 66B93412
  • mov ecx, 12345678h
    mov ecx, 12345678h表示将立即数12345678h存储到32位寄存器ecx中。
    查询指令手册,与MOV r32,imm32指令相符,其操作码为B8+ rd,rd表示目的操作数ecx寄存器编号。
    在这里插入图片描述
    当前指令ecx编号为1,因此操作码为B8+1=B9。
    由于在X64下,默认操作数宽度是32位,刚好合适,因此不需添加指令前缀66H。
    因此指令的机器码组成,如下所示:
汇编指令 操作码 立即数 机器码
mov ecx, 12345678h B9 12345678 B978563412
  • mov rcx, 1122334455667788h
    mov rcx, 1122334455667788h表示将立即数1122334455667788h存储到64位寄存器rcx中。
    查询指令手册,与MOV r64,imm64指令相符,其操作码为REX.W + B8+ rd,rd表示目的操作数rcx寄存器编号。
    在这里插入图片描述
    当前指令rcx编号为1,因此操作码为B8+1=B9。
    REX.W说明需要REX前缀,REX.W=1表示操作位宽为64位,因此REX=48h。
    因此指令的机器码组成,如下所示:
汇编指令 REX前缀 操作码 立即数 机器码
mov rcx, 1122334455667788h 48 B9 1122334455667788h 48 B9 88 77 66 55 44 33 22 11

2.2 mov rcx,[r8]与mov [r8],rcx

  • mov rcx,[r8]
    mov rcx,[r8]表示将r8寄存器中地址指向的内存单元,存储到rcx中。
    查询指令手册,与MOV r64,r/m64指令相符,其操作码为REX.W + 8B /r,/r表示这条指令具有ModR/M字段。
    在这里插入图片描述
    因此,尝试推导ModR/M值。当前指令寻址方式属于《X64指令基本格式》中“第一种,无SIB字节的内存寻址”,ModRM.mod、ModRM.r/m、REX.B三者确定一种内存寻址方式,如下图:
    X64(64位)汇编指令与机器码转换原理_第3张图片
    第一步,在源和目的操作数中,以内存寻址操作数为坐标点,反推ModRM.mod、ModRM.r/m、REX.B。
    这里内存寻址操作数为[r8],故ModRM.mod=00,ModRM.r/m=000,REX.B=1。
    第二步,在源和目的操作数中,以寄存器操作数,反推ModRM.reg与REX.R。
    这里寄存器操作数为rcx,其寄存器编号Rrrr=0001,故REX.R=0,ModRM.reg=001。

REX.W说明需要REX前缀,REX格式为0100WRXB,W表示操作数宽度,W=1表示64位,X位默认为0,因此REX=01001001=49h。ModRM=00001000=08h。
因此指令的机器码组成,如下所示:

汇编指令 REX前缀 操作码 ModRM 机器码
mov rcx,[r8] 49 8B 08 498B08
  • mov [r8],rcx
    mov [r8],rcx表示将rcx寄存器内容,存储到r8寄存器中地址指向的内存单元中。
    查询指令手册,与MOV r/m64,r64指令相符,其操作码为REX.W + 89 /r,/r表示这条指令具有ModR/M字段。
    在这里插入图片描述
    因此,尝试推导ModR/M值。当前指令寻址方式属于《X64指令基本格式》中“第一种,无SIB字节的内存寻址”,ModRM.mod、ModRM.r/m、REX.B三者确定一种内存寻址方式,如下图:
    X64(64位)汇编指令与机器码转换原理_第4张图片
    第一步,在源和目的操作数中,以内存寻址操作数为坐标点,反推ModRM.mod、ModRM.r/m、REX.B。
    这里内存寻址操作数为[r8],故ModRM.mod=00,ModRM.r/m=000,REX.B=1。
    第二步,在源和目的操作数中,以寄存器操作数,反推ModRM.reg与REX.R。
    这里寄存器操作数为rcx,其寄存器编号Rrrr=0001,故REX.R=0,ModRM.reg=001。

REX.W说明需要REX前缀,REX格式为0100WRXB,W表示操作数宽度,W=1表示64位,X位默认为0,因此REX=01001001=49h。ModRM=00001000=08h。
因此指令的机器码组成,如下所示:

汇编指令 REX前缀 操作码 ModRM 机器码
mov [r8],rcx 49 89 08 498908

发现没有,源操作数与目的操作数,交换传输方向后,仅操作码发生变化。也就是说,寄存器与内存之间传递数据的方向,是靠操作码来分辨的,与REX前缀、ModRM无关。

2.3 mov rcx,[r8+r9*2]

mov rcx,[r8+r9*2]表示将r8寄存器中地址+r9寄存器中地址*2,指向的内存单元,存储到rcx中。
查询指令手册,与MOV r64,r/m64指令相符,其操作码为REX.W + 8B /r,/r表示这条指令具有ModR/M字段。
在这里插入图片描述
因此,尝试推导ModR/M值。当前指令寻址方式属于《X64指令基本格式》中“第三种,带SIB字节的内存寻址”,如下图所示:
X64(64位)汇编指令与机器码转换原理_第5张图片
由于此场景下REX.B与SIB.base合并,不再与ModRM.r/m合并。
因此ModRM.mod、ModRM.r/m两者就可以确定[SIB]内存寻址方式,如下图:
X64(64位)汇编指令与机器码转换原理_第6张图片
第一步,以内存寻址操作数为坐标点,反推ModRM.mod、ModRM.r/m。
这里内存寻址操作数为[r8+r9 * 2],故ModRM.mod=00,ModRM.r/m=100。
第二步,以寄存器操作数,反推ModRM.reg与REX.R。
这里寄存器操作数为rcx,其寄存器编号Rrrr=0001,故REX.R=0,ModRM.reg=001。
第三步,。。。。。。

REX.W说明需要REX前缀,REX格式为0100WRXB,W表示操作数宽度,W=1表示64位,X位默认为0,因此REX=01001001=49h。ModRM=00001000=08h。
因此指令的机器码组成,如下所示:

汇编指令 REX前缀 操作码 ModRM 机器码
mov [r8],rcx 49 89 08 4B 8B 0C 48

发现没有,源操作数与目的操作数,交换传输方向后,仅操作码发生变化。也就是说,寄存器与内存之间传递数据的方向,是靠操作码来分辨的,与REX前缀、ModRM无关

未完待续。。。。

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