diff --git a/decode.c b/decode.c index a6bac57..4c300cb 100644 --- a/decode.c +++ b/decode.c @@ -560,6 +560,16 @@ prefix_end: } } + if (UNLIKELY(instr->type == FDI_3DNOW)) + { + unsigned opc3dn = instr->imm; + if (opc3dn & 0x40) + return FD_ERR_UD; + uint64_t msk = opc3dn & 0x80 ? 0x88d144d144d14400 : 0x30003000; + if (!(msk >> (opc3dn & 0x3f) & 1)) + return FD_ERR_UD; + } + if (UNLIKELY(prefix_lock)) { if (!DESC_LOCK(desc) || instr->operands[0].type != FD_OT_MEM) return FD_ERR_UD; diff --git a/tests/test_decode.c b/tests/test_decode.c index ef95550..6712861 100644 --- a/tests/test_decode.c +++ b/tests/test_decode.c @@ -509,6 +509,20 @@ main(int argc, char** argv) TEST32("\xd9\x20", "fldenv [eax]"); TEST64("\xd9\x20", "fldenv [rax]"); + // 3DNow! + TEST("\x0f\x0f\xc0\x00", "UD"); + TEST("\x0f\x0f\xc0\x0c", "3dnow mm0, mm0, 0xc"); // PI2FW + TEST("\x0f\x0f\xc0\x0d", "3dnow mm0, mm0, 0xd"); // PI2FD + TEST("\x0f\x0f\xc0\x0e", "UD"); + TEST("\x0f\x0f\xc0\x1c", "3dnow mm0, mm0, 0x1c"); // PF2IW + TEST("\x0f\x0f\xc0\x1d", "3dnow mm0, mm0, 0x1d"); // PF2ID + TEST("\x0f\x0f\xc0\x42", "UD"); + TEST("\x0f\x0f\xc0\x80", "UD"); + TEST("\x0f\x0f\xc0\x8a", "3dnow mm0, mm0, 0x8a"); // PFNACC + TEST("\x0f\x0f\xc0\xa0", "3dnow mm0, mm0, 0xa0"); // PFCMPGT + TEST("\x0f\x0f\xc0\xb6", "3dnow mm0, mm0, 0xb6"); // PFRCPIT2 + TEST("\x0f\x0f\xc0\xbf", "3dnow mm0, mm0, 0xbf"); // PAVGUSB + puts(failed ? "Some tests FAILED" : "All tests PASSED"); return failed ? EXIT_FAILURE : EXIT_SUCCESS; }