diff --git a/fadec.h b/fadec.h index 2b1f293..e746301 100644 --- a/fadec.h +++ b/fadec.h @@ -135,7 +135,24 @@ int fd_decode(const uint8_t* buf, size_t len, int mode, uintptr_t address, **/ void fd_format(const FdInstr* instr, char* buf, size_t len); +/** Format an instruction to a string. + * NOTE: API stability is currently not guaranteed for this function; its name + * and/or signature may change in future. + * + * \param instr The instruction. + * \param addr The base address to use for printing FD_OT_OFF operands. + * \param buf The buffer to hold the formatted string. + * \param len The length of the buffer. + **/ +void fd_format_abs(const FdInstr* instr, uint64_t addr, char* buf, size_t len); + /** Get the stringified name of an instruction type. + * NOTE: API stability is currently not guaranteed for this function; changes + * to the signature and/or the returned string can be expected. E.g., a future + * version may take an extra parameter for the instruction operand size; or may + * take a complete decoded instruction as first parameter and return the + * mnemonic returned by fd_format. + * * \param ty An instruction type * \return The instruction type as string, or "(invalid)". **/ diff --git a/format.c b/format.c index 8ec8a80..8aa92ec 100644 --- a/format.c +++ b/format.c @@ -2,11 +2,70 @@ #include #include #include -#include #include +static const char* +reg_name(unsigned rt, unsigned ri, unsigned size) +{ + unsigned max; + const char (* table)[6]; + +#define TABLE(name, ...) \ + case name: { \ + static const char tab[][6] = { __VA_ARGS__ }; \ + table = tab; max = sizeof(tab) / sizeof(*tab); \ + break; \ + } + + switch (rt) { + default: return "(inv-ty)"; + case FD_RT_GPL: + switch (size) { + default: return "(inv-sz)"; + TABLE(1, + "al","cl","dl","bl","spl","bpl","sil","dil", + "r8b","r9b","r10b","r11b","r12b","r13b","r14b","r15b") + TABLE(2, + "ax","cx","dx","bx","sp","bp","si","di", + "r8w","r9w","r10w","r11w","r12w","r13w","r14w","r15w","ip") + TABLE(4, + "eax","ecx","edx","ebx","esp","ebp","esi","edi", + "r8d","r9d","r10d","r11d","r12d","r13d","r14d","r15d","eip") + TABLE(8, + "rax","rcx","rdx","rbx","rsp","rbp","rsi","rdi", + "r8","r9","r10","r11","r12","r13","r14","r15","rip") + } + break; + + TABLE(FD_RT_GPH, "(inv)","(inv)","(inv)","(inv)","ah","ch","dh","bh") + TABLE(FD_RT_SEG, "es","cs","ss","ds","fs","gs") + TABLE(FD_RT_FPU, "st(0)","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)") + TABLE(FD_RT_MMX, "mm0","mm1","mm2","mm3","mm4","mm5","mm6","mm7") + TABLE(FD_RT_CR, "cr0","(inv)","cr2","cr3","cr4","(inv)","(inv)","(inv)","cr8") + TABLE(FD_RT_DR, "dr0","dr1","dr2","dr3","dr4","dr5","dr6","dr7") + + case FD_RT_VEC: + switch (size) { + default: return "(inv-sz)"; + case 1: + case 2: + case 4: + case 8: + TABLE(16, + "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7", + "xmm8","xmm9","xmm10","xmm11","xmm12","xmm13","xmm14","xmm15") + TABLE(32, + "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7", + "ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15") + } + break; + } + + return ri < max ? table[ri] : "(inv-idx)"; +} + #define FD_DECODE_TABLE_STRTAB1 static const char* _mnemonic_str = #include @@ -19,6 +78,27 @@ static const uint16_t _mnemonic_offs[] = { }; #undef FD_DECODE_TABLE_STRTAB2 +static char* +fd_strplcpy(char* dst, const char* src, size_t size) +{ + while (*src && size > 1) + *dst++ = *src++, size--; + if (size) + *dst = 0; + return dst; +} + +static char* +fd_format_hex(uint64_t val, char buf[static 17]) { + unsigned idx = 17; + buf[--idx] = 0; + do { + buf[--idx] = "0123456789abcdef"[val % 16]; + val /= 16; + } while (val); + return &buf[idx]; +} + const char* fdi_name(FdInstrType ty) { if (ty >= sizeof(_mnemonic_offs) / sizeof(_mnemonic_offs[0])) @@ -26,102 +106,236 @@ fdi_name(FdInstrType ty) { return &_mnemonic_str[_mnemonic_offs[ty]]; } -#define FMT_CONCAT(buf, end, ...) do { \ - buf += snprintf(buf, end - buf, __VA_ARGS__); \ - if (buf > end) \ - buf = end; \ - } while (0) - void fd_format(const FdInstr* instr, char* buffer, size_t len) { + fd_format_abs(instr, 0, buffer, len); +} + +void +fd_format_abs(const FdInstr* instr, uint64_t addr, char* buffer, size_t len) +{ + char tmp[21]; + char* buf = buffer; char* end = buffer + len; - FMT_CONCAT(buf, end, "["); if (FD_HAS_REP(instr)) - FMT_CONCAT(buf, end, "rep:"); + buf = fd_strplcpy(buf, "rep ", end-buf); if (FD_HAS_REPNZ(instr)) - FMT_CONCAT(buf, end, "repnz:"); - if (FD_SEGMENT(instr) < 6) - FMT_CONCAT(buf, end, "%cs:", "ecsdfg"[FD_SEGMENT(instr)]); - if (FD_IS64(instr) && FD_ADDRSIZE(instr) == 4) - FMT_CONCAT(buf, end, "addr32:"); - if (!FD_IS64(instr) && FD_ADDRSIZE(instr) == 2) - FMT_CONCAT(buf, end, "addr16:"); + buf = fd_strplcpy(buf, "repnz ", end-buf); if (FD_HAS_LOCK(instr)) - FMT_CONCAT(buf, end, "lock:"); + buf = fd_strplcpy(buf, "lock ", end-buf); - FMT_CONCAT(buf, end, "%s", fdi_name(FD_TYPE(instr))); - if (FD_OPSIZE(instr)) - FMT_CONCAT(buf, end, "_%u", FD_OPSIZE(instr)); + const char* mnemonic = fdi_name(FD_TYPE(instr)); + + bool prefix_addrsize = false; + bool prefix_segment = false; + + char sizesuffix[3] = {0, 0, 0}; + switch (FD_OPSIZE(instr)) { + default: break; + case 1: sizesuffix[0] = 'b'; break; + case 2: sizesuffix[0] = 'w'; break; + case 4: sizesuffix[0] = 'd'; break; + case 8: sizesuffix[0] = 'q'; break; + } + + if (FD_OP_TYPE(instr, 0) == FD_OT_OFF && FD_OP_SIZE(instr, 0) == 2) + sizesuffix[0] = 'w'; + + switch (FD_TYPE(instr)) { + case FDI_C_SEP: + switch (FD_OPSIZE(instr)) { + default: break; + case 2: mnemonic = "cwd"; break; + case 4: mnemonic = "cdq"; break; + case 8: mnemonic = "cqo"; break; + } + sizesuffix[0] = 0; + break; + case FDI_C_EX: + switch (FD_OPSIZE(instr)) { + default: break; + case 2: mnemonic = "cbw"; break; + case 4: mnemonic = "cwde"; break; + case 8: mnemonic = "cdqe"; break; + } + sizesuffix[0] = 0; + break; + case FDI_CMPXCHGD: + switch (FD_OPSIZE(instr)) { + default: break; + case 4: mnemonic = "cmpxchg8b"; break; + case 8: mnemonic = "cmpxchg16b"; break; + } + sizesuffix[0] = 0; + break; + case FDI_JCXZ: + switch (FD_ADDRSIZE(instr)) { + default: break; + case 4: mnemonic = "jecxz"; break; + case 8: mnemonic = "jrcxz"; break; + } + break; + case FDI_ENTER: + buf = fd_strplcpy(buf, mnemonic, end-buf); + if (FD_OPSIZE(instr) == 2) + buf = fd_strplcpy(buf, "w", end-buf); + char* fmt = fd_format_hex(FD_OP_IMM(instr, 0) & 0xffff, tmp + 3); + *--fmt = 'x'; + *--fmt = '0'; + *--fmt = ' '; + buf = fd_strplcpy(buf, fmt, end-buf); + fmt = fd_format_hex(FD_OP_IMM(instr, 0) >> 16, tmp + 4); + *--fmt = 'x'; + *--fmt = '0'; + *--fmt = ' '; + *--fmt = ','; + buf = fd_strplcpy(buf, fmt, end-buf); + return; + case FDI_PUSH: + if (FD_OP_SIZE(instr, 0) == 2 && FD_OP_TYPE(instr, 0) == FD_OT_IMM) + sizesuffix[0] = 'w'; + // FALLTHROUGH + case FDI_POP: + if (FD_OP_SIZE(instr, 0) == 2 && FD_OP_TYPE(instr, 0) == FD_OT_REG && + FD_OP_REG_TYPE(instr, 0) == FD_RT_SEG) + sizesuffix[0] = 'w'; + break; + case FDI_FXSAVE: + case FDI_FXRSTOR: + case FDI_XSAVE: + case FDI_XSAVEC: + case FDI_XSAVEOPT: + case FDI_XSAVES: + case FDI_XRSTOR: + case FDI_XRSTORS: + if (FD_OPSIZE(instr) == 8) + sizesuffix[0] = '6', sizesuffix[1] = '4'; + else + sizesuffix[0] = 0; + break; + case FDI_RET: + case FDI_LEAVE: + if (FD_OPSIZE(instr) == (FD_IS64(instr) ? 8 : 4)) + sizesuffix[0] = 0; + break; + case FDI_LODS: + case FDI_MOVS: + case FDI_CMPS: + case FDI_OUTS: + prefix_segment = true; + // FALLTHROUGH + case FDI_STOS: + case FDI_SCAS: + case FDI_INS: + prefix_addrsize = true; + break; + default: break; + } + + if (prefix_addrsize) { + if (FD_IS64(instr) && FD_ADDRSIZE(instr) == 4) + buf = fd_strplcpy(buf, "addr32 ", end-buf); + if (!FD_IS64(instr) && FD_ADDRSIZE(instr) == 2) + buf = fd_strplcpy(buf, "addr16 ", end-buf); + } + if (prefix_segment && FD_SEGMENT(instr) != FD_REG_NONE) { + buf = fd_strplcpy(buf, reg_name(FD_RT_SEG, FD_SEGMENT(instr), 2), end-buf); + buf = fd_strplcpy(buf, " ", end-buf); + } + + buf = fd_strplcpy(buf, mnemonic, end-buf); + buf = fd_strplcpy(buf, sizesuffix, end-buf); for (int i = 0; i < 4; i++) { FdOpType op_type = FD_OP_TYPE(instr, i); if (op_type == FD_OT_NONE) break; + buf = fd_strplcpy(buf, ", " + (i == 0), end-buf); - const char* op_type_name = &"reg\0imm\0mem\0off"[op_type * 4] - 4; - FMT_CONCAT(buf, end, " %s%u:", op_type_name, FD_OP_SIZE(instr, i)); + unsigned size = FD_OP_SIZE(instr, i); - switch (op_type) - { - size_t immediate; - bool has_base; - bool has_idx; - bool has_disp; - case FD_OT_REG: - if (FD_OP_REG_HIGH(instr, i)) - FMT_CONCAT(buf, end, "r%uh", FD_OP_REG(instr, i) - 4); - else - FMT_CONCAT(buf, end, "r%u", FD_OP_REG(instr, i)); - break; - case FD_OT_OFF: - if (FD_OP_SIZE(instr, i) == 2) - FMT_CONCAT(buf, end, "ip+"); - else if (FD_OP_SIZE(instr, i) == 4) - FMT_CONCAT(buf, end, "eip+"); - else if (FD_OP_SIZE(instr, i) == 8) - FMT_CONCAT(buf, end, "rip+"); - // fallthrough - case FD_OT_IMM: - immediate = FD_OP_IMM(instr, i); + if (op_type == FD_OT_REG) { + unsigned type = FD_OP_REG_TYPE(instr, i); + unsigned idx = FD_OP_REG(instr, i); + buf = fd_strplcpy(buf, reg_name(type, idx, size), end-buf); + } else if (op_type == FD_OT_MEM) { + if (FD_TYPE(instr) == FDI_CMPXCHGD) + size = 2 * FD_OPSIZE(instr); + else if (FD_TYPE(instr) == FDI_BOUND) + size *= 2; + else if (FD_TYPE(instr) == FDI_JMPF || FD_TYPE(instr) == FDI_CALLF + || FD_TYPE(instr) == FDI_LDS || FD_TYPE(instr) == FDI_LES + || FD_TYPE(instr) == FDI_LFS || FD_TYPE(instr) == FDI_LGS + || FD_TYPE(instr) == FDI_LSS) + size = 6; + else if (!size && (FD_TYPE(instr) == FDI_FLD || + FD_TYPE(instr) == FDI_FSTP || + FD_TYPE(instr) == FDI_FBLD || + FD_TYPE(instr) == FDI_FBSTP)) + size = 10; + switch (size) { + default: break; + case 1: buf = fd_strplcpy(buf, "byte ptr ", end-buf); break; + case 2: buf = fd_strplcpy(buf, "word ptr ", end-buf); break; + case 4: buf = fd_strplcpy(buf, "dword ptr ", end-buf); break; + case 6: buf = fd_strplcpy(buf, "fword ptr ", end-buf); break; + case 8: buf = fd_strplcpy(buf, "qword ptr ", end-buf); break; + case 10: buf = fd_strplcpy(buf, "tbyte ptr ", end-buf); break; + case 16: buf = fd_strplcpy(buf, "xmmword ptr ", end-buf); break; + case 32: buf = fd_strplcpy(buf, "ymmword ptr ", end-buf); break; + } + unsigned seg = FD_SEGMENT(instr); + if (seg != FD_REG_NONE) { + buf = fd_strplcpy(buf, reg_name(FD_RT_SEG, seg, 2), end-buf); + buf = fd_strplcpy(buf, ":", end-buf); + } + buf = fd_strplcpy(buf, "[", end-buf); + + bool has_base = FD_OP_BASE(instr, i) != FD_REG_NONE; + bool has_idx = FD_OP_INDEX(instr, i) != FD_REG_NONE; + if (has_base) + buf = fd_strplcpy(buf, reg_name(FD_RT_GPL, FD_OP_BASE(instr, i), FD_ADDRSIZE(instr)), end-buf); + if (has_idx) { + if (has_base) + buf = fd_strplcpy(buf, "+", end-buf); + buf = fd_strplcpy(buf, "1*\0002*\0004*\0008*" + 3*FD_OP_SCALE(instr, i), end-buf); + buf = fd_strplcpy(buf, reg_name(FD_RT_GPL, FD_OP_INDEX(instr, i), FD_ADDRSIZE(instr)), end-buf); + } + uint64_t disp = FD_OP_DISP(instr, i); + if (disp && (has_base || has_idx)) { + buf = fd_strplcpy(buf, (int64_t) disp < 0 ? "-" : "+", end-buf); + if ((int64_t) disp < 0) + disp = -disp; + } + if (FD_ADDRSIZE(instr) == 2) + disp &= 0xffff; + else if (FD_ADDRSIZE(instr) == 4) + disp &= 0xffffffff; + if (disp || (!has_base && !has_idx)) { + char* fmt = fd_format_hex(disp, tmp + 2); + *--fmt = 'x'; + *--fmt = '0'; + buf = fd_strplcpy(buf, fmt, end-buf); + } + buf = fd_strplcpy(buf, "]", end-buf); + } else if (op_type == FD_OT_IMM || op_type == FD_OT_OFF) { + size_t immediate = FD_OP_IMM(instr, i); + if (op_type == FD_OT_OFF) + immediate += addr + FD_SIZE(instr); if (FD_OP_SIZE(instr, i) == 1) immediate &= 0xff; else if (FD_OP_SIZE(instr, i) == 2) immediate &= 0xffff; else if (FD_OP_SIZE(instr, i) == 4) immediate &= 0xffffffff; - FMT_CONCAT(buf, end, "0x%lx", immediate); - break; - case FD_OT_MEM: - has_base = FD_OP_BASE(instr, i) != FD_REG_NONE; - has_idx = FD_OP_INDEX(instr, i) != FD_REG_NONE; - has_disp = FD_OP_DISP(instr, i) != 0; - if (has_base) - { - FMT_CONCAT(buf, end, "r%u", FD_OP_BASE(instr, i)); - if (has_idx || has_disp) - FMT_CONCAT(buf, end, "+"); - } - if (has_idx) - { - FMT_CONCAT(buf, end, "%u*r%u", 1 << FD_OP_SCALE(instr, i), - FD_OP_INDEX(instr, i)); - if (has_disp) - FMT_CONCAT(buf, end, "+"); - } - if (FD_OP_DISP(instr, i) < 0) - FMT_CONCAT(buf, end, "-0x%lx", -FD_OP_DISP(instr, i)); - else if (has_disp || (!has_base && !has_idx)) - FMT_CONCAT(buf, end, "0x%lx", FD_OP_DISP(instr, i)); - break; - case FD_OT_NONE: - default: - break; + char* fmt = fd_format_hex(immediate, tmp + 2); + *--fmt = 'x'; + *--fmt = '0'; + buf = fd_strplcpy(buf, fmt, end-buf); } } - - FMT_CONCAT(buf, end, "]"); } diff --git a/parseinstrs.py b/parseinstrs.py index 9454e48..b555a2b 100644 --- a/parseinstrs.py +++ b/parseinstrs.py @@ -639,12 +639,19 @@ if __name__ == "__main__": table.deduplicate() table_data, annotations, root_offsets, descs = table.compile() + mnemonics_intel = [m.replace("SSE_", "").replace("MMX_", "") + .replace("MOVABS", "MOV") + .replace("JMPF", "JMP FAR").replace("CALLF", "CALL FAR") + .replace("_S2G", "").replace("_G2S", "") + .replace("_CR", "").replace("_DR", "") + .lower() for m in mnemonics] + defines = ["FD_TABLE_OFFSET_%d %d"%k for k in zip(args.modes, root_offsets)] decode_table = template.format( hex_table=bytes_to_table(table_data, annotations), descs="\n".join("{{{0},{1},{2},{3}}},".format(*desc) for desc in descs), - mnemonics=parse_mnemonics(mnemonics), + mnemonics=parse_mnemonics(mnemonics_intel), defines="\n".join("#define " + line for line in defines), ) args.decode_table.write(decode_table) diff --git a/tests/test_decode.c b/tests/test_decode.c index 01a802d..2a1294d 100644 --- a/tests/test_decode.c +++ b/tests/test_decode.c @@ -56,294 +56,384 @@ main(int argc, char** argv) int failed = 0; - TEST("\x90", "[NOP]"); - TEST("\x90", "[NOP]"); - TEST32("\x2e\x90", "[cs:NOP]"); - TEST64("\x2e\x90", "[NOP]"); - TEST32("\x2e\x2e\x90", "[cs:NOP]"); - TEST64("\x2e\x2e\x90", "[NOP]"); - TEST32("\x2e\x26\x90", "[es:NOP]"); - TEST64("\x2e\x26\x90", "[NOP]"); - TEST32("\x26\x2e\x90", "[cs:NOP]"); - TEST64("\x26\x2e\x90", "[NOP]"); - TEST32("\x26\x65\x90", "[gs:NOP]"); - TEST64("\x26\x65\x90", "[gs:NOP]"); - TEST32("\x65\x26\x90", "[es:NOP]"); - TEST64("\x65\x26\x90", "[gs:NOP]"); - TEST("\x0f\x10\xc1", "[SSE_MOVUPS reg16:r0 reg16:r1]"); - TEST("\x66\x0f\x10\xc1", "[SSE_MOVUPD reg16:r0 reg16:r1]"); - TEST("\xf2\x66\x0f\x10\xc1", "[SSE_MOVSD reg16:r0 reg8:r1]"); - TEST("\xf3\x66\x0f\x10\xc1", "[SSE_MOVSS reg16:r0 reg4:r1]"); - TEST("\xf3\xf2\x66\x0f\x10\xc1", "[SSE_MOVSD reg16:r0 reg8:r1]"); - TEST("\xf2\x66\xf3\x66\x0f\x10\xc1", "[SSE_MOVSS reg16:r0 reg4:r1]"); - TEST64("\x48\x90", "[NOP]"); - TEST64("\x49\x90", "[XCHG reg8:r8 reg8:r0]"); - TEST64("\x48\x91", "[XCHG reg8:r1 reg8:r0]"); - TEST64("\x48\x26\x91", "[XCHG reg4:r1 reg4:r0]"); - TEST64("\x66\x90", "[NOP]"); - TEST("\x0f\xc7\x0f", "[CMPXCHGD_4 mem0:r7]"); - TEST64("\x48\x0f\xc7\x0f", "[CMPXCHGD_8 mem0:r7]"); + TEST("\x90", "nop"); + TEST("\xac", "lodsb"); + TEST32("\x2e\xac", "cs lodsb"); + TEST64("\x2e\xac", "lodsb"); + TEST32("\x2e\x2e\xac", "cs lodsb"); + TEST64("\x2e\x2e\xac", "lodsb"); + TEST32("\x2e\x26\xac", "es lodsb"); + TEST64("\x2e\x26\xac", "lodsb"); + TEST32("\x26\x2e\xac", "cs lodsb"); + TEST64("\x26\x2e\xac", "lodsb"); + TEST32("\x26\x65\xac", "gs lodsb"); + TEST64("\x26\x65\xac", "gs lodsb"); + TEST32("\x65\x26\xac", "es lodsb"); + TEST64("\x65\x26\xac", "gs lodsb"); + TEST("\x0f\x10\xc1", "movups xmm0, xmm1"); + TEST("\x66\x0f\x10\xc1", "movupd xmm0, xmm1"); + TEST("\xf2\x66\x0f\x10\xc1", "movsd xmm0, xmm1"); + TEST("\xf3\x66\x0f\x10\xc1", "movss xmm0, xmm1"); + TEST("\xf3\xf2\x66\x0f\x10\xc1", "movsd xmm0, xmm1"); + TEST("\xf2\x66\xf3\x66\x0f\x10\xc1", "movss xmm0, xmm1"); + TEST64("\x48\x90", "nop"); + TEST64("\x49\x90", "xchg r8, rax"); + TEST64("\x48\x91", "xchg rcx, rax"); + TEST64("\x48\x26\x91", "xchg ecx, eax"); + TEST64("\x66\x90", "nop"); + TEST32("\x0f\xc7\x0f", "cmpxchg8b qword ptr [edi]"); + TEST64("\x0f\xc7\x0f", "cmpxchg8b qword ptr [rdi]"); + TEST64("\x48\x0f\xc7\x0f", "cmpxchg16b xmmword ptr [rdi]"); TEST("\x66", "PARTIAL"); TEST("\x0f", "PARTIAL"); TEST("\x0f\x38", "PARTIAL"); TEST("\x0f\x3a", "PARTIAL"); TEST("\x80", "PARTIAL"); - TEST("\x0F\x01\x22", "[SMSW mem2:r2]"); - TEST64("\x48\x0F\x01\x22", "[SMSW mem2:r2]"); - TEST("\x66\x0F\x01\x22", "[SMSW mem2:r2]"); - TEST("\x0F\x01\xE2", "[SMSW reg4:r2]"); - TEST("\x66\x0F\x01\xE2", "[SMSW reg2:r2]"); - TEST64("\x66\x48\x0F\x01\xE2", "[SMSW reg8:r2]"); - TEST32("\x66\x0f\x20\x00", "[MOV_CR reg4:r0 reg0:r0]"); // mod=0, 66h - TEST64("\x66\x0f\x20\x00", "[MOV_CR reg8:r0 reg0:r0]"); // mod=0, 66h + TEST32("\x0F\x01\x22", "smsw word ptr [edx]"); + TEST64("\x0F\x01\x22", "smsw word ptr [rdx]"); + TEST64("\x48\x0F\x01\x22", "smsw word ptr [rdx]"); + TEST32("\x66\x0F\x01\x22", "smsw word ptr [edx]"); + TEST64("\x66\x0F\x01\x22", "smsw word ptr [rdx]"); + TEST("\x0F\x01\xE2", "smsw edx"); + TEST("\x66\x0F\x01\xE2", "smsw dx"); + TEST64("\x66\x48\x0F\x01\xE2", "smsw rdx"); + TEST32("\x66\x0f\x20\x00", "mov eax, cr0"); // mod=0, 66h + TEST64("\x66\x0f\x20\x00", "mov rax, cr0"); // mod=0, 66h TEST("\x0f\x20\xc8", "UD"); // cr1 - TEST32("\x0f\x20\xd0", "[MOV_CR reg4:r0 reg0:r2]"); // cr2 - TEST64("\x0f\x20\xd0", "[MOV_CR reg8:r0 reg0:r2]"); // cr2 - TEST64("\x48\x0f\x20\xd0", "[MOV_CR reg8:r0 reg0:r2]"); // cr2 + REX.W + TEST32("\x0f\x20\xd0", "mov eax, cr2"); // cr2 + TEST64("\x0f\x20\xd0", "mov rax, cr2"); // cr2 + TEST64("\x48\x0f\x20\xd0", "mov rax, cr2"); // cr2 + REX.W TEST64("\x44\x0f\x20\x08", "UD"); // cr9 TEST64("\x44\x0f\x21\x00", "UD"); // dr8 - TEST("\x8c\xc0", "[MOV_S2G reg2:r0 reg2:r0]"); - TEST64("\x44\x8c\xc0", "[MOV_S2G reg2:r0 reg2:r0]"); + TEST("\x8c\xc0", "mov ax, es"); + TEST64("\x44\x8c\xc0", "mov ax, es"); TEST64("\x44\x8c\xf0", "UD"); // no segment register 6 TEST64("\x44\x8c\xf8", "UD"); // no segment register 7 - TEST("\x8e\xc0", "[MOV_G2S reg2:r0 reg2:r0]"); + TEST("\x8e\xc0", "mov es, ax"); TEST("\x8e\xc8", "UD"); // No mov cs, eax - TEST("\xd8\xc1", "[FADD reg0:r0 reg0:r1]"); - TEST("\xdc\xc1", "[FADD reg0:r1 reg0:r0]"); - TEST64("\x41\xd8\xc1", "[FADD reg0:r0 reg0:r1]"); // REX.B ignored - TEST64("\xd9\xc9", "[FXCH reg0:r1]"); - TEST64("\xd9\xd0", "[FNOP]"); - TEST64("\x41\xdf\xe0", "[FSTSW reg2:r0]"); + TEST("\xd8\xc1", "fadd st(0), st(1)"); + TEST("\xdc\xc1", "fadd st(1), st(0)"); + TEST64("\x41\xd8\xc1", "fadd st(0), st(1)"); // REX.B ignored + TEST64("\xd9\xc9", "fxch st(1)"); + TEST64("\xd9\xd0", "fnop"); + TEST64("\x41\xdf\xe0", "fstsw ax"); // ModRM Test cases // reg - TEST("\x01\xc0", "[ADD reg4:r0 reg4:r0]"); - TEST("\x01\xc1", "[ADD reg4:r1 reg4:r0]"); - TEST("\x01\xd0", "[ADD reg4:r0 reg4:r2]"); - TEST("\x01\xff", "[ADD reg4:r7 reg4:r7]"); - TEST64("\x41\x01\xd0", "[ADD reg4:r8 reg4:r2]"); - TEST64("\x45\x01\xd0", "[ADD reg4:r8 reg4:r10]"); - TEST64("\x45\x01\xff", "[ADD reg4:r15 reg4:r15]"); + TEST("\x01\xc0", "add eax, eax"); + TEST("\x01\xc1", "add ecx, eax"); + TEST("\x01\xd0", "add eax, edx"); + TEST("\x01\xff", "add edi, edi"); + TEST64("\x41\x01\xd0", "add r8d, edx"); + TEST64("\x45\x01\xd0", "add r8d, r10d"); + TEST64("\x45\x01\xff", "add r15d, r15d"); // [reg] - TEST("\x01\x00", "[ADD mem4:r0 reg4:r0]"); - TEST("\x01\x08", "[ADD mem4:r0 reg4:r1]"); - TEST("\x01\x01", "[ADD mem4:r1 reg4:r0]"); - TEST("\x01\x07", "[ADD mem4:r7 reg4:r0]"); - TEST("\x01\x38", "[ADD mem4:r0 reg4:r7]"); - TEST("\x01\x04\x24", "[ADD mem4:r4 reg4:r0]"); - TEST64("\x41\x01\x00", "[ADD mem4:r8 reg4:r0]"); - TEST64("\x44\x01\x08", "[ADD mem4:r0 reg4:r9]"); - TEST64("\x45\x01\x00", "[ADD mem4:r8 reg4:r8]"); - TEST64("\x41\x01\x07", "[ADD mem4:r15 reg4:r0]"); - TEST64("\x41\x01\x04\x24", "[ADD mem4:r12 reg4:r0]"); + TEST32("\x01\x00", "add dword ptr [eax], eax"); + TEST64("\x01\x00", "add dword ptr [rax], eax"); + TEST32("\x01\x08", "add dword ptr [eax], ecx"); + TEST64("\x01\x08", "add dword ptr [rax], ecx"); + TEST32("\x01\x01", "add dword ptr [ecx], eax"); + TEST64("\x01\x01", "add dword ptr [rcx], eax"); + TEST32("\x01\x07", "add dword ptr [edi], eax"); + TEST64("\x01\x07", "add dword ptr [rdi], eax"); + TEST32("\x01\x38", "add dword ptr [eax], edi"); + TEST64("\x01\x38", "add dword ptr [rax], edi"); + TEST32("\x01\x04\x24", "add dword ptr [esp], eax"); + TEST64("\x01\x04\x24", "add dword ptr [rsp], eax"); + TEST64("\x41\x01\x00", "add dword ptr [r8], eax"); + TEST64("\x44\x01\x08", "add dword ptr [rax], r9d"); + TEST64("\x45\x01\x00", "add dword ptr [r8], r8d"); + TEST64("\x41\x01\x07", "add dword ptr [r15], eax"); + TEST64("\x41\x01\x04\x24", "add dword ptr [r12], eax"); // [disp32] - TEST32("\x01\x05\x01\x00\x00\x00", "[ADD mem4:0x1 reg4:r0]"); - TEST32("\x01\x05\xff\xff\xff\xff", "[ADD mem4:-0x1 reg4:r0]"); - TEST("\x01\x04\x25\x01\x00\x00\x00", "[ADD mem4:0x1 reg4:r0]"); - TEST64("\x41\x01\x04\x25\x01\x00\x00\x00", "[ADD mem4:0x1 reg4:r0]"); + TEST32("\x01\x05\x01\x00\x00\x00", "add dword ptr [0x1], eax"); + TEST32("\x01\x05\xff\xff\xff\xff", "add dword ptr [0xffffffff], eax"); + TEST("\x01\x04\x25\x01\x00\x00\x00", "add dword ptr [0x1], eax"); + TEST32("\x01\x04\x25\x00\x00\x00\x80", "add dword ptr [0x80000000], eax"); + TEST64("\x01\x04\x25\x00\x00\x00\x80", "add dword ptr [0xffffffff80000000], eax"); + TEST64("\x41\x01\x04\x25\x01\x00\x00\x00", "add dword ptr [0x1], eax"); // [rip+disp32] - TEST64("\x01\x05\x01\x00\x00\x00", "[ADD mem4:r16+0x1 reg4:r0]"); - TEST64("\x41\x01\x05\x01\x00\x00\x00", "[ADD mem4:r16+0x1 reg4:r0]"); + TEST64("\x01\x05\x01\x00\x00\x00", "add dword ptr [rip+0x1], eax"); + TEST64("\x41\x01\x05\x01\x00\x00\x00", "add dword ptr [rip+0x1], eax"); // [reg+disp32] - TEST("\x01\x80\x01\x00\x00\x00", "[ADD mem4:r0+0x1 reg4:r0]"); + TEST32("\x01\x80\x01\x00\x00\x00", "add dword ptr [eax+0x1], eax"); + TEST64("\x01\x80\x01\x00\x00\x00", "add dword ptr [rax+0x1], eax"); + TEST32("\x01\x80\x00\x00\x00\x80", "add dword ptr [eax-0x80000000], eax"); + TEST64("\x01\x80\x00\x00\x00\x80", "add dword ptr [rax-0x80000000], eax"); // [reg+eiz+disp32] - TEST("\x01\x84\x25\x01\x00\x00\x00", "[ADD mem4:r5+0x1 reg4:r0]"); + TEST32("\x01\x84\x25\x01\x00\x00\x00", "add dword ptr [ebp+0x1], eax"); + TEST64("\x01\x84\x25\x01\x00\x00\x00", "add dword ptr [rbp+0x1], eax"); // [reg+s*reg+disp32] - TEST64("\x42\x01\x84\x25\x01\x00\x00\x00", "[ADD mem4:r5+1*r12+0x1 reg4:r0]"); + TEST64("\x42\x01\x84\x25\x01\x00\x00\x00", "add dword ptr [rbp+1*r12+0x1], eax"); - TEST("\x04\x01", "[ADD reg1:r0 imm1:0x1]"); - TEST("\x66\x68\xff\xad", "[PUSH imm2:0xadff]"); - TEST32("\x68\xff\xad\x90\xbc", "[PUSH imm4:0xbc90adff]"); - TEST64("\x68\xff\xad\x90\xbc", "[PUSH imm8:0xffffffffbc90adff]"); - TEST("\x66\x6a\xff", "[PUSH imm2:0xffff]"); - TEST32("\x6a\xff", "[PUSH imm4:0xffffffff]"); - TEST64("\x6a\xff", "[PUSH imm8:0xffffffffffffffff]"); - TEST("\xb0\xf0", "[MOVABS reg1:r0 imm1:0xf0]"); - TEST("\xb8\xf0\xf0\xab\xff", "[MOVABS reg4:r0 imm4:0xffabf0f0]"); - TEST64("\x48\xb8\xf0\xf0\xab\xff\x00\x12\x12\xcd", "[MOVABS reg8:r0 imm8:0xcd121200ffabf0f0]"); - TEST64("\xcd\x80", "[INT imm1:0x80]"); + TEST("\x04\x01", "add al, 0x1"); + TEST("\x66\x68\xff\xad", "pushw 0xadff"); + TEST32("\x68\xff\xad\x90\xbc", "push 0xbc90adff"); + TEST64("\x68\xff\xad\x90\xbc", "push 0xffffffffbc90adff"); + TEST("\x66\x6a\xff", "pushw 0xffff"); + TEST32("\x6a\xff", "push 0xffffffff"); + TEST64("\x6a\xff", "push 0xffffffffffffffff"); + TEST("\xb0\xf0", "mov al, 0xf0"); + TEST("\x66\xb8\xf0\xf0", "mov ax, 0xf0f0"); + TEST("\xb8\xf0\xf0\xab\xff", "mov eax, 0xffabf0f0"); + TEST64("\x48\xb8\xf0\xf0\xab\xff\x00\x12\x12\xcd", "mov rax, 0xcd121200ffabf0f0"); + TEST64("\xcd\x80", "int 0x80"); - TEST("\x66\xc8\x00\x00\x00", "[ENTER_2 imm4:0x0]"); - TEST("\x66\xc8\x00\x0f\x00", "[ENTER_2 imm4:0xf00]"); - TEST("\x66\xc8\x00\x00\x01", "[ENTER_2 imm4:0x10000]"); - TEST32("\xc8\x00\x00\x00", "[ENTER_4 imm4:0x0]"); - TEST32("\xc8\x00\x0f\x00", "[ENTER_4 imm4:0xf00]"); - TEST32("\xc8\x00\x00\x01", "[ENTER_4 imm4:0x10000]"); - TEST64("\xc8\x00\x00\x00", "[ENTER_8 imm4:0x0]"); - TEST64("\xc8\x00\x0f\x00", "[ENTER_8 imm4:0xf00]"); - TEST64("\xc8\x00\x00\x01", "[ENTER_8 imm4:0x10000]"); + TEST("\x66\xc8\x00\x00\x00", "enterw 0x0, 0x0"); + TEST("\x66\xc8\x00\x0f\x00", "enterw 0xf00, 0x0"); + TEST("\x66\xc8\x00\x00\x01", "enterw 0x0, 0x1"); + TEST32("\xc8\x00\x00\x00", "enter 0x0, 0x0"); + TEST32("\xc8\x00\x0f\x00", "enter 0xf00, 0x0"); + TEST32("\xc8\x00\x00\x01", "enter 0x0, 0x1"); + TEST64("\xc8\x00\x00\x00", "enter 0x0, 0x0"); + TEST64("\xc8\x00\x0f\x00", "enter 0xf00, 0x0"); + TEST64("\xc8\x00\x00\x01", "enter 0x0, 0x1"); - TEST64("\xd3\xe0", "[SHL reg4:r0 reg1:r1]"); - TEST64("\x0f\xa5\xd0", "[SHLD reg4:r0 reg4:r2 reg1:r1]"); + TEST64("\xd3\xe0", "shl eax, cl"); + TEST64("\xd0\x3e", "sar byte ptr [rsi], 0x1"); + TEST64("\x0f\xa5\xd0", "shld eax, edx, cl"); - TEST("\x69\xC7\x08\x01\x00\x00", "[IMUL reg4:r0 reg4:r7 imm4:0x108]"); - TEST("\x6B\xC7\x08", "[IMUL reg4:r0 reg4:r7 imm4:0x8]"); + TEST("\x69\xC7\x08\x01\x00\x00", "imul eax, edi, 0x108"); + TEST("\x6B\xC7\x08", "imul eax, edi, 0x8"); TEST("\x0f\x38\xf0\xd1", "UD"); // MOVBE doesn't allow register moves - TEST("\x0f\x38\xf0\x11", "[MOVBE reg4:r2 mem4:r1]"); - TEST("\x66\x0f\x38\xf0\x11", "[MOVBE reg2:r2 mem2:r1]"); - TEST64("\x48\x0f\x38\xf0\x01", "[MOVBE reg8:r0 mem8:r1]"); - TEST("\xf2\x0f\x38\xf0\xd1", "[CRC32 reg4:r2 reg1:r1]"); - TEST("\xf2\x66\x0f\x38\xf1\xd1", "[CRC32 reg4:r2 reg2:r1]"); - TEST("\xf2\x0f\x38\xf1\xd1", "[CRC32 reg4:r2 reg4:r1]"); - TEST64("\xf2\x48\x0f\x38\xf1\xd1", "[CRC32 reg4:r2 reg8:r1]"); - TEST64("\xf2\x4c\x0f\x38\xf1\xd1", "[CRC32 reg4:r10 reg8:r1]"); + TEST32("\x0f\x38\xf0\x11", "movbe edx, dword ptr [ecx]"); + TEST64("\x0f\x38\xf0\x11", "movbe edx, dword ptr [rcx]"); + TEST32("\x66\x0f\x38\xf0\x11", "movbe dx, word ptr [ecx]"); + TEST64("\x66\x0f\x38\xf0\x11", "movbe dx, word ptr [rcx]"); + TEST64("\x48\x0f\x38\xf0\x01", "movbe rax, qword ptr [rcx]"); + TEST("\xf2\x0f\x38\xf0\xd1", "crc32 edx, cl"); + TEST("\xf2\x66\x0f\x38\xf1\xd1", "crc32 edx, cx"); + TEST("\xf2\x0f\x38\xf1\xd1", "crc32 edx, ecx"); + TEST64("\xf2\x48\x0f\x38\xf1\xd1", "crc32 edx, rcx"); + TEST64("\xf2\x4c\x0f\x38\xf1\xd1", "crc32 r10d, rcx"); - TEST("\x8d\x00", "[LEA reg4:r0 mem0:r0]"); + TEST32("\x8d\x00", "lea eax, [eax]"); + TEST64("\x8d\x00", "lea eax, [rax]"); TEST("\x8d\xc0", "UD"); - TEST32("\x40", "[INC reg4:r0]"); - TEST32("\x43", "[INC reg4:r3]"); - TEST32("\x66\x47", "[INC reg2:r7]"); - TEST("\xfe\xc0", "[INC reg1:r0]"); - TEST("\xfe\xc4", "[INC reg1:r0h]"); - TEST("\xff\xc0", "[INC reg4:r0]"); - TEST("\xff\xc4", "[INC reg4:r4]"); - TEST("\xff\x00", "[INC mem4:r0]"); - TEST("\xf0\xff\x00", "[lock:INC mem4:r0]"); - TEST("\x66\xff\xc0", "[INC reg2:r0]"); - TEST("\x66\xff\xc4", "[INC reg2:r4]"); - TEST64("\x48\xff\xc0", "[INC reg8:r0]"); - TEST64("\x48\xff\xc4", "[INC reg8:r4]"); - TEST64("\x49\xff\xc7", "[INC reg8:r15]"); + TEST32("\x40", "inc eax"); + TEST32("\x43", "inc ebx"); + TEST32("\x66\x47", "inc di"); + TEST("\xfe\xc0", "inc al"); + TEST("\xfe\xc4", "inc ah"); + TEST("\xff\xc0", "inc eax"); + TEST("\xff\xc4", "inc esp"); + TEST32("\xff\x00", "inc dword ptr [eax]"); + TEST64("\xff\x00", "inc dword ptr [rax]"); + TEST32("\xf0\xff\x00", "lock inc dword ptr [eax]"); + TEST64("\xf0\xff\x00", "lock inc dword ptr [rax]"); + TEST("\x66\xff\xc0", "inc ax"); + TEST("\x66\xff\xc4", "inc sp"); + TEST64("\x48\xff\xc0", "inc rax"); + TEST64("\x48\xff\xc4", "inc rsp"); + TEST64("\x49\xff\xc7", "inc r15"); - TEST32("\xe9\x00\x00\x00\x00", "[JMP off4:eip+0x0]"); - TEST32("\x66\xe9\x01\x00", "[JMP off2:ip+0x1]"); - TEST64("\xe9\x00\x00\x00\x00", "[JMP off8:rip+0x0]"); - TEST64("\x66\xe9\x00\x00\x00\x00", "[JMP off8:rip+0x0]"); - TEST64("\x66\xeb\x00", "[JMP off8:rip+0x0]"); - TEST64("\x66\xeb\xff", "[JMP off8:rip+0xffffffffffffffff]"); + TEST32("\xe9\x00\x00\x00\x00", "jmp 0x5"); + TEST32("\x66\xe9\x01\x00", "jmpw 0x5"); + TEST64("\xe9\x00\x00\x00\x00", "jmp 0x5"); + TEST64("\x66\xe9\x00\x00\x00\x00", "jmp 0x6"); + TEST64("\x66\xeb\x00", "jmp 0x3"); + TEST64("\x66\xeb\xff", "jmp 0x2"); TEST("\x66\xe9\x00", "PARTIAL"); TEST("\x66\xe9", "PARTIAL"); - TEST32("\xc7\xf8\xd3\x9c\xff\xff", "[XBEGIN off4:eip+0xffff9cd3]"); - TEST32("\x66\xc7\xf8\xd3\x9c", "[XBEGIN off4:eip+0xffff9cd3]"); - TEST64("\xc7\xf8\xd3\x9c\xff\xff", "[XBEGIN off8:rip+0xffffffffffff9cd3]"); - TEST64("\x66\xc7\xf8\xd3\x9c", "[XBEGIN off8:rip+0xffffffffffff9cd3]"); + TEST32("\xc7\xf8\xd3\x9c\xff\xff", "xbegin 0xffff9cd9"); + TEST32("\x66\xc7\xf8\xd3\x9c", "xbegin 0xffff9cd8"); + TEST64("\xc7\xf8\xd3\x9c\xff\xff", "xbegin 0xffffffffffff9cd9"); + TEST64("\x66\xc7\xf8\xd3\x9c", "xbegin 0xffffffffffff9cd8"); - TEST("\xa5", "[MOVS_4]"); - TEST("\x66\xa5", "[MOVS_2]"); - TEST("\xf3\xa5", "[rep:MOVS_4]"); - TEST("\xf3\x66\xa5", "[rep:MOVS_2]"); + TEST("\xa5", "movsd"); + TEST("\x66\xa5", "movsw"); + TEST("\xf3\xa5", "rep movsd"); + TEST("\xf3\x66\xa5", "rep movsw"); - TEST("\x66\x0f\xbe\xc2", "[MOVSX reg2:r0 reg1:r2]"); - TEST("\x0f\xbe\xc2", "[MOVSX reg4:r0 reg1:r2]"); - TEST("\x0f\xbf\xc2", "[MOVSX reg4:r0 reg2:r2]"); - TEST64("\x48\x0f\xbf\xc2", "[MOVSX reg8:r0 reg2:r2]"); - TEST64("\x48\x63\xc2", "[MOVSX reg8:r0 reg4:r2]"); + TEST("\x66\x0f\xbe\xc2", "movsx ax, dl"); + TEST("\x0f\xbe\xc2", "movsx eax, dl"); + TEST("\x0f\xbf\xc2", "movsx eax, dx"); + TEST64("\x48\x0f\xbf\xc2", "movsx rax, dx"); + TEST64("\x48\x63\xc2", "movsx rax, edx"); - TEST32("\x66\xc3", "[RET_2]"); - TEST32("\x66\xc2\x00\x00", "[RET_2 imm2:0x0]"); - TEST32("\x66\xc2\x0d\x00", "[RET_2 imm2:0xd]"); - TEST32("\x66\xc2\x0d\xff", "[RET_2 imm2:0xff0d]"); - TEST64("\x66\xc3", "[RET_8]"); - TEST64("\x66\xc2\x00\x00", "[RET_8 imm2:0x0]"); - TEST64("\x66\xc2\x0d\x00", "[RET_8 imm2:0xd]"); - TEST64("\x66\xc2\x0d\xff", "[RET_8 imm2:0xff0d]"); - TEST32("\xc3", "[RET_4]"); - TEST32("\xc2\x00\x00", "[RET_4 imm2:0x0]"); - TEST32("\xc2\x0d\x00", "[RET_4 imm2:0xd]"); - TEST32("\xc2\x0d\xff", "[RET_4 imm2:0xff0d]"); - TEST64("\xc3", "[RET_8]"); - TEST64("\xc2\x00\x00", "[RET_8 imm2:0x0]"); - TEST64("\xc2\x0d\x00", "[RET_8 imm2:0xd]"); - TEST64("\xc2\x0d\xff", "[RET_8 imm2:0xff0d]"); + TEST32("\x66\xc3", "retw"); + TEST32("\x66\xc2\x00\x00", "retw 0x0"); + TEST32("\x66\xc2\x0d\x00", "retw 0xd"); + TEST32("\x66\xc2\x0d\xff", "retw 0xff0d"); + TEST64("\x66\xc3", "ret"); + TEST64("\x66\xc2\x00\x00", "ret 0x0"); + TEST64("\x66\xc2\x0d\x00", "ret 0xd"); + TEST64("\x66\xc2\x0d\xff", "ret 0xff0d"); + TEST32("\xc3", "ret"); + TEST32("\xc2\x00\x00", "ret 0x0"); + TEST32("\xc2\x0d\x00", "ret 0xd"); + TEST32("\xc2\x0d\xff", "ret 0xff0d"); + TEST64("\xc3", "ret"); + TEST64("\xc2\x00\x00", "ret 0x0"); + TEST64("\xc2\x0d\x00", "ret 0xd"); + TEST64("\xc2\x0d\xff", "ret 0xff0d"); // NFx/66+F2/F3 combinations - TEST("\x0f\xc7\xf0", "[RDRAND reg4:r0]"); - TEST64("\x48\x0f\xc7\xf0", "[RDRAND reg8:r0]"); - TEST("\x66\x0f\xc7\xf0", "[RDRAND reg2:r0]"); - TEST64("\x66\x48\x0f\xc7\xf0", "[RDRAND reg8:r0]"); - TEST("\x0f\xc7\xf8", "[RDSEED reg4:r0]"); - TEST64("\x48\x0f\xc7\xf8", "[RDSEED reg8:r0]"); - TEST("\x66\x0f\xc7\xf8", "[RDSEED reg2:r0]"); - TEST64("\x66\x48\x0f\xc7\xf8", "[RDSEED reg8:r0]"); - TEST32("\xf3\x0f\xc7\xf8", "[RDPID reg4:r0]"); - TEST32("\x66\xf3\x0f\xc7\xf8", "[RDPID reg4:r0]"); - TEST32("\xf3\x66\x0f\xc7\xf8", "[RDPID reg4:r0]"); - TEST64("\xf3\x0f\xc7\xf8", "[RDPID reg8:r0]"); - TEST64("\x66\xf3\x0f\xc7\xf8", "[RDPID reg8:r0]"); - TEST64("\xf3\x66\x0f\xc7\xf8", "[RDPID reg8:r0]"); + TEST("\x0f\xc7\xf0", "rdrand eax"); + TEST64("\x48\x0f\xc7\xf0", "rdrand rax"); + TEST("\x66\x0f\xc7\xf0", "rdrand ax"); + TEST64("\x66\x48\x0f\xc7\xf0", "rdrand rax"); + TEST("\x0f\xc7\xf8", "rdseed eax"); + TEST64("\x48\x0f\xc7\xf8", "rdseed rax"); + TEST("\x66\x0f\xc7\xf8", "rdseed ax"); + TEST64("\x66\x48\x0f\xc7\xf8", "rdseed rax"); + TEST32("\xf3\x0f\xc7\xf8", "rdpid eax"); + TEST32("\x66\xf3\x0f\xc7\xf8", "rdpid eax"); + TEST32("\xf3\x66\x0f\xc7\xf8", "rdpid eax"); + TEST64("\xf3\x0f\xc7\xf8", "rdpid rax"); + TEST64("\x66\xf3\x0f\xc7\xf8", "rdpid rax"); + TEST64("\xf3\x66\x0f\xc7\xf8", "rdpid rax"); TEST64("\xf3\x0f\xc7\x00", "UD"); - TEST64("\x0f\xc7\x30", "[VMPTRLD mem8:r0]"); - TEST64("\x66\x0f\xc7\x30", "[VMCLEAR mem8:r0]"); - TEST64("\xf3\x0f\xc7\x30", "[VMXON mem8:r0]"); + TEST64("\x0f\xc7\x30", "vmptrld qword ptr [rax]"); + TEST64("\x66\x0f\xc7\x30", "vmclear qword ptr [rax]"); + TEST64("\xf3\x0f\xc7\x30", "vmxon qword ptr [rax]"); - TEST64("\x0f\x09", "[WBINVD]"); - TEST64("\xf3\x0f\x09", "[WBNOINVD]"); + TEST64("\x0f\x09", "wbinvd"); + TEST64("\xf3\x0f\x09", "wbnoinvd"); - TEST64("\x0f\xae\xe8", "[LFENCE]"); + TEST64("\x0f\xae\xe8", "lfence"); - TEST("\xf3\x0f\x2a\xc1", "[SSE_CVTSI2SS reg4:r0 reg4:r1]"); - TEST("\xf3\x66\x0f\x2a\xc1", "[SSE_CVTSI2SS reg4:r0 reg4:r1]"); - TEST("\x66\xf3\x0f\x2a\xc1", "[SSE_CVTSI2SS reg4:r0 reg4:r1]"); - TEST64("\xf3\x48\x0f\x2a\xc1", "[SSE_CVTSI2SS reg4:r0 reg8:r1]"); - TEST64("\x66\xf3\x48\x0f\x2a\xc1", "[SSE_CVTSI2SS reg4:r0 reg8:r1]"); - TEST64("\x66\x0f\x50\xc1", "[SSE_MOVMSKPD reg8:r0 reg16:r1]"); - TEST("\x66\x0f\xc6\xc0\x01", "[SSE_SHUFPD reg16:r0 reg16:r0 imm1:0x1]"); - TEST("\x66\x0f\x71\xd0\x01", "[SSE_PSRLW reg16:r0 imm1:0x1]"); - TEST("\x66\x0f\x3a\x20\xc4\x01", "[SSE_PINSRB reg16:r0 reg1:r4 imm1:0x1]"); + TEST("\xf3\x0f\x2a\xc1", "cvtsi2ss xmm0, ecx"); + TEST("\xf3\x66\x0f\x2a\xc1", "cvtsi2ss xmm0, ecx"); + TEST("\x66\xf3\x0f\x2a\xc1", "cvtsi2ss xmm0, ecx"); + TEST64("\xf3\x48\x0f\x2a\xc1", "cvtsi2ss xmm0, rcx"); + TEST64("\x66\xf3\x48\x0f\x2a\xc1", "cvtsi2ss xmm0, rcx"); + TEST64("\x66\x0f\x50\xc1", "movmskpd rax, xmm1"); + TEST("\x66\x0f\xc6\xc0\x01", "shufpd xmm0, xmm0, 0x1"); + TEST("\x66\x0f\x71\xd0\x01", "psrlw xmm0, 0x1"); + TEST("\x66\x0f\x3a\x20\xc4\x01", "pinsrb xmm0, spl, 0x1"); TEST("\x66\x0f\x71\x10\x01", "UD"); - TEST32("\xc4\x00", "[LES reg4:r0 mem0:r0]"); - TEST32("\xc5\x00", "[LDS reg4:r0 mem0:r0]"); - TEST("\xc5\xf2\x2a\xc0", "[VCVTSI2SS reg16:r0 reg16:r1 reg4:r0]"); + TEST32("\xc4\x00", "les eax, fword ptr [eax]"); + TEST32("\xc5\x00", "lds eax, fword ptr [eax]"); + TEST32("\x0f\xb2\x00", "lss eax, fword ptr [eax]"); + TEST64("\x0f\xb2\x00", "lss eax, fword ptr [rax]"); + TEST64("\x48\x0f\xb2\x00", "lss rax, fword ptr [rax]"); + TEST("\xc5\xf2\x2a\xc0", "vcvtsi2ss xmm0, xmm1, eax"); TEST("\xf3\xc5\xf2\x2a\xc0", "UD"); // VEX+REP TEST("\xf2\xc5\xf2\x2a\xc0", "UD"); // VEX+REPNZ TEST("\xf2\xf3\xc5\xf2\x2a\xc0", "UD"); // VEX+REP+REPNZ TEST("\x66\xc5\xf2\x2a\xc0", "UD"); // VEX+66 TEST("\xf0\xc5\xf2\x2a\xc0", "UD"); // VEX+LOCK TEST64("\x40\xc5\xf2\x2a\xc0", "UD"); // VEX+REX - TEST64("\x40\x26\xc5\xf2\x2a\xc0", "[VCVTSI2SS reg16:r0 reg16:r1 reg4:r0]"); // VEX+REX, but REX doesn't precede VEX + TEST64("\x40\x26\xc5\xf2\x2a\xc0", "vcvtsi2ss xmm0, xmm1, eax"); // VEX+REX, but REX doesn't precede VEX - TEST("\xf3\x0f\x7e\x5c\x24\x08", "[SSE_MOVQ reg16:r3 mem8:r4+0x8]"); - TEST32("\xc4\xe1\x00\x58\xc1", "[VADDPS reg16:r0 reg16:r7 reg16:r1]"); // MSB in vvvv ignored - TEST64("\xc4\xe1\x00\x58\xc1", "[VADDPS reg16:r0 reg16:r15 reg16:r1]"); - TEST32("\xc4\xc1\x78\x58\xc0", "[VADDPS reg16:r0 reg16:r0 reg16:r0]"); // VEX.B ignored in 32-bit - TEST64("\xc4\xc1\x78\x58\xc0", "[VADDPS reg16:r0 reg16:r0 reg16:r8]"); - TEST("\xc5\xf9\x6e\xc8", "[VMOVD reg4:r1 reg4:r0]"); - TEST64("\xc4\xe1\xf9\x6e\xc8", "[VMOVQ reg8:r1 reg8:r0]"); - TEST32("\xc4\xe1\xf9\x6e\xc8", "[VMOVD reg4:r1 reg4:r0]"); - TEST("\xc5\xf2\x2a\xc0", "[VCVTSI2SS reg16:r0 reg16:r1 reg4:r0]"); - TEST32("\xc4\xe1\xf2\x2a\xc0", "[VCVTSI2SS reg16:r0 reg16:r1 reg4:r0]"); - TEST64("\xc4\xe1\xf2\x2a\xc0", "[VCVTSI2SS reg16:r0 reg16:r1 reg8:r0]"); - TEST64("\xc4\xe2\x75\x90\x04\xe7", "[VPGATHERDD reg32:r0 mem32:r7+8*r4 reg32:r1]"); + TEST32("\xf3\x0f\x7e\x5c\x24\x08", "movq xmm3, qword ptr [esp+0x8]"); + TEST64("\xf3\x0f\x7e\x5c\x24\x08", "movq xmm3, qword ptr [rsp+0x8]"); + TEST32("\xc4\xe1\x00\x58\xc1", "vaddps xmm0, xmm7, xmm1"); // MSB in vvvv ignored + TEST64("\xc4\xe1\x00\x58\xc1", "vaddps xmm0, xmm15, xmm1"); + TEST32("\xc4\xc1\x78\x58\xc0", "vaddps xmm0, xmm0, xmm0"); // VEX.B ignored in 32-bit + TEST64("\xc4\xc1\x78\x58\xc0", "vaddps xmm0, xmm0, xmm8"); + TEST("\xc5\xf9\x6e\xc8", "vmovd xmm1, eax"); + TEST64("\xc4\xe1\xf9\x6e\xc8", "vmovq xmm1, rax"); + TEST32("\xc4\xe1\xf9\x6e\xc8", "vmovd xmm1, eax"); + TEST("\xc5\xf2\x2a\xc0", "vcvtsi2ss xmm0, xmm1, eax"); + TEST32("\xc4\xe1\xf2\x2a\xc0", "vcvtsi2ss xmm0, xmm1, eax"); + TEST64("\xc4\xe1\xf2\x2a\xc0", "vcvtsi2ss xmm0, xmm1, rax"); + TEST64("\xc4\xe2\x75\x90\x04\xe7", "vpgatherdd ymm0, ymmword ptr [rdi+8*rsp], ymm1"); - TEST("\xc4\xe3\x79\x14\xc0\x00", "[VPEXTRB reg1:r0 reg16:r0 imm1:0x0]"); - TEST("\xc4\xe3\xf9\x14\xc0\x00", "[VPEXTRB reg1:r0 reg16:r0 imm1:0x0]"); - TEST("\xc4\xe3\x79\x15\xc0\x00", "[VPEXTRW reg2:r0 reg16:r0 imm1:0x0]"); - TEST("\xc4\xe3\xf9\x15\xc0\x00", "[VPEXTRW reg2:r0 reg16:r0 imm1:0x0]"); - TEST32("\xc4\xe1\x79\xc5\xc0\x00", "[VPEXTRW reg4:r0 reg16:r0 imm1:0x0]"); - TEST64("\xc4\xe1\x79\xc5\xc0\x00", "[VPEXTRW reg8:r0 reg16:r0 imm1:0x0]"); - TEST("\xc4\xe3\x79\x16\xc0\x00", "[VPEXTRD reg4:r0 reg16:r0 imm1:0x0]"); - TEST32("\xc4\xe3\xf9\x16\xc0\x00", "[VPEXTRD reg4:r0 reg16:r0 imm1:0x0]"); - TEST64("\xc4\xe3\xf9\x16\xc0\x00", "[VPEXTRQ reg8:r0 reg16:r0 imm1:0x0]"); + TEST("\xc4\xe3\x79\x14\xc0\x00", "vpextrb al, xmm0, 0x0"); + TEST("\xc4\xe3\xf9\x14\xc0\x00", "vpextrb al, xmm0, 0x0"); + TEST("\xc4\xe3\x79\x15\xc0\x00", "vpextrw ax, xmm0, 0x0"); + TEST("\xc4\xe3\xf9\x15\xc0\x00", "vpextrw ax, xmm0, 0x0"); + TEST32("\xc4\xe1\x79\xc5\xc0\x00", "vpextrw eax, xmm0, 0x0"); + TEST64("\xc4\xe1\x79\xc5\xc0\x00", "vpextrw rax, xmm0, 0x0"); + TEST("\xc4\xe3\x79\x16\xc0\x00", "vpextrd eax, xmm0, 0x0"); + TEST32("\xc4\xe3\xf9\x16\xc0\x00", "vpextrd eax, xmm0, 0x0"); + TEST64("\xc4\xe3\xf9\x16\xc0\x00", "vpextrq rax, xmm0, 0x0"); - TEST("\xc4\xe3\x71\x20\xc0\x00", "[VPINSRB reg16:r0 reg16:r1 reg1:r0 imm1:0x0]"); - TEST("\xc4\xe3\xf1\x20\xc0\x00", "[VPINSRB reg16:r0 reg16:r1 reg1:r0 imm1:0x0]"); - TEST("\xc4\xe1\x71\xc4\xc0\x00", "[VPINSRW reg16:r0 reg16:r1 reg2:r0 imm1:0x0]"); - TEST("\xc4\xe1\xf1\xc4\xc0\x00", "[VPINSRW reg16:r0 reg16:r1 reg2:r0 imm1:0x0]"); - TEST("\xc4\xe3\x71\x22\xc0\x00", "[VPINSRD reg16:r0 reg16:r1 reg4:r0 imm1:0x0]"); - TEST32("\xc4\xe3\xf1\x22\xc0\x00", "[VPINSRD reg16:r0 reg16:r1 reg4:r0 imm1:0x0]"); - TEST64("\xc4\xe3\xf1\x22\xc0\x00", "[VPINSRQ reg16:r0 reg16:r1 reg8:r0 imm1:0x0]"); + TEST("\xc4\xe3\x71\x20\xc0\x00", "vpinsrb xmm0, xmm1, al, 0x0"); + TEST("\xc4\xe3\xf1\x20\xc0\x00", "vpinsrb xmm0, xmm1, al, 0x0"); + TEST("\xc4\xe1\x71\xc4\xc0\x00", "vpinsrw xmm0, xmm1, ax, 0x0"); + TEST("\xc4\xe1\xf1\xc4\xc0\x00", "vpinsrw xmm0, xmm1, ax, 0x0"); + TEST("\xc4\xe3\x71\x22\xc0\x00", "vpinsrd xmm0, xmm1, eax, 0x0"); + TEST32("\xc4\xe3\xf1\x22\xc0\x00", "vpinsrd xmm0, xmm1, eax, 0x0"); + TEST64("\xc4\xe3\xf1\x22\xc0\x00", "vpinsrq xmm0, xmm1, rax, 0x0"); TEST("\xc4\xe3\x75\x20\xc0\x00", "UD"); // VEX.L != 0 TEST("\xc4\xe1\x75\xc4\xc0\x00", "UD"); // VEX.L != 0 TEST("\xc4\xe1\xf5\xc4\xc0\x00", "UD"); // VEX.L != 0 TEST("\xc4\xe3\x75\x22\xc0\x00", "UD"); // VEX.L != 0 TEST("\xc4\xe3\xf5\x22\xc0\x00", "UD"); // VEX.L != 0 - TEST("\xc4\xe2\x71\x45\xc2", "[VPSRLVD reg16:r0 reg16:r1 reg16:r2]"); - TEST("\xc4\xe2\x75\x45\xc2", "[VPSRLVD reg32:r0 reg32:r1 reg32:r2]"); - TEST("\xc4\xe2\xf1\x45\xc2", "[VPSRLVQ reg16:r0 reg16:r1 reg16:r2]"); - TEST("\xc4\xe2\xf5\x45\xc2", "[VPSRLVQ reg32:r0 reg32:r1 reg32:r2]"); + TEST("\xc4\xe2\x71\x45\xc2", "vpsrlvd xmm0, xmm1, xmm2"); + TEST("\xc4\xe2\x75\x45\xc2", "vpsrlvd ymm0, ymm1, ymm2"); + TEST("\xc4\xe2\xf1\x45\xc2", "vpsrlvq xmm0, xmm1, xmm2"); + TEST("\xc4\xe2\xf5\x45\xc2", "vpsrlvq ymm0, ymm1, ymm2"); - TEST("\xc4\xe2\x7d\x5a\x20", "[VBROADCASTI128 reg32:r4 mem16:r0]"); - TEST64("\xc4\x62\x7d\x5a\x20", "[VBROADCASTI128 reg32:r12 mem16:r0]"); + TEST32("\xc4\xe2\x7d\x5a\x20", "vbroadcasti128 ymm4, xmmword ptr [eax]"); + TEST64("\xc4\xe2\x7d\x5a\x20", "vbroadcasti128 ymm4, xmmword ptr [rax]"); + TEST64("\xc4\x62\x7d\x5a\x20", "vbroadcasti128 ymm12, xmmword ptr [rax]"); TEST("\xc4\xe2\x75\x5a\x20", "UD"); // VEX.vvvv != 1111 TEST("\xc4\xe2\x7d\x5a\xc0", "UD"); // ModRM.mod != 11 TEST("\xc4\xe2\x79\x5a\x20", "UD"); // VEX.L != 1 TEST("\xc4\xe2\xfd\x5a\x20", "UD"); // VEX.W != 0 + // Intel-Syntax special cases + TEST("\x66\x98", "cbw"); + TEST("\x98", "cwde"); + TEST64("\x48\x98", "cdqe"); + TEST("\x66\x99", "cwd"); + TEST("\x99", "cdq"); + TEST64("\x48\x99", "cqo"); + + TEST32("\x0f\xae\x00", "fxsave [eax]"); + TEST64("\x0f\xae\x00", "fxsave [rax]"); + TEST64("\x48\x0f\xae\x00", "fxsave64 [rax]"); + TEST32("\x66\xff\xe0", "jmp ax"); + TEST64("\x66\xff\xe0", "jmp rax"); + TEST32("\x66\x70\x00", "jow 0x3"); + TEST64("\x66\x70\x00", "jo 0x3"); + TEST32("\xe3\xfe", "jecxz 0x0"); + TEST64("\xe3\xfe", "jrcxz 0x0"); + TEST32("\x67\xe3\xfd", "jcxz 0x0"); + TEST64("\x67\xe3\xfd", "jecxz 0x0"); + TEST("\xa5", "movsd"); + TEST("\x64\xa5", "fs movsd"); + TEST32("\x2e\xa5", "cs movsd"); + TEST64("\x2e\xa5", "movsd"); + TEST32("\x67\xa5", "addr16 movsd"); + TEST64("\x67\xa5", "addr32 movsd"); + TEST("\xaf", "scasd"); + TEST("\x64\xaf", "scasd"); // SCAS doesn't use segment overrides + TEST("\xec", "inb"); + TEST32("\x66\x61", "popaw"); + TEST32("\x61", "popad"); + TEST("\x66\x9d", "popfw"); + TEST32("\x9d", "popfd"); + TEST64("\x9d", "popfq"); + TEST("\x66\xcf", "iretw"); + TEST("\xcf", "iretd"); + TEST64("\x48\xcf", "iretq"); + TEST32("\x06", "push es"); + TEST32("\x66\x06", "pushw es"); + TEST32("\x07", "pop es"); + TEST32("\x66\x07", "popw es"); + TEST32("\x0e", "push cs"); + TEST32("\x66\x0e", "pushw cs"); + TEST32("\x16", "push ss"); + TEST32("\x66\x16", "pushw ss"); + TEST32("\x17", "pop ss"); + TEST32("\x66\x17", "popw ss"); + TEST("\x0f\xa8", "push gs"); + TEST("\x66\x0f\xa8", "pushw gs"); + TEST("\x0f\xa9", "pop gs"); + TEST("\x66\x0f\xa9", "popw gs"); + TEST32("\x0f\x21\xd0", "mov eax, dr2"); + TEST64("\x0f\x21\xd0", "mov rax, dr2"); + TEST32("\x62\x00", "bound eax, qword ptr [eax]"); + TEST32("\x66\x62\x00", "bound ax, dword ptr [eax]"); + TEST32("\x0f\xae\x38", "clflush byte ptr [eax]"); + TEST64("\x0f\xae\x38", "clflush byte ptr [rax]"); + TEST32("\xdd\x00", "fld qword ptr [eax]"); + TEST64("\xdd\x00", "fld qword ptr [rax]"); + TEST32("\xdb\x28", "fld tbyte ptr [eax]"); + TEST64("\xdb\x28", "fld tbyte ptr [rax]"); + TEST32("\xd9\x20", "fldenv [eax]"); + TEST64("\xd9\x20", "fldenv [rax]"); + puts(failed ? "Some tests FAILED" : "All tests PASSED"); return failed ? EXIT_FAILURE : EXIT_SUCCESS; }