From 7c09cd975b9251f633a3adb0b6149ea98d3dcee7 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 2 Aug 2020 18:40:15 -0700 Subject: x87 support, plus several other missing instructions --- CHANGELOG | 12 + src/long_mode/display.rs | 191 ++++++++++++ src/long_mode/mod.rs | 753 +++++++++++++++++++++++++++++++++++++++++------ test/long_mode/mod.rs | 419 +++++++++++++++++++++++++- 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 > Colorize { write!(out, "{}", colors.arithmetic_op(self)) } Opcode::POPF | Opcode::PUSHF | @@ -1476,6 +1608,10 @@ impl > Colorize { 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 > Colorize { write!(out, "{}", colors.stop_op(self)) } Opcode::CALL | @@ -1780,7 +1918,34 @@ impl > Colorize> Colorize> Colorize> Colorize 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>(bytes_iter: &mut T, instr: &mut Instru } } #[allow(non_snake_case)] +pub(self) fn read_E_st>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result { + 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>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result { if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, RegisterBank::X) @@ -5492,10 +5610,6 @@ fn read_instr>(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>(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>(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>(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>(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>(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>(decoder: &InstDecoder, mut bytes_iter Ok(()) } +fn decode_x87>(_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>(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]); +} -- cgit v1.1