aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG2
-rw-r--r--src/long_mode/mod.rs30
-rw-r--r--test/long_mode/operand.rs5
3 files changed, 32 insertions, 5 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5266739..f454bc6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,8 @@
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
## 2.0.0
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 5163ba6..1e1d387 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -3852,7 +3852,8 @@ enum OperandCase {
G_E_xmm_Ib,
AL_Ibs,
AX_Ivd,
- Ivs,
+ PushIbs,
+ PushIvs,
ModRM_0x83,
Ed_G_xmm,
G_Ed_xmm,
@@ -4029,11 +4030,16 @@ enum OperandCase {
#[repr(u16)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum OperandCode {
- Ivs = OperandCodeBuilder::new().operand_case(OperandCase::Ivs).bits(),
I_3 = OperandCodeBuilder::new().operand_case(OperandCase::I_3).bits(),
Nothing = OperandCodeBuilder::new().operand_case(OperandCase::Nothing).bits(),
Ib = OperandCodeBuilder::new().operand_case(OperandCase::Ib).bits(),
Ibs = OperandCodeBuilder::new().only_imm().operand_case(OperandCase::Ibs).bits(),
+ // `push` of an immediate means we have to set a memory size, but `Ibs` is also the operand
+ // form for short relative (conditional) branches. to avoid the conditional in that relatively
+ // hot path, push is a different operand code so we can shove a `mem_size = 8` into the
+ // instruction later.
+ PushIbs = OperandCodeBuilder::new().operand_case(OperandCase::PushIbs).bits(),
+ PushIvs = OperandCodeBuilder::new().operand_case(OperandCase::PushIvs).bits(),
Jvds = OperandCodeBuilder::new().only_imm().operand_case(OperandCase::Jvds).bits(),
Yv_Xv = OperandCodeBuilder::new().operand_case(OperandCase::Yv_Xv).bits(),
@@ -4500,9 +4506,9 @@ const OPCODES: [OpcodeRecord; 256] = [
OpcodeRecord::new(Interpretation::Prefix, OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Prefix, OperandCode::Nothing),
OpcodeRecord::new(Interpretation::Prefix, OperandCode::Nothing),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::PUSH), OperandCode::Ivs),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::PUSH), OperandCode::PushIvs),
OpcodeRecord::new(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev_Iv),
- OpcodeRecord::new(Interpretation::Instruction(Opcode::PUSH), OperandCode::Ibs),
+ OpcodeRecord::new(Interpretation::Instruction(Opcode::PUSH), OperandCode::PushIbs),
OpcodeRecord::new(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev_Ib),
OpcodeRecord::new(Interpretation::Instruction(Opcode::INS), OperandCode::Yb_DX),
OpcodeRecord::new(Interpretation::Instruction(Opcode::INS), OperandCode::Yv_DX),
@@ -5942,6 +5948,18 @@ fn read_operands<
OperandCase::Internal | OperandCase::Gv_M |
OperandCase::Ibs | OperandCase::Jvds => {
}
+ OperandCase::PushIbs => {
+ instruction.mem_size = 8;
+ instruction.imm = read_imm_signed(words, 1)? as u64;
+ instruction.operands[0] = OperandSpec::ImmI8;
+ 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.operand_count = 1;
+ }
OperandCase::SingleMMMOper => {
instruction.operands[0] = mem_oper;
instruction.operand_count = 1;
@@ -6484,7 +6502,9 @@ fn read_operands<
.with_id(words.offset() as u32 * 8 - numwidth as u32 * 8 + 1)
);
}
- OperandCase::Ivs => {
+ OperandCase::PushIvs => {
+ instruction.mem_size = 8;
+
if instruction.prefixes.rex_unchecked().w() || !instruction.prefixes.operand_size() {
instruction.imm = read_imm_unsigned(words, 4)?;
instruction.operands[0] = OperandSpec::ImmI32;
diff --git a/test/long_mode/operand.rs b/test/long_mode/operand.rs
index 0faa1c3..b94d39f 100644
--- a/test/long_mode/operand.rs
+++ b/test/long_mode/operand.rs
@@ -27,6 +27,8 @@ fn memory_widths() {
assert_eq!(mem_size_of(&[0x66, 0x33, 0x00]).size_name(), "word");
assert_eq!(mem_size_of(&[0x33, 0x00]).size_name(), "dword");
assert_eq!(mem_size_of(&[0x48, 0x33, 0x00]).size_name(), "qword");
+ assert_eq!(mem_size_of(&[0x6a, 0x00]).size_name(), "qword");
+ assert_eq!(mem_size_of(&[0x68, 0x00, 0x00, 0x00, 0x00]).size_name(), "qword");
}
#[test]
@@ -45,6 +47,9 @@ fn test_implied_memory_width() {
assert_eq!(mem_size_of(&[0x66, 0x58]), Some(8));
assert_eq!(mem_size_of(&[0xff, 0xf0]), Some(8));
assert_eq!(mem_size_of(&[0x66, 0xff, 0xf0]), Some(2));
+ // push imm
+ assert_eq!(mem_size_of(&[0x6a, 0xaa]), Some(8));
+ assert_eq!(mem_size_of(&[0x68, 0xaa, 0xbb, 0xcc, 0xdd]), Some(8));
// 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));