From 5e9c3238e2d7f4565c510f396c57864901d76827 Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 17 Apr 2026 02:22:24 +0000 Subject: more precise about 0f0d prefetch/nop --- CHANGELOG | 1 + src/long_mode/mod.rs | 12 +++++++----- test/long_mode/mod.rs | 2 ++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index bbda929..c513e0a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ zero-extended to 64 bits for storage. writing to "eax" in this way implies the 32->64 bit zero-extend, whereas writing to "ax" does not imply any zero-extension. mov reg-to-seg is unchanged and uses a 16-bit form for source GPR. +* reject 0f0d prefetch/nop with a register operand, which was incorrectly decoded before. ## 2.0.0 diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 06e5b21..6433464 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -7239,12 +7239,14 @@ fn read_operands< instruction.opcode = Opcode::NOP; } } - instruction.operands[0] = mem_oper; - if instruction.operands[0] != OperandSpec::RegMMM { - instruction.mem_size = 64; - } else { - instruction.regs[1].bank = bank; + if mem_oper == OperandSpec::RegMMM { + // *found* this from running `0f0dc0` under KVM on a Zen 5 system. this is + // consistent with the register number being used to pick kinds of prefetch. + return Err(DecodeError::InvalidOperand); } + + instruction.operands[0] = mem_oper; + instruction.mem_size = 64; instruction.operand_count = 1; } OperandCase::ModRM_0x0f0f => { diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 3b55f32..f3676dd 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -2854,6 +2854,8 @@ fn test_adx() { #[test] fn test_prefetchw() { test_display(&[0x0f, 0x0d, 0x08], "prefetchw zmmword [rax]"); + test_display(&[0x0f, 0x0d, 0x00], "nop zmmword [rax]"); + test_invalid(&[0x0f, 0x0d, 0xc0]); } #[test] -- cgit v1.1