aboutsummaryrefslogtreecommitdiff
path: root/src/real_mode/behavior.rs
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2026-05-25 19:21:31 +0000
committeriximeow <me@iximeow.net>2026-05-25 19:24:01 +0000
commitfe6b2b898aee944ba3490c35f4aed4d155485c0e (patch)
tree984496e7ec908c43272d591db12a566c49ea07a2 /src/real_mode/behavior.rs
parentb43f483a50f650dbf385d2d55d0d38171f08e32b (diff)
push/pop width in 16/32-bit modes are receptive to operand width prefix
Diffstat (limited to 'src/real_mode/behavior.rs')
-rw-r--r--src/real_mode/behavior.rs68
1 files changed, 67 insertions, 1 deletions
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()