diff options
-rw-r--r-- | CHANGELOG | 2 | ||||
-rw-r--r-- | src/long_mode/mod.rs | 437 | ||||
-rw-r--r-- | src/long_mode/vex.rs | 62 | ||||
-rw-r--r-- | test/long_mode/mod.rs | 5 |
4 files changed, 247 insertions, 259 deletions
@@ -8,6 +8,8 @@ * discovered that `jna` and `jnb` are named what they are, instead of `jbe`/`jae` like their `setcc` an `cmovcc` counterparts. sorry. these will become `jbe` and `jae` in 2.x. +* fix incorrect decode of a0/a1/a2/a3 mov register when rex.b is set + (rex.b would select register 8, but the register is unconditionally A) ## 1.1.5 * fix several typos across crate docs - thank you Bruce! (aka github user waywardmonkeys) diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 34f1d34..3b2b68d 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -264,10 +264,18 @@ impl RegSpec { } #[inline] - fn gp_from_parts(num: u8, extended: bool, width: u8, rex: bool) -> RegSpec { + fn gp_from_parts_byte(num: u8, extended: bool, rex: bool) -> RegSpec { RegSpec { num: num + if extended { 0b1000 } else { 0 }, - bank: width_to_gp_reg_bank(width, rex) + bank: if rex { RegisterBank::rB } else { RegisterBank::B } + } + } + + #[inline] + fn gp_from_parts_non_byte(num: u8, extended: bool, bank: RegisterBank) -> RegSpec { + RegSpec { + num: num + if extended { 0b1000 } else { 0 }, + bank } } @@ -5679,9 +5687,8 @@ const OPCODES: [OpcodeRecord; 256] = [ pub(self) fn read_E< T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>, S: DescriptionSink<FieldDescription>, ->(words: &mut T, instr: &mut Instruction, modrm: u8, width: u8, sink: &mut S) -> Result<OperandSpec, DecodeError> { +>(words: &mut T, instr: &mut Instruction, modrm: u8, bank: RegisterBank, sink: &mut S) -> Result<OperandSpec, DecodeError> { if modrm >= 0b11000000 { - let bank = width_to_gp_reg_bank(width, instr.prefixes.rex_unchecked().present()); read_modrm_reg(instr, words, modrm, bank, sink) } else { read_M(words, instr, modrm, sink) @@ -6133,15 +6140,6 @@ fn read_M< Ok(op_spec) } -#[inline] -fn width_to_gp_reg_bank(width: u8, rex: bool) -> RegisterBank { - if width == 1 && rex { - RegisterBank::rB - } else { - unsafe { std::mem::transmute::<u8, RegisterBank>(width) } - } -} - #[inline(always)] fn read_0f_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord { // seems like f2 takes priority, then f3, then 66, then "no prefix". for SOME instructions an @@ -6839,32 +6837,28 @@ fn read_operands< let opcode_start = modrm_start - 8; if operand_code.is_only_modrm_operands() { - let modrm; - let opwidth; + let modrm = read_modrm(words)?; let mem_oper; - let mut bank = RegisterBank::Q; - // cool! we can precompute opwidth and know we need to read_E. + let bank; + let mut r = 0; + // cool! we can precompute width and know we need to read_E. if !operand_code.has_byte_operands() { // further, this is an vdq E - opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.mem_size = opwidth; - if opwidth == 4 { - bank = RegisterBank::D; - } else if opwidth == 2 { - bank = RegisterBank::W; - } + bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.regs[0].bank = bank; + instruction.mem_size = bank as u8; + r = if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 }; } else { - opwidth = 1; - instruction.mem_size = opwidth; - if instruction.prefixes.rex_unchecked().present() { - bank = RegisterBank::rB; + bank = if instruction.prefixes.rex_unchecked().present() { + r = if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 }; + RegisterBank::rB } else { - bank = RegisterBank::B; - } + RegisterBank::B + }; + instruction.regs[0].bank = bank; + instruction.mem_size = 1; }; - modrm = read_modrm(words)?; - instruction.regs[0].bank = bank; - instruction.regs[0].num = ((modrm >> 3) & 7) + if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 }; + instruction.regs[0].num = ((modrm >> 3) & 7) + r; sink.record( modrm_start + 3, modrm_start + 5, @@ -6910,26 +6904,22 @@ fn read_operands< let mut modrm = 0; let mut opwidth = 0; let mut mem_oper = OperandSpec::Nothing; - let mut bank = RegisterBank::Q; if operand_code.has_read_E() { - // cool! we can precompute opwidth and know we need to read_E. + let bank; + // cool! we can precompute width and know we need to read_E. if !operand_code.has_byte_operands() { // further, this is an vdq E - opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.mem_size = opwidth; - if opwidth == 4 { - bank = RegisterBank::D; - } else if opwidth == 2 { - bank = RegisterBank::W; - } + bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.mem_size = bank as u8; + opwidth = bank as u8; } else { - opwidth = 1; - instruction.mem_size = opwidth; - if instruction.prefixes.rex_unchecked().present() { - bank = RegisterBank::rB; + bank = if instruction.prefixes.rex_unchecked().present() { + RegisterBank::rB } else { - bank = RegisterBank::B; - } + RegisterBank::B + }; + instruction.mem_size = 1; + opwidth = 1; }; modrm = read_modrm(words)?; instruction.regs[0].bank = bank; @@ -7004,14 +6994,7 @@ fn read_operands< match z_operand_code.category() { 0 => { // these are Zv_R - let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); - let bank = if opwidth == 4 { - RegisterBank::D - } else if opwidth == 2 { - RegisterBank::W - } else { - RegisterBank::Q - }; + let bank = bank_from_prefixes_64(SizeCode::vq, instruction.prefixes); instruction.regs[0] = RegSpec::from_parts(reg, instruction.prefixes.rex_unchecked().b(), bank); instruction.mem_size = 8; @@ -7040,14 +7023,7 @@ fn read_operands< instruction.operand_count = 0; return Ok(()); } - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - let bank = if opwidth == 4 { - RegisterBank::D - } else if opwidth == 2 { - RegisterBank::W - } else { - RegisterBank::Q - }; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); // always *ax, but size is determined by prefixes (or lack thereof) instruction.regs[0] = RegSpec::from_parts(0, false, bank); @@ -7093,7 +7069,7 @@ fn read_operands< 2 => { // these are Zb_Ib_R instruction.regs[0] = - RegSpec::gp_from_parts(reg, instruction.prefixes.rex_unchecked().b(), 1, instruction.prefixes.rex_unchecked().present()); + RegSpec::gp_from_parts_byte(reg, instruction.prefixes.rex_unchecked().b(), instruction.prefixes.rex_unchecked().present()); sink.record( opcode_start, opcode_start + 2, @@ -7119,14 +7095,7 @@ fn read_operands< } 3 => { // category == 3, Zv_Ivq_R - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - let bank = if opwidth == 4 { - RegisterBank::D - } else if opwidth == 2 { - RegisterBank::W - } else { - RegisterBank::Q - }; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); instruction.regs[0] = RegSpec::from_parts(reg, instruction.prefixes.rex_unchecked().b(), bank); sink.record( @@ -7144,18 +7113,18 @@ fn read_operands< ); } instruction.imm = - read_imm_ivq(words, opwidth)?; - instruction.operands[1] = match opwidth { + read_imm_ivq(words, bank as u8)?; + instruction.operands[1] = match bank as u8 { 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, 8 => OperandSpec::ImmI64, _ => unsafe { unreachable_unchecked() } }; sink.record( - words.offset() as u32 * 8 - (8 * opwidth as u32), + words.offset() as u32 * 8 - (8 * bank as u8 as u32), words.offset() as u32 * 8 - 1, InnerDescription::Number("imm", instruction.imm as i64) - .with_id(words.offset() as u32 * 8 - (8 * opwidth as u32) + 1) + .with_id(words.offset() as u32 * 8 - (8 * bank as u8 as u32) + 1) ); } _ => { @@ -7457,35 +7426,40 @@ fn read_operands< op @ 15 | op @ 16 => { let w = if op == 15 { - 1 + instruction.mem_size = 1; + if instruction.prefixes.rex_unchecked().present() { + RegisterBank::rB + } else { + RegisterBank::B + } } else { - 2 + instruction.mem_size = 2; + RegisterBank::W }; - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); let modrm = read_modrm(words)?; instruction.operands[1] = read_E(words, instruction, modrm, w, sink)?; instruction.regs[0] = - RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth, instruction.prefixes.rex_unchecked().present()); + RegSpec::gp_from_parts_non_byte((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), bank); sink.record( modrm_start as u32 + 3, modrm_start as u32 + 5, InnerDescription::RegisterNumber("rrr", (modrm >> 3) & 7, instruction.regs[0]) .with_id(modrm_start as u32 + 3) ); - if instruction.operands[1] != OperandSpec::RegMMM { - instruction.mem_size = w; + if instruction.operands[1] == OperandSpec::RegMMM { + instruction.mem_size = 0; } instruction.operand_count = 2; }, 17 => { - let opwidth = 8; let modrm = read_modrm(words)?; - instruction.operands[1] = read_E(words, instruction, modrm, 4 /* opwidth */, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; instruction.mem_size = 4; instruction.regs[0] = - RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth, instruction.prefixes.rex_unchecked().present()); + RegSpec::gp_from_parts_non_byte((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::Q); sink.record( modrm_start as u32 + 3, modrm_start as u32 + 5, @@ -7584,10 +7558,10 @@ fn read_operands< instruction.operands[1] = OperandSpec::ImmI8; } 24 => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - let numwidth = if opwidth == 8 { 4 } else { opwidth }; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let numwidth = if bank as u8 == 8 { 4 } else { bank as u8 }; instruction.regs[0] = - RegSpec::gp_from_parts(0, false, opwidth, false); + RegSpec::gp_from_parts_non_byte(0, false, bank); sink.record( modrm_start as u32 - 8, modrm_start as u32 - 1, @@ -7596,7 +7570,7 @@ fn read_operands< ); instruction.imm = read_imm_signed(words, numwidth)? as u64; - instruction.operands[1] = match opwidth { + instruction.operands[1] = match bank as u8 { 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, 8 => OperandSpec::ImmI64, @@ -7911,16 +7885,16 @@ fn unlikely_operands< instruction.operand_count = 0; }, _ => { - let (sz, bank) = if instruction.prefixes.rex_unchecked().w() { - (8, RegisterBank::Q) + let bank = if instruction.prefixes.rex_unchecked().w() { + RegisterBank::Q } else if !instruction.prefixes.operand_size() { - (4, RegisterBank::D) + RegisterBank::D } else { - (2, RegisterBank::W) + RegisterBank::W }; instruction.operands[1] = OperandSpec::RegRRR; - instruction.operands[0] = read_E(words, instruction, modrm, sz, sink)?; - instruction.mem_size = sz; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; + instruction.mem_size = bank as u8; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), bank); instruction.operand_count = 2; @@ -8018,7 +7992,7 @@ fn unlikely_operands< OperandCode::G_mm_Ew_Ib => { let modrm = read_modrm(words)?; - instruction.operands[1] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, false, RegisterBank::MM); if instruction.operands[1] == OperandSpec::RegMMM { @@ -8054,10 +8028,10 @@ fn unlikely_operands< instruction.regs[1].num &= 0b111; }, OperandCode::Gv_Ew_LSL => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let opwidth = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); let modrm = read_modrm(words)?; - instruction.operands[1] = read_E(words, instruction, modrm, 2, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::W, sink)?; // lsl is weird. the full register width is written, but only the low 16 bits are used. if instruction.operands[1] == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; @@ -8065,44 +8039,47 @@ fn unlikely_operands< instruction.mem_size = 2; } instruction.regs[0] = - RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth, instruction.prefixes.rex_unchecked().present()); + RegSpec::gp_from_parts_non_byte((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth); }, OperandCode::Gdq_Ev => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); let modrm = read_modrm(words)?; - instruction.operands[1] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, bank, sink)?; // `opwidth` can be 2, 4, or 8 here. if opwidth is 2, the first operand is a dword. // if opwidth is 4, both registers are dwords. and if opwidth is 8, both registers are // qword. if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 4; } - let regwidth = if opwidth == 2 { - 4 + let regbank = if bank == RegisterBank::W { + RegisterBank::D } else { - opwidth + bank }; instruction.regs[0] = - RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), regwidth, instruction.prefixes.rex_unchecked().present()); + RegSpec::gp_from_parts_non_byte((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), regbank); instruction.operand_count = 2; }, op @ OperandCode::AL_Ob | op @ OperandCode::AX_Ov => { - let opwidth = match op { - OperandCode::AL_Ob => 1, + match op { + OperandCode::AL_Ob => { + instruction.mem_size = 1; + instruction.regs[0] = RegSpec::al(); + } OperandCode::AX_Ov => { - imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes) + let b = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.mem_size = b as u8; + instruction.regs[0].num = 0; + instruction.regs[0].bank = b; } _ => { unsafe { unreachable_unchecked() } } }; - instruction.mem_size = opwidth; let addr_width = if instruction.prefixes.address_size() { 4 } else { 8 }; let imm = read_num(words, addr_width)?; - instruction.regs[0] = - RegSpec::gp_from_parts(0, instruction.prefixes.rex_unchecked().b(), opwidth, instruction.prefixes.rex_unchecked().present()); instruction.disp = imm; if instruction.prefixes.address_size() { instruction.operands[1] = OperandSpec::DispU32; @@ -8113,16 +8090,21 @@ fn unlikely_operands< } op @ OperandCode::Ob_AL | op @ OperandCode::Ov_AX => { - let opwidth = match op { - OperandCode::Ob_AL => 1, + match op { + OperandCode::Ob_AL => { + instruction.mem_size = 1; + instruction.regs[0] = RegSpec::al(); + } OperandCode::Ov_AX => { - imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes) + let b = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.mem_size = b as u8; + instruction.regs[0].num = 0; + instruction.regs[0].bank = b; } _ => { unsafe { unreachable_unchecked() } } }; - instruction.mem_size = opwidth; let addr_width = if instruction.prefixes.address_size() { 4 } else { 8 }; let imm = read_num(words, addr_width)?; instruction.disp = imm; @@ -8131,8 +8113,6 @@ fn unlikely_operands< } else { OperandSpec::DispU64 }; - instruction.regs[0] = - RegSpec::gp_from_parts(0, instruction.prefixes.rex_unchecked().b(), opwidth, instruction.prefixes.rex_unchecked().present()); instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; } @@ -8164,18 +8144,18 @@ fn unlikely_operands< instruction.operand_count = 0; } OperandCode::Mdq_Gdq => { - let opwidth = if instruction.prefixes.rex_unchecked().w() { 8 } else { 4 }; + let bank = if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D }; let modrm = read_modrm(words)?; instruction.operands[1] = instruction.operands[0]; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } else { - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8 } instruction.regs[0] = - RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth, instruction.prefixes.rex_unchecked().present()); + RegSpec::gp_from_parts_non_byte((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), bank); instruction.operand_count = 2; } @@ -8196,7 +8176,7 @@ fn unlikely_operands< let modrm = read_modrm(words)?; - instruction.operands[0] = read_E(words, instruction, modrm, 8, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::Q, sink)?; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::Q); @@ -8215,7 +8195,7 @@ fn unlikely_operands< instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::Q); - instruction.operands[1] = read_E(words, instruction, modrm, 8, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::Q, sink)?; instruction.operand_count = 2; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 8; @@ -8267,7 +8247,7 @@ fn unlikely_operands< let modrm = read_modrm(words)?; let r = (modrm >> 3) & 0b111; - let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vq, instruction.prefixes); match r { 1 => { @@ -8277,7 +8257,7 @@ fn unlikely_operands< instruction.opcode = Opcode::NOP; } } - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 64; } @@ -8393,8 +8373,8 @@ fn unlikely_operands< instruction.mem_size = 8; } instruction.operand_count = 1; - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; } return Ok(()); } @@ -8404,7 +8384,7 @@ fn unlikely_operands< } } if instruction.prefixes.operand_size() { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); let modrm = read_modrm(words)?; let is_reg = (modrm & 0xc0) == 0xc0; @@ -8422,14 +8402,14 @@ fn unlikely_operands< instruction.mem_size = 8; } instruction.operand_count = 1; - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; } return Ok(()); } 6 => { instruction.opcode = Opcode::VMCLEAR; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; if instruction.operands[0] == OperandSpec::RegMMM { // this would be invalid as `vmclear`, so fall back to the parse as // 66-prefixed rdrand. this is a register operand, so just demote it to the @@ -8443,7 +8423,7 @@ fn unlikely_operands< return Ok(()); } 7 => { - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; if instruction.operands[0] == OperandSpec::RegMMM { // this would be invalid as `vmclear`, so fall back to the parse as // 66-prefixed rdrand. this is a register operand, so just demote it to the @@ -8463,7 +8443,7 @@ fn unlikely_operands< } if instruction.prefixes.rep() { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); let modrm = read_modrm(words)?; let is_reg = (modrm & 0xc0) == 0xc0; @@ -8481,13 +8461,13 @@ fn unlikely_operands< instruction.mem_size = 8; } instruction.operand_count = 1; - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; } } 6 => { instruction.opcode = Opcode::VMXON; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; if instruction.operands[0] == OperandSpec::RegMMM { // invalid as `vmxon`, reg-form is `senduipi` instruction.opcode = Opcode::SENDUIPI; @@ -8500,7 +8480,7 @@ fn unlikely_operands< } 7 => { instruction.opcode = Opcode::RDPID; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; if instruction.operands[0] != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -8591,8 +8571,8 @@ fn unlikely_operands< instruction.opcode = opcode; instruction.operand_count = 1; - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; }, OperandCode::ModRM_0x0f71 => { if instruction.prefixes.rep() || instruction.prefixes.repnz() { @@ -9015,29 +8995,21 @@ fn unlikely_operands< instruction.operand_count = 2; } OperandCode::AX_Xv => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.regs[0] = match opwidth { - 2 => RegSpec::ax(), - 4 => RegSpec::eax(), - 8 => RegSpec::rax(), - _ => { unreachable!(); } - }; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.regs[0].num = 0; + instruction.regs[0].bank = bank; if instruction.prefixes.address_size() { instruction.regs[1] = RegSpec::esi(); } else { instruction.regs[1] = RegSpec::rsi(); } instruction.operands[1] = OperandSpec::Deref; - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8; } OperandCode::Yv_AX => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.regs[0] = match opwidth { - 2 => RegSpec::ax(), - 4 => RegSpec::eax(), - 8 => RegSpec::rax(), - _ => { unreachable!(); } - }; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.regs[0].num = 0; + instruction.regs[0].bank = bank; if instruction.prefixes.address_size() { instruction.regs[1] = RegSpec::edi(); } else { @@ -9045,11 +9017,11 @@ fn unlikely_operands< } instruction.operands[0] = OperandSpec::Deref; instruction.operands[1] = OperandSpec::RegRRR; - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8; } OperandCode::Yv_Xv => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - instruction.mem_size = opwidth; + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + instruction.mem_size = bank as u8; if instruction.prefixes.address_size() { instruction.operands[0] = OperandSpec::Deref_edi; instruction.operands[1] = OperandSpec::Deref_esi; @@ -9145,7 +9117,6 @@ fn unlikely_operands< instruction.regs[0].bank = RegisterBank::X; } OperandCode::Ew_Sw => { - let opwidth = 2; let modrm = read_modrm(words)?; // check r @@ -9165,7 +9136,7 @@ fn unlikely_operands< RegSpec { bank: RegisterBank::W, num: modrm & 7}; instruction.operands[0] = OperandSpec::RegMMM; } else { - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::W, sink)?; instruction.mem_size = 2; } }, @@ -9204,24 +9175,24 @@ fn unlikely_operands< } }, OperandCode::CVT_AA => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; - instruction.opcode = match opwidth { - 2 => { Opcode::CBW }, - 4 => { Opcode::CWDE }, - 8 => { Opcode::CDQE }, + instruction.opcode = match bank { + RegisterBank::W => { Opcode::CBW }, + RegisterBank::D => { Opcode::CWDE }, + RegisterBank::Q => { Opcode::CDQE }, _ => { unreachable!("invalid operation width"); }, } } OperandCode::CVT_DA => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes); instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; - instruction.opcode = match opwidth { - 2 => { Opcode::CWD }, - 4 => { Opcode::CDQ }, - 8 => { Opcode::CQO }, + instruction.opcode = match bank { + RegisterBank::W => { Opcode::CWD }, + RegisterBank::D => { Opcode::CDQ }, + RegisterBank::Q => { Opcode::CQO }, _ => { unreachable!("invalid operation width"); }, } } @@ -9268,13 +9239,13 @@ fn unlikely_operands< } else { unreachable!("r <= 8"); } - instruction.operands[0] = read_E(words, instruction, modrm, 2, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::W, sink)?; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 2; } } OperandCode::ModRM_0x0f01 => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vq, instruction.prefixes); let modrm = read_modrm(words)?; let r = (modrm >> 3) & 7; if r == 0 { @@ -9314,7 +9285,7 @@ fn unlikely_operands< instruction.opcode = Opcode::SGDT; instruction.operand_count = 1; instruction.mem_size = 63; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; } } else if r == 1 { let mod_bits = modrm >> 6; @@ -9369,7 +9340,7 @@ fn unlikely_operands< instruction.opcode = Opcode::SIDT; instruction.operand_count = 1; instruction.mem_size = 63; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; } } else if r == 2 { let mod_bits = modrm >> 6; @@ -9408,7 +9379,7 @@ fn unlikely_operands< instruction.opcode = Opcode::LGDT; instruction.operand_count = 1; instruction.mem_size = 63; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; } } else if r == 3 { let mod_bits = modrm >> 6; @@ -9472,7 +9443,7 @@ fn unlikely_operands< instruction.opcode = Opcode::LIDT; instruction.operand_count = 1; instruction.mem_size = 63; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; } } else if r == 4 { // TODO: this permits storing only to word-size registers @@ -9480,7 +9451,7 @@ fn unlikely_operands< instruction.opcode = Opcode::SMSW; instruction.operand_count = 1; instruction.mem_size = 2; - instruction.operands[0] = read_E(words, instruction, modrm, 2, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::W, sink)?; } else if r == 5 { let mod_bits = modrm >> 6; if mod_bits != 0b11 { @@ -9488,7 +9459,7 @@ fn unlikely_operands< return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::RSTORSSP; - instruction.operands[0] = read_E(words, instruction, modrm, 8, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::Q, sink)?; instruction.mem_size = 8; instruction.operand_count = 1; return Ok(()); @@ -9588,7 +9559,7 @@ fn unlikely_operands< instruction.opcode = Opcode::LMSW; instruction.operand_count = 1; instruction.mem_size = 2; - instruction.operands[0] = read_E(words, instruction, modrm, 2, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::W, sink)?; } else if r == 7 { let mod_bits = modrm >> 6; let m = modrm & 7; @@ -9673,7 +9644,7 @@ fn unlikely_operands< instruction.opcode = Opcode::INVLPG; instruction.operand_count = 1; instruction.mem_size = 1; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; } } else { unreachable!("r <= 8"); @@ -9698,7 +9669,7 @@ fn unlikely_operands< return Err(DecodeError::InvalidOpcode); } }; - instruction.operands[0] = read_E(words, instruction, modrm, 1 /* opwidth */, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::B /* opwidth */, sink)?; instruction.mem_size = 64; instruction.operand_count = 1; } else { @@ -9710,8 +9681,8 @@ fn unlikely_operands< return Err(DecodeError::InvalidOpcode); } }; - let opwidth = if instruction.prefixes.rex_unchecked().w() { 8 } else { 4 }; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + let bank = if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D }; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; instruction.operand_count = 1; } @@ -9746,14 +9717,14 @@ fn unlikely_operands< return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::PTWRITE; - let opwidth = if instruction.prefixes.rex_unchecked().w() { - 8 + let bank = if instruction.prefixes.rex_unchecked().w() { + RegisterBank::Q } else { - 4 + RegisterBank::D }; - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; if instruction.operands[0] != OperandSpec::RegMMM { - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8; } instruction.operand_count = 1; return Ok(()); @@ -9831,7 +9802,7 @@ fn unlikely_operands< match r { 6 => { instruction.opcode = Opcode::CLRSSBSY; - instruction.operands[0] = read_E(words, instruction, modrm, 8, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::Q, sink)?; instruction.operand_count = 1; instruction.mem_size = 8; return Ok(()); @@ -9908,7 +9879,7 @@ fn unlikely_operands< } } OperandCode::ModRM_0x0fba => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); + let bank = bank_from_prefixes_64(SizeCode::vq, instruction.prefixes); let modrm = read_modrm(words)?; let r = (modrm >> 3) & 7; match r { @@ -9932,9 +9903,9 @@ fn unlikely_operands< } } - instruction.operands[0] = read_E(words, instruction, modrm, opwidth, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, bank, sink)?; if instruction.operands[0] != OperandSpec::RegMMM { - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8; } instruction.imm = read_imm_signed(words, 1)? as u64; @@ -10006,12 +9977,8 @@ fn unlikely_operands< instruction.operand_count = 2; } OperandCode::AX_Ib => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vd, instruction.prefixes); - instruction.regs[0] = if opwidth == 4 { - RegSpec::eax() - } else { - RegSpec::ax() - }; + instruction.regs[0].num = 0; + instruction.regs[0].bank = bank_from_prefixes_64(SizeCode::vd, instruction.prefixes); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::ImmU8; instruction.operand_count = 2; @@ -10024,23 +9991,15 @@ fn unlikely_operands< instruction.operand_count = 2; } OperandCode::Ib_AX => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vd, instruction.prefixes); - instruction.regs[0] = if opwidth == 4 { - RegSpec::eax() - } else { - RegSpec::ax() - }; + instruction.regs[0].num = 0; + instruction.regs[0].bank = bank_from_prefixes_64(SizeCode::vd, instruction.prefixes); instruction.operands[0] = OperandSpec::ImmU8; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; } OperandCode::AX_DX => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vd, instruction.prefixes); - instruction.regs[0] = if opwidth == 4 { - RegSpec::eax() - } else { - RegSpec::ax() - }; + instruction.regs[0].num = 0; + instruction.regs[0].bank = bank_from_prefixes_64(SizeCode::vd, instruction.prefixes); instruction.regs[1] = RegSpec::dx(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegMMM; @@ -10054,12 +10013,8 @@ fn unlikely_operands< instruction.operand_count = 2; } OperandCode::DX_AX => { - let opwidth = imm_width_from_prefixes_64(SizeCode::vd, instruction.prefixes); - instruction.regs[0] = if opwidth == 4 { - RegSpec::eax() - } else { - RegSpec::ax() - }; + instruction.regs[0].num = 0; + instruction.regs[0].bank = bank_from_prefixes_64(SizeCode::vd, instruction.prefixes); instruction.regs[1] = RegSpec::dx(); instruction.operands[0] = OperandSpec::RegMMM; instruction.operands[1] = OperandSpec::RegRRR; @@ -10554,7 +10509,7 @@ fn decode_x87< OperandCodeX87::St_Ew => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); - instruction.operands[1] = read_E(words, instruction, modrm, 2, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::W, sink)?; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 2; } @@ -10563,7 +10518,7 @@ fn decode_x87< OperandCodeX87::St_Mm => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); - instruction.operands[1] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if instruction.operands[1] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -10573,7 +10528,7 @@ fn decode_x87< OperandCodeX87::St_Mq => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); - instruction.operands[1] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if instruction.operands[1] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -10583,7 +10538,7 @@ fn decode_x87< OperandCodeX87::St_Md => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); - instruction.operands[1] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if instruction.operands[1] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -10593,7 +10548,7 @@ fn decode_x87< OperandCodeX87::St_Mw => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); - instruction.operands[1] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[1] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if instruction.operands[1] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -10601,7 +10556,7 @@ fn decode_x87< instruction.operand_count = 2; } OperandCodeX87::Ew => { - instruction.operands[0] = read_E(words, instruction, modrm, 2, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::W, sink)?; instruction.operand_count = 1; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 2; @@ -10641,7 +10596,7 @@ fn decode_x87< instruction.operand_count = 2; } OperandCodeX87::Mm_St => { - instruction.operands[0] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -10651,7 +10606,7 @@ fn decode_x87< instruction.operand_count = 2; } OperandCodeX87::Mq_St => { - instruction.operands[0] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -10661,7 +10616,7 @@ fn decode_x87< instruction.operand_count = 2; } OperandCodeX87::Md_St => { - instruction.operands[0] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -10671,7 +10626,7 @@ fn decode_x87< instruction.operand_count = 2; } OperandCodeX87::Mw_St => { - instruction.operands[0] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } @@ -10681,7 +10636,7 @@ fn decode_x87< instruction.operand_count = 2; } OperandCodeX87::Ex87S => { - instruction.operands[0] = read_E(words, instruction, modrm, 4, sink)?; + instruction.operands[0] = read_E(words, instruction, modrm, RegisterBank::D, sink)?; instruction.operand_count = 1; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); @@ -10696,7 +10651,7 @@ fn decode_x87< Ok(()) } -#[inline] +#[inline(always)] fn read_num<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(bytes: &mut T, width: u8) -> Result<u64, DecodeError> { match width { 1 => { bytes.next().ok().ok_or(DecodeError::ExhaustedInput).map(|x| x as u64) } @@ -10757,6 +10712,32 @@ fn read_imm_unsigned<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as y } #[inline] +fn bank_from_prefixes_64(interpretation: SizeCode, prefixes: Prefixes) -> RegisterBank { + match interpretation { + SizeCode::b => RegisterBank::B, + SizeCode::vd => { + if prefixes.rex_unchecked().w() || !prefixes.operand_size() { RegisterBank::D } else { RegisterBank::W } + }, + SizeCode::vq => { + if prefixes.operand_size() { + RegisterBank::W + } else { + RegisterBank::Q + } + }, + SizeCode::vqp => { + if prefixes.rex_unchecked().w() { + RegisterBank::Q + } else if prefixes.operand_size() { + RegisterBank::W + } else { + RegisterBank::D + } + }, + } +} + +#[inline] fn imm_width_from_prefixes_64(interpretation: SizeCode, prefixes: Prefixes) -> u8 { match interpretation { SizeCode::b => 1, diff --git a/src/long_mode/vex.rs b/src/long_mode/vex.rs index 206e4f1..31f9e11 100644 --- a/src/long_mode/vex.rs +++ b/src/long_mode/vex.rs @@ -605,7 +605,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); - let mem_oper = read_E(words, instruction, modrm, 4, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::D, sink)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; instruction.operands[2] = OperandSpec::ImmU8; @@ -640,7 +640,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); - let mem_oper = read_E(words, instruction, modrm, 8, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::Q, sink)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; if mem_oper != OperandSpec::RegMMM { @@ -657,7 +657,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); - let mem_oper = read_E(words, instruction, modrm, 4, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::D, sink)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; if mem_oper != OperandSpec::RegMMM { @@ -674,7 +674,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); - let mem_oper = read_E(words, instruction, modrm, 8, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::Q, sink)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; if mem_oper != OperandSpec::RegMMM { @@ -691,7 +691,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); - let mem_oper = read_E(words, instruction, modrm, 4, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::D, sink)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; if mem_oper != OperandSpec::RegMMM { @@ -708,7 +708,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::D); - let mem_oper = read_E(words, instruction, modrm, 4, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if let OperandSpec::RegMMM = mem_oper { instruction.regs[1].bank = RegisterBank::X; } else { @@ -727,7 +727,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Q); - let mem_oper = read_E(words, instruction, modrm, 4, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if let OperandSpec::RegMMM = mem_oper { instruction.regs[1].bank = RegisterBank::X; } else { @@ -1178,7 +1178,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); - let mem_oper = read_E(words, instruction, modrm, 4, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::D, sink)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; @@ -1192,7 +1192,7 @@ fn read_vex_operands< let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); - let mem_oper = read_E(words, instruction, modrm, 8, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::Q, sink)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; @@ -1307,60 +1307,60 @@ fn read_vex_operands< } VEXOperandCode::G_V_E => { let modrm = read_modrm(words)?; - let (opwidth, bank) = if instruction.prefixes.vex_unchecked().w() { - (8, RegisterBank::Q) + let bank = if instruction.prefixes.vex_unchecked().w() { + RegisterBank::Q } else { - (4, RegisterBank::D) + RegisterBank::D }; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), bank); instruction.regs[3].bank = bank; - let mem_oper = read_E(words, instruction, modrm, opwidth, sink)?; + let mem_oper = read_E(words, instruction, modrm, bank, sink)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; if mem_oper != OperandSpec::RegMMM { - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8; } instruction.operand_count = 3; Ok(()) } VEXOperandCode::G_E_V => { let modrm = read_modrm(words)?; - let (opwidth, bank) = if instruction.prefixes.vex_unchecked().w() { - (8, RegisterBank::Q) + let bank = if instruction.prefixes.vex_unchecked().w() { + RegisterBank::Q } else { - (4, RegisterBank::D) + RegisterBank::D }; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), bank); instruction.regs[3].bank = bank; - let mem_oper = read_E(words, instruction, modrm, opwidth, sink)?; + let mem_oper = read_E(words, instruction, modrm, bank, sink)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; instruction.operands[2] = OperandSpec::RegVex; if mem_oper != OperandSpec::RegMMM { - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8; } instruction.operand_count = 3; Ok(()) } VEXOperandCode::G_E_Ib => { let modrm = read_modrm(words)?; - let (opwidth, bank) = if instruction.prefixes.vex_unchecked().w() { - (8, RegisterBank::Q) + let bank = if instruction.prefixes.vex_unchecked().w() { + RegisterBank::Q } else { - (4, RegisterBank::D) + RegisterBank::D }; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), bank); - let mem_oper = read_E(words, instruction, modrm, opwidth, sink)?; + let mem_oper = read_E(words, instruction, modrm, bank, sink)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; instruction.imm = read_imm_unsigned(words, 1)?; instruction.operands[2] = OperandSpec::ImmI8; if mem_oper != OperandSpec::RegMMM { - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8; } instruction.operand_count = 3; Ok(()) @@ -1382,19 +1382,19 @@ fn read_vex_operands< return Err(DecodeError::InvalidOpcode); } }; - let (opwidth, bank) = if instruction.prefixes.vex_unchecked().w() { - (8, RegisterBank::Q) + let bank = if instruction.prefixes.vex_unchecked().w() { + RegisterBank::Q } else { - (4, RegisterBank::D) + RegisterBank::D }; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), bank); - let mem_oper = read_E(words, instruction, modrm, opwidth, sink)?; + let mem_oper = read_E(words, instruction, modrm, bank, sink)?; instruction.operands[0] = OperandSpec::RegVex; instruction.operands[1] = mem_oper; instruction.operand_count = 2; if mem_oper != OperandSpec::RegMMM { - instruction.mem_size = opwidth; + instruction.mem_size = bank as u8; } instruction.regs[3].bank = bank; Ok(()) @@ -1413,7 +1413,7 @@ fn read_vex_operands< return Err(DecodeError::InvalidOpcode); } }; - let mem_oper = read_E(words, instruction, modrm, 4, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::D, sink)?; if let OperandSpec::RegMMM = mem_oper { return Err(DecodeError::InvalidOperand); } @@ -1515,7 +1515,7 @@ fn read_vex_operands< RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), RegisterBank::X); instruction.regs[3].bank = RegisterBank::X; // TODO: but the memory access is word-sized - let mem_oper = read_E(words, instruction, modrm, 4, sink)?; + let mem_oper = read_E(words, instruction, modrm, RegisterBank::D, sink)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 12d5f96..5a1d02d 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -2717,6 +2717,11 @@ fn only_64bit() { test_display(&[0x67, 0xaf], "scas dword es:[edi], eax"); test_display(&[0x67, 0xac], "lods al, byte ds:[esi]"); test_display(&[0x67, 0xaa], "stos byte es:[edi], al"); + // note that rax.b does *not* change the register + test_display(&[0x4f, 0xa0, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34], "mov al, byte [0x3412341234123412]"); + test_display(&[0x4f, 0xa1, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34], "mov rax, qword [0x3412341234123412]"); + test_display(&[0x4f, 0xa2, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34], "mov byte [0x3412341234123412], al"); + test_display(&[0x4f, 0xa3, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34], "mov qword [0x3412341234123412], rax"); } #[test] |