From fe6b2b898aee944ba3490c35f4aed4d155485c0e Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 25 May 2026 19:21:31 +0000 Subject: push/pop width in 16/32-bit modes are receptive to operand width prefix --- src/real_mode/behavior.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) (limited to 'src/real_mode/behavior.rs') diff --git a/src/real_mode/behavior.rs b/src/real_mode/behavior.rs index 8941ee5..7724a0a 100644 --- a/src/real_mode/behavior.rs +++ b/src/real_mode/behavior.rs @@ -140,6 +140,16 @@ impl Instruction { .set_operand(1, Access::Read) .set_operand(2, Access::Read); } + } else if self.opcode == Opcode::PUSH { + if self.prefixes.operand_size() { + behavior = behavior + .set_implicit_ops(PUSHW_OPS_IDX); + } + } else if self.opcode == Opcode::PUSHF { + if self.prefixes.operand_size() { + behavior = behavior + .set_implicit_ops(PUSHFW_OPS_IDX); + } } else if self.opcode == Opcode::DIV || self.opcode == Opcode::IDIV { let op_width = if self.operands[0] == OperandSpec::RegMMM { self.regs[1].width() @@ -1960,6 +1970,28 @@ static PUSH_OPS: &'static [ImplicitOperand] = &[ } ]; +static PUSHW_OPS: &'static [ImplicitOperand] = &[ + ImplicitOperand { + spec: OperandSpec::Disp, + reg: RegSpec::sp(), + disp: -4i32, + write: true, + }, + // push.. pushes the value (above), then does a RMW on rsp. + ImplicitOperand { + spec: OperandSpec::RegRRR, + reg: RegSpec::sp(), + disp: 0, + write: false, + }, + ImplicitOperand { + spec: OperandSpec::RegRRR, + reg: RegSpec::sp(), + disp: 0, + write: true, + } +]; + static POP_OPS: &'static [ImplicitOperand] = &[ ImplicitOperand { spec: OperandSpec::Deref, @@ -2127,6 +2159,34 @@ static PUSHF_OPS: &'static [ImplicitOperand] = &[ } ]; +static PUSHFW_OPS: &'static [ImplicitOperand] = &[ + ImplicitOperand { + spec: OperandSpec::RegRRR, + reg: RegSpec::eflags(), + disp: 0, + write: false, + }, + ImplicitOperand { + spec: OperandSpec::Disp, + reg: RegSpec::sp(), + disp: -4i32, + write: true, + }, + // push.. pushes the value (above), then does a RMW on rsp. + ImplicitOperand { + spec: OperandSpec::RegRRR, + reg: RegSpec::sp(), + disp: 0, + write: false, + }, + ImplicitOperand { + spec: OperandSpec::RegRRR, + reg: RegSpec::sp(), + disp: 0, + write: true, + } +]; + static POPF_OPS: &'static [ImplicitOperand] = &[ ImplicitOperand { spec: OperandSpec::Deref, @@ -3689,8 +3749,10 @@ const PUSHA_IDX: u16 = 72; const POPA_IDX: u16 = 73; const PUSHAD_IDX: u16 = 74; const POPAD_IDX: u16 = 75; +const PUSHW_OPS_IDX: u16 = 76; +const PUSHFW_OPS_IDX: u16 = 77; -static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 76] = [ +static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 78] = [ &[], // implicit ops list 0 is not used PUSH_OPS, POP_OPS, @@ -3767,6 +3829,8 @@ static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 76] = [ POPA_OPS, PUSHAD_OPS, POPAD_OPS, + PUSHW_OPS, + PUSHFW_OPS, ]; fn opcode2behavior(opc: &Opcode) -> BehaviorDigest { @@ -3910,6 +3974,7 @@ static TABLE: [BehaviorDigest; 1428] = [ .set_operand(0, Access::Read), /* PUSH => */ BehaviorDigest::empty() .set_implicit_ops(PUSH_OPS_IDX) + .set_nontrivial(true) .set_pl_any() .set_operand(0, Access::Read), /* POP => */ BehaviorDigest::empty() @@ -3957,6 +4022,7 @@ static TABLE: [BehaviorDigest; 1428] = [ .set_pl_any(), /* PUSHF => */ BehaviorDigest::empty() .set_implicit_ops(PUSHF_IDX) + .set_nontrivial(true) .set_pl_any(), /* WAIT => */ GENERAL, /* CBW => */ BehaviorDigest::empty() -- cgit v1.1