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