aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2020-08-02 18:40:15 -0700
committeriximeow <me@iximeow.net>2020-08-09 01:38:57 -0700
commit7c09cd975b9251f633a3adb0b6149ea98d3dcee7 (patch)
treeca4e65d84bc5e515adc653b7336e0d4f26a85de9
parent2eebbc76c7185a21bc22e7b78db0e6cbc4bd3de2 (diff)
x87 support, plus several other missing instructions
-rw-r--r--CHANGELOG12
-rw-r--r--src/long_mode/display.rs191
-rw-r--r--src/long_mode/mod.rs753
-rw-r--r--test/long_mode/mod.rs419
4 files changed, 1280 insertions, 95 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3a24ffb..1362dff 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,15 @@
+## 0.0.15
+
+* the `x87` instruction set is now fully supported
+ - textual disassembly differs slightly from other decoders in that
+ yaxpeax-x86 does not prefer using `st` in place of `st(0)`
+* do not decode `into` in 64-bit mode
+* support `vmread`, `vmwrite`
+* support `iret`/`iretd`/`iretq`
+* support `enter`
+* support `maskmovq`, `movnti`, and `movntq`
+ - this brings full support to non-vex-coded x86 instructions
+
## 0.0.14
* `netburst` supported `cmpxchg16b` from its first x86_64 incarnation. since no
diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs
index 17f2c86..260d5dc 100644
--- a/src/long_mode/display.rs
+++ b/src/long_mode/display.rs
@@ -374,6 +374,8 @@ const MNEMONICS: &[&'static str] = &[
"int",
"into",
"iret",
+ "iretd",
+ "iretq",
"retf",
"enter",
"leave",
@@ -1139,6 +1141,100 @@ const MNEMONICS: &[&'static str] = &[
"wrfsbase",
"wrgsbase",
"crc32",
+ "xlat",
+
+ "f2xm1",
+ "fabs",
+ "fadd",
+ "faddp",
+ "fbld",
+ "fbstp",
+ "fchs",
+ "fcmovb",
+ "fcmovbe",
+ "fcmove",
+ "fcmovnb",
+ "fcmovnbe",
+ "fcmovne",
+ "fcmovnu",
+ "fcmovu",
+ "fcom",
+ "fcomi",
+ "fcomip",
+ "fcomp",
+ "fcompp",
+ "fcos",
+ "fdecstp",
+ "fdisi8087_nop",
+ "fdiv",
+ "fdivp",
+ "fdivr",
+ "fdivrp",
+ "feni8087_nop",
+ "ffree",
+ "ffreep",
+ "fiadd",
+ "ficom",
+ "ficomp",
+ "fidiv",
+ "fidivr",
+ "fild",
+ "fimul",
+ "fincstp",
+ "fist",
+ "fistp",
+ "fisttp",
+ "fisub",
+ "fisubr",
+ "fld",
+ "fld1",
+ "fldcw",
+ "fldenv",
+ "fldl2e",
+ "fldl2t",
+ "fldlg2",
+ "fldln2",
+ "fldpi",
+ "fldz",
+ "fmul",
+ "fmulp",
+ "fnclex",
+ "fninit",
+ "fnop",
+ "fnsave",
+ "fnstcw",
+ "fnstenv",
+ "fnstor",
+ "fnstsw",
+ "fpatan",
+ "fprem",
+ "fprem1",
+ "fptan",
+ "frndint",
+ "frstor",
+ "fscale",
+ "fsetpm287_nop",
+ "fsin",
+ "fsincos",
+ "fsqrt",
+ "fst",
+ "fstp",
+ "fstpnce",
+ "fsub",
+ "fsubp",
+ "fsubr",
+ "fsubrp",
+ "ftst",
+ "fucom",
+ "fucomi",
+ "fucomip",
+ "fucomp",
+ "fucompp",
+ "fxam",
+ "fxch",
+ "fxtract",
+ "fyl2x",
+ "fyl2xp1",
];
impl Opcode {
@@ -1468,6 +1564,42 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::SLHD |
Opcode::UCOMISD |
Opcode::UCOMISS |
+ Opcode::F2XM1 |
+ Opcode::FABS |
+ Opcode::FADD |
+ Opcode::FADDP |
+ Opcode::FCHS |
+ Opcode::FCOS |
+ Opcode::FDIV |
+ Opcode::FDIVP |
+ Opcode::FDIVR |
+ Opcode::FDIVRP |
+ Opcode::FIADD |
+ Opcode::FIDIV |
+ Opcode::FIDIVR |
+ Opcode::FIMUL |
+ Opcode::FISUB |
+ Opcode::FISUBR |
+ Opcode::FMUL |
+ Opcode::FMULP |
+ Opcode::FNCLEX |
+ Opcode::FNINIT |
+ Opcode::FPATAN |
+ Opcode::FPREM |
+ Opcode::FPREM1 |
+ Opcode::FPTAN |
+ Opcode::FRNDINT |
+ Opcode::FSCALE |
+ Opcode::FSIN |
+ Opcode::FSINCOS |
+ Opcode::FSQRT |
+ Opcode::FSUB |
+ Opcode::FSUBP |
+ Opcode::FSUBR |
+ Opcode::FSUBRP |
+ Opcode::FXTRACT |
+ Opcode::FYL2X |
+ Opcode::FYL2XP1 |
Opcode::IMUL => { write!(out, "{}", colors.arithmetic_op(self)) }
Opcode::POPF |
Opcode::PUSHF |
@@ -1476,6 +1608,10 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::PUSH |
Opcode::POP => { write!(out, "{}", colors.stack_op(self)) }
Opcode::WAIT |
+ Opcode::FNOP |
+ Opcode::FDISI8087_NOP |
+ Opcode::FENI8087_NOP |
+ Opcode::FSETPM287_NOP |
Opcode::PREFETCHNTA |
Opcode::PREFETCH0 |
Opcode::PREFETCH1 |
@@ -1488,6 +1624,8 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::INT |
Opcode::INTO |
Opcode::IRET |
+ Opcode::IRETD |
+ Opcode::IRETQ |
Opcode::RETF |
Opcode::RETURN => { write!(out, "{}", colors.stop_op(self)) }
Opcode::CALL |
@@ -1780,7 +1918,34 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::MOVZX_w |
Opcode::MOVSX |
Opcode::MOVSXD |
+ Opcode::FILD |
+ Opcode::FBLD |
+ Opcode::FBSTP |
+ Opcode::FIST |
+ Opcode::FISTP |
+ Opcode::FISTTP |
+ Opcode::FLD |
+ Opcode::FLD1 |
+ Opcode::FLDCW |
+ Opcode::FLDENV |
+ Opcode::FLDL2E |
+ Opcode::FLDL2T |
+ Opcode::FLDLG2 |
+ Opcode::FLDLN2 |
+ Opcode::FLDPI |
+ Opcode::FLDZ |
+ Opcode::FST |
+ Opcode::FSTP |
+ Opcode::FSTPNCE |
+ Opcode::FNSAVE |
+ Opcode::FNSTCW |
+ Opcode::FNSTENV |
+ Opcode::FNSTOR |
+ Opcode::FNSTSW |
+ Opcode::FRSTOR |
+ Opcode::FXCH |
Opcode::XCHG |
+ Opcode::XLAT |
Opcode::CMOVA |
Opcode::CMOVB |
Opcode::CMOVG |
@@ -1797,6 +1962,14 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::CMOVP |
Opcode::CMOVS |
Opcode::CMOVZ |
+ Opcode::FCMOVB |
+ Opcode::FCMOVBE |
+ Opcode::FCMOVE |
+ Opcode::FCMOVNB |
+ Opcode::FCMOVNBE |
+ Opcode::FCMOVNE |
+ Opcode::FCMOVNU |
+ Opcode::FCMOVU |
Opcode::SETO |
Opcode::SETNO |
Opcode::SETB |
@@ -1885,6 +2058,20 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::CMPS |
Opcode::SCAS |
Opcode::TEST |
+ Opcode::FTST |
+ Opcode::FXAM |
+ Opcode::FUCOM |
+ Opcode::FUCOMI |
+ Opcode::FUCOMIP |
+ Opcode::FUCOMP |
+ Opcode::FUCOMPP |
+ Opcode::FCOM |
+ Opcode::FCOMI |
+ Opcode::FCOMIP |
+ Opcode::FCOMP |
+ Opcode::FCOMPP |
+ Opcode::FICOM |
+ Opcode::FICOMP |
Opcode::CMPSD |
Opcode::CMPSS |
Opcode::CMP |
@@ -2000,6 +2187,10 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::SHA256RNDS2 |
Opcode::SHA256MSG1 |
Opcode::SHA256MSG2 |
+ Opcode::FFREE |
+ Opcode::FFREEP |
+ Opcode::FDECSTP |
+ Opcode::FINCSTP |
Opcode::AESDEC |
Opcode::AESDECLAST |
Opcode::AESENC |
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 065d1ae..6c2b80d 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -65,6 +65,18 @@ impl RegSpec {
}
#[inline]
+ fn st(num: u8) -> RegSpec {
+ if num >= 8 {
+ panic!("invalid x87 reg st({})", num);
+ }
+
+ RegSpec {
+ num,
+ bank: RegisterBank::ST
+ }
+ }
+
+ #[inline]
fn from_parts(num: u8, extended: bool, bank: RegisterBank) -> RegSpec {
RegSpec {
num: num + if extended { 0b1000 } else { 0 },
@@ -356,8 +368,7 @@ impl OperandSpec {
OperandSpec::RegRRR |
OperandSpec::RegMMM |
OperandSpec::RegVex |
- OperandSpec::AL |
- OperandSpec::CL |
+ OperandSpec::EnterFrameSize |
OperandSpec::Nothing => {
false
}
@@ -381,12 +392,6 @@ impl Operand {
OperandSpec::RegVex => {
Operand::Register(inst.vex_reg)
}
- OperandSpec::AL => {
- Operand::Register(RegSpec::al())
- }
- OperandSpec::CL => {
- Operand::Register(RegSpec::cl())
- }
OperandSpec::ImmI8 => Operand::ImmediateI8(inst.imm as i8),
OperandSpec::ImmU8 => Operand::ImmediateU8(inst.imm as u8),
OperandSpec::ImmI16 => Operand::ImmediateI16(inst.imm as i16),
@@ -395,6 +400,7 @@ impl Operand {
OperandSpec::ImmU32 => Operand::ImmediateU32(inst.imm as u32),
OperandSpec::ImmI64 => Operand::ImmediateI64(inst.imm as i64),
OperandSpec::ImmU64 => Operand::ImmediateU64(inst.imm as u64),
+ OperandSpec::EnterFrameSize => Operand::ImmediateU16(inst.disp as u16),
OperandSpec::DispU32 => Operand::DisplacementU32(inst.disp as u32),
OperandSpec::DispU64 => Operand::DisplacementU64(inst.disp as u64),
OperandSpec::Deref => {
@@ -655,6 +661,8 @@ pub enum Opcode {
INT,
INTO,
IRET,
+ IRETD,
+ IRETQ,
RETF,
ENTER,
LEAVE,
@@ -1435,6 +1443,100 @@ pub enum Opcode {
WRGSBASE,
CRC32,
+ XLAT,
+
+ F2XM1,
+ FABS,
+ FADD,
+ FADDP,
+ FBLD,
+ FBSTP,
+ FCHS,
+ FCMOVB,
+ FCMOVBE,
+ FCMOVE,
+ FCMOVNB,
+ FCMOVNBE,
+ FCMOVNE,
+ FCMOVNU,
+ FCMOVU,
+ FCOM,
+ FCOMI,
+ FCOMIP,
+ FCOMP,
+ FCOMPP,
+ FCOS,
+ FDECSTP,
+ FDISI8087_NOP,
+ FDIV,
+ FDIVP,
+ FDIVR,
+ FDIVRP,
+ FENI8087_NOP,
+ FFREE,
+ FFREEP,
+ FIADD,
+ FICOM,
+ FICOMP,
+ FIDIV,
+ FIDIVR,
+ FILD,
+ FIMUL,
+ FINCSTP,
+ FIST,
+ FISTP,
+ FISTTP,
+ FISUB,
+ FISUBR,
+ FLD,
+ FLD1,
+ FLDCW,
+ FLDENV,
+ FLDL2E,
+ FLDL2T,
+ FLDLG2,
+ FLDLN2,
+ FLDPI,
+ FLDZ,
+ FMUL,
+ FMULP,
+ FNCLEX,
+ FNINIT,
+ FNOP,
+ FNSAVE,
+ FNSTCW,
+ FNSTENV,
+ FNSTOR,
+ FNSTSW,
+ FPATAN,
+ FPREM,
+ FPREM1,
+ FPTAN,
+ FRNDINT,
+ FRSTOR,
+ FSCALE,
+ FSETPM287_NOP,
+ FSIN,
+ FSINCOS,
+ FSQRT,
+ FST,
+ FSTP,
+ FSTPNCE,
+ FSUB,
+ FSUBP,
+ FSUBR,
+ FSUBRP,
+ FTST,
+ FUCOM,
+ FUCOMI,
+ FUCOMIP,
+ FUCOMP,
+ FUCOMPP,
+ FXAM,
+ FXCH,
+ FXTRACT,
+ FYL2X,
+ FYL2XP1,
}
#[derive(Debug)]
@@ -1486,10 +1588,6 @@ enum OperandSpec {
RegMMM,
// the register selected by vex-vvvv bits
RegVex,
- // the register `al`. Used for MOVS.
- AL,
- // the register `cl`. Used for SHLD and SHRD.
- CL,
ImmI8,
ImmI16,
ImmI32,
@@ -1498,6 +1596,9 @@ enum OperandSpec {
ImmU16,
ImmU32,
ImmU64,
+ // ENTER is a two-immediate instruction, where the first immediate is stored in the disp field.
+ // for this case, a second immediate-style operand is needed.
+ EnterFrameSize,
DispU32,
DispU64,
Deref,
@@ -2308,9 +2409,6 @@ impl InstDecoder {
Opcode::PINSRB |
Opcode::PINSRD |
Opcode::PINSRQ |
- Opcode::PEXTRB |
- Opcode::PEXTRW |
- Opcode::PEXTRQ |
Opcode::PMOVSXBW |
Opcode::PMOVZXBW |
Opcode::PMOVSXBD |
@@ -3234,6 +3332,7 @@ impl EmbeddedOperandInstructions {
}
}
+#[allow(non_snake_case)]
impl OperandCodeBuilder {
const fn new() -> Self {
OperandCodeBuilder { bits: 0 }
@@ -3411,10 +3510,16 @@ pub enum OperandCode {
Yb_Xb,
Yv_AX,
Yv_Xv,
- G_E_q = 0x8b00,
- E_G_q,
- G_mm_Ew_Ib = 0x8c00,
- Mq_Dq,
+
+ x87_d8 = OperandCodeBuilder::new().special_case(31).bits(),
+ x87_d9 = OperandCodeBuilder::new().special_case(32).bits(),
+ x87_da = OperandCodeBuilder::new().special_case(33).bits(),
+ x87_db = OperandCodeBuilder::new().special_case(34).bits(),
+ x87_dc = OperandCodeBuilder::new().special_case(35).bits(),
+ x87_dd = OperandCodeBuilder::new().special_case(36).bits(),
+ x87_de = OperandCodeBuilder::new().special_case(37).bits(),
+ x87_df = OperandCodeBuilder::new().special_case(38).bits(),
+
// Implied,
Unsupported,
ModRM_0x0f00 = OperandCodeBuilder::new().read_modrm().special_case(0).bits(),
@@ -3621,11 +3726,11 @@ pub enum OperandCode {
Gv_Ew_LSL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(7).bits(),
Gdq_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(6).bits(),
Gdq_Ev = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(10).bits(),
+ Mdq_Gdq = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(11).bits(),
G_E_mm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(2).bits(),
G_E_xmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(8).bits(),
AL_Ob = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(0).bits(),
AL_Xb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(1).bits(),
- AX_AL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(2).bits(),
AX_Ov = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(3).bits(),
AL_Ibs = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().byte_operands().operand_case(0).bits(),
AX_Ivd = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(9).bits(),
@@ -3665,6 +3770,11 @@ pub enum OperandCode {
G_mm_E = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(20).bits(),
Ev_Gv_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(21).bits(),
Ev_Gv_CL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(22).bits(),
+ G_mm_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(32).bits(),
+ G_Md_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(33).bits(),
+ G_mm_Ew_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(20).bits(),
+ G_E_q = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(21).bits(),
+ E_G_q = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(22).bits(),
}
fn base_opcode_map(v: u8) -> Opcode {
@@ -4782,7 +4892,7 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb),
OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv),
OpcodeRecord(Interpretation::Instruction(Opcode::CMPPS), OperandCode::G_E_xmm_Ib),
- OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTI), OperandCode::Mq_Dq),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTI), OperandCode::Mdq_Gdq),
OpcodeRecord(Interpretation::Instruction(Opcode::PINSRW), OperandCode::G_mm_Ew_Ib),
OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::Rv_Gmm_Ib),
OpcodeRecord(Interpretation::Instruction(Opcode::SHUFPS), OperandCode::G_E_xmm_Ib),
@@ -4823,7 +4933,7 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::PMULHUW), OperandCode::G_E_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PMULHW), OperandCode::G_E_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
- OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTQ), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTQ), OperandCode::G_Md_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSB), OperandCode::G_E_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSW), OperandCode::G_E_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PMINSW), OperandCode::G_E_mm),
@@ -4840,7 +4950,7 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::PMULUDQ), OperandCode::G_E_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PMADDWD), OperandCode::G_E_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PSADBW), OperandCode::G_E_mm),
- OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVQ), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVQ), OperandCode::G_mm_U_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PSUBB), OperandCode::G_E_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PSUBW), OperandCode::G_E_mm),
OpcodeRecord(Interpretation::Instruction(Opcode::PSUBD), OperandCode::G_E_mm),
@@ -5034,7 +5144,7 @@ const OPCODES: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_AA),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_DA),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
- OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::WAIT), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::PUSHF), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::POPF), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::SAHF), OperandCode::AH),
@@ -5087,7 +5197,7 @@ const OPCODES: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::RETF), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::I_3),
OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::Ib),
- OpcodeRecord(Interpretation::Instruction(Opcode::INTO), OperandCode::Fw),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::IRET), OperandCode::Fw),
// 0xd0
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd0_Eb_1),
@@ -5098,23 +5208,23 @@ const OPCODES: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
// XLAT
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XLAT), OperandCode::Nothing),
// x86 d8
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_d8),
// x86 d9
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_d9),
// x86 da
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_da),
// x86 db
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_db),
// x86 dc
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_dc),
// x86 dd
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_dd),
// x86 de
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_de),
// x86 df
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_df),
// 0xe0
// LOOPNZ
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
@@ -5170,6 +5280,14 @@ pub(self) fn read_E<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instru
}
}
#[allow(non_snake_case)]
+pub(self) fn read_E_st<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
+ if modrm >= 0b11000000 {
+ read_modrm_reg(instr, modrm, RegisterBank::ST)
+ } else {
+ read_M(bytes_iter, instr, modrm, length)
+ }
+}
+#[allow(non_snake_case)]
pub(self) fn read_E_xmm<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
if modrm >= 0b11000000 {
read_modrm_reg(instr, modrm, RegisterBank::X)
@@ -5492,10 +5610,6 @@ fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, in
0x67 => {
prefixes.set_address_size();
},
- 0x9b => {
- // TODO: WAIT prefix
- return Err(DecodeError::IncompleteDecoder);
- },
0xf0 => {
prefixes.set_lock();
},
@@ -5651,52 +5765,6 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,
} else {
let operand_code: OperandCode = unsafe { core::mem::transmute(operand_code.bits()) };
match operand_code {
- /*
- Gv_Ev_Iv,
- Gb_Eb_Ib,
- Yb_DX,
- Yv_DX,
- DX_Xb,
- DX_Xv,
- OR,
- AH,
- AL_Ib,
- AL_Ob,
- AL_Xb,
- AX_AL,
- AX_Ivd,
- AX_Ov,
- AX_Xv,
- DX_AX,
- Eb_1,
- Eb_Ib,
- Eb_CL,
- Ev,
- Ev_1,
- Ev_CL,
- Ev_Ibs,
- Ev_Iv,
- Ev_Ivs,
- Ew_Sw,
- Fw,
- Gv_M,
- I_3,
- Ib,
- Ibs,
- Ivs,
- Iw,
- Iw_Ib,
- Ob_AL,
- Ov_AX,
- Sw_Ew,
- Yb_AL,
- Yb_Xb,
- Yv_AX,
- Yv_Xv,
- Zb_Ib,
- Zv,
- Zv_AX,
- */
OperandCode::Eb_R0 => {
if (modrm & 0b00111000) != 0 {
instruction.opcode = Opcode::Invalid;
@@ -6159,7 +6227,8 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,
OperandCode::Ev_Gv_CL => {
instruction.operands[0] = mem_oper;
instruction.operands[1] = OperandSpec::RegRRR;
- instruction.operands[2] = OperandSpec::CL;
+ instruction.operands[2] = OperandSpec::RegVex;
+ instruction.vex_reg = RegSpec::cl();
instruction.operand_count = 3;
}
OperandCode::I_3 => {
@@ -6180,6 +6249,85 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
OperandCode::Unsupported => {
return Err(DecodeError::IncompleteDecoder);
}
+ OperandCode::Iw_Ib => {
+ instruction.disp = read_num(&mut bytes_iter, 2)? as u64;
+ instruction.imm = read_num(&mut bytes_iter, 1)? as u64;
+ instruction.operands[0] = OperandSpec::EnterFrameSize;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ instruction.operand_count = 2;
+ *length += 3;
+ }
+ OperandCode::Fw => {
+ if instruction.prefixes.rex().w() {
+ instruction.opcode = Opcode::IRETQ;
+ } else if instruction.prefixes.operand_size() {
+ instruction.opcode = Opcode::IRET;
+ } else {
+ instruction.opcode = Opcode::IRETD;
+ }
+ instruction.operand_count = 0;
+ }
+ OperandCode::Mdq_Gdq => {
+ let opwidth = if instruction.prefixes.rex().w() { 8 } else { 4 };
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ instruction.operands[1] = instruction.operands[0];
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), opwidth, instruction.prefixes.rex().present());
+ instruction.operand_count = 2;
+
+ }
+ OperandCode::G_mm_U_mm => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ if mem_oper != OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.modrm_mmm.bank = RegisterBank::MM;
+ instruction.modrm_mmm.num &= 0b111;
+ instruction.modrm_rrr.num &= 0b111;
+ instruction.operand_count = 2;
+ },
+ OperandCode::E_G_q => {
+ if instruction.prefixes.operand_size() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 8, length)?;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), RegisterBank::Q);
+ instruction.operand_count = 2;
+ }
+ OperandCode::G_E_q => {
+ if instruction.prefixes.operand_size() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), RegisterBank::Q);
+ instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 8, length)?;
+ instruction.operand_count = 2;
+ }
+ OperandCode::G_Md_mm => {
+ instruction.operands[1] = instruction.operands[0];
+ instruction.operands[0] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ if mem_oper == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.modrm_rrr.num &= 0b111;
+ instruction.operand_count = 2;
+ },
OperandCode::MOVQ_f30f => {
// if rex.w is set, the f3 prefix no longer applies and this becomes an 0f7e movq,
// rather than f30f7e movq.
@@ -7117,17 +7265,24 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
}
// sure hope these aren't backwards huh
OperandCode::AL_Xb => {
- instruction.operands[0] = OperandSpec::AL;
- instruction.operands[1] = OperandSpec::Deref_rsi;
+ instruction.modrm_rrr = RegSpec::al();
+ instruction.modrm_mmm = RegSpec::rsi();
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::Deref;
+ instruction.operand_count = 2;
}
// TODO: two memory operands! this is wrong!!!
OperandCode::Yb_Xb => {
instruction.operands[0] = OperandSpec::Deref_rdi;
instruction.operands[1] = OperandSpec::Deref_rsi;
+ instruction.operand_count = 2;
}
OperandCode::Yb_AL => {
- instruction.operands[0] = OperandSpec::Deref_rdi;
- instruction.operands[1] = OperandSpec::AL;
+ instruction.modrm_rrr = RegSpec::al();
+ instruction.modrm_mmm = RegSpec::rsi();
+ instruction.operands[0] = OperandSpec::Deref;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
}
OperandCode::AX_Xv => {
let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
@@ -7811,6 +7966,16 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
instruction.operands[1] = OperandSpec::Deref;
instruction.operand_count = 2;
}
+ OperandCode::x87_d8 |
+ OperandCode::x87_d9 |
+ OperandCode::x87_da |
+ OperandCode::x87_db |
+ OperandCode::x87_dc |
+ OperandCode::x87_dd |
+ OperandCode::x87_de |
+ OperandCode::x87_df => {
+ return decode_x87(decoder, bytes_iter, instruction, operand_code, length);
+ }
_ => {
// TODO: this should be unreachable - safe to panic now?
// can't simply delete this arm because the non-unlikely operands are handled outside
@@ -7827,6 +7992,416 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
Ok(())
}
+fn decode_x87<T: Iterator<Item=u8>>(_decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, length: &mut u8) -> Result<(), DecodeError> {
+ #[allow(non_camel_case_types)]
+ enum OperandCodeX87 {
+ Est,
+ St_Est,
+ St_Ew,
+ St_Ed,
+ St_Md,
+ Md,
+ Ew,
+ Est_St,
+ Ed_St,
+ Md_St,
+ Ex87S,
+ Nothing,
+ }
+
+ // every x87 instruction is conditional on rrr bits
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ let r = (modrm >> 3) & 0b111;
+
+ let (opcode, x87_operands) = match operand_code {
+ OperandCode::x87_d8 => {
+ match r {
+ 0 => (Opcode::FADD, OperandCodeX87::St_Est),
+ 1 => (Opcode::FMUL, OperandCodeX87::St_Est),
+ 2 => (Opcode::FCOM, OperandCodeX87::St_Est),
+ 3 => (Opcode::FCOMP, OperandCodeX87::St_Est),
+ 4 => (Opcode::FSUB, OperandCodeX87::St_Est),
+ 5 => (Opcode::FSUBR, OperandCodeX87::St_Est),
+ 6 => (Opcode::FDIV, OperandCodeX87::St_Est),
+ 7 => (Opcode::FDIVR, OperandCodeX87::St_Est),
+ _ => { unreachable!("impossible r"); }
+ }
+ }
+ OperandCode::x87_d9 => {
+ match r {
+ 0 => (Opcode::FLD, OperandCodeX87::St_Est),
+ 1 => {
+ if modrm >= 0xc0 {
+ (Opcode::FXCH, OperandCodeX87::St_Est)
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ },
+ 2 => {
+ if modrm >= 0xc0 {
+ if modrm == 0xd0 {
+ (Opcode::FNOP, OperandCodeX87::Nothing)
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ } else {
+ (Opcode::FST, OperandCodeX87::Ed_St)
+ }
+ }
+ 3 => {
+ if modrm >= 0xc0 {
+ (Opcode::FSTPNCE, OperandCodeX87::Est_St)
+ } else {
+ (Opcode::FSTP, OperandCodeX87::Est_St)
+ }
+ },
+ 4 => {
+ if modrm >= 0xc0 {
+ match modrm {
+ 0xe0 => (Opcode::FCHS, OperandCodeX87::Nothing),
+ 0xe1 => (Opcode::FABS, OperandCodeX87::Nothing),
+ 0xe2 => { return Err(DecodeError::InvalidOpcode); },
+ 0xe3 => { return Err(DecodeError::InvalidOpcode); },
+ 0xe4 => (Opcode::FTST, OperandCodeX87::Nothing),
+ 0xe5 => (Opcode::FXAM, OperandCodeX87::Nothing),
+ 0xe6 => { return Err(DecodeError::InvalidOpcode); },
+ 0xe7 => { return Err(DecodeError::InvalidOpcode); },
+ _ => { unreachable!("invalid modrm"); }
+ }
+ } else {
+ (Opcode::FLDENV, OperandCodeX87::Ex87S) // x87 state
+ }
+ },
+ 5 => {
+ if modrm >= 0xc0 {
+ match modrm {
+ 0xe8 => (Opcode::FLD1, OperandCodeX87::Nothing),
+ 0xe9 => (Opcode::FLDL2T, OperandCodeX87::Nothing),
+ 0xea => (Opcode::FLDL2E, OperandCodeX87::Nothing),
+ 0xeb => (Opcode::FLDPI, OperandCodeX87::Nothing),
+ 0xec => (Opcode::FLDLG2, OperandCodeX87::Nothing),
+ 0xed => (Opcode::FLDLN2, OperandCodeX87::Nothing),
+ 0xee => (Opcode::FLDZ, OperandCodeX87::Nothing),
+ 0xef => (Opcode::Invalid, OperandCodeX87::Nothing),
+ _ => { unreachable!("invalid modrm"); }
+ }
+ } else {
+ (Opcode::FLDCW, OperandCodeX87::Ew)
+ }
+ }
+ 6 => {
+ if modrm >= 0xc0 {
+ match modrm {
+ 0xf0 => (Opcode::F2XM1, OperandCodeX87::Nothing),
+ 0xf1 => (Opcode::FYL2X, OperandCodeX87::Nothing),
+ 0xf2 => (Opcode::FPTAN, OperandCodeX87::Nothing),
+ 0xf3 => (Opcode::FPATAN, OperandCodeX87::Nothing),
+ 0xf4 => (Opcode::FXTRACT, OperandCodeX87::Nothing),
+ 0xf5 => (Opcode::FPREM1, OperandCodeX87::Nothing),
+ 0xf6 => (Opcode::FDECSTP, OperandCodeX87::Nothing),
+ 0xf7 => (Opcode::FINCSTP, OperandCodeX87::Nothing),
+ _ => { unreachable!("invalid modrm"); }
+ }
+ } else {
+ (Opcode::FNSTENV, OperandCodeX87::Ex87S) // x87 state
+ }
+ }
+ 7 => {
+ if modrm >= 0xc0 {
+ match modrm {
+ 0xf8 => (Opcode::FPREM, OperandCodeX87::Nothing),
+ 0xf9 => (Opcode::FYL2XP1, OperandCodeX87::Nothing),
+ 0xfa => (Opcode::FSQRT, OperandCodeX87::Nothing),
+ 0xfb => (Opcode::FSINCOS, OperandCodeX87::Nothing),
+ 0xfc => (Opcode::FRNDINT, OperandCodeX87::Nothing),
+ 0xfd => (Opcode::FSCALE, OperandCodeX87::Nothing),
+ 0xfe => (Opcode::FSIN, OperandCodeX87::Nothing),
+ 0xff => (Opcode::FCOS, OperandCodeX87::Nothing),
+ _ => { unreachable!("invalid modrm"); }
+ }
+ } else {
+ (Opcode::FNSTCW, OperandCodeX87::Ew)
+ }
+ }
+ _ => { unreachable!("impossible r"); }
+ }
+ }
+ OperandCode::x87_da => {
+ if modrm >= 0xc0 {
+ match r {
+ 0 => (Opcode::FCMOVB, OperandCodeX87::St_Est),
+ 1 => (Opcode::FCMOVE, OperandCodeX87::St_Est),
+ 2 => (Opcode::FCMOVBE, OperandCodeX87::St_Est),
+ 3 => (Opcode::FCMOVU, OperandCodeX87::St_Est),
+ _ => {
+ if modrm == 0xe9 {
+ (Opcode::FUCOMPP, OperandCodeX87::Nothing)
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ } else {
+ match r {
+ 0 => (Opcode::FIADD, OperandCodeX87::St_Md), // 0xd9d0 -> fnop
+ 1 => (Opcode::FIMUL, OperandCodeX87::St_Md),
+ 2 => (Opcode::FICOM, OperandCodeX87::St_Md), // FCMOVE
+ 3 => (Opcode::FICOMP, OperandCodeX87::St_Md), // FCMOVBE
+ 4 => (Opcode::FISUB, OperandCodeX87::St_Md),
+ 5 => (Opcode::FISUBR, OperandCodeX87::St_Md), // FUCOMPP
+ 6 => (Opcode::FIDIV, OperandCodeX87::St_Md),
+ 7 => (Opcode::FIDIVR, OperandCodeX87::St_Md),
+ _ => { unreachable!("impossible r"); }
+ }
+ }
+ }
+ OperandCode::x87_db => {
+ if modrm >= 0xc0 {
+ match r {
+ 0 => (Opcode::FCMOVNB, OperandCodeX87::St_Est),
+ 1 => (Opcode::FCMOVNE, OperandCodeX87::St_Est),
+ 2 => (Opcode::FCMOVNBE, OperandCodeX87::St_Est),
+ 3 => (Opcode::FCMOVNU, OperandCodeX87::St_Est),
+ 4 => {
+ match modrm {
+ 0xe0 => (Opcode::FENI8087_NOP, OperandCodeX87::Nothing),
+ 0xe1 => (Opcode::FDISI8087_NOP, OperandCodeX87::Nothing),
+ 0xe2 => (Opcode::FNCLEX, OperandCodeX87::Nothing),
+ 0xe3 => (Opcode::FNINIT, OperandCodeX87::Nothing),
+ 0xe4 => (Opcode::FSETPM287_NOP, OperandCodeX87::Nothing),
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ 5 => (Opcode::FUCOMI, OperandCodeX87::St_Est),
+ 6 => (Opcode::FCOMI, OperandCodeX87::St_Est),
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else {
+ match r {
+ 0 => (Opcode::FILD, OperandCodeX87::St_Md),
+ 1 => (Opcode::FISTTP, OperandCodeX87::Md_St),
+ 2 => (Opcode::FIST, OperandCodeX87::Md_St),
+ 3 => (Opcode::FISTP, OperandCodeX87::Md_St),
+ 5 => (Opcode::FLD, OperandCodeX87::St_Md), // 80bit
+ 7 => (Opcode::FSTP, OperandCodeX87::Md_St), // 80bit
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+
+ }
+ OperandCode::x87_dc => {
+ // mod=11 swaps operand order for some instructions
+ if modrm >= 0xc0 {
+ match r {
+ 0 => (Opcode::FADD, OperandCodeX87::Est_St),
+ 1 => (Opcode::FMUL, OperandCodeX87::Est_St),
+ 2 => (Opcode::FCOM, OperandCodeX87::St_Est),
+ 3 => (Opcode::FCOMP, OperandCodeX87::St_Est),
+ 4 => (Opcode::FSUBR, OperandCodeX87::Est_St),
+ 5 => (Opcode::FSUB, OperandCodeX87::Est_St),
+ 6 => (Opcode::FDIVR, OperandCodeX87::Est_St),
+ 7 => (Opcode::FDIV, OperandCodeX87::Est_St),
+ _ => { unreachable!("impossible r"); }
+ }
+ } else {
+ match r {
+ 0 => (Opcode::FADD, OperandCodeX87::St_Est),
+ 1 => (Opcode::FMUL, OperandCodeX87::St_Est),
+ 2 => (Opcode::FCOM, OperandCodeX87::St_Est),
+ 3 => (Opcode::FCOMP, OperandCodeX87::St_Est),
+ 4 => (Opcode::FSUB, OperandCodeX87::St_Est),
+ 5 => (Opcode::FSUBR, OperandCodeX87::St_Est),
+ 6 => (Opcode::FDIV, OperandCodeX87::St_Est),
+ 7 => (Opcode::FDIVR, OperandCodeX87::St_Est),
+ _ => { unreachable!("impossible r"); }
+ }
+ }
+ }
+ OperandCode::x87_dd => {
+ if modrm >= 0xc0 {
+ match r {
+ 0 => (Opcode::FFREE, OperandCodeX87::Est),
+ 1 => (Opcode::FXCH, OperandCodeX87::St_Est),
+ 2 => (Opcode::FST, OperandCodeX87::Est_St),
+ 3 => (Opcode::FSTP, OperandCodeX87::Est_St),
+ 4 => (Opcode::FUCOM, OperandCodeX87::St_Est),
+ 5 => (Opcode::FUCOMP, OperandCodeX87::St_Est),
+ 6 => (Opcode::Invalid, OperandCodeX87::Nothing),
+ 7 => (Opcode::Invalid, OperandCodeX87::Nothing),
+ _ => { unreachable!("impossible r"); }
+ }
+ } else {
+ match r {
+ 0 => (Opcode::FLD, OperandCodeX87::St_Est),
+ 1 => (Opcode::FISTTP, OperandCodeX87::Est_St),
+ 2 => (Opcode::FST, OperandCodeX87::Est_St),
+ 3 => (Opcode::FSTP, OperandCodeX87::Est_St),
+ 4 => (Opcode::FRSTOR, OperandCodeX87::Md), // TODO: m94/108byte
+ 5 => (Opcode::Invalid, OperandCodeX87::Nothing),
+ 6 => (Opcode::FNSAVE, OperandCodeX87::Est),
+ 7 => (Opcode::FNSTSW, OperandCodeX87::Ew),
+ _ => { unreachable!("impossible r"); }
+ }
+ }
+ }
+ OperandCode::x87_de => {
+ if modrm >= 0xc0 {
+ match r {
+ 0 => (Opcode::FADDP, OperandCodeX87::Est_St),
+ 1 => (Opcode::FMULP, OperandCodeX87::Est_St),
+ // undocumented in intel manual, argument order inferred from
+ // by xed and capstone. TODO: check amd manual.
+ 2 => (Opcode::FCOMP, OperandCodeX87::St_Est),
+ 3 => {
+ if modrm == 0xd9 {
+ (Opcode::FCOMPP, OperandCodeX87::Nothing)
+ } else {
+ return Err(DecodeError::InvalidOperand);
+ }
+ },
+ 4 => (Opcode::FSUBRP, OperandCodeX87::Est_St),
+ 5 => (Opcode::FSUBP, OperandCodeX87::Est_St),
+ 6 => (Opcode::FDIVRP, OperandCodeX87::Est_St),
+ 7 => (Opcode::FDIVP, OperandCodeX87::Est_St),
+ _ => { unreachable!("impossible r"); }
+ }
+ } else {
+ match r {
+ 0 => (Opcode::FIADD, OperandCodeX87::St_Ew),
+ 1 => (Opcode::FIMUL, OperandCodeX87::St_Ew),
+ 2 => (Opcode::FICOM, OperandCodeX87::St_Ew),
+ 3 => (Opcode::FICOMP, OperandCodeX87::St_Ew),
+ 4 => (Opcode::FISUB, OperandCodeX87::St_Ew),
+ 5 => (Opcode::FISUBR, OperandCodeX87::St_Ew),
+ 6 => (Opcode::FIDIV, OperandCodeX87::St_Ew),
+ 7 => (Opcode::FIDIVR, OperandCodeX87::St_Ew),
+ _ => { unreachable!("impossible r"); }
+ }
+ }
+ }
+ OperandCode::x87_df => {
+ if modrm >= 0xc0 {
+ match r {
+ 0 => (Opcode::FFREEP, OperandCodeX87::Est),
+ 1 => (Opcode::FXCH, OperandCodeX87::St_Est),
+ 2 => (Opcode::FSTP, OperandCodeX87::Est_St),
+ 3 => (Opcode::FSTP, OperandCodeX87::Est_St),
+ 4 => {
+ if modrm == 0xe0 {
+ (Opcode::FNSTSW, OperandCodeX87::Ew)
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ },
+ 5 => (Opcode::FUCOMIP, OperandCodeX87::St_Est),
+ 6 => (Opcode::FCOMIP, OperandCodeX87::St_Est),
+ 7 => {
+ return Err(DecodeError::InvalidOpcode);
+ },
+ _ => { unreachable!("impossible r"); }
+ }
+ } else {
+ match r {
+ 0 => (Opcode::FILD, OperandCodeX87::St_Est),
+ 1 => (Opcode::FISTTP, OperandCodeX87::Est_St),
+ 2 => (Opcode::FIST, OperandCodeX87::Est_St),
+ 3 => (Opcode::FISTP, OperandCodeX87::Est_St),
+ 4 => (Opcode::FBLD, OperandCodeX87::St_Est),
+ 5 => (Opcode::FILD, OperandCodeX87::St_Est),
+ 6 => (Opcode::FBSTP, OperandCodeX87::Est_St),
+ 7 => (Opcode::FISTP, OperandCodeX87::Est_St),
+ _ => { unreachable!("impossible r"); }
+ }
+ }
+ }
+ other => {
+ panic!("invalid x87 operand dispatch, operand code is {:?}", other);
+ }
+ };
+ instruction.opcode = opcode;
+ // TODO: support 80-bit operands
+ match x87_operands {
+ OperandCodeX87::Est => {
+ instruction.operands[0] = read_E_st(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.operand_count = 1;
+ }
+ OperandCodeX87::St_Est => {
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.modrm_rrr = RegSpec::st(0);
+ instruction.operands[1] = read_E_st(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.operand_count = 2;
+ }
+ OperandCodeX87::St_Ew => {
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.modrm_rrr = RegSpec::st(0);
+ instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?;
+ instruction.operand_count = 2;
+ }
+ OperandCodeX87::St_Ed => {
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.modrm_rrr = RegSpec::st(0);
+ instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?;
+ instruction.operand_count = 2;
+ }
+ OperandCodeX87::St_Md => {
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.modrm_rrr = RegSpec::st(0);
+ instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?;
+ if instruction.operands[1] == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.operand_count = 2;
+ }
+ OperandCodeX87::Md => {
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?;
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.operand_count = 1;
+ }
+ OperandCodeX87::Ew => {
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?;
+ instruction.operand_count = 1;
+ }
+ OperandCodeX87::Est_St => {
+ instruction.operands[0] = read_E_st(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.modrm_rrr = RegSpec::st(0);
+ instruction.operand_count = 2;
+ }
+ OperandCodeX87::Ed_St => {
+ instruction.operands[0] = read_E_st(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.modrm_rrr = RegSpec::st(0);
+ instruction.operand_count = 2;
+ }
+ OperandCodeX87::Md_St => {
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?;
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.modrm_rrr = RegSpec::st(0);
+ instruction.operand_count = 2;
+ }
+ OperandCodeX87::Ex87S => {
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?;
+ instruction.operand_count = 1;
+ }
+ OperandCodeX87::Nothing => {
+ instruction.operand_count = 0;
+ },
+ }
+
+ Ok(())
+}
+
fn decode_one<'b, T: IntoIterator<Item=u8>>(decoder: &InstDecoder, bytes: T, instr: &'b mut Instruction) -> Result<(), DecodeError> {
instr.operands = [
OperandSpec::Nothing,
diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs
index a9a894a..8f041e9 100644
--- a/test/long_mode/mod.rs
+++ b/test/long_mode/mod.rs
@@ -113,6 +113,19 @@ fn test_modrm_decode() {
#[test]
fn test_mmx() {
+ test_display(&[0x4f, 0x0f, 0xf7, 0xc1], "maskmovq mm0, mm1");
+ test_display(&[0x0f, 0xf7, 0xc1], "maskmovq mm0, mm1");
+ test_invalid(&[0x0f, 0xf7, 0x01]);
+
+ test_display(&[0x4f, 0x0f, 0xe7, 0x03], "movntq [r11], mm0");
+ test_display(&[0x0f, 0xe7, 0x03], "movntq [rbx], mm0");
+ test_invalid(&[0x0f, 0xe7, 0xc3]);
+
+ test_display(&[0x4f, 0x0f, 0xc3, 0x03], "movnti [r11], r8");
+ test_display(&[0x66, 0x0f, 0xc3, 0x03], "movnti [rbx], eax");
+ test_display(&[0x0f, 0xc3, 0x03], "movnti [rbx], eax");
+ test_invalid(&[0x0f, 0xc3, 0xc3]);
+
test_display(&[0x4f, 0x0f, 0x7e, 0xcf], "movd r15, mm1");
test_display(&[0x41, 0x0f, 0x7e, 0xcf], "movd r15d, mm1");
test_display(&[0x4f, 0x0f, 0x7f, 0xcf], "movq mm7, mm1");
@@ -1061,9 +1074,6 @@ fn test_prefixes() {
test_display(&[0x66, 0x41, 0x31, 0xc0], "xor r8w, ax");
test_display(&[0x66, 0x41, 0x32, 0xc0], "xor al, r8b");
test_display(&[0x40, 0x32, 0xc5], "xor al, bpl");
-
- // test that WAIT doesn't blow up, at least...
- assert_eq!(InstDecoder::default().decode([0x9b, 0xf8].iter().cloned()).err(), Some(DecodeError::IncompleteDecoder));
}
#[test]
@@ -1173,9 +1183,16 @@ fn test_bitwise() {
#[test]
fn test_misc() {
- // TODO
-// test_display(&[0xf2, 0x0f, 0x38, 0xf0, 0xc1], "crc32 eax, cl");
-// test_display(&[0xf2, 0x0f, 0x38, 0xf1, 0xc1], "crc32 eax, ecx");
+ test_display(&[0xc8, 0x01, 0x02, 0x03], "enter 0x201, 0x3");
+ test_display(&[0xc9], "leave");
+ test_display(&[0xca, 0x12, 0x34], "retf 0x3412");
+ test_display(&[0xcb], "retf");
+ test_display(&[0x66, 0xcf], "iret");
+ test_display(&[0xcf], "iretd");
+ test_display(&[0x48, 0xcf], "iretq");
+ test_display(&[0x66, 0x4f, 0xcf], "iretq");
+ test_display(&[0xf2, 0x0f, 0x38, 0xf0, 0xc1], "crc32 eax, cl");
+ test_display(&[0xf2, 0x0f, 0x38, 0xf1, 0xc1], "crc32 eax, ecx");
test_display(&[0xfe, 0x00], "inc [rax]"); // TODO: inc byte [rax]
test_display(&[0xfe, 0x08], "dec [rax]"); // TODO: dec byte [rax]
test_display(&[0xff, 0x00], "inc [rax]"); // TODO: inc dword [rax]
@@ -1468,6 +1485,10 @@ fn prefixed_0f() {
test_display(&[0x66, 0x45, 0x0f, 0xa4, 0xcf, 0x11], "shld r15w, r9w, 0x11");
test_display(&[0x0f, 0xa5, 0xc0], "shld eax, eax, cl");
test_display(&[0x0f, 0xa5, 0xc9], "shld ecx, ecx, cl");
+ test_display(&[0x0f, 0xac, 0xc0, 0x11], "shrd eax, eax, 0x11");
+ test_display(&[0x66, 0x0f, 0xac, 0xcf, 0x11], "shrd di, cx, 0x11");
+ test_display(&[0x66, 0x45, 0x0f, 0xac, 0xcf, 0x11], "shrd r15w, r9w, 0x11");
+ test_display(&[0x0f, 0xad, 0xc9], "shrd ecx, ecx, cl");
}
#[test]
@@ -1526,6 +1547,12 @@ fn test_svm() {
test_display(&[0x0f, 0x01, 0xda], "vmload rax");
test_display(&[0x0f, 0x01, 0xd9], "vmmcall");
test_display(&[0x0f, 0x01, 0xd8], "vmrun rax");
+ test_display(&[0x0f, 0x78, 0xc4], "vmread rsp, rax");
+ test_display(&[0x0f, 0x79, 0xc5], "vmwrite rax, rbp");
+ test_display(&[0x0f, 0x78, 0x0b], "vmread [rbx], rcx");
+ test_invalid(&[0x66, 0x0f, 0x78, 0x03]);
+ test_display(&[0x0f, 0x79, 0x0b], "vmwrite rcx, [rbx]");
+ test_invalid(&[0x66, 0x0f, 0x79, 0x03]);
}
#[test]
@@ -1591,3 +1618,383 @@ fn test_cmpxchg8b() {
test_display(&[0x0f, 0xc7, 0x0f], "cmpxchg8b [rdi]");
test_display(&[0x4f, 0x0f, 0xc7, 0x0f], "cmpxchg16b [r15]");
}
+
+#[test]
+fn test_x87() {
+// test_display(&[0xd8, 0x03], "fadd st, dword ptr [rbx]");
+ test_display(&[0xd8, 0x03], "fadd st(0), [rbx]");
+// test_display(&[0xd8, 0x0b], "fmul st, dword ptr [rbx]");
+ test_display(&[0xd8, 0x0b], "fmul st(0), [rbx]");
+// test_display(&[0xd8, 0x13], "fcom st, dword ptr [rbx]");
+ test_display(&[0xd8, 0x13], "fcom st(0), [rbx]");
+// test_display(&[0xd8, 0x1b], "fcomp st, dword ptr [rbx]");
+ test_display(&[0xd8, 0x1b], "fcomp st(0), [rbx]");
+// test_display(&[0xd8, 0x23], "fsub st, dword ptr [rbx]");
+ test_display(&[0xd8, 0x23], "fsub st(0), [rbx]");
+// test_display(&[0xd8, 0x2b], "fsubr st, dword ptr [rbx]");
+ test_display(&[0xd8, 0x2b], "fsubr st(0), [rbx]");
+// test_display(&[0xd8, 0x33], "fdiv st, dword ptr [rbx]");
+ test_display(&[0xd8, 0x33], "fdiv st(0), [rbx]");
+// test_display(&[0xd8, 0x3b], "fdivr st, dword ptr [rbx]");
+ test_display(&[0xd8, 0x3b], "fdivr st(0), [rbx]");
+// test_display(&[0xd8, 0xc3], "fadd st, st(3)");
+ test_display(&[0xd8, 0xc3], "fadd st(0), st(3)");
+// test_display(&[0xd8, 0xcb], "fmul st, st(3)");
+ test_display(&[0xd8, 0xcb], "fmul st(0), st(3)");
+// test_display(&[0xd8, 0xd3], "fcom st, st(3)");
+ test_display(&[0xd8, 0xd3], "fcom st(0), st(3)");
+// test_display(&[0xd8, 0xdb], "fcomp st, st(3)");
+ test_display(&[0xd8, 0xdb], "fcomp st(0), st(3)");
+// test_display(&[0xd8, 0xe3], "fsub st, st(3)");
+ test_display(&[0xd8, 0xe3], "fsub st(0), st(3)");
+// test_display(&[0xd8, 0xeb], "fsubr st, st(3)");
+ test_display(&[0xd8, 0xeb], "fsubr st(0), st(3)");
+// test_display(&[0xd8, 0xf3], "fdiv st, st(3)");
+ test_display(&[0xd8, 0xf3], "fdiv st(0), st(3)");
+// test_display(&[0xd8, 0xfb], "fdivr st, st(3)");
+ test_display(&[0xd8, 0xfb], "fdivr st(0), st(3)");
+// test_display(&[0xd9, 0x03], "fld st, dword ptr [rbx]");
+ test_display(&[0xd9, 0x03], "fld st(0), [rbx]");
+ test_invalid(&[0xd9, 0x08]);
+ test_invalid(&[0xd9, 0x09]);
+ test_invalid(&[0xd9, 0x0a]);
+ test_invalid(&[0xd9, 0x0b]);
+ test_invalid(&[0xd9, 0x0c]);
+ test_invalid(&[0xd9, 0x0d]);
+ test_invalid(&[0xd9, 0x0e]);
+ test_invalid(&[0xd9, 0x0f]);
+// test_display(&[0xd9, 0x13], "fst dword ptr [rbx], st");
+ test_display(&[0xd9, 0x13], "fst [rbx], st(0)");
+// test_display(&[0xd9, 0x1b], "fstp dword ptr [rbx], st");
+ test_display(&[0xd9, 0x1b], "fstp [rbx], st(0)");
+// test_display(&[0xd9, 0x23], "fldenv ptr [rbx]");
+ test_display(&[0xd9, 0x23], "fldenv [rbx]");
+// test_display(&[0xd9, 0x2b], "fldcw word ptr [rbx]");
+ test_display(&[0xd9, 0x2b], "fldcw [rbx]");
+// test_display(&[0xd9, 0x33], "fnstenv ptr [rbx]");
+ test_display(&[0xd9, 0x33], "fnstenv [rbx]");
+// test_display(&[0xd9, 0x3b], "fnstcw word ptr [rbx]");
+ test_display(&[0xd9, 0x3b], "fnstcw [rbx]");
+// test_display(&[0xd9, 0xc3], "fld st, st(3)");
+ test_display(&[0xd9, 0xc3], "fld st(0), st(3)");
+// test_display(&[0xd9, 0xcb], "fxch st, st(3)");
+ test_display(&[0xd9, 0xcb], "fxch st(0), st(3)");
+ test_display(&[0xd9, 0xd0], "fnop");
+ test_invalid(&[0xd9, 0xd1]);
+ test_invalid(&[0xd9, 0xd2]);
+ test_invalid(&[0xd9, 0xd3]);
+ test_invalid(&[0xd9, 0xd4]);
+ test_invalid(&[0xd9, 0xd5]);
+ test_invalid(&[0xd9, 0xd6]);
+ test_invalid(&[0xd9, 0xd7]);
+ // undocumented save for intel xed
+// test_display(&[0xd9, 0xdb], "fstpnce st(3), st");
+ test_display(&[0xd9, 0xdb], "fstpnce st(3), st(0)");
+ test_display(&[0xd9, 0xe0], "fchs");
+ test_display(&[0xd9, 0xe1], "fabs");
+ test_invalid(&[0xd9, 0xe2]);
+ test_invalid(&[0xd9, 0xe3]);
+ test_display(&[0xd9, 0xe4], "ftst");
+ test_display(&[0xd9, 0xe5], "fxam");
+ test_invalid(&[0xd9, 0xe6]);
+ test_invalid(&[0xd9, 0xe7]);
+ test_display(&[0xd9, 0xe8], "fld1");
+ test_display(&[0xd9, 0xe9], "fldl2t");
+ test_display(&[0xd9, 0xea], "fldl2e");
+ test_display(&[0xd9, 0xeb], "fldpi");
+ test_display(&[0xd9, 0xec], "fldlg2");
+ test_display(&[0xd9, 0xed], "fldln2");
+ test_display(&[0xd9, 0xee], "fldz");
+ test_invalid(&[0xd9, 0xef]);
+ test_display(&[0xd9, 0xf0], "f2xm1");
+ test_display(&[0xd9, 0xf1], "fyl2x");
+ test_display(&[0xd9, 0xf2], "fptan");
+ test_display(&[0xd9, 0xf3], "fpatan");
+ test_display(&[0xd9, 0xf4], "fxtract");
+ test_display(&[0xd9, 0xf5], "fprem1");
+ test_display(&[0xd9, 0xf6], "fdecstp");
+ test_display(&[0xd9, 0xf7], "fincstp");
+ test_display(&[0xd9, 0xf8], "fprem");
+ test_display(&[0xd9, 0xf9], "fyl2xp1");
+ test_display(&[0xd9, 0xfa], "fsqrt");
+ test_display(&[0xd9, 0xfb], "fsincos");
+ test_display(&[0xd9, 0xfc], "frndint");
+ test_display(&[0xd9, 0xfd], "fscale");
+ test_display(&[0xd9, 0xfe], "fsin");
+ test_display(&[0xd9, 0xff], "fcos");
+// test_display(&[0xda, 0x03], "fiadd st, dword ptr [rbx]");
+ test_display(&[0xda, 0x03], "fiadd st(0), [rbx]");
+// test_display(&[0xda, 0x0b], "fimul st, dword ptr [rbx]");
+ test_display(&[0xda, 0x0b], "fimul st(0), [rbx]");
+// test_display(&[0xda, 0x13], "ficom st, dword ptr [rbx]");
+ test_display(&[0xda, 0x13], "ficom st(0), [rbx]");
+// test_display(&[0xda, 0x1b], "ficomp st, dword ptr [rbx]");
+ test_display(&[0xda, 0x1b], "ficomp st(0), [rbx]");
+// test_display(&[0xda, 0x23], "fisub st, dword ptr [rbx]");
+ test_display(&[0xda, 0x23], "fisub st(0), [rbx]");
+// test_display(&[0xda, 0x2b], "fisubr st, dword ptr [rbx]");
+ test_display(&[0xda, 0x2b], "fisubr st(0), [rbx]");
+// test_display(&[0xda, 0x33], "fidiv st, dword ptr [rbx]");
+ test_display(&[0xda, 0x33], "fidiv st(0), [rbx]");
+// test_display(&[0xda, 0x3b], "fidivr st, dword ptr [rbx]");
+ test_display(&[0xda, 0x3b], "fidivr st(0), [rbx]");
+// test_display(&[0xda, 0xc3], "fcmovb st, st(3)");
+ test_display(&[0xda, 0xc3], "fcmovb st(0), st(3)");
+// test_display(&[0xda, 0xcb], "fcmove st, st(3)");
+ test_display(&[0xda, 0xcb], "fcmove st(0), st(3)");
+// test_display(&[0xda, 0xd3], "fcmovbe st, st(3)");
+ test_display(&[0xda, 0xd3], "fcmovbe st(0), st(3)");
+// test_display(&[0xda, 0xdb], "fcmovu st, st(3)");
+ test_display(&[0xda, 0xdb], "fcmovu st(0), st(3)");
+ test_invalid(&[0xda, 0xe0]);
+ test_invalid(&[0xda, 0xe1]);
+ test_invalid(&[0xda, 0xe2]);
+ test_invalid(&[0xda, 0xe3]);
+ test_invalid(&[0xda, 0xe4]);
+ test_invalid(&[0xda, 0xe5]);
+ test_invalid(&[0xda, 0xe6]);
+ test_invalid(&[0xda, 0xe7]);
+ test_invalid(&[0xda, 0xe8]);
+ test_display(&[0xda, 0xe9], "fucompp");
+ test_invalid(&[0xda, 0xea]);
+ test_invalid(&[0xda, 0xeb]);
+ test_invalid(&[0xda, 0xec]);
+ test_invalid(&[0xda, 0xed]);
+ test_invalid(&[0xda, 0xee]);
+ test_invalid(&[0xda, 0xef]);
+ test_invalid(&[0xda, 0xf0]);
+ test_invalid(&[0xda, 0xf1]);
+ test_invalid(&[0xda, 0xf2]);
+ test_invalid(&[0xda, 0xf3]);
+ test_invalid(&[0xda, 0xf4]);
+ test_invalid(&[0xda, 0xf5]);
+ test_invalid(&[0xda, 0xf6]);
+ test_invalid(&[0xda, 0xf7]);
+ test_invalid(&[0xda, 0xf8]);
+ test_invalid(&[0xda, 0xf9]);
+ test_invalid(&[0xda, 0xfa]);
+ test_invalid(&[0xda, 0xfb]);
+ test_invalid(&[0xda, 0xfc]);
+ test_invalid(&[0xda, 0xfd]);
+ test_invalid(&[0xda, 0xfe]);
+ test_invalid(&[0xda, 0xff]);
+// test_display(&[0xdb, 0x03], "fild st, dword ptr [rbx]");
+ test_display(&[0xdb, 0x03], "fild st(0), [rbx]");
+// test_display(&[0xdb, 0x0b], "fisttp dword ptr [rbx], st");
+ test_display(&[0xdb, 0x0b], "fisttp [rbx], st(0)");
+// test_display(&[0xdb, 0x13], "fist dword ptr [rbx], st");
+ test_display(&[0xdb, 0x13], "fist [rbx], st(0)");
+// test_display(&[0xdb, 0x1b], "fistp dword ptr [rbx], st");
+ test_display(&[0xdb, 0x1b], "fistp [rbx], st(0)");
+ test_invalid(&[0xdb, 0x20]);
+ test_invalid(&[0xdb, 0x21]);
+ test_invalid(&[0xdb, 0x22]);
+ test_invalid(&[0xdb, 0x23]);
+ test_invalid(&[0xdb, 0x24]);
+ test_invalid(&[0xdb, 0x25]);
+ test_invalid(&[0xdb, 0x26]);
+ test_invalid(&[0xdb, 0x27]);
+// test_display(&[0xdb, 0x2b], "fld st, ptr [rbx]");
+ test_display(&[0xdb, 0x2b], "fld st(0), [rbx]");
+ test_invalid(&[0xdb, 0x30]);
+ test_invalid(&[0xdb, 0x31]);
+ test_invalid(&[0xdb, 0x32]);
+ test_invalid(&[0xdb, 0x33]);
+ test_invalid(&[0xdb, 0x34]);
+ test_invalid(&[0xdb, 0x35]);
+ test_invalid(&[0xdb, 0x36]);
+ test_invalid(&[0xdb, 0x37]);
+// test_display(&[0xdb, 0x3b], "fstp ptr [rbx], st");
+ test_display(&[0xdb, 0x3b], "fstp [rbx], st(0)");
+// test_display(&[0xdb, 0xc3], "fcmovnb st, st(3)");
+ test_display(&[0xdb, 0xc3], "fcmovnb st(0), st(3)");
+// test_display(&[0xdb, 0xcb], "fcmovne st, st(3)");
+ test_display(&[0xdb, 0xcb], "fcmovne st(0), st(3)");
+// test_display(&[0xdb, 0xd3], "fcmovnbe st, st(3)");
+ test_display(&[0xdb, 0xd3], "fcmovnbe st(0), st(3)");
+// test_display(&[0xdb, 0xdb], "fcmovnu st, st(3)");
+ test_display(&[0xdb, 0xdb], "fcmovnu st(0), st(3)");
+ test_display(&[0xdb, 0xe0], "feni8087_nop");
+ test_display(&[0xdb, 0xe1], "fdisi8087_nop");
+ test_display(&[0xdb, 0xe2], "fnclex");
+ test_display(&[0xdb, 0xe3], "fninit");
+ test_display(&[0xdb, 0xe4], "fsetpm287_nop");
+ test_invalid(&[0xdb, 0xe5]);
+ test_invalid(&[0xdb, 0xe6]);
+ test_invalid(&[0xdb, 0xe7]);
+// test_display(&[0xdb, 0xeb], "fucomi st, st(3)");
+ test_display(&[0xdb, 0xeb], "fucomi st(0), st(3)");
+// test_display(&[0xdb, 0xf3], "fcomi st, st(3)");
+ test_display(&[0xdb, 0xf3], "fcomi st(0), st(3)");
+ test_invalid(&[0xdb, 0xf8]);
+ test_invalid(&[0xdb, 0xf9]);
+ test_invalid(&[0xdb, 0xfa]);
+ test_invalid(&[0xdb, 0xfb]);
+ test_invalid(&[0xdb, 0xfc]);
+ test_invalid(&[0xdb, 0xfd]);
+ test_invalid(&[0xdb, 0xfe]);
+ test_invalid(&[0xdb, 0xff]);
+// test_display(&[0xdc, 0x03], "fadd st, qword ptr [rbx]");
+ test_display(&[0xdc, 0x03], "fadd st(0), [rbx]");
+// test_display(&[0xdc, 0x0b], "fmul st, qword ptr [rbx]");
+ test_display(&[0xdc, 0x0b], "fmul st(0), [rbx]");
+// test_display(&[0xdc, 0x13], "fcom st, qword ptr [rbx]");
+ test_display(&[0xdc, 0x13], "fcom st(0), [rbx]");
+// test_display(&[0xdc, 0x1b], "fcomp st, qword ptr [rbx]");
+ test_display(&[0xdc, 0x1b], "fcomp st(0), [rbx]");
+// test_display(&[0xdc, 0x23], "fsub st, qword ptr [rbx]");
+ test_display(&[0xdc, 0x23], "fsub st(0), [rbx]");
+// test_display(&[0xdc, 0x2b], "fsubr st, qword ptr [rbx]");
+ test_display(&[0xdc, 0x2b], "fsubr st(0), [rbx]");
+// test_display(&[0xdc, 0x33], "fdiv st, qword ptr [rbx]");
+ test_display(&[0xdc, 0x33], "fdiv st(0), [rbx]");
+// test_display(&[0xdc, 0x3b], "fdivr st, qword ptr [rbx]");
+ test_display(&[0xdc, 0x3b], "fdivr st(0), [rbx]");
+// test_display(&[0xdc, 0xc3], "fadd st(3), st");
+ test_display(&[0xdc, 0xc3], "fadd st(3), st(0)");
+// test_display(&[0xdc, 0xcb], "fmul st(3), st");
+ test_display(&[0xdc, 0xcb], "fmul st(3), st(0)");
+// test_display(&[0xdc, 0xd3], "fcom st, st(3)");
+ test_display(&[0xdc, 0xd3], "fcom st(0), st(3)");
+// test_display(&[0xdc, 0xdb], "fcomp st, st(3)");
+ test_display(&[0xdc, 0xdb], "fcomp st(0), st(3)");
+// test_display(&[0xdc, 0xe3], "fsubr st(3), st");
+ test_display(&[0xdc, 0xe3], "fsubr st(3), st(0)");
+// test_display(&[0xdc, 0xeb], "fsub st(3), st");
+ test_display(&[0xdc, 0xeb], "fsub st(3), st(0)");
+// test_display(&[0xdc, 0xf3], "fdivr st(3), st");
+ test_display(&[0xdc, 0xf3], "fdivr st(3), st(0)");
+// test_display(&[0xdc, 0xfb], "fdiv st(3), st");
+ test_display(&[0xdc, 0xfb], "fdiv st(3), st(0)");
+// test_display(&[0xdd, 0x03], "fld st, qword ptr [rbx]");
+ test_display(&[0xdd, 0x03], "fld st(0), [rbx]");
+// test_display(&[0xdd, 0x0b], "fisttp qword ptr [rbx], st");
+ test_display(&[0xdd, 0x0b], "fisttp [rbx], st(0)");
+// test_display(&[0xdd, 0x13], "fst qword ptr [rbx], st");
+ test_display(&[0xdd, 0x13], "fst [rbx], st(0)");
+// test_display(&[0xdd, 0x1b], "fstp qword ptr [rbx], st");
+ test_display(&[0xdd, 0x1b], "fstp [rbx], st(0)");
+// test_display(&[0xdd, 0x23], "frstor ptr [rbx]");
+ test_display(&[0xdd, 0x23], "frstor [rbx]");
+ test_invalid(&[0xdd, 0x28]);
+ test_invalid(&[0xdd, 0x29]);
+ test_invalid(&[0xdd, 0x2a]);
+ test_invalid(&[0xdd, 0x2b]);
+ test_invalid(&[0xdd, 0x2c]);
+ test_invalid(&[0xdd, 0x2d]);
+ test_invalid(&[0xdd, 0x2e]);
+ test_invalid(&[0xdd, 0x2f]);
+// test_display(&[0xdd, 0x33], "fnsave ptr [rbx]");
+ test_display(&[0xdd, 0x33], "fnsave [rbx]");
+// test_display(&[0xdd, 0x3b], "fnstsw word ptr [rbx]");
+ test_display(&[0xdd, 0x3b], "fnstsw [rbx]");
+ test_display(&[0xdd, 0xc3], "ffree st(3)");
+// test_display(&[0xdd, 0xcb], "fxch st, st(3)");
+ test_display(&[0xdd, 0xcb], "fxch st(0), st(3)");
+// test_display(&[0xdd, 0xd3], "fst st(3), st");
+ test_display(&[0xdd, 0xd3], "fst st(3), st(0)");
+// test_display(&[0xdd, 0xdb], "fstp st(3), st");
+ test_display(&[0xdd, 0xdb], "fstp st(3), st(0)");
+// test_display(&[0xdd, 0xe3], "fucom st, st(3)");
+ test_display(&[0xdd, 0xe3], "fucom st(0), st(3)");
+// test_display(&[0xdd, 0xeb], "fucomp st, st(3)");
+ test_display(&[0xdd, 0xeb], "fucomp st(0), st(3)");
+ test_invalid(&[0xdd, 0xf0]);
+ test_invalid(&[0xdd, 0xf1]);
+ test_invalid(&[0xdd, 0xf2]);
+ test_invalid(&[0xdd, 0xf3]);
+ test_invalid(&[0xdd, 0xf4]);
+ test_invalid(&[0xdd, 0xf5]);
+ test_invalid(&[0xdd, 0xf6]);
+ test_invalid(&[0xdd, 0xf7]);
+ test_invalid(&[0xdd, 0xf8]);
+ test_invalid(&[0xdd, 0xf9]);
+ test_invalid(&[0xdd, 0xfa]);
+ test_invalid(&[0xdd, 0xfb]);
+ test_invalid(&[0xdd, 0xfc]);
+ test_invalid(&[0xdd, 0xfd]);
+ test_invalid(&[0xdd, 0xfe]);
+ test_invalid(&[0xdd, 0xff]);
+// test_display(&[0xde, 0x03], "fiadd st, word ptr [rbx]");
+ test_display(&[0xde, 0x03], "fiadd st(0), [rbx]");
+// test_display(&[0xde, 0x0b], "fimul st, word ptr [rbx]");
+ test_display(&[0xde, 0x0b], "fimul st(0), [rbx]");
+// test_display(&[0xde, 0x13], "ficom st, word ptr [rbx]");
+ test_display(&[0xde, 0x13], "ficom st(0), [rbx]");
+// test_display(&[0xde, 0x1b], "ficomp st, word ptr [rbx]");
+ test_display(&[0xde, 0x1b], "ficomp st(0), [rbx]");
+// test_display(&[0xde, 0x23], "fisub st, word ptr [rbx]");
+ test_display(&[0xde, 0x23], "fisub st(0), [rbx]");
+// test_display(&[0xde, 0x2b], "fisubr st, word ptr [rbx]");
+ test_display(&[0xde, 0x2b], "fisubr st(0), [rbx]");
+// test_display(&[0xde, 0x33], "fidiv st, word ptr [rbx]");
+ test_display(&[0xde, 0x33], "fidiv st(0), [rbx]");
+// test_display(&[0xde, 0x3b], "fidivr st, word ptr [rbx]");
+ test_display(&[0xde, 0x3b], "fidivr st(0), [rbx]");
+// test_display(&[0xde, 0xc3], "faddp st(3), st");
+ test_display(&[0xde, 0xc3], "faddp st(3), st(0)");
+// test_display(&[0xde, 0xcb], "fmulp st(3), st");
+ test_display(&[0xde, 0xcb], "fmulp st(3), st(0)");
+// test_display(&[0xde, 0xd3], "fcomp st, st(3)");
+ test_display(&[0xde, 0xd3], "fcomp st(0), st(3)");
+ test_invalid(&[0xde, 0xd8]);
+ test_display(&[0xde, 0xd9], "fcompp");
+ test_invalid(&[0xde, 0xda]);
+ test_invalid(&[0xde, 0xdb]);
+ test_invalid(&[0xde, 0xdc]);
+ test_invalid(&[0xde, 0xdd]);
+ test_invalid(&[0xde, 0xde]);
+ test_invalid(&[0xde, 0xdf]);
+// test_display(&[0xde, 0xe3], "fsubrp st(3), st");
+ test_display(&[0xde, 0xe3], "fsubrp st(3), st(0)");
+// test_display(&[0xde, 0xeb], "fsubp st(3), st");
+ test_display(&[0xde, 0xeb], "fsubp st(3), st(0)");
+// test_display(&[0xde, 0xf3], "fdivrp st(3), st");
+ test_display(&[0xde, 0xf3], "fdivrp st(3), st(0)");
+// test_display(&[0xde, 0xfb], "fdivp st(3), st");
+ test_display(&[0xde, 0xfb], "fdivp st(3), st(0)");
+// test_display(&[0xdf, 0x03], "fild st, word ptr [rbx]");
+ test_display(&[0xdf, 0x03], "fild st(0), [rbx]");
+// test_display(&[0xdf, 0x0b], "fisttp word ptr [rbx], st");
+ test_display(&[0xdf, 0x0b], "fisttp [rbx], st(0)");
+// test_display(&[0xdf, 0x13], "fist word ptr [rbx], st");
+ test_display(&[0xdf, 0x13], "fist [rbx], st(0)");
+// test_display(&[0xdf, 0x1b], "fistp word ptr [rbx], st");
+ test_display(&[0xdf, 0x1b], "fistp [rbx], st(0)");
+// test_display(&[0xdf, 0x23], "fbld st, ptr [rbx]");
+ test_display(&[0xdf, 0x23], "fbld st(0), [rbx]");
+// test_display(&[0xdf, 0x2b], "fild st, qword ptr [rbx]");
+ test_display(&[0xdf, 0x2b], "fild st(0), [rbx]");
+// test_display(&[0xdf, 0x33], "fbstp ptr [rbx], st");
+ test_display(&[0xdf, 0x33], "fbstp [rbx], st(0)");
+// test_display(&[0xdf, 0x3b], "fistp qword ptr [rbx], st");
+ test_display(&[0xdf, 0x3b], "fistp [rbx], st(0)");
+// test_display(&[0xdf, 0xc3], "ffreep st(3)");
+ test_display(&[0xdf, 0xc3], "ffreep st(3)");
+// test_display(&[0xdf, 0xcb], "fxch st, st(3)");
+ test_display(&[0xdf, 0xcb], "fxch st(0), st(3)");
+// test_display(&[0xdf, 0xd3], "fstp st(3), st");
+ test_display(&[0xdf, 0xd3], "fstp st(3), st(0)");
+// test_display(&[0xdf, 0xdb], "fstp st(3), st");
+ test_display(&[0xdf, 0xdb], "fstp st(3), st(0)");
+ test_display(&[0xdf, 0xe0], "fnstsw ax");
+ test_invalid(&[0xdf, 0xe1]);
+ test_invalid(&[0xdf, 0xe2]);
+ test_invalid(&[0xdf, 0xe3]);
+ test_invalid(&[0xdf, 0xe4]);
+ test_invalid(&[0xdf, 0xe5]);
+ test_invalid(&[0xdf, 0xe6]);
+ test_invalid(&[0xdf, 0xe7]);
+// test_display(&[0xdf, 0xeb], "fucomip st, st(3)");
+ test_display(&[0xdf, 0xeb], "fucomip st(0), st(3)");
+// test_display(&[0xdf, 0xf3], "fcomip st, st(3)");
+ test_display(&[0xdf, 0xf3], "fcomip st(0), st(3)");
+ test_invalid(&[0xdf, 0xf8]);
+ test_invalid(&[0xdf, 0xf9]);
+ test_invalid(&[0xdf, 0xfa]);
+ test_invalid(&[0xdf, 0xfb]);
+ test_invalid(&[0xdf, 0xfc]);
+ test_invalid(&[0xdf, 0xfd]);
+ test_invalid(&[0xdf, 0xfe]);
+ test_invalid(&[0xdf, 0xff]);
+}