diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/long_mode/display.rs | 54 | ||||
| -rw-r--r-- | src/long_mode/mod.rs | 316 | ||||
| -rw-r--r-- | src/long_mode/uarch.rs | 4 | ||||
| -rw-r--r-- | src/long_mode/vex.rs | 182 | ||||
| -rw-r--r-- | src/protected_mode/display.rs | 46 | ||||
| -rw-r--r-- | src/protected_mode/mod.rs | 272 | ||||
| -rw-r--r-- | src/protected_mode/uarch.rs | 4 | ||||
| -rw-r--r-- | src/protected_mode/vex.rs | 166 | 
8 files changed, 936 insertions, 108 deletions
| diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index 5318ebb..807565c 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -306,6 +306,9 @@ impl fmt::Display for Opcode {              &Opcode::BTC => write!(f, "btc"),              &Opcode::BSF => write!(f, "bsf"),              &Opcode::BSR => write!(f, "bsr"), +            &Opcode::BZHI => write!(f, "bzhi"), +            &Opcode::PDEP => write!(f, "pdep"), +            &Opcode::PEXT => write!(f, "pext"),              &Opcode::TZCNT => write!(f, "tzcnt"),              &Opcode::MOVSS => write!(f, "movss"),              &Opcode::SQRTSS => write!(f, "sqrtss"), @@ -354,17 +357,30 @@ impl fmt::Display for Opcode {              &Opcode::RDMSR => write!(f, "rdmsr"),              &Opcode::RDTSC => write!(f, "rdtsc"),              &Opcode::RDPMC => write!(f, "rdpmc"), +            &Opcode::RDPID => write!(f, "rdpid"), +            &Opcode::RDFSBASE => write!(f, "rdfsbase"), +            &Opcode::RDGSBASE => write!(f, "rdgsbase"), +            &Opcode::WRFSBASE => write!(f, "wrfsbase"), +            &Opcode::WRGSBASE => write!(f, "wrgsbase"),              &Opcode::FXSAVE => write!(f, "fxsave"),              &Opcode::FXRSTOR => write!(f, "fxrstor"),              &Opcode::LDMXCSR => write!(f, "ldmxcsr"),              &Opcode::STMXCSR => write!(f, "stmxcsr"),              &Opcode::XSAVE => write!(f, "xsave"), +            &Opcode::XSAVEC => write!(f, "xsavec"), +            &Opcode::XSAVES => write!(f, "xsaves"), +            &Opcode::XSAVEC64 => write!(f, "xsavec64"), +            &Opcode::XSAVES64 => write!(f, "xsaves64"),              &Opcode::XRSTOR => write!(f, "xrstor"), +            &Opcode::XRSTORS => write!(f, "xrstors"), +            &Opcode::XRSTORS64 => write!(f, "xrstors64"),              &Opcode::XSAVEOPT => write!(f, "xsaveopt"),              &Opcode::LFENCE => write!(f, "lfence"),              &Opcode::MFENCE => write!(f, "mfence"),              &Opcode::SFENCE => write!(f, "sfence"),              &Opcode::CLFLUSH => write!(f, "clflush"), +            &Opcode::CLFLUSHOPT => write!(f, "clflushopt"), +            &Opcode::CLWB => write!(f, "clwb"),              &Opcode::SGDT => write!(f, "sgdt"),              &Opcode::SIDT => write!(f, "sidt"),              &Opcode::LGDT => write!(f, "lgdt"), @@ -450,11 +466,15 @@ impl fmt::Display for Opcode {              &Opcode::SAR => write!(f, "sar"),              &Opcode::SAL => write!(f, "sal"),              &Opcode::SHR => write!(f, "shr"), +            &Opcode::SARX => write!(f, "sarx"), +            &Opcode::SHLX => write!(f, "shlx"), +            &Opcode::SHRX => write!(f, "shrx"),              &Opcode::SHRD => write!(f, "shrd"),              &Opcode::SHL => write!(f, "shl"),              &Opcode::RCR => write!(f, "rcr"),              &Opcode::RCL => write!(f, "rcl"),              &Opcode::ROR => write!(f, "ror"), +            &Opcode::RORX => write!(f, "rorx"),              &Opcode::ROL => write!(f, "rol"),              &Opcode::CMOVA => write!(f, "cmova"),              &Opcode::CMOVB => write!(f, "cmovb"), @@ -475,9 +495,12 @@ impl fmt::Display for Opcode {              &Opcode::NEG => write!(f, "neg"),              &Opcode::NOT => write!(f, "not"),              &Opcode::MUL => write!(f, "mul"), +            &Opcode::MULX => write!(f, "mulx"),              &Opcode::DIV => write!(f, "div"),              &Opcode::IDIV => write!(f, "idiv"),              &Opcode::CMPXCHG => write!(f, "cmpxchg"), +            &Opcode::CMPXCHG8B => write!(f, "cmpxchg8b"), +            &Opcode::CMPXCHG16B => write!(f, "cmpxchg16b"),              &Opcode::MOVSX_b => write!(f, "movsx"),              &Opcode::MOVSX_w => write!(f, "movsx"),              &Opcode::MOVZX_b => write!(f, "movzx"), @@ -652,6 +675,8 @@ impl fmt::Display for Opcode {              &Opcode::BLSMSK => write!(f, "blsmsk"),              &Opcode::BLSR => write!(f, "blsr"),              &Opcode::VMCLEAR => write!(f, "vmclear"), +            &Opcode::VMPTRLD => write!(f, "vmptrld"), +            &Opcode::VMPTRST => write!(f, "vmptrst"),              &Opcode::VMXON => write!(f, "vmxon"),              &Opcode::VMCALL => write!(f, "vmcall"),              &Opcode::VMLAUNCH => write!(f, "vmlaunch"), @@ -1310,16 +1335,21 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color              Opcode::DIV |              Opcode::IDIV |              Opcode::MUL | +            Opcode::MULX |              Opcode::NEG |              Opcode::NOT |              Opcode::SAR |              Opcode::SAL |              Opcode::SHR | +            Opcode::SARX | +            Opcode::SHLX | +            Opcode::SHRX |              Opcode::SHRD |              Opcode::SHL |              Opcode::RCR |              Opcode::RCL |              Opcode::ROR | +            Opcode::RORX |              Opcode::ROL |              Opcode::INC |              Opcode::DEC | @@ -1341,6 +1371,9 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color              Opcode::BTC |              Opcode::BSF |              Opcode::BSR | +            Opcode::BZHI | +            Opcode::PDEP | +            Opcode::PEXT |              Opcode::TZCNT |              Opcode::ANDN |              Opcode::BEXTR | @@ -1833,23 +1866,38 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color              Opcode::CMP |              Opcode::CMPPS |              Opcode::CMPPD | +            Opcode::CMPXCHG8B | +            Opcode::CMPXCHG16B |              Opcode::CMPXCHG => { write!(out, "{}", colors.comparison_op(self)) }              Opcode::WRMSR |              Opcode::RDMSR |              Opcode::RDTSC |              Opcode::RDPMC | +            Opcode::RDPID | +            Opcode::RDFSBASE | +            Opcode::RDGSBASE | +            Opcode::WRFSBASE | +            Opcode::WRGSBASE |              Opcode::FXSAVE |              Opcode::FXRSTOR |              Opcode::LDMXCSR |              Opcode::STMXCSR |              Opcode::XSAVE | +            Opcode::XSAVEC | +            Opcode::XSAVES | +            Opcode::XSAVEC64 | +            Opcode::XSAVES64 |              Opcode::XRSTOR | +            Opcode::XRSTORS | +            Opcode::XRSTORS64 |              Opcode::XSAVEOPT |              Opcode::LFENCE |              Opcode::MFENCE |              Opcode::SFENCE |              Opcode::CLFLUSH | +            Opcode::CLFLUSHOPT | +            Opcode::CLWB |              Opcode::SGDT |              Opcode::SIDT |              Opcode::LGDT | @@ -1886,6 +1934,8 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color              Opcode::VMREAD |              Opcode::VMWRITE |              Opcode::VMCLEAR | +            Opcode::VMPTRLD | +            Opcode::VMPTRST |              Opcode::VMXON |              Opcode::VMCALL |              Opcode::VMLAUNCH | @@ -1993,6 +2043,10 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> ShowContextual<u6          self.opcode.colorize(colors, out)?; +        if self.opcode == Opcode::XBEGIN { +            return write!(out, " $+{}", colors.number(signed_i32_hex(self.imm as i32))); +        } +          match self.operands[0] {              OperandSpec::Nothing => {                  return Ok(()); diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 20abe1f..58d4c57 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -528,17 +528,36 @@ const BMI1: [Opcode; 6] = [      Opcode::TZCNT,  ]; +const BMI2: [Opcode; 8] = [ +    Opcode::BZHI, +    Opcode::MULX, +    Opcode::PDEP, +    Opcode::PEXT, +    Opcode::RORX, +    Opcode::SARX, +    Opcode::SHRX, +    Opcode::SHLX, +]; + +#[allow(dead_code)] +const XSAVE: [Opcode; 10] = [ +    Opcode::XGETBV, +    Opcode::XRSTOR, +    Opcode::XRSTORS, +    Opcode::XSAVE, +    Opcode::XSAVEC, +    Opcode::XSAVEC64, +    Opcode::XSAVEOPT, +    Opcode::XSAVES, +    Opcode::XSAVES64, +    Opcode::XSETBV, +]; +  // TODO:  // PTWRITE -// RDFSBASE -// RDGSBASE -// WRFSBASE -// WRGSBASE  // TPAUSE  // UMONITOR  // UMWAIT -// CLFLUSHOPT -// CLWB  #[allow(non_camel_case_types)]  #[derive(Copy, Clone, Debug, Eq, PartialEq)]  pub enum Opcode { @@ -740,6 +759,8 @@ pub enum Opcode {      MFENCE,      SFENCE,      CLFLUSH, +    CLFLUSHOPT, +    CLWB,      WRMSR,      RDTSC,      RDMSR, @@ -1376,6 +1397,32 @@ pub enum Opcode {      ADOX,      PREFETCHW, + +    RDPID, +    CMPXCHG8B, +    CMPXCHG16B, +    VMPTRLD, +    VMPTRST, + +    BZHI, +    MULX, +    SHLX, +    SHRX, +    SARX, +    PDEP, +    PEXT, +    RORX, +    XRSTORS, +    XRSTORS64, +    XSAVEC, +    XSAVEC64, +    XSAVES, +    XSAVES64, + +    RDFSBASE, +    RDGSBASE, +    WRFSBASE, +    WRGSBASE,  }  #[derive(Debug)] @@ -2094,7 +2141,7 @@ impl InstDecoder {      /// the clearest documentation on when these instructions were reintroduced into 64-bit      /// architectures seems to be      /// [wikipedia](https://en.wikipedia.org/wiki/X86-64#Older_implementations): -    /// ``` +    /// ```text      /// Early AMD64 and Intel 64 CPUs lacked LAHF and SAHF instructions in 64-bit mode. AMD      /// introduced these instructions (also in 64-bit mode) with their Athlon 64, Opteron and      /// Turion 64 revision D processors in March 2005[48][49][50] while Intel introduced the @@ -2686,9 +2733,8 @@ impl InstDecoder {                   * (if CPUID.01H:ECX.POPCNT[bit 23] = 1).                   * ```                   */ -                if self.intel_quirks() && (!self.sse4_2() || !self.popcnt()) { -                    inst.opcode = Opcode::Invalid; -                    return Err(DecodeError::InvalidOpcode); +                if self.intel_quirks() && (self.sse4_2() || self.popcnt()) { +                    return Ok(());                  } else if !self.popcnt() {                      /*                       * elsewhere from the amd APM: @@ -2795,6 +2841,11 @@ impl InstDecoder {                          return Err(DecodeError::InvalidOpcode);                      }                  } +                if !self.bmi2() { +                    if BMI2.contains(&other) { +                        return Err(DecodeError::InvalidOpcode); +                    } +                }              }          }          Ok(()) @@ -3137,6 +3188,8 @@ pub enum OperandCode {      ModRM_0x0fae,      ModRM_0x0fba,      ModRM_0xf238, +    ModRM_0xf30fae, +    ModRM_0x660fae,      ModRM_0xf30fc7,      ModRM_0x660f38,      ModRM_0xf30f38, @@ -3513,7 +3566,7 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660fae),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),  // 0xb0      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -4075,7 +4128,7 @@ const OPCODE_F30F_MAP: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30fae),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),  // 0xb0      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -5379,13 +5432,12 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,                      return Ok(());                  } else {                      instruction.opcode = Opcode::XBEGIN; -                    instruction.disp = if opwidth == 2 { +                    instruction.imm = if opwidth == 2 {                          read_imm_signed(&mut bytes_iter, 2, length)? as i16 as i64 as u64                      } else {                          read_imm_signed(&mut bytes_iter, 4, length)? as i32 as i64 as u64                      }; -                    instruction.modrm_mmm = RegSpec::rip(); -                    instruction.operands[0] = OperandSpec::RegDisp; +                    instruction.operands[0] = OperandSpec::ImmI32;                      instruction.operand_count = 1;                      return Ok(());                  } @@ -5628,6 +5680,9 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,              instruction.imm =                  read_num(&mut bytes_iter, 1)? as u8 as u64;              *length += 1; +            if instruction.operands[1] == OperandSpec::RegMMM { +                instruction.modrm_mmm.bank = RegisterBank::MM; +            }              instruction.operands[2] = OperandSpec::ImmI8;              instruction.operand_count = 3;          }, @@ -5776,7 +5831,7 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter          }          OperandCode::ModRM_0x0f0d => {              let modrm = read_modrm(&mut bytes_iter, length)?; -            let r = modrm & 0b111; +            let r = (modrm >> 3) & 0b111;              let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); @@ -5842,46 +5897,94 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter              return read_operands(decoder, bytes_iter, instruction, operands, length);          },          OperandCode::ModRM_0x0f3a => { +            let opcode = read_modrm(&mut bytes_iter, length)?; +            if opcode == 0xcc { +                instruction.opcode = Opcode::SHA1RNDS4; +                return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); +            } else if opcode == 0x0f { +                instruction.opcode = Opcode::PALIGNR; +                return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm_Ib, length); +            }          },          OperandCode::ModRM_0x0fc7 => {              let modrm = read_modrm(&mut bytes_iter, length)?; -            if modrm >> 6 == 0b11 { -                match (modrm >> 3) & 0b111 { -                    0b111 => { -                        instruction.opcode = Opcode::RDSEED; -                        instruction.operand_count = 1; -                        instruction.operands[0] = OperandSpec::RegRRR; -                        let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); -                        instruction.modrm_rrr = -                            RegSpec::from_parts(modrm & 7, instruction.prefixes.rex().r(), match opwidth { -                                8 => RegisterBank::Q, -                                4 => RegisterBank::D, -                                2 => RegisterBank::W, -                                _ => unreachable!() -                            }); +            let is_reg = (modrm & 0xc0) == 0xc0; + +            let r = (modrm >> 3) & 0b111; + +            let opcode = match r { +                0b001 => { +                    if is_reg { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOperand); +                    } else { +                        if instruction.prefixes.rex().w() { +                            Opcode::CMPXCHG16B +                        } else { +                            Opcode::CMPXCHG8B +                        }                      } -                    0b110 => { -                        instruction.opcode = Opcode::RDRAND; -                        instruction.operand_count = 1; -                        instruction.operands[0] = OperandSpec::RegRRR; -                        let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); -                        instruction.modrm_rrr = -                            RegSpec::from_parts(modrm & 7, instruction.prefixes.rex().r(), match opwidth { -                                8 => RegisterBank::Q, -                                4 => RegisterBank::D, -                                2 => RegisterBank::W, -                                _ => unreachable!() -                            }); +                } +                0b011 => { +                    if is_reg { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOperand); +                    } else { +                        if instruction.prefixes.rex().w() { +                            Opcode::XRSTORS64 +                        } else { +                            Opcode::XRSTORS +                        }                      } -                    _ => { +                } +                0b100 => { +                    if is_reg {                          instruction.opcode = Opcode::Invalid; -                        return Err(DecodeError::InvalidOpcode); +                        return Err(DecodeError::InvalidOperand); +                    } else { +                        if instruction.prefixes.rex().w() { +                            Opcode::XSAVEC64 +                        } else { +                            Opcode::XSAVEC +                        }                      }                  } -            } else { -                instruction.opcode = Opcode::Invalid; -                return Err(DecodeError::InvalidOpcode); -            } +                0b101 => { +                    if is_reg { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOperand); +                    } else { +                        if instruction.prefixes.rex().w() { +                            Opcode::XSAVES64 +                        } else { +                            Opcode::XSAVES +                        } +                    } +                } +                0b110 => { +                    if is_reg { +                        Opcode::RDRAND +                    } else { +                        Opcode::VMPTRLD +                    } +                } +                0b111 => { +                    if is_reg { +                        Opcode::RDSEED +                    } else { +                        Opcode::VMPTRST +                    } +                } +                _ => { +                    instruction.opcode = Opcode::Invalid; +                    return Err(DecodeError::InvalidOperand); +                } +            }; + +            instruction.opcode = opcode; +            instruction.operand_count = 1; +            let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); +            instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;          },          OperandCode::ModRM_0x0f71 => {              instruction.operand_count = 2; @@ -6168,15 +6271,33 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter              instruction.operands[1] = OperandSpec::ImmU8;          },          OperandCode::ModRM_0x660fc7 => { +            let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);              let modrm = read_modrm(&mut bytes_iter, length)?;              let r = (modrm >> 3) & 7;              match r {                  6 => {                      instruction.opcode = Opcode::VMCLEAR; -                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?; +                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;                      if instruction.operands[0] == OperandSpec::RegMMM { -                        return Err(DecodeError::InvalidOperand); +                        // 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 +                        // word-form operand: +                        instruction.modrm_mmm = RegSpec { bank: RegisterBank::W, num: instruction.modrm_mmm.num }; +                        instruction.opcode = Opcode::RDRAND; +                    } +                    instruction.operand_count = 1; +                } +                7 => { +                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; +                    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 +                        // word-form operand: +                        instruction.modrm_mmm = RegSpec { bank: RegisterBank::W, num: instruction.modrm_mmm.num }; +                        instruction.opcode = Opcode::RDSEED; +                    } else { +                        return Err(DecodeError::InvalidOpcode);                      }                      instruction.operand_count = 1;                  } @@ -6185,15 +6306,108 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter                  }              }          }, +        OperandCode::ModRM_0x660fae => { +            let modrm = read_modrm(&mut bytes_iter, length)?; +            if modrm < 0xc0 { +                instruction.opcode = match (modrm >> 3) & 7 { +                    6 => { +                        Opcode::CLWB +                    } +                    7 => { +                        Opcode::CLFLUSHOPT +                    } +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                }; +                instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* opwidth */, length)?; +                instruction.operand_count = 1; +            } else { +                instruction.opcode = Opcode::Invalid; +                return Err(DecodeError::InvalidOpcode); +            } +        }, +        OperandCode::ModRM_0xf30fae => { +            let modrm = read_modrm(&mut bytes_iter, length)?; + +            if (modrm & 0xc0) == 0xc0 { +                let r = (modrm >> 3) & 7; +                let m = modrm & 7; +                match r { +                    0 => { +                        instruction.opcode = Opcode::RDFSBASE; +                        let opwidth = if instruction.prefixes.rex().w() { +                            RegisterBank::Q +                        } else { +                            RegisterBank::D +                        }; +                        instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); +                        instruction.operands[0] = OperandSpec::RegMMM; +                        instruction.operand_count = 1; +                    } +                    1 => { +                        instruction.opcode = Opcode::RDGSBASE; +                        let opwidth = if instruction.prefixes.rex().w() { +                            RegisterBank::Q +                        } else { +                            RegisterBank::D +                        }; +                        instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); +                        instruction.operands[0] = OperandSpec::RegMMM; +                        instruction.operand_count = 1; + +                    } +                    2 => { +                        instruction.opcode = Opcode::WRFSBASE; +                        let opwidth = if instruction.prefixes.rex().w() { +                            RegisterBank::Q +                        } else { +                            RegisterBank::D +                        }; +                        instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); +                        instruction.operands[0] = OperandSpec::RegMMM; +                        instruction.operand_count = 1; +                    } +                    3 => { +                        instruction.opcode = Opcode::WRGSBASE; +                        let opwidth = if instruction.prefixes.rex().w() { +                            RegisterBank::Q +                        } else { +                            RegisterBank::D +                        }; +                        instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); +                        instruction.operands[0] = OperandSpec::RegMMM; +                        instruction.operand_count = 1; + +                    } +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                } +            } +        }          OperandCode::ModRM_0xf30fc7 => { +            let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);              let modrm = read_modrm(&mut bytes_iter, length)?;              let r = (modrm >> 3) & 7;              match r {                  6 => {                      instruction.opcode = Opcode::VMXON; -                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?; +                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;                      if instruction.operands[0] == OperandSpec::RegMMM { +                        // this would be invalid as `vmxon`, so fall back to the parse as +                        // f3-prefixed rdrand +                        instruction.opcode = Opcode::RDRAND; +                    } +                    instruction.operand_count = 1; +                } +                7 => { +                    instruction.opcode = Opcode::RDPID; +                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; +                    if instruction.operands[0] != OperandSpec::RegMMM {                          return Err(DecodeError::InvalidOperand);                      }                      instruction.operand_count = 1; diff --git a/src/long_mode/uarch.rs b/src/long_mode/uarch.rs index b2b1201..94b6b45 100644 --- a/src/long_mode/uarch.rs +++ b/src/long_mode/uarch.rs @@ -203,7 +203,9 @@ pub mod intel {      /// common denominator: if you want a `Skylake` decoder with AVX512, something like the      /// following:      /// ``` -    /// InstDecoder::skylake().with_avx512_f().with_avx512_dq() +    /// yaxpeax_x86::long_mode::uarch::intel::skylake() +    ///     .with_avx512_f() +    ///     .with_avx512_dq();      /// ```      /// is likely your best option.      pub fn skylake() -> InstDecoder { diff --git a/src/long_mode/vex.rs b/src/long_mode/vex.rs index fe50c4e..cf30622 100644 --- a/src/long_mode/vex.rs +++ b/src/long_mode/vex.rs @@ -83,6 +83,10 @@ enum VEXOperandCode {      Ed_G_xmm,      G_xmm_Ed,      G_xmm_Eq, +    G_E_V, +    G_V_E, +    G_E_Ib, +    BMI1_F3,  }  #[inline(never)] @@ -694,6 +698,88 @@ fn read_vex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instruction: &mut Inst              instruction.operands[2] = OperandSpec::RegVex;              Ok(())          } +        VEXOperandCode::G_V_E => { +            let modrm = read_modrm(bytes, length)?; +            let (opwidth, bank) = if instruction.prefixes.vex().w() { +                (8, RegisterBank::Q) +            } else { +                (4, RegisterBank::D) +            }; +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank); +            instruction.vex_reg.bank = bank; +            let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operands[1] = OperandSpec::RegVex; +            instruction.operands[2] = mem_oper; +            instruction.operand_count = 3; +            Ok(()) +        } +        VEXOperandCode::G_E_V => { +            let modrm = read_modrm(bytes, length)?; +            let (opwidth, bank) = if instruction.prefixes.vex().w() { +                (8, RegisterBank::Q) +            } else { +                (4, RegisterBank::D) +            }; +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank); +            instruction.vex_reg.bank = bank; +            let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operands[1] = mem_oper; +            instruction.operands[2] = OperandSpec::RegVex; +            instruction.operand_count = 3; +            Ok(()) +        } +        VEXOperandCode::G_E_Ib => { +            let modrm = read_modrm(bytes, length)?; +            let (opwidth, bank) = if instruction.prefixes.vex().w() { +                (8, RegisterBank::Q) +            } else { +                (4, RegisterBank::D) +            }; +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank); +            let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operands[1] = mem_oper; +            instruction.imm = read_imm_unsigned(bytes, 1, length)?; +            instruction.operands[2] = OperandSpec::ImmI8; +            instruction.operand_count = 3; +            Ok(()) +        } +        VEXOperandCode::BMI1_F3 => { +            let modrm = read_modrm(bytes, length)?; +            instruction.opcode = match (modrm >> 3) & 7 { +                1 => { +                    Opcode::BLSR +                } +                2 => { +                    Opcode::BLSMSK +                } +                3 => { +                    Opcode::BLSI +                } +                _ => { +                    instruction.opcode = Opcode::Invalid; +                    return Err(DecodeError::InvalidOpcode); +                } +            }; +            let (opwidth, bank) = if instruction.prefixes.vex().w() { +                (8, RegisterBank::Q) +            } else { +                (4, RegisterBank::D) +            }; +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank); +            let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?; +            instruction.operands[0] = OperandSpec::RegVex; +            instruction.operands[1] = mem_oper; +            instruction.operand_count = 2; +            instruction.vex_reg.bank = bank; +            Ok(()) +        }          VEXOperandCode::G_E_ymm_imm8 |          VEXOperandCode::G_V_E_xmm_xmm4 | @@ -2270,15 +2356,92 @@ fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: &                      } else {                          VEXOperandCode::G_V_E_xmm                      }), +                    0xF7 => (Opcode::SHLX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }), +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                } +            } else if let VEXOpcodePrefix::PrefixF2 = p { +                match opc { +                    0xF5 => (Opcode::PDEP, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_V_E +                    }), +                    0xF6 => (Opcode::MULX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_V_E +                    }), +                    0xF7 => (Opcode::SHRX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }), +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                } +            } else if let VEXOpcodePrefix::PrefixF3 = p { +                match opc { +                    0xF5 => (Opcode::PEXT, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_V_E +                    }), +                    0xF7 => (Opcode::SARX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }),                      _ => {                          instruction.opcode = Opcode::Invalid;                          return Err(DecodeError::InvalidOpcode);                      }                  }              } else { -                // the only VEX* 0f38 instructions have an implied 66 prefix. -                instruction.opcode = Opcode::Invalid; -                return Err(DecodeError::InvalidOpcode); +                match opc { +                    0xF2 => (Opcode::ANDN, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_V_E +                    }), +                    0xF3 => (Opcode::Invalid, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::BMI1_F3 +                    }), +                    0xF5 => (Opcode::BZHI, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }), +                    0xF7 => (Opcode::BEXTR, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }), +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                }              }          }          VEXOpcodeMap::Map0F3A => { @@ -2504,6 +2667,19 @@ fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: &                          return Err(DecodeError::InvalidOpcode);                      }                  } +            } else if let VEXOpcodePrefix::PrefixF2 = p { +                match opc { +                    0xF0 => (Opcode::RORX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_Ib +                    }), +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                }              } else {                  // the only VEX* 0f3a instructions have an implied 66 prefix.                  instruction.opcode = Opcode::Invalid; diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs index ed8d44c..77d39ff 100644 --- a/src/protected_mode/display.rs +++ b/src/protected_mode/display.rs @@ -291,6 +291,9 @@ impl fmt::Display for Opcode {              &Opcode::BTC => write!(f, "btc"),              &Opcode::BSF => write!(f, "bsf"),              &Opcode::BSR => write!(f, "bsr"), +            &Opcode::BZHI => write!(f, "bzhi"), +            &Opcode::PDEP => write!(f, "pdep"), +            &Opcode::PEXT => write!(f, "pext"),              &Opcode::TZCNT => write!(f, "tzcnt"),              &Opcode::MOVSS => write!(f, "movss"),              &Opcode::SQRTSS => write!(f, "sqrtss"), @@ -339,17 +342,27 @@ impl fmt::Display for Opcode {              &Opcode::RDMSR => write!(f, "rdmsr"),              &Opcode::RDTSC => write!(f, "rdtsc"),              &Opcode::RDPMC => write!(f, "rdpmc"), +            &Opcode::RDPID => write!(f, "rdpid"), +            &Opcode::RDFSBASE => write!(f, "rdfsbase"), +            &Opcode::RDGSBASE => write!(f, "rdgsbase"), +            &Opcode::WRFSBASE => write!(f, "wrfsbase"), +            &Opcode::WRGSBASE => write!(f, "wrgsbase"),              &Opcode::FXSAVE => write!(f, "fxsave"),              &Opcode::FXRSTOR => write!(f, "fxrstor"),              &Opcode::LDMXCSR => write!(f, "ldmxcsr"),              &Opcode::STMXCSR => write!(f, "stmxcsr"),              &Opcode::XSAVE => write!(f, "xsave"), +            &Opcode::XSAVEC => write!(f, "xsavec"), +            &Opcode::XSAVES => write!(f, "xsaves"),              &Opcode::XRSTOR => write!(f, "xrstor"), +            &Opcode::XRSTORS => write!(f, "xrstors"),              &Opcode::XSAVEOPT => write!(f, "xsaveopt"),              &Opcode::LFENCE => write!(f, "lfence"),              &Opcode::MFENCE => write!(f, "mfence"),              &Opcode::SFENCE => write!(f, "sfence"),              &Opcode::CLFLUSH => write!(f, "clflush"), +            &Opcode::CLFLUSHOPT => write!(f, "clflushopt"), +            &Opcode::CLWB => write!(f, "clwb"),              &Opcode::LDS => write!(f, "lds"),              &Opcode::LES => write!(f, "les"),              &Opcode::SGDT => write!(f, "sgdt"), @@ -437,11 +450,15 @@ impl fmt::Display for Opcode {              &Opcode::SAR => write!(f, "sar"),              &Opcode::SAL => write!(f, "sal"),              &Opcode::SHR => write!(f, "shr"), +            &Opcode::SARX => write!(f, "sarx"), +            &Opcode::SHLX => write!(f, "shlx"), +            &Opcode::SHRX => write!(f, "shrx"),              &Opcode::SHRD => write!(f, "shrd"),              &Opcode::SHL => write!(f, "shl"),              &Opcode::RCR => write!(f, "rcr"),              &Opcode::RCL => write!(f, "rcl"),              &Opcode::ROR => write!(f, "ror"), +            &Opcode::RORX => write!(f, "rorx"),              &Opcode::ROL => write!(f, "rol"),              &Opcode::CMOVA => write!(f, "cmova"),              &Opcode::CMOVB => write!(f, "cmovb"), @@ -462,9 +479,11 @@ impl fmt::Display for Opcode {              &Opcode::NEG => write!(f, "neg"),              &Opcode::NOT => write!(f, "not"),              &Opcode::MUL => write!(f, "mul"), +            &Opcode::MULX => write!(f, "mulx"),              &Opcode::DIV => write!(f, "div"),              &Opcode::IDIV => write!(f, "idiv"),              &Opcode::CMPXCHG => write!(f, "cmpxchg"), +            &Opcode::CMPXCHG8B => write!(f, "cmpxchg8b"),              &Opcode::MOVSX_b => write!(f, "movsx"),              &Opcode::MOVSX_w => write!(f, "movsx"),              &Opcode::MOVZX_b => write!(f, "movzx"), @@ -639,6 +658,8 @@ impl fmt::Display for Opcode {              &Opcode::BLSMSK => write!(f, "blsmsk"),              &Opcode::BLSR => write!(f, "blsr"),              &Opcode::VMCLEAR => write!(f, "vmclear"), +            &Opcode::VMPTRLD => write!(f, "vmptrld"), +            &Opcode::VMPTRST => write!(f, "vmptrst"),              &Opcode::VMXON => write!(f, "vmxon"),              &Opcode::VMCALL => write!(f, "vmcall"),              &Opcode::VMLAUNCH => write!(f, "vmlaunch"), @@ -1297,16 +1318,21 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color              Opcode::DIV |              Opcode::IDIV |              Opcode::MUL | +            Opcode::MULX |              Opcode::NEG |              Opcode::NOT |              Opcode::SAR |              Opcode::SAL |              Opcode::SHR | +            Opcode::SARX | +            Opcode::SHLX | +            Opcode::SHRX |              Opcode::SHRD |              Opcode::SHL |              Opcode::RCR |              Opcode::RCL |              Opcode::ROR | +            Opcode::RORX |              Opcode::ROL |              Opcode::INC |              Opcode::DEC | @@ -1328,6 +1354,9 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color              Opcode::BTC |              Opcode::BSF |              Opcode::BSR | +            Opcode::BZHI | +            Opcode::PDEP | +            Opcode::PEXT |              Opcode::TZCNT |              Opcode::ANDN |              Opcode::BEXTR | @@ -1819,23 +1848,34 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color              Opcode::CMP |              Opcode::CMPPS |              Opcode::CMPPD | +            Opcode::CMPXCHG8B |              Opcode::CMPXCHG => { write!(out, "{}", colors.comparison_op(self)) }              Opcode::WRMSR |              Opcode::RDMSR |              Opcode::RDTSC |              Opcode::RDPMC | +            Opcode::RDPID | +            Opcode::RDFSBASE | +            Opcode::RDGSBASE | +            Opcode::WRFSBASE | +            Opcode::WRGSBASE |              Opcode::FXSAVE |              Opcode::FXRSTOR |              Opcode::LDMXCSR |              Opcode::STMXCSR |              Opcode::XSAVE | +            Opcode::XSAVEC | +            Opcode::XSAVES |              Opcode::XRSTOR | +            Opcode::XRSTORS |              Opcode::XSAVEOPT |              Opcode::LFENCE |              Opcode::MFENCE |              Opcode::SFENCE |              Opcode::CLFLUSH | +            Opcode::CLFLUSHOPT | +            Opcode::CLWB |              Opcode::LDS |              Opcode::LES |              Opcode::SGDT | @@ -1875,6 +1915,8 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color              Opcode::VMREAD |              Opcode::VMWRITE |              Opcode::VMCLEAR | +            Opcode::VMPTRST | +            Opcode::VMPTRLD |              Opcode::VMXON |              Opcode::VMCALL |              Opcode::VMLAUNCH | @@ -1982,6 +2024,10 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> ShowContextual<u6          self.opcode.colorize(colors, out)?; +        if self.opcode == Opcode::XBEGIN { +            return write!(out, " $+{}", colors.number(signed_i32_hex(self.imm as i32))); +        } +          match self.operands[0] {              OperandSpec::Nothing => {                  return Ok(()); diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index 89c485f..2fe3b3e 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -478,17 +478,34 @@ const BMI1: [Opcode; 6] = [      Opcode::TZCNT,  ]; +const BMI2: [Opcode; 8] = [ +    Opcode::BZHI, +    Opcode::MULX, +    Opcode::PDEP, +    Opcode::PEXT, +    Opcode::RORX, +    Opcode::SARX, +    Opcode::SHRX, +    Opcode::SHLX, +]; + +#[allow(dead_code)] +const XSAVE: [Opcode; 8] = [ +    Opcode::XGETBV, +    Opcode::XRSTOR, +    Opcode::XRSTORS, +    Opcode::XSAVE, +    Opcode::XSAVEC, +    Opcode::XSAVEOPT, +    Opcode::XSAVES, +    Opcode::XSETBV, +]; +  // TODO:  // PTWRITE -// RDFSBASE -// RDGSBASE -// WRFSBASE -// WRGSBASE  // TPAUSE  // UMONITOR  // UMWAIT -// CLFLUSHOPT -// CLWB  #[allow(non_camel_case_types)]  #[derive(Copy, Clone, Debug, Eq, PartialEq)]  pub enum Opcode { @@ -692,6 +709,8 @@ pub enum Opcode {      MFENCE,      SFENCE,      CLFLUSH, +    CLFLUSHOPT, +    CLWB,      WRMSR,      RDTSC,      RDMSR, @@ -1328,6 +1347,28 @@ pub enum Opcode {      ADOX,      PREFETCHW, + +    RDPID, +    CMPXCHG8B, +    VMPTRLD, +    VMPTRST, + +    BZHI, +    MULX, +    SHLX, +    SHRX, +    SARX, +    PDEP, +    PEXT, +    RORX, +    XRSTORS, +    XSAVEC, +    XSAVES, + +    RDFSBASE, +    RDGSBASE, +    WRFSBASE, +    WRGSBASE,  }  #[derive(Debug)] @@ -2044,7 +2085,7 @@ impl InstDecoder {      /// the clearest documentation on when these instructions were reintroduced into 64-bit      /// architectures seems to be      /// [wikipedia](https://en.wikipedia.org/wiki/X86-64#Older_implementations): -    /// ``` +    /// ```text      /// Early AMD64 and Intel 64 CPUs lacked LAHF and SAHF instructions in 64-bit mode. AMD      /// introduced these instructions (also in 64-bit mode) with their Athlon 64, Opteron and      /// Turion 64 revision D processors in March 2005[48][49][50] while Intel introduced the @@ -2635,9 +2676,8 @@ impl InstDecoder {                   * (if CPUID.01H:ECX.POPCNT[bit 23] = 1).                   * ```                   */ -                if self.intel_quirks() && (!self.sse4_2() || !self.popcnt()) { -                    inst.opcode = Opcode::Invalid; -                    return Err(DecodeError::InvalidOpcode); +                if self.intel_quirks() && (self.sse4_2() || self.popcnt()) { +                    return Ok(());                  } else if !self.popcnt() {                      /*                       * elsewhere from the amd APM: @@ -2744,6 +2784,11 @@ impl InstDecoder {                          return Err(DecodeError::InvalidOpcode);                      }                  } +                if !self.bmi2() { +                    if BMI2.contains(&other) { +                        return Err(DecodeError::InvalidOpcode); +                    } +                }              }          }          Ok(()) @@ -3066,6 +3111,8 @@ pub enum OperandCode {      ModRM_0x0fae,      ModRM_0x0fba,      ModRM_0xf238, +    ModRM_0xf30fae, +    ModRM_0x660fae,      ModRM_0xf30fc7,      ModRM_0x660f38,      ModRM_0xf30f38, @@ -3444,7 +3491,7 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660fae),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),  // 0xb0      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -4006,7 +4053,7 @@ const OPCODE_F30F_MAP: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30fae),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),  // 0xb0      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -5371,13 +5418,12 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,                      return Ok(());                  } else {                      instruction.opcode = Opcode::XBEGIN; -                    instruction.disp = if opwidth == 2 { +                    instruction.imm = if opwidth == 2 {                          read_imm_signed(&mut bytes_iter, 2, length)? as i16 as i32 as u32                      } else {                          read_imm_signed(&mut bytes_iter, 4, length)? as i32 as u32                      }; -                    instruction.modrm_mmm = RegSpec::eip(); -                    instruction.operands[0] = OperandSpec::RegDisp; +                    instruction.operands[0] = OperandSpec::ImmI32;                      instruction.operand_count = 1;                      return Ok(());                  } @@ -5618,6 +5664,9 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,              instruction.imm =                  read_num(&mut bytes_iter, 1)? as u8 as u32;              *length += 1; +            if instruction.operands[1] == OperandSpec::RegMMM { +                instruction.modrm_mmm.bank = RegisterBank::MM; +            }              instruction.operands[2] = OperandSpec::ImmI8;              instruction.operand_count = 3;          }, @@ -5747,7 +5796,7 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter          }          OperandCode::ModRM_0x0f0d => {              let modrm = read_modrm(&mut bytes_iter, length)?; -            let r = modrm & 0b111; +            let r = (modrm >> 3) & 0b111;              let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); @@ -5813,44 +5862,78 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter              return read_operands(decoder, bytes_iter, instruction, operands, length);          },          OperandCode::ModRM_0x0f3a => { +            let opcode = read_modrm(&mut bytes_iter, length)?; +            if opcode == 0xcc { +                instruction.opcode = Opcode::SHA1RNDS4; +                return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); +            } else if opcode == 0x0f { +                instruction.opcode = Opcode::PALIGNR; +                return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm_Ib, length); +            }          },          OperandCode::ModRM_0x0fc7 => {              let modrm = read_modrm(&mut bytes_iter, length)?; -            if modrm >> 6 == 0b11 { -                match (modrm >> 3) & 0b111 { -                    0b111 => { -                        instruction.opcode = Opcode::RDSEED; -                        instruction.operand_count = 1; -                        instruction.operands[0] = OperandSpec::RegRRR; -                        let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); -                        instruction.modrm_rrr = -                            RegSpec::from_parts(modrm & 7, match opwidth { -                                4 => RegisterBank::D, -                                2 => RegisterBank::W, -                                _ => unreachable!() -                            }); +            let is_reg = (modrm & 0xc0) == 0xc0; + +            let r = (modrm >> 3) & 0b111; + +            let opcode = match r { +                0b001 => { +                    if is_reg { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOperand); +                    } else { +                        Opcode::CMPXCHG8B                      } -                    0b110 => { -                        instruction.opcode = Opcode::RDRAND; -                        instruction.operand_count = 1; -                        instruction.operands[0] = OperandSpec::RegRRR; -                        let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); -                        instruction.modrm_rrr = -                            RegSpec::from_parts(modrm & 7, match opwidth { -                                4 => RegisterBank::D, -                                2 => RegisterBank::W, -                                _ => unreachable!() -                            }); +                } +                0b011 => { +                    if is_reg { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOperand); +                    } else { +                        Opcode::XRSTORS                      } -                    _ => { +                } +                0b100 => { +                    if is_reg {                          instruction.opcode = Opcode::Invalid; -                        return Err(DecodeError::InvalidOpcode); +                        return Err(DecodeError::InvalidOperand); +                    } else { +                        Opcode::XSAVEC                      }                  } -            } else { -                instruction.opcode = Opcode::Invalid; -                return Err(DecodeError::InvalidOpcode); -            } +                0b101 => { +                    if is_reg { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOperand); +                    } else { +                        Opcode::XSAVES +                    } +                } +                0b110 => { +                    if is_reg { +                        Opcode::RDRAND +                    } else { +                        Opcode::VMPTRLD +                    } +                } +                0b111 => { +                    if is_reg { +                        Opcode::RDSEED +                    } else { +                        Opcode::VMPTRST +                    } +                } +                _ => { +                    instruction.opcode = Opcode::Invalid; +                    return Err(DecodeError::InvalidOperand); +                } +            }; + +            instruction.opcode = opcode; +            instruction.operand_count = 1; +            let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); +            instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;          },          OperandCode::ModRM_0x0f71 => {              instruction.operand_count = 2; @@ -6137,15 +6220,33 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter              instruction.operands[1] = OperandSpec::ImmU8;          },          OperandCode::ModRM_0x660fc7 => { +            let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);              let modrm = read_modrm(&mut bytes_iter, length)?;              let r = (modrm >> 3) & 7;              match r {                  6 => {                      instruction.opcode = Opcode::VMCLEAR; -                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?; +                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;                      if instruction.operands[0] == OperandSpec::RegMMM { -                        return Err(DecodeError::InvalidOperand); +                        // 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 +                        // word-form operand: +                        instruction.modrm_mmm = RegSpec { bank: RegisterBank::W, num: instruction.modrm_mmm.num }; +                        instruction.opcode = Opcode::RDRAND; +                    } +                    instruction.operand_count = 1; +                } +                7 => { +                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; +                    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 +                        // word-form operand: +                        instruction.modrm_mmm = RegSpec { bank: RegisterBank::W, num: instruction.modrm_mmm.num }; +                        instruction.opcode = Opcode::RDSEED; +                    } else { +                        return Err(DecodeError::InvalidOpcode);                      }                      instruction.operand_count = 1;                  } @@ -6154,15 +6255,88 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter                  }              }          }, +        OperandCode::ModRM_0x660fae => { +            let modrm = read_modrm(&mut bytes_iter, length)?; +            if modrm < 0xc0 { +                instruction.opcode = match (modrm >> 3) & 7 { +                    6 => { +                        Opcode::CLWB +                    } +                    7 => { +                        Opcode::CLFLUSHOPT +                    } +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                }; +                instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* opwidth */, length)?; +                instruction.operand_count = 1; +            } else { +                instruction.opcode = Opcode::Invalid; +                return Err(DecodeError::InvalidOpcode); +            } +        }, +        OperandCode::ModRM_0xf30fae => { +            let modrm = read_modrm(&mut bytes_iter, length)?; + +            if (modrm & 0xc0) == 0xc0 { +                let r = (modrm >> 3) & 7; +                let m = modrm & 7; +                match r { +                    0 => { +                        instruction.opcode = Opcode::RDFSBASE; +                        instruction.modrm_mmm = RegSpec::from_parts(m, RegisterBank::D); +                        instruction.operands[0] = OperandSpec::RegMMM; +                        instruction.operand_count = 1; +                    } +                    1 => { +                        instruction.opcode = Opcode::RDGSBASE; +                        instruction.modrm_mmm = RegSpec::from_parts(m, RegisterBank::D); +                        instruction.operands[0] = OperandSpec::RegMMM; +                        instruction.operand_count = 1; + +                    } +                    2 => { +                        instruction.opcode = Opcode::WRFSBASE; +                        instruction.modrm_mmm = RegSpec::from_parts(m, RegisterBank::D); +                        instruction.operands[0] = OperandSpec::RegMMM; +                        instruction.operand_count = 1; +                    } +                    3 => { +                        instruction.opcode = Opcode::WRGSBASE; +                        instruction.modrm_mmm = RegSpec::from_parts(m, RegisterBank::D); +                        instruction.operands[0] = OperandSpec::RegMMM; +                        instruction.operand_count = 1; + +                    } +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                } +            } +        }          OperandCode::ModRM_0xf30fc7 => { +            let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);              let modrm = read_modrm(&mut bytes_iter, length)?;              let r = (modrm >> 3) & 7;              match r {                  6 => {                      instruction.opcode = Opcode::VMXON; -                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?; +                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;                      if instruction.operands[0] == OperandSpec::RegMMM { +                        // this would be invalid as `vmxon`, so fall back to the parse as +                        // f3-prefixed rdrand +                        instruction.opcode = Opcode::RDRAND; +                    } +                    instruction.operand_count = 1; +                } +                7 => { +                    instruction.opcode = Opcode::RDPID; +                    instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; +                    if instruction.operands[0] != OperandSpec::RegMMM {                          return Err(DecodeError::InvalidOperand);                      }                      instruction.operand_count = 1; diff --git a/src/protected_mode/uarch.rs b/src/protected_mode/uarch.rs index b2b1201..20c434f 100644 --- a/src/protected_mode/uarch.rs +++ b/src/protected_mode/uarch.rs @@ -203,7 +203,9 @@ pub mod intel {      /// common denominator: if you want a `Skylake` decoder with AVX512, something like the      /// following:      /// ``` -    /// InstDecoder::skylake().with_avx512_f().with_avx512_dq() +    /// yaxpeax_x86::protected_mode::uarch::intel::skylake() +    ///     .with_avx512_f() +    ///     .with_avx512_dq();      /// ```      /// is likely your best option.      pub fn skylake() -> InstDecoder { diff --git a/src/protected_mode/vex.rs b/src/protected_mode/vex.rs index b4716d7..b2a845e 100644 --- a/src/protected_mode/vex.rs +++ b/src/protected_mode/vex.rs @@ -83,6 +83,10 @@ enum VEXOperandCode {      Ed_G_xmm,      G_xmm_Ed,      G_xmm_Eq, +    G_E_V, +    G_V_E, +    G_E_Ib, +    BMI1_F3,  }  #[inline(never)] @@ -691,6 +695,72 @@ fn read_vex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instruction: &mut Inst              instruction.operands[2] = OperandSpec::RegVex;              Ok(())          } +        VEXOperandCode::G_V_E => { +            let modrm = read_modrm(bytes, length)?; +            let (opwidth, bank) = (4, RegisterBank::D); +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7, bank); +            instruction.vex_reg.bank = bank; +            let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operands[1] = OperandSpec::RegVex; +            instruction.operands[2] = mem_oper; +            instruction.operand_count = 3; +            Ok(()) +        } +        VEXOperandCode::G_E_V => { +            let modrm = read_modrm(bytes, length)?; +            let (opwidth, bank) = (4, RegisterBank::D); +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7, bank); +            instruction.vex_reg.bank = bank; +            let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operands[1] = mem_oper; +            instruction.operands[2] = OperandSpec::RegVex; +            instruction.operand_count = 3; +            Ok(()) +        } +        VEXOperandCode::G_E_Ib => { +            let modrm = read_modrm(bytes, length)?; +            let (opwidth, bank) = (4, RegisterBank::D); +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7, bank); +            let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operands[1] = mem_oper; +            instruction.imm = read_imm_unsigned(bytes, 1, length)?; +            instruction.operands[2] = OperandSpec::ImmI8; +            instruction.operand_count = 3; +            Ok(()) +        } +        VEXOperandCode::BMI1_F3 => { +            let modrm = read_modrm(bytes, length)?; +            instruction.opcode = match (modrm >> 3) & 7 { +                1 => { +                    Opcode::BLSR +                } +                2 => { +                    Opcode::BLSMSK +                } +                3 => { +                    Opcode::BLSI +                } +                _ => { +                    instruction.opcode = Opcode::Invalid; +                    return Err(DecodeError::InvalidOpcode); +                } +            }; +            let (opwidth, bank) = (4, RegisterBank::D); +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7, bank); +            let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?; +            instruction.operands[0] = OperandSpec::RegVex; +            instruction.operands[1] = mem_oper; +            instruction.operand_count = 2; +            instruction.vex_reg.bank = bank; +            Ok(()) +        }          VEXOperandCode::G_E_ymm_imm8 |          VEXOperandCode::G_V_E_xmm_xmm4 | @@ -2267,15 +2337,92 @@ fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: &                      } else {                          VEXOperandCode::G_V_E_xmm                      }), +                    0xF7 => (Opcode::SHLX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }), +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                } +            } else if let VEXOpcodePrefix::PrefixF2 = p { +                match opc { +                    0xF5 => (Opcode::PDEP, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_V_E +                    }), +                    0xF6 => (Opcode::MULX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_V_E +                    }), +                    0xF7 => (Opcode::SHRX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }), +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                } +            } else if let VEXOpcodePrefix::PrefixF3 = p { +                match opc { +                    0xF5 => (Opcode::PEXT, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_V_E +                    }), +                    0xF7 => (Opcode::SARX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }),                      _ => {                          instruction.opcode = Opcode::Invalid;                          return Err(DecodeError::InvalidOpcode);                      }                  }              } else { -                // the only VEX* 0f38 instructions have an implied 66 prefix. -                instruction.opcode = Opcode::Invalid; -                return Err(DecodeError::InvalidOpcode); +                match opc { +                    0xF2 => (Opcode::ANDN, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_V_E +                    }), +                    0xF3 => (Opcode::Invalid, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::BMI1_F3 +                    }), +                    0xF5 => (Opcode::BZHI, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }), +                    0xF7 => (Opcode::BEXTR, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_V +                    }), +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                }              }          }          VEXOpcodeMap::Map0F3A => { @@ -2501,6 +2648,19 @@ fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: &                          return Err(DecodeError::InvalidOpcode);                      }                  } +            } else if let VEXOpcodePrefix::PrefixF2 = p { +                match opc { +                    0xF0 => (Opcode::RORX, if L { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } else { +                        VEXOperandCode::G_E_Ib +                    }), +                    _ => { +                        instruction.opcode = Opcode::Invalid; +                        return Err(DecodeError::InvalidOpcode); +                    } +                }              } else {                  // the only VEX* 0f3a instructions have an implied 66 prefix.                  instruction.opcode = Opcode::Invalid; | 
