aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2026-05-25 17:32:57 +0000
committeriximeow <me@iximeow.net>2026-05-25 18:00:30 +0000
commitf2a2a09688421f2c532ab6f02527bf68f095407a (patch)
treee7b5c3c5302c4c1a4ef89c1a5852b50059850986 /src
parent94f39674e0aee55ff6f6bb59f7d7c4873d2d1a6c (diff)
j*cxz/pusha/popa alternate size forms
these all existed since forever but the library did not distinguish them and did not provide prefix information for users to tell which had been decoded.
Diffstat (limited to 'src')
-rw-r--r--src/long_mode/behavior.rs12
-rw-r--r--src/long_mode/display.rs12
-rw-r--r--src/long_mode/mod.rs22
-rw-r--r--src/protected_mode/behavior.rs38
-rw-r--r--src/protected_mode/display.rs13
-rw-r--r--src/protected_mode/mod.rs40
-rw-r--r--src/real_mode/behavior.rs38
-rw-r--r--src/real_mode/display.rs13
-rw-r--r--src/real_mode/mod.rs40
9 files changed, 167 insertions, 61 deletions
diff --git a/src/long_mode/behavior.rs b/src/long_mode/behavior.rs
index 3e1b4a7..478c07a 100644
--- a/src/long_mode/behavior.rs
+++ b/src/long_mode/behavior.rs
@@ -229,8 +229,7 @@ impl Instruction {
}
} else if self.opcode() == Opcode::LOOPNZ
|| self.opcode() == Opcode::LOOPZ
- || self.opcode() == Opcode::LOOP
- || self.opcode() == Opcode::JRCXZ {
+ || self.opcode() == Opcode::LOOP {
if self.prefixes.rex_unchecked().w() {
behavior = behavior
.set_implicit_ops(RW_RCX_IDX);
@@ -3559,7 +3558,7 @@ fn behavior_table_size_is_right() {
}
/// this table MUST line up with Opcode declaration order in `mod.rs`.
-static TABLE: [BehaviorDigest; 1413] = [
+static TABLE: [BehaviorDigest; 1414] = [
/* ADD => */ GENERAL_RW_R_FLAGWRITE,
/* OR => */ GENERAL_RW_R_FLAGWRITE,
/* ADC => */ GENERAL_RW_R_FLAGRW,
@@ -5167,7 +5166,7 @@ static TABLE: [BehaviorDigest; 1413] = [
/* JRCXZ => */ BehaviorDigest::empty()
.set_pl_any()
.set_operand(0, Access::Read)
- .set_nontrivial(true),
+ .set_implicit_ops(RW_RCX_IDX),
// started shipping in Tremont, 2020 sept 23
// while this instruction is marked "write, read", the written first operand is a register
@@ -5871,4 +5870,9 @@ static TABLE: [BehaviorDigest; 1413] = [
.set_pl0()
.set_flags_access(Access::Write)
.set_complex(true),
+
+ /* JECXZ => */ BehaviorDigest::empty()
+ .set_pl_any()
+ .set_operand(0, Access::Read)
+ .set_implicit_ops(RW_ECX_IDX),
];
diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs
index f215d07..a00dd22 100644
--- a/src/long_mode/display.rs
+++ b/src/long_mode/display.rs
@@ -2100,6 +2100,8 @@ const MNEMONICS: &[&'static str] = &[
"pvalidate",
"rmpadjust",
"rmpupdate",
+
+ "jecxz",
];
impl Opcode {
@@ -2699,6 +2701,7 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {
Opcode::LOOPZ |
Opcode::LOOP |
Opcode::JRCXZ |
+ Opcode::JECXZ |
Opcode::CALL |
Opcode::CALLF |
Opcode::JMP |
@@ -4018,6 +4021,10 @@ pub(crate) fn contextualize_c<T: DisplaySink>(instr: &Instruction, out: &mut T)
out.write_str("if rcx == 0 then jmp ")?;
write_jmp_operand(instr.operand(0), out)?;
},
+ Opcode::JECXZ => {
+ out.write_str("if ecx == 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), out)?;
+ },
Opcode::LOOP => {
out.write_str("rcx--; if rcx != 0 then jmp ")?;
write_jmp_operand(instr.operand(0), out)?;
@@ -4216,8 +4223,9 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St
}
}
-static RELATIVE_BRANCHES: [Opcode; 22] = [
- Opcode::JMP, Opcode::CALL, Opcode::JRCXZ,
+static RELATIVE_BRANCHES: [Opcode; 23] = [
+ Opcode::JMP, Opcode::CALL,
+ Opcode::JRCXZ, Opcode::JECXZ,
Opcode::LOOP, Opcode::LOOPZ, Opcode::LOOPNZ,
Opcode::JO, Opcode::JNO,
Opcode::JB, Opcode::JNB,
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index c477b16..f2fac5b 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -2593,6 +2593,9 @@ pub enum Opcode {
PVALIDATE,
RMPADJUST,
RMPUPDATE,
+
+ // this was present since initial x86-64 but the library missed the prefix handling..
+ JECXZ,
}
impl PartialEq for Instruction {
@@ -4047,6 +4050,7 @@ enum OperandCase {
ModRM_0xf30f38fa,
ModRM_0xf30f38fb,
ModRM_0xf30f3af0,
+ CXZ,
}
#[allow(non_camel_case_types)]
@@ -4381,6 +4385,7 @@ enum OperandCode {
Ev_G_xmm_Ib = OperandCodeBuilder::new().read_E().operand_case(OperandCase::Ev_G_xmm_Ib).bits(),
G_E_mm_Ib = OperandCodeBuilder::new().read_E().operand_case(OperandCase::G_E_mm_Ib).bits(),
MASKMOVDQU = OperandCodeBuilder::new().read_E().reg_mem().operand_case(OperandCase::MASKMOVDQU).bits(),
+ CXZ = OperandCodeBuilder::new().operand_case(OperandCase::CXZ).bits(),
}
fn base_opcode_map(v: u8) -> Opcode {
@@ -4684,7 +4689,7 @@ const OPCODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOPNZ), OperandCode::Ibs),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOPZ), OperandCode::Ibs),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOP), OperandCode::Ibs),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::JRCXZ), OperandCode::Ibs),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::JRCXZ), OperandCode::CXZ),
OpcodeRecord::new(Interpretation::Instruction(Opcode::IN), OperandCode::AL_Ib),
OpcodeRecord::new(Interpretation::Instruction(Opcode::IN), OperandCode::AX_Ib),
OpcodeRecord::new(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AL),
@@ -9117,6 +9122,21 @@ fn read_operands<
instruction.regs[0].bank = RegisterBank::Q;
};
}
+ OperandCase::CXZ => {
+ if instruction.prefixes.address_size() {
+ // address-size overridden from 64-bit to 32-bit
+ instruction.opcode = Opcode::JECXZ;
+ }
+ instruction.imm =
+ read_imm_signed(words, 1)? as u64;
+ sink.record(
+ words.offset() as u32 * 8 - 8,
+ words.offset() as u32 * 8 - 1,
+ InnerDescription::Number("1-byte immediate", instruction.imm as i64)
+ .with_id(words.offset() as u32 * 8),
+ );
+ instruction.operands[0] = OperandSpec::ImmI8;
+ },
};
Ok(())
}
diff --git a/src/protected_mode/behavior.rs b/src/protected_mode/behavior.rs
index 43bace0..22d1f9e 100644
--- a/src/protected_mode/behavior.rs
+++ b/src/protected_mode/behavior.rs
@@ -129,22 +129,6 @@ impl Instruction {
.set_operand(1, Access::Read)
.set_operand(2, Access::Read);
}
- } else if self.opcode == Opcode::PUSHA {
- if !self.prefixes.operand_size() {
- behavior = behavior
- .set_implicit_ops(PUSHAD_IDX);
- } else {
- behavior = behavior
- .set_implicit_ops(PUSHA_IDX);
- }
- } else if self.opcode == Opcode::POPA {
- if !self.prefixes.operand_size() {
- behavior = behavior
- .set_implicit_ops(POPAD_IDX);
- } else {
- behavior = behavior
- .set_implicit_ops(POPA_IDX);
- }
} else if self.opcode == Opcode::DIV || self.opcode == Opcode::IDIV {
let op_width = if self.operands[0] == OperandSpec::RegMMM {
self.regs[1].width()
@@ -247,8 +231,7 @@ impl Instruction {
}
} else if self.opcode() == Opcode::LOOPNZ
|| self.opcode() == Opcode::LOOPZ
- || self.opcode() == Opcode::LOOP
- || self.opcode() == Opcode::JECXZ {
+ || self.opcode() == Opcode::LOOP {
if self.prefixes.operand_size() {
behavior = behavior
.set_implicit_ops(RW_CX_IDX);
@@ -3840,7 +3823,7 @@ fn behavior_table_size_is_right() {
}
/// this table MUST line up with Opcode declaration order in `mod.rs`.
-static TABLE: [BehaviorDigest; 1425] = [
+static TABLE: [BehaviorDigest; 1428] = [
/* ADD => */ GENERAL_RW_R_FLAGWRITE,
/* OR => */ GENERAL_RW_R_FLAGWRITE,
/* ADC => */ GENERAL_RW_R_FLAGRW,
@@ -5456,14 +5439,14 @@ static TABLE: [BehaviorDigest; 1425] = [
/* JECXZ => */ BehaviorDigest::empty()
.set_pl_any()
.set_operand(0, Access::Read)
- .set_nontrivial(true),
+ .set_implicit_ops(RW_ECX_IDX),
/* PUSHA => */ BehaviorDigest::empty()
.set_pl_any()
- .set_nontrivial(true), // 66 prefix adjusts size of pushed registers
+ .set_implicit_ops(PUSHA_IDX),
/* POPA => */ BehaviorDigest::empty()
.set_pl_any()
- .set_nontrivial(true), // 66 prefix adjusts size of popped registers
+ .set_implicit_ops(POPA_IDX),
/* BOUND => */ BehaviorDigest::empty()
.set_pl_any()
.set_operand(0, Access::Read)
@@ -6202,4 +6185,15 @@ static TABLE: [BehaviorDigest; 1425] = [
.set_pl0()
.set_flags_access(Access::Write)
.set_complex(true),
+
+ /* PUSHAD => */ BehaviorDigest::empty()
+ .set_pl_any()
+ .set_implicit_ops(PUSHAD_IDX),
+ /* POPAD => */ BehaviorDigest::empty()
+ .set_pl_any()
+ .set_implicit_ops(POPAD_IDX),
+ /* JCXZ => */ BehaviorDigest::empty()
+ .set_pl_any()
+ .set_operand(0, Access::Read)
+ .set_implicit_ops(RW_CX_IDX),
];
diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs
index 46449d1..bbb43ab 100644
--- a/src/protected_mode/display.rs
+++ b/src/protected_mode/display.rs
@@ -2092,6 +2092,10 @@ const MNEMONICS: &[&'static str] = &[
"pvalidate",
"rmpadjust",
"rmpupdate",
+
+ "pushad",
+ "popad",
+ "jcxz",
];
impl Opcode {
@@ -2574,6 +2578,10 @@ pub(crate) fn contextualize_c<T: DisplaySink>(instr: &Instruction, out: &mut T)
out.write_str("if ecx == 0 then jmp ")?;
write_jmp_operand(instr.operand(0), out)?;
},
+ Opcode::JCXZ => {
+ out.write_str("if cx == 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), out)?;
+ },
Opcode::LOOP => {
out.write_str("ecx--; if ecx != 0 then jmp ")?;
write_jmp_operand(instr.operand(0), out)?;
@@ -2764,8 +2772,9 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St
}
}
-static RELATIVE_BRANCHES: [Opcode; 22] = [
- Opcode::JMP, Opcode::CALL, Opcode::JECXZ,
+static RELATIVE_BRANCHES: [Opcode; 23] = [
+ Opcode::JMP, Opcode::CALL,
+ Opcode::JECXZ, Opcode::JCXZ,
Opcode::LOOP, Opcode::LOOPZ, Opcode::LOOPNZ,
Opcode::JO, Opcode::JNO,
Opcode::JB, Opcode::JNB,
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index 5e7ddc6..5c895a7 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -2511,6 +2511,13 @@ pub enum Opcode {
PVALIDATE,
RMPADJUST,
RMPUPDATE,
+
+ // these were part of the base ISA but were reported as distinct opcodes relatively late.
+ PUSHAD,
+ POPAD,
+
+ // likewise with alternate-size jecxz/jcxz..
+ JCXZ,
}
impl PartialEq for Instruction {
@@ -3965,6 +3972,7 @@ enum OperandCase {
ModRM_0xf30f38fa,
ModRM_0xf30f38fb,
ModRM_0xf30f3af0,
+ CXZ,
}
#[allow(non_camel_case_types)]
@@ -4292,6 +4300,7 @@ enum OperandCode {
ModRM_0xc4 = OperandCodeBuilder::new().operand_case(OperandCase::ModRM_0xc4).bits(),
ModRM_0xc5 = OperandCodeBuilder::new().operand_case(OperandCase::ModRM_0xc5).bits(),
MASKMOVDQU = OperandCodeBuilder::new().read_E().reg_mem().operand_case(OperandCase::MASKMOVDQU).bits(),
+ CXZ = OperandCodeBuilder::new().operand_case(OperandCase::CXZ).bits(),
}
fn base_opcode_map(v: u8) -> Opcode {
@@ -4595,7 +4604,7 @@ const OPCODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOPNZ), OperandCode::Ibs),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOPZ), OperandCode::Ibs),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOP), OperandCode::Ibs),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::JECXZ), OperandCode::Ibs),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::JECXZ), OperandCode::CXZ),
OpcodeRecord::new(Interpretation::Instruction(Opcode::IN), OperandCode::AL_Ib),
OpcodeRecord::new(Interpretation::Instruction(Opcode::IN), OperandCode::AX_Ib),
OpcodeRecord::new(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AL),
@@ -6476,9 +6485,19 @@ fn read_operands<
} else if instruction.opcode == Opcode::XLAT {
instruction.mem_size = 1;
} else if instruction.opcode == Opcode::PUSHA {
- instruction.mem_size = 4 * 8;
+ if instruction.prefixes.operand_size() {
+ instruction.mem_size = 2 * 8;
+ } else {
+ instruction.opcode = Opcode::PUSHAD;
+ instruction.mem_size = 4 * 8;
+ }
} else if instruction.opcode == Opcode::POPA {
- instruction.mem_size = 4 * 8;
+ if instruction.prefixes.operand_size() {
+ instruction.mem_size = 2 * 8;
+ } else {
+ instruction.opcode = Opcode::POPAD;
+ instruction.mem_size = 4 * 8;
+ }
}
instruction.operands[0] = OperandSpec::Nothing;
instruction.operand_count = 0;
@@ -9011,6 +9030,21 @@ fn read_operands<
instruction.mem_size = 2;
instruction.operand_count = 2;
},
+ OperandCase::CXZ => {
+ if instruction.prefixes.address_size() {
+ // address-size overridden from 32-bit to 16-bit
+ instruction.opcode = Opcode::JCXZ;
+ }
+ instruction.imm =
+ read_imm_signed(words, 1)? as u32;
+ sink.record(
+ words.offset() as u32 * 8 - 8,
+ words.offset() as u32 * 8 - 1,
+ InnerDescription::Number("1-byte immediate", instruction.imm as i64)
+ .with_id(words.offset() as u32 * 8),
+ );
+ instruction.operands[0] = OperandSpec::ImmI8;
+ },
};
Ok(())
}
diff --git a/src/real_mode/behavior.rs b/src/real_mode/behavior.rs
index cc7f705..8941ee5 100644
--- a/src/real_mode/behavior.rs
+++ b/src/real_mode/behavior.rs
@@ -140,22 +140,6 @@ impl Instruction {
.set_operand(1, Access::Read)
.set_operand(2, Access::Read);
}
- } else if self.opcode == Opcode::PUSHA {
- if self.prefixes.operand_size() {
- behavior = behavior
- .set_implicit_ops(PUSHAD_IDX);
- } else {
- behavior = behavior
- .set_implicit_ops(PUSHA_IDX);
- }
- } else if self.opcode == Opcode::POPA {
- if self.prefixes.operand_size() {
- behavior = behavior
- .set_implicit_ops(POPAD_IDX);
- } else {
- behavior = behavior
- .set_implicit_ops(POPA_IDX);
- }
} else if self.opcode == Opcode::DIV || self.opcode == Opcode::IDIV {
let op_width = if self.operands[0] == OperandSpec::RegMMM {
self.regs[1].width()
@@ -257,8 +241,7 @@ impl Instruction {
}
} else if self.opcode() == Opcode::LOOPNZ
|| self.opcode() == Opcode::LOOPZ
- || self.opcode() == Opcode::LOOP
- || self.opcode() == Opcode::JCXZ {
+ || self.opcode() == Opcode::LOOP {
if !self.prefixes.operand_size() {
behavior = behavior
.set_implicit_ops(RW_CX_IDX);
@@ -3808,7 +3791,7 @@ fn behavior_table_size_is_right() {
}
/// this table MUST line up with Opcode declaration order in `mod.rs`.
-static TABLE: [BehaviorDigest; 1425] = [
+static TABLE: [BehaviorDigest; 1428] = [
/* ADD => */ GENERAL_RW_R_FLAGWRITE,
/* OR => */ GENERAL_RW_R_FLAGWRITE,
/* ADC => */ GENERAL_RW_R_FLAGRW,
@@ -5424,14 +5407,14 @@ static TABLE: [BehaviorDigest; 1425] = [
/* JCXZ => */ BehaviorDigest::empty()
.set_pl_any()
.set_operand(0, Access::Read)
- .set_nontrivial(true),
+ .set_implicit_ops(RW_CX_IDX),
/* PUSHA => */ BehaviorDigest::empty()
.set_pl_any()
- .set_nontrivial(true),
+ .set_implicit_ops(PUSHA_IDX),
/* POPA => */ BehaviorDigest::empty()
.set_pl_any()
- .set_nontrivial(true),
+ .set_implicit_ops(POPA_IDX),
/* BOUND => */ BehaviorDigest::empty()
.set_pl_any()
.set_operand(0, Access::Read)
@@ -6170,4 +6153,15 @@ static TABLE: [BehaviorDigest; 1425] = [
.set_pl0()
.set_flags_access(Access::Write)
.set_complex(true),
+
+ /* PUSHAD => */ BehaviorDigest::empty()
+ .set_pl_any()
+ .set_implicit_ops(PUSHAD_IDX),
+ /* POPAD => */ BehaviorDigest::empty()
+ .set_pl_any()
+ .set_implicit_ops(POPAD_IDX),
+ /* JECXZ => */ BehaviorDigest::empty()
+ .set_pl_any()
+ .set_operand(0, Access::Read)
+ .set_implicit_ops(RW_ECX_IDX),
];
diff --git a/src/real_mode/display.rs b/src/real_mode/display.rs
index e686b0a..888b0b1 100644
--- a/src/real_mode/display.rs
+++ b/src/real_mode/display.rs
@@ -2094,6 +2094,10 @@ const MNEMONICS: &[&'static str] = &[
"pvalidate",
"rmpadjust",
"rmpupdate",
+
+ "pushad",
+ "popad",
+ "jecxz",
];
impl Opcode {
@@ -2572,6 +2576,10 @@ pub(crate) fn contextualize_c<T: DisplaySink>(instr: &Instruction, out: &mut T)
out.write_str("jmp ")?;
write_jmp_operand(instr.operand(0), out)?;
},
+ Opcode::JECXZ => {
+ out.write_str("if ecx == 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), out)?;
+ },
Opcode::JCXZ => {
out.write_str("if cx == 0 then jmp ")?;
write_jmp_operand(instr.operand(0), out)?;
@@ -2766,8 +2774,9 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St
}
}
-static RELATIVE_BRANCHES: [Opcode; 22] = [
- Opcode::JMP, Opcode::CALL, Opcode::JCXZ,
+static RELATIVE_BRANCHES: [Opcode; 23] = [
+ Opcode::JMP, Opcode::CALL,
+ Opcode::JECXZ, Opcode::JCXZ,
Opcode::LOOP, Opcode::LOOPZ, Opcode::LOOPNZ,
Opcode::JO, Opcode::JNO,
Opcode::JB, Opcode::JNB,
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index f538fa5..8dd29b1 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -2508,6 +2508,13 @@ pub enum Opcode {
PVALIDATE,
RMPADJUST,
RMPUPDATE,
+
+ // these were part of the base (i386) ISA but were reported as distinct opcodes relatively late.
+ PUSHAD,
+ POPAD,
+
+ // likewise with alternate-size jecxz/jcxz..
+ JECXZ,
}
impl PartialEq for Instruction {
@@ -3992,6 +3999,7 @@ enum OperandCase {
ModRM_0xf30f38fa,
ModRM_0xf30f38fb,
ModRM_0xf30f3af0,
+ CXZ, // catch-all for "j*cxz and prefix handling"
}
#[allow(non_camel_case_types)]
@@ -4319,6 +4327,7 @@ enum OperandCode {
ModRM_0xc4 = OperandCodeBuilder::new().operand_case(OperandCase::ModRM_0xc4).bits(),
ModRM_0xc5 = OperandCodeBuilder::new().operand_case(OperandCase::ModRM_0xc5).bits(),
MASKMOVDQU = OperandCodeBuilder::new().read_E().reg_mem().operand_case(OperandCase::MASKMOVDQU).bits(),
+ CXZ = OperandCodeBuilder::new().operand_case(OperandCase::CXZ).bits(),
}
fn base_opcode_map(v: u8) -> Opcode {
@@ -4622,7 +4631,7 @@ const OPCODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOPNZ), OperandCode::Ibs),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOPZ), OperandCode::Ibs),
OpcodeRecord::new(Interpretation::Instruction(Opcode::LOOP), OperandCode::Ibs),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::JCXZ), OperandCode::Ibs),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::JCXZ), OperandCode::CXZ),
OpcodeRecord::new(Interpretation::Instruction(Opcode::IN), OperandCode::AL_Ib),
OpcodeRecord::new(Interpretation::Instruction(Opcode::IN), OperandCode::AX_Ib),
OpcodeRecord::new(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AL),
@@ -6510,9 +6519,19 @@ fn read_operands<
} else if instruction.opcode == Opcode::XLAT {
instruction.mem_size = 1;
} else if instruction.opcode == Opcode::PUSHA {
- instruction.mem_size = 2 * 8;
+ if !instruction.prefixes.operand_size() {
+ instruction.mem_size = 2 * 8;
+ } else {
+ instruction.opcode = Opcode::PUSHAD;
+ instruction.mem_size = 4 * 8;
+ }
} else if instruction.opcode == Opcode::POPA {
- instruction.mem_size = 2 * 8;
+ if !instruction.prefixes.operand_size() {
+ instruction.mem_size = 2 * 8;
+ } else {
+ instruction.opcode = Opcode::POPAD;
+ instruction.mem_size = 4 * 8;
+ }
}
instruction.operands[0] = OperandSpec::Nothing;
instruction.operand_count = 0;
@@ -9050,6 +9069,21 @@ fn read_operands<
instruction.mem_size = 2;
instruction.operand_count = 2;
},
+ OperandCase::CXZ => {
+ if instruction.prefixes.address_size() {
+ // address-size overridden from 16-bit to 32-bit
+ instruction.opcode = Opcode::JECXZ;
+ }
+ instruction.imm =
+ read_imm_signed(words, 1)? as u32;
+ sink.record(
+ words.offset() as u32 * 8 - 8,
+ words.offset() as u32 * 8 - 1,
+ InnerDescription::Number("1-byte immediate", instruction.imm as i64)
+ .with_id(words.offset() as u32 * 8),
+ );
+ instruction.operands[0] = OperandSpec::ImmI8;
+ },
};
Ok(())
}