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