diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/display.rs | 42 | ||||
| -rw-r--r-- | src/lib.rs | 708 | 
2 files changed, 475 insertions, 275 deletions
| diff --git a/src/display.rs b/src/display.rs index fc3f1bd..e70734d 100644 --- a/src/display.rs +++ b/src/display.rs @@ -6,7 +6,7 @@ use std::fmt;  use yaxpeax_arch::{Colorize, ColorSettings, ShowContextual, YaxColors};  use yaxpeax_arch::display::*; -use ::{RegSpec, RegisterBank, Opcode, Operand, Instruction, Segment, PrefixRex}; +use ::{RegSpec, RegisterBank, Opcode, Operand, Instruction, Segment, PrefixRex, OperandSpec};  impl fmt::Display for PrefixRex {      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -690,17 +690,18 @@ impl <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instructi              Some(s) => { write!(out, " {}", s)?; },              None => {                  match self.operands[0] { -                    Operand::Nothing => { +                    OperandSpec::Nothing => {                          return Ok(());                      }, -                    ref x @ _ => { +                    _ => {                          write!(out, " ")?;                          if let Some(prefix) = self.segment_override_for_op(0) {                              write!(out, "{}:", prefix)?;                          } -                        x.colorize(colors, out)?;                      }                  } +                let x = Operand::from_spec(self, self.operands[0]); +                x.colorize(colors, out)?;              }          };          match self.opcode { @@ -710,24 +711,21 @@ impl <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instructi                      Some(s) => { write!(out, ", {}", s) }                      None => {                          match &self.operands[1] { -                            &Operand::Nothing => { -                                return Ok(()); +                            &OperandSpec::Nothing => { +                                unreachable!();                              }, -                            x @ &Operand::Register(_) => { +                            &OperandSpec::RegMMM => {                                  write!(out, ", ")?; -                                if let Some(prefix) = self.segment_override_for_op(1) { -                                    write!(out, "{}:", prefix)?; -                                } -                                x.colorize(colors, out)                              }                              x @ _ => {                                  write!(out, ", byte ")?;                                  if let Some(prefix) = self.segment_override_for_op(1) {                                      write!(out, "{}:", prefix)?;                                  } -                                x.colorize(colors, out)                              }                          } +                        let x = Operand::from_spec(self, self.operands[1]); +                        x.colorize(colors, out)                      }                  }              }, @@ -737,24 +735,21 @@ impl <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instructi                      Some(s) => { write!(out, ", {}", s) }                      None => {                          match &self.operands[1] { -                            &Operand::Nothing => { -                                return Ok(()); +                            &OperandSpec::Nothing => { +                                unreachable!();                              }, -                            x @ &Operand::Register(_) => { +                            &OperandSpec::RegMMM => {                                  write!(out, ", ")?; -                                if let Some(prefix) = self.segment_override_for_op(1) { -                                    write!(out, "{}:", prefix)?; -                                } -                                x.colorize(colors, out)                              } -                            x @ _ => { +                            _ => {                                  write!(out, ", word ")?;                                  if let Some(prefix) = self.segment_override_for_op(1) {                                      write!(out, "{}:", prefix)?;                                  } -                                x.colorize(colors, out)                              }                          } +                        let x = Operand::from_spec(self, self.operands[1]); +                        x.colorize(colors, out)                      }                  }              }, @@ -763,14 +758,15 @@ impl <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instructi                      Some(s) => { write!(out, ", {}", s) }                      None => {                          match &self.operands[1] { -                            &Operand::Nothing => { +                            &OperandSpec::Nothing => {                                  return Ok(());                              }, -                            x @ _ => { +                            _ => {                                  write!(out, ", ")?;                                  if let Some(prefix) = self.segment_override_for_op(1) {                                      write!(out, "{}:", prefix)?;                                  } +                                let x = Operand::from_spec(self, self.operands[1]);                                  x.colorize(colors, out)                              }                          } @@ -202,7 +202,114 @@ pub enum Operand {      Nothing,  } +impl OperandSpec { +    pub fn is_memory(&self) -> bool { +        match self { +            OperandSpec::Disp | +            OperandSpec::Deref | +            OperandSpec::RegDisp | +            OperandSpec::RegScale | +            OperandSpec::RegIndexBase | +            OperandSpec::RegIndexBaseDisp | +            OperandSpec::RegScaleDisp | +            OperandSpec::RegIndexBaseScale | +            OperandSpec::RegIndexBaseScaleDisp => { +                true +            }, +            OperandSpec::Imm | +            OperandSpec::RegRRR | +            OperandSpec::RegMMM | +            OperandSpec::Nothing => { +                false +            } +        } +    } +}  impl Operand { +    fn from_spec(inst: &Instruction, spec: OperandSpec) -> Operand { +        match spec { +            OperandSpec::Nothing => { +                Operand::Nothing +            } +            // the register in modrm_rrr +            OperandSpec::RegRRR => { +                Operand::Register(inst.modrm_rrr) +            } +            // the register in modrm_mmm (eg modrm mod bits were 11) +            OperandSpec::RegMMM => { +                Operand::Register(inst.modrm_mmm) +            } +            OperandSpec::Imm => { +                match inst.imm { +                    ImmediateKind::ImmediateI8(i) => Operand::ImmediateI8(i), +                    ImmediateKind::ImmediateU8(i) => Operand::ImmediateU8(i), +                    ImmediateKind::ImmediateI16(i) => Operand::ImmediateI16(i), +                    ImmediateKind::ImmediateU16(i) => Operand::ImmediateU16(i), +                    ImmediateKind::ImmediateI32(i) => Operand::ImmediateI32(i), +                    ImmediateKind::ImmediateU32(i) => Operand::ImmediateU32(i), +                    ImmediateKind::ImmediateI64(i) => Operand::ImmediateI64(i), +                    ImmediateKind::ImmediateU64(i) => Operand::ImmediateU64(i), +                } +            } +            OperandSpec::Disp => { +                match inst.disp { +                    DisplacementKind::DisplacementU32(d) => Operand::DisplacementU32(d), +                    DisplacementKind::DisplacementI32(_) => { +                        panic!("invalid state, signed displacement isn't available except for complex memory modes"); +                    } +                    DisplacementKind::DisplacementU64(d) => Operand::DisplacementU64(d), +                } +            } +            OperandSpec::Deref => { +                Operand::RegDeref(inst.modrm_mmm) +            } +            OperandSpec::RegDisp => { +                let disp = match inst.disp { +                    DisplacementKind::DisplacementI32(d) => d, +                    _ => { +                        unreachable!("unsigned displacement isn't available in complex memory modes"); +                    } +                }; +                Operand::RegDisp(inst.modrm_mmm, disp) +            } +            OperandSpec::RegScale => { +                Operand::RegScale(inst.sib_index, inst.scale) +            } +            OperandSpec::RegIndexBase => { +                Operand::RegIndexBase(inst.sib_index, inst.modrm_mmm) +            } +            OperandSpec::RegIndexBaseDisp => { +                let disp = match inst.disp { +                    DisplacementKind::DisplacementI32(d) => d, +                    _ => { +                        unreachable!("unsigned displacement isn't available in complex memory modes"); +                    } +                }; +                Operand::RegIndexBaseDisp(inst.sib_index, inst.modrm_mmm, disp) +            } +            OperandSpec::RegScaleDisp => { +                let disp = match inst.disp { +                    DisplacementKind::DisplacementI32(d) => d, +                    _ => { +                        unreachable!("unsigned displacement isn't available in complex memory modes"); +                    } +                }; +                Operand::RegScaleDisp(inst.sib_index, inst.scale, disp) +            } +            OperandSpec::RegIndexBaseScale => { +                Operand::RegIndexBaseScale(inst.sib_index, inst.modrm_mmm, inst.scale) +            } +            OperandSpec::RegIndexBaseScaleDisp => { +                let disp = match inst.disp { +                    DisplacementKind::DisplacementI32(d) => d, +                    _ => { +                        unreachable!("unsigned displacement isn't available in complex memory modes"); +                    } +                }; +                Operand::RegIndexBaseScaleDisp(inst.sib_index, inst.modrm_mmm, inst.scale, disp) +            } +        } +    }      pub fn is_memory(&self) -> bool {          match self {              Operand::DisplacementU32(_) | @@ -244,9 +351,10 @@ impl Operand {  #[test]  fn operand_size() { +    assert_eq!(std::mem::size_of::<OperandSpec>(), 1);      assert_eq!(std::mem::size_of::<RegSpec>(), 2);      assert_eq!(std::mem::size_of::<Prefixes>(), 4); -    assert_eq!(std::mem::size_of::<Operand>(), 3); +    // assert_eq!(std::mem::size_of::<Instruction>(), 3);  }  #[allow(non_camel_case_types)] @@ -495,11 +603,56 @@ pub enum Opcode {  #[derive(Debug)]  pub struct Instruction {      pub prefixes: Prefixes, +    modrm_rrr: RegSpec, +    modrm_mmm: RegSpec, // doubles as sib_base +    sib_index: RegSpec, +    scale: u8, +    disp: DisplacementKind, +    imm: ImmediateKind, +    operand_count: u8, +    operands: [OperandSpec; 4],      pub opcode: Opcode, -    pub operands: [Operand; 2],      pub length: u8  } +#[derive(Debug, Copy, Clone)] +enum DisplacementKind { +    DisplacementU32(u32), +    DisplacementI32(i32), +    DisplacementU64(u64), +} + +#[derive(Debug, Copy, Clone)] +enum ImmediateKind { +    ImmediateI8(i8), +    ImmediateU8(u8), +    ImmediateI16(i16), +    ImmediateU16(u16), +    ImmediateI32(i32), +    ImmediateU32(u32), +    ImmediateI64(i64), +    ImmediateU64(u64), +} + +#[derive(Debug, Copy, Clone)] +enum OperandSpec { +    Nothing, +    // the register in modrm_rrr +    RegRRR, +    // the register in modrm_mmm (eg modrm mod bits were 11) +    RegMMM, +    Imm, +    Disp, +    Deref, +    RegDisp, +    RegScale, +    RegIndexBase, +    RegIndexBaseDisp, +    RegScaleDisp, +    RegIndexBaseScale, +    RegIndexBaseScaleDisp +} +  // the Hash, Eq, and PartialEq impls here are possibly misleading.  // They exist because downstream some structs are spelled like  // Foo<T> for T == x86_64. This is only to access associated types @@ -549,7 +702,14 @@ impl Instruction {          Instruction {              prefixes: Prefixes::new(0),              opcode: Opcode::Invalid, -            operands: [Operand::Nothing, Operand::Nothing], +            modrm_rrr: RegSpec::rax(), +            modrm_mmm: RegSpec::rax(), // doubles as sib_base +            sib_index: RegSpec::rax(), +            scale: 0, +            disp: DisplacementKind::DisplacementU32(0), +            imm: ImmediateKind::ImmediateI8(0), +            operand_count: 0, +            operands: [OperandSpec::Nothing; 4],              length: 0          }      } @@ -2109,7 +2269,8 @@ fn read_E_xmm<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction,  #[allow(non_snake_case)]  fn read_modrm_reg<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, result: usize, reg_bank: RegisterBank) -> Result<(), ()> { -    instr.operands[result] = Operand::Register(RegSpec::from_parts(modrm & 7, instr.prefixes.rex().b(), reg_bank)); +    instr.modrm_mmm = RegSpec::from_parts(modrm & 7, instr.prefixes.rex().b(), reg_bank); +    instr.operands[result] = OperandSpec::RegMMM;      Ok(())  } @@ -2134,51 +2295,57 @@ fn read_sib<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, m          if ((sibbyte >> 3) & 7) == 0b100 {              if modbits == 0b00 && !instr.prefixes.rex().x() { -                Operand::DisplacementU32(disp as u32) +                instr.disp = DisplacementKind::DisplacementU32(disp as u32); + +                OperandSpec::RegDisp              } else {                  let reg = RegSpec::gp_from_parts(0b100, instr.prefixes.rex().x(), addr_width, instr.prefixes.rex().present()); +                instr.modrm_mmm = reg;                  if disp == 0 { -                    Operand::RegDeref(reg) +                    OperandSpec::Deref                  } else { -                    Operand::RegDisp(reg, disp as i32) +                    instr.disp = DisplacementKind::DisplacementI32(disp); +                    OperandSpec::RegDisp                  }              }          } else { -            let base_reg = RegSpec::gp_from_parts(5, instr.prefixes.rex().b(), addr_width, instr.prefixes.rex().present()); +            instr.modrm_mmm = RegSpec::gp_from_parts(5, instr.prefixes.rex().b(), addr_width, instr.prefixes.rex().present()); -            let index_reg = RegSpec::gp_from_parts((sibbyte >> 3) & 7, instr.prefixes.rex().x(), addr_width, instr.prefixes.rex().present()); +            instr.sib_index = RegSpec::gp_from_parts((sibbyte >> 3) & 7, instr.prefixes.rex().x(), addr_width, instr.prefixes.rex().present()); +            instr.disp = DisplacementKind::DisplacementI32(disp);              let scale = 1u8 << (sibbyte >> 6); +            instr.scale = scale;              match (scale, modbits, disp) {                  (0, 0b00, 0) => { -                    Operand::RegDeref(index_reg) +                    OperandSpec::Deref                  },                  (0, 0b00, _) => { -                    Operand::RegDisp(index_reg, disp as i32) +                    OperandSpec::RegDisp                  },                  (0, _, 0) => { -                    Operand::RegIndexBase(base_reg, index_reg) +                    OperandSpec::RegIndexBase                  },                  (0, _, _) => { -                    Operand::RegIndexBaseDisp(base_reg, index_reg, disp as i32) +                    OperandSpec::RegIndexBaseDisp                  },                  (_, 0b00, 0) => { -                    Operand::RegScale(index_reg, scale) +                    OperandSpec::RegScale                  },                  (_, 0b00, _) => { -                    Operand::RegScaleDisp(index_reg, scale, disp as i32) +                    OperandSpec::RegScaleDisp                  },                  (_, _, 0) => { -                    Operand::RegIndexBaseScale(base_reg, index_reg, scale) +                    OperandSpec::RegIndexBaseScale                  },                  (_, _, _) => { -                    Operand::RegIndexBaseScaleDisp(base_reg, index_reg, scale, disp as i32) +                    OperandSpec::RegIndexBaseScaleDisp                  }              }          }      } else { -        let base_reg = RegSpec::gp_from_parts((sibbyte & 7), instr.prefixes.rex().b(), addr_width, instr.prefixes.rex().present()); +        instr.modrm_mmm = RegSpec::gp_from_parts((sibbyte & 7), instr.prefixes.rex().b(), addr_width, instr.prefixes.rex().present());          let disp = if modbits == 0b00 {              0 @@ -2187,28 +2354,29 @@ fn read_sib<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, m          } else {              read_num(bytes_iter, 4, &mut instr.length)? as i32          }; +        instr.disp = DisplacementKind::DisplacementI32(disp);          if ((sibbyte >> 3) & 7) == 0b100 {              if disp == 0 { -                Operand::RegDeref(base_reg) +                OperandSpec::Deref              } else { -                Operand::RegDisp(base_reg, disp as i32) +                OperandSpec::RegDisp              }          } else { -            let index_reg = RegSpec::gp_from_parts((sibbyte >> 3) & 7, instr.prefixes.rex().x(), addr_width, instr.prefixes.rex().present()); +            instr.sib_index = RegSpec::gp_from_parts((sibbyte >> 3) & 7, instr.prefixes.rex().x(), addr_width, instr.prefixes.rex().present());              let scale = 1u8 << (sibbyte >> 6); +            instr.scale = scale;              if disp == 0 {                  if scale == 0 { -                    Operand::RegIndexBase(base_reg, index_reg) +                    OperandSpec::RegIndexBase                  } else { -                    Operand::RegIndexBaseScale(base_reg, index_reg, scale) +                    OperandSpec::RegIndexBaseScale                  }              } else {                  if scale == 0 { - -                    Operand::RegIndexBaseDisp(base_reg, index_reg, disp as i32) +                    OperandSpec::RegIndexBaseDisp                  } else { -                    Operand::RegIndexBaseScaleDisp(base_reg, index_reg, scale, disp as i32) +                    OperandSpec::RegIndexBaseScaleDisp                  }              }          } @@ -2229,23 +2397,24 @@ fn read_M<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, mod  //            println!("scale: {:b}, index: {:b}, base: {:b}", ss, index, base);      } else if mmm == 5 && modbits == 0b00 { -        let disp = read_num(bytes_iter, 4, &mut instr.length)?; -        Operand::RegDisp( -            if addr_width == 8 { RegSpec::rip() } else { RegSpec::eip() }, -            disp as i32 -        ) +        let disp = read_num(bytes_iter, 4, &mut instr.length)? as i32; +        instr.modrm_mmm = +            if addr_width == 8 { RegSpec::rip() } else { RegSpec::eip() }; +        instr.disp = DisplacementKind::DisplacementI32(disp); +        OperandSpec::RegDisp      } else { -        let reg = RegSpec::gp_from_parts(mmm, instr.prefixes.rex().b(), addr_width, instr.prefixes.rex().present()); +        instr.modrm_mmm = RegSpec::gp_from_parts(mmm, instr.prefixes.rex().b(), addr_width, instr.prefixes.rex().present());          if modbits == 0b00 { -            Operand::RegDeref(reg) +            OperandSpec::Deref          } else {              let disp = if modbits == 0b01 {                  read_num(bytes_iter, 1, &mut instr.length)? as i8 as i32              } else {                  read_num(bytes_iter, 4, &mut instr.length)? as i32              }; -            Operand::RegDisp(reg, disp) +            instr.disp = DisplacementKind::DisplacementI32(disp); +            OperandSpec::RegDisp          }      };      Ok(()) @@ -2364,35 +2533,43 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut  //                println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);          read_E(&mut bytes_iter, instruction, modrm, 1, opwidth)?; -        instruction.operands[0] = -            Operand::Register(RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present())); +        instruction.modrm_rrr = +            RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present()); +        instruction.operands[0] = OperandSpec::RegRRR; +        instruction.operand_count = 2;      } else if operand_code == OperandCode::Ev_Gv {          let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes);          let modrm = read_modrm(&mut bytes_iter, instruction)?;          read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?; -        instruction.operands[1] = -            Operand::Register(RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present())); +        instruction.modrm_rrr = +            RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present()); +        instruction.operands[1] = OperandSpec::RegRRR; +        instruction.operand_count = 2;      } else if operand_code == OperandCode::Jbs {          // TODO: arch width (8 in 64, 4 in 32, 2 in 16) -        instruction.operands = [ -            read_imm_signed(&mut bytes_iter, 1, 8, &mut instruction.length)?, -            Operand::Nothing -        ]; +        instruction.imm = +            read_imm_signed(&mut bytes_iter, 1, 8, &mut instruction.length)?; +        instruction.operands[0] = OperandSpec::Imm; +        instruction.operand_count = 1;      } else if operand_code == OperandCode::Gb_Eb {          let opwidth = 1;          let modrm = read_modrm(&mut bytes_iter, instruction)?;          read_E(&mut bytes_iter, instruction, modrm, 1, opwidth)?; -        instruction.operands[0] = -            Operand::Register(RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present())); +        instruction.modrm_rrr = +            RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present()); +        instruction.operands[0] = OperandSpec::RegRRR; +        instruction.operand_count = 2;      } else if operand_code == OperandCode::Eb_Gb {          let opwidth = 1;          let modrm = read_modrm(&mut bytes_iter, instruction)?;          read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?; -        instruction.operands[1] = -            Operand::Register(RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present())); +        instruction.modrm_rrr = +            RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present()); +        instruction.operands[1] = OperandSpec::RegRRR; +        instruction.operand_count = 2;      } else {      match operand_code {          /* @@ -2451,6 +2628,7 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              }              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?; +            instruction.operand_count = 1;          },          op @ OperandCode::AL_Ob |          op @ OperandCode::AX_Ov => { @@ -2467,14 +2645,16 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              // stupid RCT thing:              let addr_width = if prefixes.address_size() { 2 } else { 4 };              let imm = read_num(&mut bytes_iter, addr_width, &mut instruction.length)?; -            instruction.operands = [ -                Operand::Register(RegSpec::gp_from_parts(0, prefixes.rex().b(), opwidth, prefixes.rex().present())), -                if prefixes.address_size() { -                    Operand::DisplacementU32(imm as u32) -                } else { -                    Operand::DisplacementU64(imm) -                } -            ]; +            instruction.modrm_rrr = +                RegSpec::gp_from_parts(0, prefixes.rex().b(), opwidth, prefixes.rex().present()); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.disp = if prefixes.address_size() { +                DisplacementKind::DisplacementU32(imm as u32) +            } else { +                DisplacementKind::DisplacementU64(imm) +            }; +            instruction.operands[1] = OperandSpec::Disp; +            instruction.operand_count = 2;          }          op @ OperandCode::Ob_AL |          op @ OperandCode::Ov_AX => { @@ -2491,14 +2671,16 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              // stupid RCT thing:              let addr_width = if prefixes.address_size() { 2 } else { 4 };              let imm = read_num(&mut bytes_iter, addr_width, &mut instruction.length)?; -            instruction.operands = [ -                if prefixes.address_size() { -                    Operand::DisplacementU32(imm as u32) -                } else { -                    Operand::DisplacementU64(imm) -                }, -                Operand::Register(RegSpec::gp_from_parts(0, prefixes.rex().b(), opwidth, prefixes.rex().present())) -            ]; +            instruction.disp = if prefixes.address_size() { +                DisplacementKind::DisplacementU32(imm as u32) +            } else { +                DisplacementKind::DisplacementU64(imm) +            }; +            instruction.operands[0] = OperandSpec::Disp; +            instruction.modrm_rrr = +                RegSpec::gp_from_parts(0, prefixes.rex().b(), opwidth, prefixes.rex().present()); +            instruction.operands[1] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          }          op @ OperandCode::ModRM_0x80_Eb_Ib |          op @ OperandCode::ModRM_0x81_Ev_Ivs => { @@ -2514,9 +2696,10 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              let modrm = read_modrm(&mut bytes_iter, instruction)?;              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?; -            let imm = read_imm_signed(&mut bytes_iter, if opwidth == 8 { 4 } else { opwidth }, opwidth, &mut instruction.length)?; +            instruction.imm = read_imm_signed(&mut bytes_iter, if opwidth == 8 { 4 } else { opwidth }, opwidth, &mut instruction.length)?;              instruction.opcode = base_opcode_map((modrm >> 3) & 7); -            instruction.operands[1] = imm; +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          },          op @ OperandCode::ModRM_0xc0_Eb_Ib |          op @ OperandCode::ModRM_0xc1_Ev_Ib => { @@ -2534,7 +2717,9 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;              let num = read_num(&mut bytes_iter, 1, &mut instruction.length)? as i8;              instruction.opcode = BITWISE_OPCODE_MAP[((modrm >> 3) & 7) as usize].clone(); -            instruction.operands[1] = Operand::ImmediateI8(num); +            instruction.imm = ImmediateKind::ImmediateI8(num); +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          },          op @ OperandCode::ModRM_0xc6_Eb_Ib |          op @ OperandCode::ModRM_0xc7_Ev_Iv => { @@ -2556,7 +2741,9 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;              instruction.opcode = Opcode::MOV; -            instruction.operands[1] = read_imm_signed(&mut bytes_iter, if opwidth == 8 { 4 } else { opwidth }, opwidth, &mut instruction.length)?; +            instruction.imm = read_imm_signed(&mut bytes_iter, if opwidth == 8 { 4 } else { opwidth }, opwidth, &mut instruction.length)?; +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          },          op @ OperandCode::ModRM_0xd0_Eb_1 |          op @ OperandCode::ModRM_0xd1_Ev_1 => { @@ -2573,7 +2760,9 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;              instruction.opcode = BITWISE_OPCODE_MAP[((modrm >> 3) & 7) as usize].clone(); -            instruction.operands[1] = Operand::ImmediateI8(1); +            instruction.imm = ImmediateKind::ImmediateI8(1); +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          },          OperandCode::ModRM_0xd3_Ev_CL => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes); @@ -2583,7 +2772,9 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;              let opcode = BITWISE_OPCODE_MAP[r as usize].clone();              instruction.opcode = opcode; -            instruction.operands[1] = Operand::Register(RegSpec::cl()); +            instruction.modrm_rrr = RegSpec::cl(); +            instruction.operands[1] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          }          op @ OperandCode::ModRM_0xf6 |          op @ OperandCode::ModRM_0xf7 => { @@ -2598,11 +2789,14 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              };              let modrm = read_modrm(&mut bytes_iter, instruction)?;              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?; +            instruction.operand_count = 1;              match ((modrm >> 3) & 7) {                  0 | 1 => {                      instruction.opcode = Opcode::TEST;                      let numwidth = if opwidth == 8 { 4 } else { opwidth }; -                    instruction.operands[1] = read_imm_signed(&mut bytes_iter, numwidth, opwidth, &mut instruction.length)?; +                    instruction.imm = read_imm_signed(&mut bytes_iter, numwidth, opwidth, &mut instruction.length)?; +                    instruction.operands[1] = OperandSpec::Imm; +                    instruction.operand_count = 2;                  },                  2 => {                      instruction.opcode = Opcode::NOT; @@ -2642,7 +2836,7 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                  Opcode::Invalid,                  Opcode::Invalid              ][((modrm >> 3) & 7) as usize]; -            instruction.operands[1] = Operand::Nothing; +            instruction.operand_count = 1;          }          OperandCode::ModRM_0xff_Ev => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes); @@ -2660,14 +2854,14 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                  Opcode::Invalid              ][((modrm >> 3) & 7) as usize];              instruction.opcode = opcode; -            instruction.operands[1] = Operand::Nothing; +            instruction.operand_count = 1;          }          OperandCode::Ev => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes);              let modrm = read_modrm(&mut bytes_iter, instruction)?;              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?; -            instruction.operands[1] = Operand::Nothing; +            instruction.operand_count = 1;          },          OperandCode::Gb_Eb_Ib => {              let opwidth = 1; @@ -2679,28 +2873,36 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              // TODO              panic!("oh no, a mul!");  //            read_E(&mut bytes_iter, instruction, modrm, opwidth, &mut ext[0])?; +            /*              instruction.operands[0] = -                Operand::Register(RegSpec::gp_from_parts(r, prefixes.rex().r(), opwidth, prefixes.rex().present())); +                RegSpec::gp_from_parts(r, prefixes.rex().r(), opwidth, prefixes.rex().present());              read_imm_signed(&mut bytes_iter, 1, 1, &mut instruction.length).map(|imm| {                  ext[1] = imm;                  instruction.operands[1] = Operand::Many(ext);              })? + +            instruction.operand_count = 3; +            */          }          OperandCode::Gv_Eb => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes);              let modrm = read_modrm(&mut bytes_iter, instruction)?;              read_E(&mut bytes_iter, instruction, modrm, 1, opwidth)?; -            instruction.operands[0] = -                Operand::Register(RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present())); +            instruction.modrm_rrr = +                RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present()); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          },          OperandCode::Gv_Ew => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes);              let modrm = read_modrm(&mut bytes_iter, instruction)?;              read_E(&mut bytes_iter, instruction, modrm, 1, 2)?; -            instruction.operands[0] = -                Operand::Register(RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present())); +            instruction.modrm_rrr = +                RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present()); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          },          OperandCode::Ew_Sw => {              let opwidth = 2; @@ -2711,13 +2913,16 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                  return Err(()); //Err("Invalid r".to_owned());              } -            instruction.operands[1] = -                Operand::Register(RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 }); +            instruction.modrm_rrr = +                RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 }; +            instruction.operands[1] = OperandSpec::RegRRR; +            instruction.operand_count = 2;              let mod_bits = modrm >> 6;              if mod_bits == 0b11 { -                instruction.operands[0] = -                    Operand::Register(RegSpec { bank: RegisterBank::W, num: modrm & 7}); +                instruction.modrm_mmm = +                    RegSpec { bank: RegisterBank::W, num: modrm & 7}; +                instruction.operands[0] = OperandSpec::RegMMM;              } else {                  read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;              } @@ -2731,15 +2936,18 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                  return Err(()); // Err("Invalid r".to_owned());              } -            instruction.operands[0] = -                Operand::Register(RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 }); +            instruction.modrm_rrr = +                RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 }; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 2;              let mod_bits = modrm >> 6;              if mod_bits == 0b11 { -                instruction.operands[1] = -                    Operand::Register(RegSpec { bank: RegisterBank::W, num: modrm & 7}); +                instruction.modrm_mmm = +                    RegSpec { bank: RegisterBank::W, num: modrm & 7}; +                instruction.operands[1] = OperandSpec::RegMMM;              } else { -                read_E(&mut bytes_iter, instruction, modrm, 1, opwidth)?; +                read_M(&mut bytes_iter, instruction, modrm, 1)?;              }          },          OperandCode::Gdq_Ed => { @@ -2748,8 +2956,10 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut  //                println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);              read_E(&mut bytes_iter, instruction, modrm, 1, 4 /* opwidth */)?; -            instruction.operands[0] = -                Operand::Register(RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present())); +            instruction.modrm_rrr = +                RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present()); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          },          OperandCode::Gv_M => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes); @@ -2757,8 +2967,10 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut  //                println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);              read_E(&mut bytes_iter, instruction, modrm, 1, opwidth)?; -            instruction.operands[0] = -                Operand::Register(RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present())); +            instruction.modrm_rrr = +                RegSpec::gp_from_parts((modrm >> 3) & 7, prefixes.rex().r(), opwidth, prefixes.rex().present()); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          },          OperandCode::Gv_Ev_Iv => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes); @@ -2770,28 +2982,34 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              // TODO              panic!("oh no, a mul!");  //            read_E(&mut bytes_iter, instruction, modrm, opwidth, &mut ext[0])?; +            /*              instruction.operands[0] = -                Operand::Register(RegSpec::gp_from_parts(r, prefixes.rex().r(), opwidth, prefixes.rex().present())); +                RegSpec::gp_from_parts(r, prefixes.rex().r(), opwidth, prefixes.rex().present());              read_imm_signed(&mut bytes_iter, if opwidth == 8 { 4 } else { opwidth }, opwidth, &mut instruction.length).map(|imm| {                  ext[1] = imm;                  instruction.operands[1] = Operand::Many(ext);              })? +            */          }          OperandCode::E_G_xmm => {              let modrm = read_modrm(&mut bytes_iter, instruction)?;  //                println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);              read_E_xmm(&mut bytes_iter, instruction, modrm, 0)?; -            instruction.operands[1] = -                Operand::Register(RegSpec::from_parts((modrm >> 3) & 7, prefixes.rex().r(), RegisterBank::X)); +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7, prefixes.rex().r(), RegisterBank::X); +            instruction.operands[1] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          },          OperandCode::G_E_xmm => {              let modrm = read_modrm(&mut bytes_iter, instruction)?;  //                println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);              read_E_xmm(&mut bytes_iter, instruction, modrm, 1)?; -            instruction.operands[0] = -                Operand::Register(RegSpec::from_parts((modrm >> 3) & 7, prefixes.rex().r(), RegisterBank::X)); +            instruction.modrm_rrr = +                RegSpec::from_parts((modrm >> 3) & 7, prefixes.rex().r(), RegisterBank::X); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          },          op @ OperandCode::Zv_Ivq_R0 |          op @ OperandCode::Zv_Ivq_R1 | @@ -2803,26 +3021,33 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut          op @ OperandCode::Zv_Ivq_R7 => {              let reg = (op as u8) - (OperandCode::Zv_Ivq_R0 as u8);              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes); -            instruction.operands = [ -                Operand::Register(RegSpec::gp_from_parts(reg, prefixes.rex().b(), opwidth, prefixes.rex().present())), -                read_imm_ivq(&mut bytes_iter, opwidth, &mut instruction.length)? -            ]; +            instruction.modrm_rrr = +                RegSpec::gp_from_parts(reg, prefixes.rex().b(), opwidth, prefixes.rex().present()); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.imm = +                read_imm_ivq(&mut bytes_iter, opwidth, &mut instruction.length)?; +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          },          OperandCode::AL_Ib => { -            let opwidth = 1; -            let numwidth = 1; -            instruction.operands = [ -                Operand::Register(RegSpec::al()), -                read_imm_signed(&mut bytes_iter, numwidth, opwidth, &mut instruction.length)? -            ]; +            instruction.modrm_rrr = +                RegSpec::al(); +            instruction.imm = +                read_imm_signed(&mut bytes_iter, 1, 1, &mut instruction.length)?; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          }          OperandCode::AX_Ivd => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, prefixes);              let numwidth = if opwidth == 8 { 4 } else { opwidth }; -            instruction.operands = [ -                Operand::Register(RegSpec::gp_from_parts(0, false, opwidth, false)), -                read_imm_signed(&mut bytes_iter, numwidth, opwidth, &mut instruction.length)? -            ]; +            instruction.modrm_rrr = +                RegSpec::gp_from_parts(0, false, opwidth, false); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.imm = +                read_imm_signed(&mut bytes_iter, numwidth, opwidth, &mut instruction.length)?; +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          }          op @ OperandCode::Zb_Ib_R0 |          op @ OperandCode::Zb_Ib_R1 | @@ -2833,29 +3058,31 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut          op @ OperandCode::Zb_Ib_R6 |          op @ OperandCode::Zb_Ib_R7 => {              let reg = (op as u8) - (OperandCode::Zb_Ib_R0 as u8); -            instruction.operands = [ -                Operand::Register(RegSpec::gp_from_parts(reg, prefixes.rex().b(), 1, prefixes.rex().present())), -                read_imm_unsigned(&mut bytes_iter, 1, &mut instruction.length)? -            ]; +            instruction.modrm_rrr = +                RegSpec::gp_from_parts(reg, prefixes.rex().b(), 1, prefixes.rex().present()); +            instruction.imm = +                read_imm_unsigned(&mut bytes_iter, 1, &mut instruction.length)?; +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          },          OperandCode::Iw => { -            instruction.operands = [ -                read_imm_unsigned(&mut bytes_iter, 2, &mut instruction.length)?, -                Operand::Nothing -            ]; +            instruction.imm = +                read_imm_unsigned(&mut bytes_iter, 2, &mut instruction.length)?; +            instruction.operands[0] = OperandSpec::Imm; +            instruction.operand_count = 1;          }          OperandCode::Ibs => { -            instruction.operands = [ -                read_imm_signed(&mut bytes_iter, 1, 8, &mut instruction.length)?, -                Operand::Nothing -            ]; +            instruction.imm = +                read_imm_signed(&mut bytes_iter, 1, 8, &mut instruction.length)?; +            instruction.operands[0] = OperandSpec::Imm; +            instruction.operand_count = 1;          },          OperandCode::Ivs => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vd, prefixes); -            instruction.operands = [ -                read_imm_unsigned(&mut bytes_iter, opwidth, &mut instruction.length)?, -                Operand::Nothing -            ]; +            instruction.imm = +                read_imm_unsigned(&mut bytes_iter, opwidth, &mut instruction.length)?; +            instruction.operands[0] = OperandSpec::Imm; +            instruction.operand_count = 1;          },          OperandCode::ModRM_0x83_Ev_Ibs => {              let modrm = read_modrm(&mut bytes_iter, instruction)?; @@ -2863,7 +3090,9 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;              instruction.opcode = base_opcode_map((modrm >> 3) & 7); -            instruction.operands[1] = read_imm_signed(&mut bytes_iter, 1, opwidth, &mut instruction.length)?; +            instruction.imm = read_imm_signed(&mut bytes_iter, 1, opwidth, &mut instruction.length)?; +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          },          op @ OperandCode::Zv_R0 |          op @ OperandCode::Zv_R1 | @@ -2875,44 +3104,42 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut          op @ OperandCode::Zv_R7 => {              let reg = (op as u8) - (OperandCode::Zv_R0 as u8);              let opwidth = imm_width_from_prefixes_64(SizeCode::vq, prefixes); -            instruction.operands = [Operand::Register( +            instruction.modrm_rrr =                  RegSpec::gp_from_parts(                      reg, prefixes.rex().b(), opwidth, prefixes.rex().present() -                ) -            ), Operand::Nothing]; +                ); +            instruction.operand_count = 1; +            instruction.operands[0] = OperandSpec::RegRRR;          },          OperandCode::Jvds => {              let offset = read_num(&mut bytes_iter, 4, &mut instruction.length)?; -            instruction.operands = [Operand::ImmediateI32(offset as i32), Operand::Nothing]; +            instruction.imm = ImmediateKind::ImmediateI32(offset as i32); +            instruction.operand_count = 1; +            instruction.operands[0] = OperandSpec::Imm;          }          OperandCode::ModRM_0x0f00 => { +            instruction.operand_count = 1;              let modrm = read_modrm(&mut bytes_iter, instruction)?;              let r = (modrm >> 3) & 7;              if r == 0 {                  instruction.opcode = Opcode::SLDT; -                instruction.operands[1] = Operand::Nothing;              } else if r == 1 {                  instruction.opcode = Opcode::STR; -                instruction.operands[1] = Operand::Nothing;              } else if r == 2 {                  instruction.opcode = Opcode::LLDT; -                instruction.operands[1] = Operand::Nothing;              } else if r == 3 {                  instruction.opcode = Opcode::LTR; -                instruction.operands[1] = Operand::Nothing;              } else if r == 4 {                  instruction.opcode = Opcode::VERR; -                instruction.operands[1] = Operand::Nothing;              } else if r == 5 {                  instruction.opcode = Opcode::VERW; -                instruction.operands[1] = Operand::Nothing;              } else if r == 6 {                  instruction.opcode = Opcode::JMPE; -                instruction.operands = [Operand::Nothing, Operand::Nothing]; +                instruction.operand_count = 0;                  return Ok(());              } else if r == 7 {                  instruction.opcode = Opcode::Invalid; -                instruction.operands = [Operand::Nothing, Operand::Nothing]; +                instruction.operand_count = 0;                  return Ok(());              } else {                  unreachable!("r <= 8"); @@ -2930,7 +3157,7 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                      panic!("Unsupported instruction: 0x0f01 with modrm: 11 000 ___");                  } else {                      instruction.opcode = Opcode::SGDT; -                    instruction.operands[1] = Operand::Nothing; +                    instruction.operand_count = 1;                      read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;                  }              } else if r == 1 { @@ -2939,10 +3166,10 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                  if mod_bits == 0b11 {                      // TOOD: MONITOR                      instruction.opcode = Opcode::NOP; -                    instruction.operands[0] = Operand::Nothing; +                    instruction.operand_count = 0;                  } else {                      instruction.opcode = Opcode::SIDT; -                    instruction.operands[1] = Operand::Nothing; +                    instruction.operand_count = 1;                      read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;                  }              } else if r == 2 { @@ -2951,10 +3178,10 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                  if mod_bits == 0b11 {                      // TOOD: XGETBV                      instruction.opcode = Opcode::NOP; -                    instruction.operands[0] = Operand::Nothing; +                    instruction.operand_count = 0;                  } else {                      instruction.opcode = Opcode::LGDT; -                    instruction.operands[1] = Operand::Nothing; +                    instruction.operand_count = 1;                      read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;                  }              } else if r == 3 { @@ -2963,23 +3190,23 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                  if mod_bits == 0b11 {                      // TOOD: VMRUN                      instruction.opcode = Opcode::NOP; -                    instruction.operands[0] = Operand::Nothing; +                    instruction.operand_count = 0;                  } else {                      instruction.opcode = Opcode::LIDT; -                    instruction.operands[1] = Operand::Nothing; +                    instruction.operand_count = 1;                      read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;                  }              } else if r == 4 {                  // TODO: this permits storing only to word-size registers                  // spec suggets this might do something different for f.ex rdi?                  instruction.opcode = Opcode::SMSW; -                instruction.operands[1] = Operand::Nothing; +                instruction.operand_count = 1;                  read_E(&mut bytes_iter, instruction, modrm, 0, 2)?;              } else if r == 5 {                  panic!("Unsupported instruction: 0x0f01 with modrm: __ 101 ___");              } else if r == 6 {                  instruction.opcode = Opcode::LMSW; -                instruction.operands[1] = Operand::Nothing; +                instruction.operand_count = 1;                  read_E(&mut bytes_iter, instruction, modrm, 0, 2)?;              } else if r == 7 {                  let mod_bits = modrm >> 6; @@ -2987,17 +3214,17 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut                  if mod_bits == 0b11 {                      if m == 1 {                          instruction.opcode = Opcode::SWAPGS; -                        instruction.operands = [Operand::Nothing, Operand::Nothing]; +                        instruction.operand_count = 0;                      } else if m == 2 {                          instruction.opcode = Opcode::RDTSCP; -                        instruction.operands = [Operand::Nothing, Operand::Nothing]; +                        instruction.operand_count = 0;                      } else {                      //    panic!("Unsupported instruction: 0x0f01 with modrm: 11 110 r >= 2");                          return Err(()); // Err("unsupported 0x0f01 variant".to_string())                      }                  } else {                      instruction.opcode = Opcode::INVLPG; -                    instruction.operands[1] = Operand::Nothing; +                    instruction.operand_count = 1;                      read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?;                  }              } else { @@ -3008,81 +3235,44 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              let modrm = read_modrm(&mut bytes_iter, instruction)?;              let r = (modrm >> 3) & 7;              let mod_bits = modrm >> 6; -            match r { -                0 => { -                    if mod_bits == 0b11 { -                        return Err(()); // Err("Invalid mod bits".to_owned()) -                    } else { -                        instruction.opcode = Opcode::FXSAVE; -                        instruction.operands[1] = Operand::Nothing; -                    } -                } -                1 => { -                    if mod_bits == 0b11 { -                        return Err(()); // Err("Invalid mod bits".to_owned()); -                    } else { -                        instruction.opcode = Opcode::FXRSTOR; -                        instruction.operands[1] = Operand::Nothing; -                    } -                } -                2 => { -                    if mod_bits == 0b11 { -                        return Err(()); // Err("Invalid mod bits".to_owned()); -                    } else { -                        instruction.opcode = Opcode::LDMXCSR; -                        instruction.operands[1] = Operand::Nothing; -                    } -                } -                3 => { -                    if mod_bits == 0b11 { -                        return Err(()); //Err("Invalid mod bits".to_owned()); -                    } else { -                        instruction.opcode = Opcode::STMXCSR; -                        instruction.operands[1] = Operand::Nothing; -                    } -                } -                4 => { -                    if mod_bits == 0b11 { -                        return Err(()); //Err("Invalid mod bits".to_owned()); -                    } else { -                        instruction.opcode = Opcode::XSAVE; -                        instruction.operands[1] = Operand::Nothing; -                    } -                } -                5 => { -                    if mod_bits == 0b11 { -                        instruction.opcode = Opcode::LFENCE; -                        instruction.operands = [Operand::Nothing, Operand::Nothing]; -                    } else { -                        instruction.opcode = Opcode::XSTOR; -                        instruction.operands[1] = Operand::Nothing; -                    } -                } -                6 => { -                    if mod_bits == 0b11 { -                        instruction.opcode = Opcode::MFENCE; -                        instruction.operands = [Operand::Nothing, Operand::Nothing]; -                        return Ok(()); -                    } else { -                        // TODO: radare reports this, but i'm not sure? -                        instruction.opcode = Opcode::XSAVEOPT; -                        instruction.operands[1] = Operand::Nothing; -                    } -                } -                7 => { -                    if mod_bits == 0b11 { -                        instruction.opcode = Opcode::SFENCE; -                        instruction.operands = [Operand::Nothing, Operand::Nothing]; -                        return Ok(()); -                    } else { -                        // TODO: radare reports this, but i'm not sure? -                        instruction.opcode = Opcode::CLFLUSH; -                        instruction.operands[1] = Operand::Nothing; -                    } + +            // all the 0b11 instructions are err or no-operands +            if mod_bits == 0b11 { +                instruction.operand_count = 0; +                match r { +                    // invalid rrr for 0x0fae, mod: 11 +                    0 | 1 | 2 | 3 | 4 => { +                        return Err(()); +                    }, +                    5 => { +                        instruction.opcode = Opcode::LFENCE +                    }, +                    6 => { +                        instruction.opcode = Opcode::MFENCE +                    }, +                    7 => { +                        instruction.opcode = Opcode::SFENCE +                    }, +                    _ => { unsafe { unreachable_unchecked() } /* r <=7 */ }                  } -                _ => { unreachable!("r < 6"); } -            } -            read_E(&mut bytes_iter, instruction, modrm, 0, 8)?; +                Ok(()) +            } else { +                instruction.operand_count = 1; +                instruction.opcode = [ +                    Opcode::FXSAVE, +                    Opcode::FXRSTOR, +                    Opcode::LDMXCSR, +                    Opcode::STMXCSR, +                    Opcode::XSAVE, +                    Opcode::XSTOR, +                    // TODO: radare reports this, but i'm not sure? +                    Opcode::XSAVEOPT, +                    // TODO: radare reports this, but i'm not sure? +                    Opcode::CLFLUSH, +                    Opcode::Invalid, +                ][r as usize]; +                read_M(&mut bytes_iter, instruction, modrm, 0) +            }?;          }          OperandCode::ModRM_0x0fba => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vq, prefixes); @@ -3112,7 +3302,9 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              read_E(&mut bytes_iter, instruction, modrm, 0, opwidth)?; -            instruction.operands[1] = read_imm_signed(&mut bytes_iter, 1, 1, &mut instruction.length)?; +            instruction.imm = read_imm_signed(&mut bytes_iter, 1, 1, &mut instruction.length)?; +            instruction.operands[1] = OperandSpec::Imm; +            instruction.operand_count = 2;          }          op @ OperandCode::Rq_Cq_0 | @@ -3131,10 +3323,13 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              if prefixes.rex().b() {                  m += 0b1000;              } -            instruction.operands = [ -                Operand::Register(RegSpec { bank: RegisterBank::Q, num: m }), -                Operand::Register(RegSpec { bank: bank, num: r }) -            ]; +            instruction.modrm_rrr = +                RegSpec { bank: RegisterBank::Q, num: m }; +            instruction.modrm_mmm = +                RegSpec { bank: bank, num: r }; +            instruction.operands[1] = OperandSpec::RegMMM; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          }          op @ OperandCode::Cq_Rq_0 |          op @ OperandCode::Dq_Rq_0 => { @@ -3152,25 +3347,34 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut              if prefixes.rex().b() {                  m += 0b1000;              } -            instruction.operands = [ -                Operand::Register(RegSpec { bank: bank, num: r }), -                Operand::Register(RegSpec { bank: RegisterBank::Q, num: m }) -            ]; +            instruction.modrm_rrr = +                RegSpec { bank: bank, num: r }; +            instruction.modrm_mmm = +                RegSpec { bank: RegisterBank::Q, num: m }; +            instruction.operands[1] = OperandSpec::RegMMM; +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 2;          }          OperandCode::FS => { -            instruction.operands = [Operand::Register(RegSpec::fs()), Operand::Nothing]; +            instruction.modrm_rrr = RegSpec::fs(); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 1;          }          OperandCode::GS => { -            instruction.operands = [Operand::Register(RegSpec::fs()), Operand::Nothing]; +            instruction.modrm_rrr = RegSpec::gs(); +            instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operand_count = 1;          }          OperandCode::I_3 => { -            instruction.operands = [Operand::ImmediateU8(3), Operand::Nothing]; +            instruction.imm = ImmediateKind::ImmediateU8(3); +            instruction.operands[0] = OperandSpec::Imm; +            instruction.operand_count = 1;          }          OperandCode::Nothing => { -            instruction.operands = [Operand::Nothing, Operand::Nothing]; +            instruction.operand_count = 0;          }          _ => { -            instruction.operands = [Operand::Nothing, Operand::Nothing]; +            instruction.operand_count = 0;              instruction.opcode = Opcode::Invalid;              return Err(()); // Err(format!("unsupported operand code: {:?}", operand_code));          //    unsafe { unreachable_unchecked(); } @@ -3231,16 +3435,16 @@ fn read_num<T: Iterator<Item=u8>>(bytes: &mut T, width: u8, length: &mut u8) ->  }  #[inline] -fn read_imm_ivq<T: Iterator<Item=u8>>(bytes: &mut T, width: u8, length: &mut u8) -> Result<Operand, ()> { +fn read_imm_ivq<T: Iterator<Item=u8>>(bytes: &mut T, width: u8, length: &mut u8) -> Result<ImmediateKind, ()> {      match width {          2 => { -            Ok(Operand::ImmediateU16(read_num(bytes, 2, length)? as u16)) +            Ok(ImmediateKind::ImmediateU16(read_num(bytes, 2, length)? as u16))          },          4 => { -            Ok(Operand::ImmediateU32(read_num(bytes, 4, length)? as u32)) +            Ok(ImmediateKind::ImmediateU32(read_num(bytes, 4, length)? as u32))          },          8 => { -            Ok(Operand::ImmediateU64(read_num(bytes, 8, length)? as u64)) +            Ok(ImmediateKind::ImmediateU64(read_num(bytes, 8, length)? as u64))          },          _ => {              unsafe { unreachable_unchecked(); } @@ -3249,7 +3453,7 @@ fn read_imm_ivq<T: Iterator<Item=u8>>(bytes: &mut T, width: u8, length: &mut u8)  }  #[inline] -fn read_imm_signed<T: Iterator<Item=u8>>(bytes: &mut T, num_width: u8, extend_to: u8, length: &mut u8) -> Result<Operand, ()> { +fn read_imm_signed<T: Iterator<Item=u8>>(bytes: &mut T, num_width: u8, extend_to: u8, length: &mut u8) -> Result<ImmediateKind, ()> {      let num = match num_width {          1 => read_num(bytes, 1, length)? as i8 as i64,          2 => read_num(bytes, 2, length)? as i16 as i64, @@ -3259,28 +3463,28 @@ fn read_imm_signed<T: Iterator<Item=u8>>(bytes: &mut T, num_width: u8, extend_to      };      match extend_to { -        1 => Ok(Operand::ImmediateI8(num as i8)), -        2 => Ok(Operand::ImmediateI16(num as i16)), -        4 => Ok(Operand::ImmediateI32(num as i32)), -        8 => Ok(Operand::ImmediateI64(num as i64)), +        1 => Ok(ImmediateKind::ImmediateI8(num as i8)), +        2 => Ok(ImmediateKind::ImmediateI16(num as i16)), +        4 => Ok(ImmediateKind::ImmediateI32(num as i32)), +        8 => Ok(ImmediateKind::ImmediateI64(num as i64)),          _ => { unsafe { unreachable_unchecked() } }      }  }  #[inline] -fn read_imm_unsigned<T: Iterator<Item=u8>>(bytes: &mut T, width: u8, length: &mut u8) -> Result<Operand, ()> { +fn read_imm_unsigned<T: Iterator<Item=u8>>(bytes: &mut T, width: u8, length: &mut u8) -> Result<ImmediateKind, ()> {      match width {          1 => { -            Ok(Operand::ImmediateU8(read_num(bytes, 1, length)? as u8)) +            Ok(ImmediateKind::ImmediateU8(read_num(bytes, 1, length)? as u8))          },          2 => { -            Ok(Operand::ImmediateU16(read_num(bytes, 2, length)? as u16)) +            Ok(ImmediateKind::ImmediateU16(read_num(bytes, 2, length)? as u16))          },          4 => { -            Ok(Operand::ImmediateU32(read_num(bytes, 4, length)? as u32)) +            Ok(ImmediateKind::ImmediateU32(read_num(bytes, 4, length)? as u32))          },          8 => { -            Ok(Operand::ImmediateU64(read_num(bytes, 4, length)? as u64)) +            Ok(ImmediateKind::ImmediateU64(read_num(bytes, 4, length)? as u64))          }          _ => {              unsafe { unreachable_unchecked(); } | 
