diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/long_mode/mod.rs | 245 | 
1 files changed, 117 insertions, 128 deletions
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 7986650..b30e4ee 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -2559,12 +2559,6 @@ impl PartialEq for Instruction {  #[derive(Debug, Clone, Copy, Eq)]  pub struct Instruction {      pub prefixes: Prefixes, -    /* -    modrm_rrr: RegSpec, -    modrm_mmm: RegSpec, // doubles as sib_base -    sib_index: RegSpec, -    vex_reg: RegSpec, -    */      regs: [RegSpec; 4],      scale: u8,      length: u8, @@ -6977,9 +6971,43 @@ fn read_operands<              }              3 => {                  // category == 3, Zv_Ivq_R -                let bank = self.vqp_size(); -                instruction.regs[0] = -                    RegSpec::from_parts(reg, instruction.prefixes.rex_unchecked().b(), bank); +                if instruction.prefixes.rex_unchecked().w() { +                    instruction.regs[0] = +                        RegSpec::from_parts(reg, instruction.prefixes.rex_unchecked().b(), RegisterBank::Q); +                    instruction.imm = read_num(words, 8)? as u64; +                    instruction.operands[1] = OperandSpec::ImmI64; +                    let width = 8; +                    sink.record( +                        words.offset() as u32 * 8 - (8 * width as u32), +                        words.offset() as u32 * 8 - 1, +                        InnerDescription::Number("imm", instruction.imm as i64) +                            .with_id(words.offset() as u32 * 8 - (8 * width as u32) + 1) +                    ); +                } else if instruction.prefixes.operand_size() { +                    instruction.regs[0] = +                        RegSpec::from_parts(reg, instruction.prefixes.rex_unchecked().b(), RegisterBank::W); +                    instruction.imm = read_num(words, 2)? as u16 as u64; +                    instruction.operands[1] = OperandSpec::ImmI16; +                    let width = 2; +                    sink.record( +                        words.offset() as u32 * 8 - (8 * width as u32), +                        words.offset() as u32 * 8 - 1, +                        InnerDescription::Number("imm", instruction.imm as i64) +                            .with_id(words.offset() as u32 * 8 - (8 * width as u32) + 1) +                    ); +                } else { +                    instruction.regs[0] = +                        RegSpec::from_parts(reg, instruction.prefixes.rex_unchecked().b(), RegisterBank::D); +                    instruction.imm = read_num(words, 4)? as u32 as u64; +                    instruction.operands[1] = OperandSpec::ImmI32; +                    let width = 4; +                    sink.record( +                        words.offset() as u32 * 8 - (8 * width as u32), +                        words.offset() as u32 * 8 - 1, +                        InnerDescription::Number("imm", instruction.imm as i64) +                            .with_id(words.offset() as u32 * 8 - (8 * width as u32) + 1) +                    ); +                }                  sink.record(                      opcode_start,                      opcode_start + 2, @@ -6994,26 +7022,6 @@ fn read_operands<                              .with_id(opcode_start + 2)                      );                  } -                instruction.imm = -                    read_imm_ivq(words, bank as u8)?; -                const TBL: [OperandSpec; 9] = [ -                    OperandSpec::ImmI16, -                    OperandSpec::ImmI16, -                    OperandSpec::ImmI16, -                    OperandSpec::ImmI32, -                    OperandSpec::ImmI32, -                    OperandSpec::ImmI64, -                    OperandSpec::ImmI64, -                    OperandSpec::ImmI64, -                    OperandSpec::ImmI64, -                ]; -                instruction.operands[1] = *TBL.get(bank as usize).unwrap_or_else(|| unsafe { unreachable_unchecked() } ); -                sink.record( -                    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 * bank as u8 as u32) + 1) -                );                  instruction.operand_count = 2;              }              _ => { @@ -7073,17 +7081,18 @@ fn read_operands<                  InnerDescription::Opcode(instruction.opcode)                      .with_id(modrm_start - 8)              ); -            let opwidth = instruction.regs[0].bank as u8; -            if opwidth == 8 { -                instruction.imm = read_imm_signed(words, 4)? as u64; +            if self.vqp_size == RegisterBank::W { +                let opwidth = 2; +                instruction.imm = read_imm_signed(words, opwidth)? as u64;                  sink.record( -                    words.offset() as u32 * 8 - 32, +                    words.offset() as u32 * 8 - (opwidth as u32 * 8),                      words.offset() as u32 * 8 - 1,                      InnerDescription::Number("imm", instruction.imm as i64) -                        .with_id(words.offset() as u32 * 8 - 32) +                        .with_id(words.offset() as u32 * 8 - (opwidth as u32 * 8))                  ); -                instruction.operands[1] = OperandSpec::ImmI64; +                instruction.operands[1] = OperandSpec::ImmI16;              } else { +                let opwidth = 4;                  instruction.imm = read_imm_signed(words, opwidth)? as u64;                  sink.record(                      words.offset() as u32 * 8 - (opwidth as u32 * 8), @@ -7091,12 +7100,12 @@ fn read_operands<                      InnerDescription::Number("imm", instruction.imm as i64)                          .with_id(words.offset() as u32 * 8 - (opwidth as u32 * 8))                  ); -                if opwidth == 4 { -                    instruction.operands[1] = OperandSpec::ImmI32; +                if self.vqp_size == RegisterBank::Q { +                    instruction.operands[1] = OperandSpec::ImmI64;                  } else { -                    instruction.operands[1] = OperandSpec::ImmI16; +                    instruction.operands[1] = OperandSpec::ImmI32;                  } -            }; +            }          },          OperandCase::MovI8 => {              if self.rrr != 0 { @@ -7135,8 +7144,8 @@ fn read_operands<          }          OperandCase::MovIv => { -            let opwidth = instruction.regs[0].bank as u8;              if self.rrr != 0 { +                let opwidth = instruction.regs[0].bank as u8;                  if mem_oper == OperandSpec::RegMMM && instruction.regs[1].num & 0b0111 == 0 {                      instruction.opcode = Opcode::XBEGIN;                      instruction.imm = if opwidth == 2 { @@ -7173,20 +7182,29 @@ fn read_operands<              instruction.operands[0] = mem_oper;              instruction.opcode = Opcode::MOV; -            let numwidth = if opwidth == 8 { 4 } else { opwidth }; -            instruction.imm = read_imm_signed(words, numwidth)? as u64; -            instruction.operands[1] = match opwidth { -                2 => OperandSpec::ImmI16, -                4 => OperandSpec::ImmI32, -                8 => OperandSpec::ImmI64, -                _ => unsafe { unreachable_unchecked() } -            }; -            sink.record( -                modrm_start + 8, -                modrm_start + numwidth as u32 * 8 - 1, -                InnerDescription::Number("imm", instruction.imm as i64) -                    .with_id(modrm_start + 8) -            ); +            if self.vqp_size == RegisterBank::W { +                instruction.imm = read_imm_signed(words, 2)? as u64; +                sink.record( +                    modrm_start + 8, +                    modrm_start + 2 as u32 * 8 - 1, +                    InnerDescription::Number("imm", instruction.imm as i64) +                        .with_id(modrm_start + 8) +                ); +                instruction.operands[1] = OperandSpec::ImmI16; +            } else { +                instruction.imm = read_imm_signed(words, 4)? as u64; +                sink.record( +                    modrm_start + 8, +                    modrm_start + 4 as u32 * 8 - 1, +                    InnerDescription::Number("imm", instruction.imm as i64) +                        .with_id(modrm_start + 8) +                ); +                if self.vqp_size == RegisterBank::Q { +                    instruction.operands[1] = OperandSpec::ImmI64; +                } else { +                    instruction.operands[1] = OperandSpec::ImmI32; +                } +            }          },          OperandCase::BitwiseWithI8 => {              instruction.operands[0] = mem_oper; @@ -7274,7 +7292,6 @@ fn read_operands<          },          OperandCase::ModRM_0xf7 => { -            let opwidth = instruction.regs[0].bank as u8;              instruction.operands[0] = mem_oper;              const TABLE: [Opcode; 8] = [                  Opcode::TEST, Opcode::TEST, Opcode::NOT, Opcode::NEG, @@ -7288,21 +7305,29 @@ fn read_operands<                      .with_id(modrm_start - 8)              );              if self.rrr < 2 { -                instruction.opcode = Opcode::TEST; -                let numwidth = if opwidth == 8 { 4 } else { opwidth }; -                instruction.imm = read_imm_signed(words, numwidth)? as u64; -                instruction.operands[1] = match opwidth { -                    2 => OperandSpec::ImmI16, -                    4 => OperandSpec::ImmI32, -                    8 => OperandSpec::ImmI64, -                    _ => unsafe { unreachable_unchecked() } +                if self.vqp_size == RegisterBank::W { +                    instruction.imm = read_imm_signed(words, 2)? as u64; +                    instruction.operands[1] = OperandSpec::ImmI16; +                    sink.record( +                        modrm_start + 8, +                        modrm_start + 8 + 2 as u32 * 8 - 1, +                        InnerDescription::Number("imm", instruction.imm as i64) +                            .with_id(modrm_start + 8) +                    ); +                } else { +                    instruction.imm = read_imm_signed(words, 4)? as u64; +                    sink.record( +                        modrm_start + 8, +                        modrm_start + 8 + 4 as u32 * 8 - 1, +                        InnerDescription::Number("imm", instruction.imm as i64) +                            .with_id(modrm_start + 8) +                    ); +                    if self.vqp_size == RegisterBank::Q { +                        instruction.operands[1] = OperandSpec::ImmI64; +                    } else { +                        instruction.operands[1] = OperandSpec::ImmI32; +                    }                  }; -                sink.record( -                    modrm_start + 8, -                    modrm_start + 8 + numwidth as u32 * 8 - 1, -                    InnerDescription::Number("imm", instruction.imm as i64) -                        .with_id(modrm_start + 8) -                );              } else {                  instruction.operand_count = 1;              } @@ -7554,21 +7579,29 @@ fn read_operands<              );          }          OperandCase::Ivs => { -            let opwidth = imm_width_from_prefixes_64(SizeCode::vd, instruction.prefixes); -            instruction.imm = -                read_imm_unsigned(words, opwidth)?; -            instruction.operands[0] = match opwidth { -                2 => OperandSpec::ImmI16, -                4 => OperandSpec::ImmI32, -                8 => OperandSpec::ImmI64, -                _ => unsafe { unreachable_unchecked() } -            }; -            sink.record( -                words.offset() as u32 * 8 - opwidth as u32 * 8, -                words.offset() as u32 * 8 - 1, -                InnerDescription::Number("imm", instruction.imm as i64) -                    .with_id(words.offset() as u32 * 8 - opwidth as u32 * 8 + 1) -            ); +            if instruction.prefixes.rex_unchecked().w() || !instruction.prefixes.operand_size() { +                instruction.imm = read_imm_unsigned(words, 4)?; +                instruction.operands[0] = OperandSpec::ImmI32; + +                let opwidth = 4; +                sink.record( +                    words.offset() as u32 * 8 - opwidth as u32 * 8, +                    words.offset() as u32 * 8 - 1, +                    InnerDescription::Number("imm", instruction.imm as i64) +                        .with_id(words.offset() as u32 * 8 - opwidth as u32 * 8 + 1) +                ); +            } else { +                instruction.imm = read_imm_unsigned(words, 2)?; +                instruction.operands[0] = OperandSpec::ImmI16; + +                let opwidth = 2; +                sink.record( +                    words.offset() as u32 * 8 - opwidth as u32 * 8, +                    words.offset() as u32 * 8 - 1, +                    InnerDescription::Number("imm", instruction.imm as i64) +                        .with_id(words.offset() as u32 * 8 - opwidth as u32 * 8 + 1) +                ); +            }              instruction.operand_count = 1;          },          OperandCase::ModRM_0x83 => { @@ -10780,24 +10813,6 @@ fn read_num<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_ar      }  } -#[inline] -fn read_imm_ivq<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(bytes: &mut T, width: u8) -> Result<u64, DecodeError> { -    match width { -        2 => { -            Ok(read_num(bytes, 2)? as u16 as u64) -        }, -        4 => { -            Ok(read_num(bytes, 4)? as u32 as u64) -        }, -        8 => { -            Ok(read_num(bytes, 8)? as u64) -        }, -        _ => { -            unsafe { unreachable_unchecked(); } -        } -    } -} -  #[inline(always)]  fn read_imm_signed<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(bytes: &mut T, num_width: u8) -> Result<i64, DecodeError> {      if num_width == 1 { @@ -10842,32 +10857,6 @@ fn bank_from_prefixes_64(interpretation: SizeCode, prefixes: Prefixes) -> Regist  }  #[inline] -fn imm_width_from_prefixes_64(interpretation: SizeCode, prefixes: Prefixes) -> u8 { -    match interpretation { -        SizeCode::b => 1, -        SizeCode::vd => { -            if prefixes.rex_unchecked().w() || !prefixes.operand_size() { 4 } else { 2 } -        }, -        SizeCode::vq => { -            if prefixes.operand_size() { -                2 -            } else { -                8 -            } -        }, -        SizeCode::vqp => { -            if prefixes.rex_unchecked().w() { -                8 -            } else if prefixes.operand_size() { -                2 -            } else { -                4 -            } -        }, -    } -} - -#[inline]  fn read_modrm<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T) -> Result<u8, DecodeError> {      words.next().ok().ok_or(DecodeError::ExhaustedInput)  }  | 
