From 657cb19b8fc4ba71092d2fc7136aaf6abf224d50 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 2 May 2026 22:04:07 +0000 Subject: vmaskmovdqu, vmovq were also incorrect in some ways... --- CHANGELOG | 2 ++ src/long_mode/vex.rs | 34 +++++++++++++++++++++++++--------- test/long_mode/mod.rs | 2 ++ test/long_mode/operand.rs | 4 ++++ 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7ceeef0..1aed610 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,8 @@ vcvtph2ps, vbroadcastf128, vmaskmovps, vmaskmovpd, vpermd, vpbroadcast{b,w,d,q}, among others * vpbroadcastb and vpbroadcastw should respect the L bit to select xmm/ymm vector width, but always decoded as ymm. +* vmaskmovqdu now reports a memory access size for the implied write to ds:[rdi/edi/di]. +* correct swapped operand order of 0xD6-opcode movq. ## 2.0.0 diff --git a/src/long_mode/vex.rs b/src/long_mode/vex.rs index b43b0fe..1d94b3c 100644 --- a/src/long_mode/vex.rs +++ b/src/long_mode/vex.rs @@ -46,7 +46,7 @@ enum VEXOperandCode { VMOVHPS_16, M_G_xmm, G_M_xmm, - G_U_xmm, + G_U_xmm_vmaskmovdqu, Gd_U_xmm, E_G_xmm_imm8, Ud_G_xmm_imm8, @@ -857,17 +857,12 @@ fn read_vex_operands< } op @ VEXOperandCode::G_M_xmm | - op @ VEXOperandCode::G_U_xmm | op @ VEXOperandCode::G_E_xmm => { if instruction.regs[3].num != 0 { return Err(DecodeError::InvalidOperand); } let modrm = read_modrm(words)?; match (op, modrm & 0xc0) { - (VEXOperandCode::G_U_xmm, 0xc0) => { - /* this is the only accepted operand */ - } - (VEXOperandCode::G_U_xmm, _) | (VEXOperandCode::G_M_xmm, 0xc0) => { return Err(DecodeError::InvalidOperand); } @@ -893,6 +888,27 @@ fn read_vex_operands< instruction.operand_count = 2; Ok(()) } + VEXOperandCode::G_U_xmm_vmaskmovdqu => { + if instruction.regs[3].num != 0 { + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + return Err(DecodeError::InvalidOperand); + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm, sink)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + if instruction.prefixes.address_size() { + instruction.mem_size = 4; + } else { + instruction.mem_size = 8; + } + instruction.operand_count = 2; + Ok(()) + } VEXOperandCode::G_xmm_E_xmm => { if instruction.regs[3].num != 0 { return Err(DecodeError::InvalidOperand); @@ -1113,7 +1129,7 @@ fn read_vex_operands< RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), bank); let mem_oper = read_E(words, instruction, modrm, bank, sink)?; if mem_oper != OperandSpec::RegMMM { - if instruction.opcode == Opcode::VMOVLPD || instruction.opcode == Opcode::VMOVHPD || instruction.opcode == Opcode::VMOVHPS { + if instruction.opcode == Opcode::VMOVLPD || instruction.opcode == Opcode::VMOVHPD || instruction.opcode == Opcode::VMOVHPS || instruction.opcode == Opcode::VMOVQ { instruction.mem_size = 8; } else { if L { @@ -1889,7 +1905,7 @@ fn read_vex_instruction< 0xD6 => (Opcode::VMOVQ, if L { return Err(DecodeError::InvalidOpcode); } else { - VEXOperandCode::G_E_xmm + VEXOperandCode::E_G_xyLmm }), 0xD7 => (Opcode::VPMOVMSKB, VEXOperandCode::Ud_G_xyLmm), 0xD8 => (Opcode::VPSUBUSB, VEXOperandCode::G_V_E_xyLmm), @@ -1949,7 +1965,7 @@ fn read_vex_instruction< 0xF7 => (Opcode::VMASKMOVDQU, if L { return Err(DecodeError::InvalidOpcode); } else { - VEXOperandCode::G_U_xmm + VEXOperandCode::G_U_xmm_vmaskmovdqu }), 0xF8 => (Opcode::VPSUBB, VEXOperandCode::G_V_E_xyLmm), 0xF9 => (Opcode::VPSUBW, VEXOperandCode::G_V_E_xyLmm), diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 9ad0df4..1524868 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -2339,6 +2339,8 @@ fn test_vex() { test_avx2(&[0xc4, 0b000_00001, 0b1_1111_101, 0x6d, 0b11_001_010], "vpunpckhqdq ymm9, ymm0, ymm10"); test_instr(&[0xc4, 0b000_00001, 0b1_1111_001, 0x6e, 0b11_001_010], "vmovq xmm9, r10"); test_instr(&[0xc4, 0b000_00001, 0b1_1111_001, 0x6e, 0b00_001_010], "vmovq xmm9, qword [r10]"); + test_instr(&[0xc4, 0b000_00001, 0b1_1111_001, 0xd6, 0b00_001_010], "vmovq qword [r10], xmm9"); + test_instr(&[0xc4, 0b000_00001, 0b1_1111_001, 0xd6, 0b11_001_010], "vmovq xmm10, xmm9"); test_invalid(&[0xc4, 0b000_00001, 0b1_1111_101, 0x6e, 0b11_001_010]); test_instr(&[0xc4, 0b000_00001, 0b0_1111_001, 0x6f, 0b11_001_010], "vmovdqa xmm9, xmm10"); test_instr(&[0xc4, 0b000_00001, 0b0_1111_101, 0x6f, 0b11_001_010], "vmovdqa ymm9, ymm10"); diff --git a/test/long_mode/operand.rs b/test/long_mode/operand.rs index fe64fb6..a1d80e8 100644 --- a/test/long_mode/operand.rs +++ b/test/long_mode/operand.rs @@ -37,6 +37,10 @@ fn memory_widths() { // "maskmovdqu xmm0, xmm1" assert_eq!(mem_size_of(&[0x66, 0x4f, 0x0f, 0xf7, 0xc1]).size_name(), "qword"); assert_eq!(mem_size_of(&[0x67, 0x66, 0x0f, 0xf7, 0xc1]).size_name(), "dword"); + + // "vmaskmovdqu xmm0, xmm1" + assert_eq!(mem_size_of(&[0xc4, 0xe1, 0x79, 0xf7, 0xc1]).size_name(), "qword"); + assert_eq!(mem_size_of(&[0x67, 0xc4, 0xe1, 0x79, 0xf7, 0xc1]).size_name(), "dword"); } #[test] -- cgit v1.1