aboutsummaryrefslogtreecommitdiff
path: root/src/real_mode
diff options
context:
space:
mode:
Diffstat (limited to 'src/real_mode')
-rw-r--r--src/real_mode/behavior.rs38
-rw-r--r--src/real_mode/display.rs13
-rw-r--r--src/real_mode/mod.rs40
3 files changed, 64 insertions, 27 deletions
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(())
}