经典变长指令_Reg/Opcode
在之前的课程中,3-5位用来标识寄存器,Mod字段 与 R/M字段共同用来标识寄存器与内存
但3-5字段,并不仅仅用来标识寄存器,有些时候,用来标识Opcode
参见Table A-2中 :
80 81 82 83 这几个编码,并没有明确给出具体的操作码是什么。
有这个Grap字段的都去看TableA-6
举例说明:
80 65 08 FF
查表步骤:
1、第一个字节为80 查TableA-2表,得到对应结构:Eb,Ib
2、第二个字节为ModR/M字段,所以拆分65:
01 100 101
Mod 与 R/M字段 查Table2-2 得到对应的结构:[EBP+DIS8]
3、100 字段 查表TableA-6 得到对应操作码为:AND
4、最终的指令格式:
AND [ebp+dis8],Ib
AND BYTE PTR SS:[EBP+08],0xFF
指令前缀
1、段前缀:
段寄存器的作用:早期8086cpu寻址范围小,Inter遍通过段寄存器来拓展内存.即通过段寄存器基址+偏移的方式来寻址。
[]中的地址为有效地址(Effect Address),有效地址+段寄存器基址才是实际地址LA(线性地址 Line Address)。
线性地址 = 段基址 + 有效地址
在后来的80386时,cpu的寻址范围大大提升,这些段寄存器便被用作了其他用途。但是DS:[]类似
这种寻址格式却被保留了下来。
实际上操作码已经决定了寻址时使用哪个段寄存器作为基址,不需要其他字节描述。
1、如果没有特别说明,[]前为DS,即DS:[]
2、PUSH POP指令,以及在[]中使用ESP/EBP的,使用SS段
3、在[Base + Index*2Scale + I]中,以Base为判断条件,没有特别说明,用DS。如果Base为ESP/EBP,则用SS段.
4、串操作指令一般使用ES。MOV ES:[EDI] DS:[ESI]中,目标EDI使用ES段,其他使用DS段.
5、EIP指向当前指令,EIP取指令时使用的是CS段.
6、如果指令加段寄存器前缀,则该条指令一律用这个段,如果加多个段寄存器前缀,默认只看op前的那个.
2、操作指令前缀
0x66 将操作数改为16字节。例子50为 PUSH EAX, 而66 50则为 PUSH AX
004183DA 50 PUSH EAX
004183DB 66:50 PUSH AX
3、操作指令前缀:修改默认寻址方式
0x67 将操作数改为16字节。例子50为 PUSH EAX, 而66 50则为 PUSH AX
004183FD 8801 MOV BYTE PTR DS:[ECX],AL
004183FF 67:8801 MOV BYTE PTR DS:[BX+DI],AL
硬编码总结
1、操作码决定后面有没有ModR/M字段和立即数
2、ModR/M决定后面有没有SIB字节和偏移
3、操作指令中只要包含Ev/Eb,则指令中一定有ModR/M字节
4、只需要把操作码确定下来,那么后面有什么字段,就都能确定了。即一切由操作码决定。
5、操作码长度
一个字节:00-FF(TableA-2 0F除外)
两个字节:OF 00 - OF FF(TableA-3)
三个字节:OF 38 / OF 3A (TableA-3 TableA-4 TableA-5)
6、其他。。。 。 。 。 。 。 。 。 。 。
说明
转滴水三期课件