aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2026-03-09 16:36:00 +0000
committeriximeow <me@iximeow.net>2026-05-25 00:59:27 +0000
commit8a2dd6bcf37a3ebb43e2153a306cf0250637c116 (patch)
tree44530b543f6718a6c709abf7c35f431f053beea8
parent63582532b8014d59117a8929afd1f7725bc1b469 (diff)
pushf, popf, enter, leave, xlat all have implicit memory access
also add "is_masked" to operand spec
-rw-r--r--CHANGELOG5
-rw-r--r--src/long_mode/mod.rs14
-rw-r--r--src/protected_mode/mod.rs14
-rw-r--r--src/real_mode/mod.rs14
-rw-r--r--test/long_mode/operand.rs8
-rw-r--r--test/protected_mode/operand.rs8
-rw-r--r--test/real_mode/operand.rs8
7 files changed, 66 insertions, 5 deletions
diff --git a/CHANGELOG b/CHANGELOG
index f454bc6..a4275f0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,8 +7,9 @@
even when their corresponding extension is not selected.
* added uarch-specific decoders for Zen 2, Zen 3, Zen 4, and Zen 5
* removed 3DNow support from AMD uarch-specific decoders after K10
-* push-immediate now reports a correct memory access side, fixing the prior
- behavior of reporting to memory access size at all
+* push-immediate, pushf, popf, enter, leave, and xlat now all report a correct memory
+ access size, fixing the prior behavior of reporting no memory access size at
+ all
## 2.0.0
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 0ffc9f5..f3b4dc0 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -474,6 +474,9 @@ impl OperandSpec {
fn is_memory(&self) -> bool {
(*self as u8) & 0x80 != 0
}
+ fn is_masked(&self) -> bool {
+ (*self as u8) & 0x40 != 0
+ }
}
/// an `avx512` merging mode.
@@ -6619,8 +6622,15 @@ fn read_operands<
instruction.mem_size = 8;
} else if instruction.opcode == Opcode::RETF {
instruction.mem_size = 10;
+ } else if instruction.opcode == Opcode::POPF {
+ instruction.mem_size = 8;
+ } else if instruction.opcode == Opcode::PUSHF {
+ instruction.mem_size = 8;
+ } else if instruction.opcode == Opcode::LEAVE {
+ instruction.mem_size = 8;
+ } else if instruction.opcode == Opcode::XLAT {
+ instruction.mem_size = 1;
}
- // TODO: leave?
instruction.operands[0] = OperandSpec::Nothing;
instruction.operand_count = 0;
return Ok(());
@@ -7102,6 +7112,8 @@ fn read_operands<
instruction.imm = read_num(words, 1)? as u64;
instruction.operands[0] = OperandSpec::ImmInDispField;
instruction.operands[1] = OperandSpec::ImmU8;
+ // because there is an implied push of the adjusted base pointer
+ instruction.mem_size = 8;
instruction.operand_count = 2;
}
OperandCase::Fw => {
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index 6f052c6..0df8cee 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -409,6 +409,9 @@ impl OperandSpec {
fn is_memory(&self) -> bool {
(*self as u8) & 0x80 != 0
}
+ fn is_masked(&self) -> bool {
+ (*self as u8) & 0x40 != 0
+ }
}
/// an `avx512` merging mode.
///
@@ -6445,8 +6448,15 @@ fn read_operands<
instruction.mem_size = 4;
} else if instruction.opcode == Opcode::RETF {
instruction.mem_size = 6;
+ } else if instruction.opcode == Opcode::POPF {
+ instruction.mem_size = 4;
+ } else if instruction.opcode == Opcode::PUSHF {
+ instruction.mem_size = 4;
+ } else if instruction.opcode == Opcode::LEAVE {
+ instruction.mem_size = 4;
+ } else if instruction.opcode == Opcode::XLAT {
+ instruction.mem_size = 1;
}
- // TODO: leave?
instruction.operands[0] = OperandSpec::Nothing;
instruction.operand_count = 0;
return Ok(());
@@ -6993,6 +7003,8 @@ fn read_operands<
instruction.imm = read_num(words, 1)? as u32;
instruction.operands[0] = OperandSpec::ImmInDispField;
instruction.operands[1] = OperandSpec::ImmU8;
+ // because there is an implied push of the adjusted base pointer
+ instruction.mem_size = 4;
instruction.operand_count = 2;
}
OperandCase::Fw => {
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index 42a0b03..c11cf00 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -409,6 +409,9 @@ impl OperandSpec {
fn is_memory(&self) -> bool {
(*self as u8) & 0x80 != 0
}
+ fn is_masked(&self) -> bool {
+ (*self as u8) & 0x40 != 0
+ }
}
/// an `avx512` merging mode.
///
@@ -6482,8 +6485,15 @@ fn read_operands<
instruction.mem_size = 2;
} else if instruction.opcode == Opcode::RETF {
instruction.mem_size = 4;
+ } else if instruction.opcode == Opcode::POPF {
+ instruction.mem_size = 2;
+ } else if instruction.opcode == Opcode::PUSHF {
+ instruction.mem_size = 2;
+ } else if instruction.opcode == Opcode::LEAVE {
+ instruction.mem_size = 2;
+ } else if instruction.opcode == Opcode::XLAT {
+ instruction.mem_size = 1;
}
- // TODO: leave?
instruction.operands[0] = OperandSpec::Nothing;
instruction.operand_count = 0;
return Ok(());
@@ -7032,6 +7042,8 @@ fn read_operands<
instruction.imm = read_num(words, 1)? as u32;
instruction.operands[0] = OperandSpec::ImmInDispField;
instruction.operands[1] = OperandSpec::ImmU8;
+ // because there is an implied push of the adjusted base pointer
+ instruction.mem_size = 2;
instruction.operand_count = 2;
}
OperandCase::Fw => {
diff --git a/test/long_mode/operand.rs b/test/long_mode/operand.rs
index b94d39f..10c4deb 100644
--- a/test/long_mode/operand.rs
+++ b/test/long_mode/operand.rs
@@ -53,4 +53,12 @@ fn test_implied_memory_width() {
// operand-size prefixed call and jump still reads 8 bytes (prefix ignored)
assert_eq!(mem_size_of(&[0x66, 0xff, 0x10]), Some(8));
assert_eq!(mem_size_of(&[0x66, 0xff, 0x20]), Some(8));
+ // pushf
+ assert_eq!(mem_size_of(&[0x9c]), Some(8));
+ // popf
+ assert_eq!(mem_size_of(&[0x9d]), Some(8));
+ // leave
+ assert_eq!(mem_size_of(&[0xc9]), Some(8));
+ // xlat
+ assert_eq!(mem_size_of(&[0xd7]), Some(1));
}
diff --git a/test/protected_mode/operand.rs b/test/protected_mode/operand.rs
index 78a34b4..fe9b54a 100644
--- a/test/protected_mode/operand.rs
+++ b/test/protected_mode/operand.rs
@@ -47,4 +47,12 @@ fn test_implied_memory_width() {
// two bytes.
assert_eq!(mem_size_of(&[0x66, 0xff, 0x10]), Some(2));
assert_eq!(mem_size_of(&[0x66, 0xff, 0x20]), Some(2));
+ // pushf
+ assert_eq!(mem_size_of(&[0x9c]), Some(4));
+ // popf
+ assert_eq!(mem_size_of(&[0x9d]), Some(4));
+ // leave
+ assert_eq!(mem_size_of(&[0xc9]), Some(4));
+ // xlat
+ assert_eq!(mem_size_of(&[0xd7]), Some(1));
}
diff --git a/test/real_mode/operand.rs b/test/real_mode/operand.rs
index 7f2b72e..e0f59e1 100644
--- a/test/real_mode/operand.rs
+++ b/test/real_mode/operand.rs
@@ -20,4 +20,12 @@ fn test_implied_memory_width() {
// four bytes.
assert_eq!(mem_size_of(&[0x66, 0xff, 0x10]), Some(4));
assert_eq!(mem_size_of(&[0x66, 0xff, 0x20]), Some(4));
+ // pushf
+ assert_eq!(mem_size_of(&[0x9c]), Some(2));
+ // popf
+ assert_eq!(mem_size_of(&[0x9d]), Some(2));
+ // leave
+ assert_eq!(mem_size_of(&[0xc9]), Some(2));
+ // xlat
+ assert_eq!(mem_size_of(&[0xd7]), Some(1));
}