From 9e17c1aa966e3f114513aceb4cf7069016cf0a04 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 29 Jan 2023 12:21:14 -0800 Subject: avoid committing values to instructions until necessary, likely opc tweaks --- src/long_mode/mod.rs | 258 +++++++++++++++++++++++++++++---------------------- 1 file changed, 149 insertions(+), 109 deletions(-) (limited to 'src') diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 052313a..de6d701 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -5850,12 +5850,20 @@ fn read_sib< let modbits = modrm >> 6; let sibbyte = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; - instr.regs[1].num |= sibbyte & 7; - instr.regs[2].num |= (sibbyte >> 3) & 7; - let disp = read_sib_disp(instr, words, modbits, sibbyte, sink)?; instr.disp = disp as u32 as u64; + let mut r = 0; + if instr.prefixes.rex_unchecked().b() { + r |= 0b1000; + } + instr.regs[1].num = r | (sibbyte & 7); + let mut r = 0; + if instr.prefixes.rex_unchecked().x() { + r = 0b1000; + } + instr.regs[2].num = r | ((sibbyte >> 3) & 7); + let scale = 1u8 << (sibbyte >> 6); instr.scale = scale; @@ -6039,16 +6047,6 @@ fn read_M< let modbits = modrm >> 6; let mmm = modrm & 7; let op_spec = if mmm == 4 { - if instr.prefixes.rex_unchecked().b() { - instr.regs[1].num = 0b1000; - } else { - instr.regs[1].num = 0; - } - if instr.prefixes.rex_unchecked().x() { - instr.regs[2].num = 0b1000; - } else { - instr.regs[2].num = 0; - } sink.record( modrm_start, modrm_start + 2, @@ -6102,12 +6100,11 @@ fn read_M< OperandSpec::RegDisp } } else { + let mut r = 0; if instr.prefixes.rex_unchecked().b() { - instr.regs[1].num = 0b1000; - } else { - instr.regs[1].num = 0; + r = 0b1000; } - instr.regs[1].num |= mmm; + instr.regs[1].num = r | mmm; sink.record( modrm_start, modrm_start + 2, @@ -6858,27 +6855,25 @@ fn read_operands< let opcode_start = modrm_start - 8; if operand_code.is_only_modrm_operands() { - let modrm = read_modrm(words)?; - let mem_oper; - let bank; - let mut r = 0; // cool! we can precompute width and know we need to read_E. - if !operand_code.has_byte_operands() { + let bank = if !operand_code.has_byte_operands() { // further, this is an vdq E - bank = instruction.prefixes.vqp_size(); + let bank = instruction.prefixes.vqp_size(); instruction.regs[0].bank = bank; instruction.mem_size = bank as u8; - r = if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 }; + bank } else { - bank = if instruction.prefixes.rex_unchecked().present() { - r = if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 }; + let bank = if instruction.prefixes.rex_unchecked().present() { RegisterBank::rB } else { RegisterBank::B }; instruction.regs[0].bank = bank; instruction.mem_size = 1; + bank }; + let r = if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 }; + let modrm = read_modrm(words)?; instruction.regs[0].num = ((modrm >> 3) & 7) + r; sink.record( modrm_start + 3, @@ -6895,7 +6890,7 @@ fn read_operands< ); } - mem_oper = if modrm >= 0b11000000 { + let mem_oper = if modrm >= 0b11000000 { sink.record( modrm_start + 6, modrm_start + 7, @@ -7218,46 +7213,67 @@ fn read_operands< } }; }, - op @ 3 | - op @ 4 => { + 3 => { if modrm == 0xf8 { - if op == 3 { - instruction.opcode = Opcode::XABORT; - instruction.imm = read_imm_signed(words, 1)? as u64; + instruction.opcode = Opcode::XABORT; + instruction.imm = read_imm_signed(words, 1)? as u64; + sink.record( + words.offset() as u32 * 8 - 8, + words.offset() as u32 * 8 - 1, + InnerDescription::Number("imm", instruction.imm as i64) + .with_id(words.offset() as u32 * 8 - 8) + ); + instruction.operands[0] = OperandSpec::ImmI8; + instruction.operand_count = 1; + return Ok(()); + } + if (modrm & 0b00111000) != 0 { + sink.record( + modrm_start + 3, + modrm_start + 5, + InnerDescription::Misc("invalid rrr field: must be zero") + .with_id(modrm_start - 8) + ); + return Err(DecodeError::InvalidOperand); // Err("Invalid modr/m for opcode 0xc7".to_string()); + } + + instruction.operands[0] = mem_oper; + instruction.opcode = Opcode::MOV; + instruction.imm = read_imm_signed(words, 1)? as u64; + instruction.operands[1] = OperandSpec::ImmI8; + sink.record( + modrm_start + 8, + modrm_start + 1 as u32 * 8 - 1, + InnerDescription::Number("imm", instruction.imm as i64) + .with_id(modrm_start + 8) + ); + + } + 4 => { + if modrm == 0xf8 { + instruction.opcode = Opcode::XBEGIN; + instruction.imm = if opwidth == 2 { + let imm = read_imm_signed(words, 2)? as i16 as i64 as u64; sink.record( - words.offset() as u32 * 8 - 8, + words.offset() as u32 * 8 - 16, words.offset() as u32 * 8 - 1, InnerDescription::Number("imm", instruction.imm as i64) - .with_id(words.offset() as u32 * 8 - 8) + .with_id(words.offset() as u32 * 8 - 16) ); - instruction.operands[0] = OperandSpec::ImmI8; - instruction.operand_count = 1; - return Ok(()); + imm } else { - instruction.opcode = Opcode::XBEGIN; - instruction.imm = if opwidth == 2 { - let imm = read_imm_signed(words, 2)? as i16 as i64 as u64; - sink.record( - words.offset() as u32 * 8 - 16, - words.offset() as u32 * 8 - 1, - InnerDescription::Number("imm", instruction.imm as i64) - .with_id(words.offset() as u32 * 8 - 16) - ); - imm - } else { - let imm = read_imm_signed(words, 4)? as i32 as i64 as u64; - sink.record( - words.offset() as u32 * 8 - 32, - words.offset() as u32 * 8 - 1, - InnerDescription::Number("imm", instruction.imm as i64) - .with_id(words.offset() as u32 * 8 - 32) - ); - imm - }; - instruction.operands[0] = OperandSpec::ImmI32; - instruction.operand_count = 1; - return Ok(()); - } + let imm = read_imm_signed(words, 4)? as i32 as i64 as u64; + sink.record( + words.offset() as u32 * 8 - 32, + words.offset() as u32 * 8 - 1, + InnerDescription::Number("imm", instruction.imm as i64) + .with_id(words.offset() as u32 * 8 - 32) + ); + imm + }; + instruction.operands[0] = OperandSpec::ImmI32; + instruction.operand_count = 1; + return Ok(()); } if (modrm & 0b00111000) != 0 { sink.record( @@ -7274,7 +7290,6 @@ fn read_operands< let numwidth = if opwidth == 8 { 4 } else { opwidth }; instruction.imm = read_imm_signed(words, numwidth)? as u64; instruction.operands[1] = match opwidth { - 1 => OperandSpec::ImmI8, 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, 8 => OperandSpec::ImmI64, @@ -7287,9 +7302,7 @@ fn read_operands< .with_id(modrm_start + 8) ); }, - op @ 5 | - op @ 7 | - op @ 9 => { + 5 => { instruction.operands[0] = mem_oper; instruction.opcode = BITWISE_OPCODE_MAP[((modrm >> 3) & 7) as usize].clone(); sink.record( @@ -7298,39 +7311,52 @@ fn read_operands< InnerDescription::Opcode(instruction.opcode) .with_id(modrm_start - 8) ); - if op == 9 { - instruction.regs[0] = RegSpec::cl(); - sink.record( - modrm_start - 8, - modrm_start - 1, - InnerDescription::RegisterNumber("reg", 1, instruction.regs[0]) - .with_id(modrm_start - 7) - ); - instruction.operands[1] = OperandSpec::RegRRR; - } else { - let num = if op == 5 { - read_num(words, 1)? - } else { - 1 - }; - if op == 5 { - sink.record( - words.offset() as u32 * 8 - 8, - words.offset() as u32 * 8 - 1, - InnerDescription::Number("imm", num as i64) - .with_id(modrm_start - 8) - ); - } else { - sink.record( - modrm_start - 8, - modrm_start - 1, - InnerDescription::Misc("opcode specifies integer immediate 1") - .with_id(modrm_start - 8) - ); - } - instruction.imm = num; - instruction.operands[1] = OperandSpec::ImmI8; - } + let num = read_num(words, 1)?; + sink.record( + words.offset() as u32 * 8 - 8, + words.offset() as u32 * 8 - 1, + InnerDescription::Number("imm", num as i64) + .with_id(modrm_start - 8) + ); + instruction.imm = num; + instruction.operands[1] = OperandSpec::ImmI8; + } + 7 => { + instruction.operands[0] = mem_oper; + instruction.opcode = BITWISE_OPCODE_MAP[((modrm >> 3) & 7) as usize].clone(); + sink.record( + modrm_start + 3, + modrm_start + 5, + InnerDescription::Opcode(instruction.opcode) + .with_id(modrm_start - 8) + ); + let num = 1; + sink.record( + modrm_start - 8, + modrm_start - 1, + InnerDescription::Misc("opcode specifies integer immediate 1") + .with_id(modrm_start - 8) + ); + instruction.imm = num; + instruction.operands[1] = OperandSpec::ImmI8; + } + 9 => { + instruction.operands[0] = mem_oper; + instruction.opcode = BITWISE_OPCODE_MAP[((modrm >> 3) & 7) as usize].clone(); + sink.record( + modrm_start + 3, + modrm_start + 5, + InnerDescription::Opcode(instruction.opcode) + .with_id(modrm_start - 8) + ); + instruction.regs[0] = RegSpec::cl(); + sink.record( + modrm_start - 8, + modrm_start - 1, + InnerDescription::RegisterNumber("reg", 1, instruction.regs[0]) + .with_id(modrm_start - 7) + ); + instruction.operands[1] = OperandSpec::RegRRR; }, 11 => { instruction.operands[0] = mem_oper; @@ -7444,19 +7470,33 @@ fn read_operands< instruction.opcode = opcode; instruction.operand_count = 1; } - op @ 15 | - op @ 16 => { - let w = if op == 15 { - instruction.mem_size = 1; - if instruction.prefixes.rex_unchecked().present() { - RegisterBank::rB - } else { - RegisterBank::B - } + 15 => { + let w = if instruction.prefixes.rex_unchecked().present() { + RegisterBank::rB } else { - instruction.mem_size = 2; - RegisterBank::W + RegisterBank::B }; + instruction.mem_size = 1; + let bank = instruction.prefixes.vqp_size(); + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E(words, instruction, modrm, w, sink)?; + instruction.regs[0] = + 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 = 0; + } + instruction.operand_count = 2; + } + 16 => { + let w = RegisterBank::W; + instruction.mem_size = 2; let bank = instruction.prefixes.vqp_size(); let modrm = read_modrm(words)?; -- cgit v1.1