From f2a2a09688421f2c532ab6f02527bf68f095407a Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 25 May 2026 17:32:57 +0000 Subject: 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. --- src/real_mode/behavior.rs | 38 ++++++++++++++++---------------------- src/real_mode/display.rs | 13 +++++++++++-- src/real_mode/mod.rs | 40 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 27 deletions(-) (limited to 'src/real_mode') 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(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 ShowContextual 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(()) } -- cgit v1.1