diff options
| -rw-r--r-- | CHANGELOG | 2 | ||||
| -rw-r--r-- | src/long_mode/mod.rs | 30 | ||||
| -rw-r--r-- | test/long_mode/operand.rs | 5 |
3 files changed, 32 insertions, 5 deletions
@@ -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)); |
