commit a3f77dbf49cf137410a7d987e4a599162279f40f Author: Alexis Engelke Date: Sun Apr 8 13:16:49 2018 +0000 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c048a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0f97558 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2018, Alexis Engelke +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..87c9e2a --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# libx86decode + +A fast and lightweight decoder for x86 and x86-64. *This is not a disassembler, it does not intend to procude valid assembly.* To meet the goal of speed, lookup tables are used to map the opcode the (internal) description of the instruction encoding. This table currently has a size of roughly 21 kiB. + +Currently, decoding 32-bit assembly required the `ARCH_386` macro to be defined and is only tested when compiling as 32-bit binary. Decoding of 64-bit instruction requires the macro `ARCH_X86_64` and is only supported in 64-bit mode. This restriction might change in future. + +### Known issues +- An implicit `FWAIT` in FPU instructions is decoded as a separate instruction. For example, the instruction `FINIT` is decoded as an `FWAIT` followed by an `FINIT` where as `FNINIT` is decoded as a plain `FINIT` instruction. +- The AVX VSIB encoding is not supported yet, all instructions using this will result in a decode error. +- A mandatory L0 or L1 in the VEX prefix is currently ignored to reduce the size of the prefix tables. The only instructions where this has an effect are `VZEROALL` (L1) and `VZEROUPPER` (L0) and are currently decoded as `VZERO`, the vector length prefix can be used to determine the actual instruction. +- The EVEX prefix (AVX-512) is not supported (yet). +- No ABI stability as the value associated with the mnemonics will change if further instructions are added. When using this library, please link it statically. +- The instruction formatter does not include prefixes. (Help needed.) +- The layout of entries in the tables can be improved to improve usage of caches. (Help needed.) +- Low test coverage. (Help needed.) +- No benchmarking has been performed yet. (Help needed.) + +If you find any other issues, please report a bug. Or, even better, send a patch fixing the issue. diff --git a/decode.c b/decode.c new file mode 100644 index 0000000..df931d4 --- /dev/null +++ b/decode.c @@ -0,0 +1,727 @@ + +#include +#include + +#include + + +#define LIKELY(x) __builtin_expect((x), 1) +#define UNLIKELY(x) __builtin_expect((x), 0) + +#define DECODE_TABLE_DATA +static const uint8_t _decode_table[] = { +#include +}; +#undef DECODE_TABLE_DATA + + +#define ENTRY_NONE 0 +#define ENTRY_INSTR 1 +#define ENTRY_TABLE256 2 +#define ENTRY_TABLE8 3 +#define ENTRY_TABLE72 4 +#define ENTRY_TABLE_PREFIX 5 +#define ENTRY_MASK 7 +#define ENTRY_IS_TABLE(kind) ((kind) >= ENTRY_TABLE256) + +#define INSTR_ENC_ADDR 0x08 +#define INSTR_ENC_IMM 0x10 +#define INSTR_ENC_MODRM 0x80 +#define INSTR_ENC_MODRM_BOTH 0x40 +#define INSTR_ENC_FLIP 0x20 +#define INSTR_ENC_OPCODE 0x40 +#define INSTR_ENC_IMPLICIT_REG 0x04 + +#define LOAD_LE_1(buf) (((size_t) ((uint8_t*) buf)[0])) +#define LOAD_LE_2(buf) (((size_t) ((uint8_t*) buf)[0]) | \ + ((size_t) ((uint8_t*) buf)[1] << 8)) +#define LOAD_LE_4(buf) (((size_t) ((uint8_t*) buf)[0]) | \ + ((size_t) ((uint8_t*) buf)[1] << 8) | \ + ((size_t) ((uint8_t*) buf)[2] << 16) | \ + ((size_t) ((uint8_t*) buf)[3] << 24)) +#if defined(ARCH_X86_64) +#define LOAD_LE_8(buf) (((size_t) ((uint8_t*) buf)[0]) | \ + ((size_t) ((uint8_t*) buf)[1] << 8) | \ + ((size_t) ((uint8_t*) buf)[2] << 16) | \ + ((size_t) ((uint8_t*) buf)[3] << 24) | \ + ((size_t) ((uint8_t*) buf)[4] << 32) | \ + ((size_t) ((uint8_t*) buf)[5] << 40) | \ + ((size_t) ((uint8_t*) buf)[6] << 48) | \ + ((size_t) ((uint8_t*) buf)[7] << 56)) +#endif + +static +int +decode_prefixes(const uint8_t* buffer, int len, PrefixSet* out_prefixes, + uint8_t* out_vex_operand) +{ + int off = 0; + PrefixSet prefixes = 0; + + while (LIKELY(off < len)) + { + uint8_t prefix = buffer[off]; + if (prefix == 0x2E) + { + prefixes |= PREFIX_SEG_CS; + } + else if (prefix == 0x64) + { + prefixes |= PREFIX_SEG_FS; + } + else if (prefix == 0x65) + { + prefixes |= PREFIX_SEG_GS; + } + else if (prefix == 0x66) + { + prefixes |= PREFIX_OPSZ; + } + else if (prefix == 0x67) + { + prefixes |= PREFIX_ADDRSZ; + } + else if (prefix == 0xF0) + { + prefixes |= PREFIX_LOCK; + } + else if (prefix == 0xF2) + { + prefixes |= PREFIX_REPNZ; + } + else if (prefix == 0xF3) + { + prefixes |= PREFIX_REP; + } +#if defined(ARCH_X86_64) + else if (LIKELY(prefix >= 0x40 && prefix <= 0x4F)) + { + prefixes |= PREFIX_REX; + if (prefix & 0x1) + { + prefixes |= PREFIX_REXB; + } + if (prefix & 0x2) + { + prefixes |= PREFIX_REXX; + } + if (prefix & 0x4) + { + prefixes |= PREFIX_REXR; + } + if (prefix & 0x8) + { + prefixes |= PREFIX_REXW; + } + // REX prefix is the last prefix. + off++; + break; + } +#endif + else if (UNLIKELY(prefix == 0xc4)) + { + // 3-byte VEX + if (UNLIKELY(off + 2 >= len)) + { + return -1; + } +#if defined(ARCH_386) + if ((buffer[off + 1] & 0xc0) != 0xc0) + { + break; + } +#endif + uint8_t byte2 = buffer[off + 1]; + uint8_t byte3 = buffer[off + 2]; + + prefixes |= PREFIX_VEX; +#if defined(ARCH_X86_64) + if ((byte2 & 0x80) == 0) + { + prefixes |= PREFIX_REXR; + } + if ((byte2 & 0x40) == 0) + { + prefixes |= PREFIX_REXX; + } + if ((byte2 & 0x20) == 0) + { + prefixes |= PREFIX_REXB; + } +#endif + switch (byte2 & 0x1f) + { + case 0x01: prefixes |= PREFIX_ESC_0F; break; + case 0x02: prefixes |= PREFIX_ESC_0F38; break; + case 0x03: prefixes |= PREFIX_ESC_0F3A; break; + default: return -1; + } + if (byte3 & 0x04) + { + prefixes |= PREFIX_VEXL; + } +#if defined(ARCH_X86_64) + // SDM Vol 2A 2-16 (Dec. 2016) + // - "In 32-bit modes, VEX.W is silently ignored." + // - VEX.W either replaces REX.W, is don't care or is reserved. + if (byte3 & 0x80) + { + prefixes |= PREFIX_REXW; + } +#endif + *out_vex_operand = ((byte3 & 0x78) >> 3) ^ 0xf; + switch (byte3 & 0x03) + { + case 1: prefixes |= PREFIX_OPSZ; break; + case 2: prefixes |= PREFIX_REP; break; + case 3: prefixes |= PREFIX_REPNZ; break; + default: break; + } + + // VEX prefix is always the last prefix. + off += 3; + break; + } + else if (UNLIKELY(prefix == 0xc5)) + { + // 2-byte VEX + if (UNLIKELY(off + 1 >= len)) + { + return -1; + } +#if defined(ARCH_386) + if ((buffer[off + 1] & 0xc0) != 0xc0) + { + break; + } +#endif + uint8_t byte = buffer[off + 1]; + + prefixes |= PREFIX_VEX | PREFIX_ESC_0F; +#if defined(ARCH_X86_64) + if ((byte & 0x80) == 0) + { + prefixes |= PREFIX_REXR; + } +#endif + if (byte & 0x04) + { + prefixes |= PREFIX_VEXL; + } + *out_vex_operand = ((byte & 0x78) >> 3) ^ 0xf; + switch (byte & 0x03) + { + case 1: prefixes |= PREFIX_OPSZ; break; + case 2: prefixes |= PREFIX_REP; break; + case 3: prefixes |= PREFIX_REPNZ; break; + default: break; + } + + // VEX prefix is always the last prefix. + off += 2; + break; + } + else + { + break; + } + off++; + } + + if (out_prefixes != NULL) + { + *out_prefixes = prefixes; + } + + return off; +} + +static +int +decode_modrm(const uint8_t* buffer, int len, Instr* instr, + struct Operand* out_o1, struct Operand* out_o2) +{ + int off = 0; + + if (UNLIKELY(off >= len)) + { + return -1; + } + + uint8_t modrm = buffer[off++]; + uint8_t mod = (modrm & 0xc0) >> 6; + uint8_t mod_reg = (modrm & 0x38) >> 3; + uint8_t rm = modrm & 0x07; + + // Operand 2 may be NULL when reg field is used as opcode extension + if (out_o2) + { + uint8_t reg_idx = mod_reg; +#if defined(ARCH_X86_64) + reg_idx += instr->prefixes & PREFIX_REXR ? 8 : 0; +#endif + out_o2->type = OT_REG; + out_o2->reg = reg_idx; + } + + if (mod == 3) + { + uint8_t reg_idx = rm; +#if defined(ARCH_X86_64) + reg_idx += instr->prefixes & PREFIX_REXB ? 8 : 0; +#endif + out_o1->type = OT_REG; + out_o1->reg = reg_idx; + return off; + } + + // SIB byte + uint8_t scale = 0; + uint8_t idx = 0; + uint8_t base = 0; + if (rm == 4) + { + if (UNLIKELY(off >= len)) + { + return -1; + } + + uint8_t sib = buffer[off++]; + scale = ((sib & 0xc0) >> 6) + 1; + idx = (sib & 0x38) >> 3; +#if defined(ARCH_X86_64) + idx += instr->prefixes & PREFIX_REXX ? 8 : 0; +#endif + base = sib & 0x07; + } + + if (mod == 1) + { + if (UNLIKELY(off + 1 > len)) + { + return -1; + } + + instr->disp = (int8_t) LOAD_LE_1(&buffer[off]); + off += 1; + } + else if (mod == 2 || (mod == 0 && (rm == 5 || base == 5))) + { + if (UNLIKELY(off + 4 > len)) + { + return -1; + } + + instr->disp = (int32_t) LOAD_LE_4(&buffer[off]); + off += 4; + } + else + { + instr->disp = 0; + } + + out_o1->type = OT_MEM; + instr->scale = scale; + + if (scale == 0) + { + if (mod == 0 && rm == 5) + { +#if defined(ARCH_X86_64) + out_o1->reg = RI_IP; +#else + out_o1->reg = REG_NONE; +#endif + return off; + } + + uint8_t reg_idx = rm; +#if defined(ARCH_X86_64) + reg_idx += instr->prefixes & PREFIX_REXB ? 8 : 0; +#endif + out_o1->reg = reg_idx; + return off; + } + + if (idx == 4) + { + instr->scale = 0; + } + else + { + instr->sreg = idx; + } + + if (base == 5 && mod == 0) + { + out_o1->reg = REG_NONE; + } + else + { + uint8_t reg_idx = base; +#if defined(ARCH_X86_64) + reg_idx += instr->prefixes & PREFIX_REXB ? 8 : 0; +#endif + out_o1->reg = reg_idx; + } + + return off; +} + +struct InstrDesc +{ + uint16_t type; + uint8_t operand_indices; + uint8_t operand_sizes; + uint8_t immediate; + + uint32_t gp_size_8 : 1; + uint32_t gp_size_def64 : 1; + uint32_t gp_instr_width : 1; + uint32_t gp_fixed_operand_size : 3; +} __attribute__((packed)); + +#define DESC_HAS_MODRM(desc) (((desc)->operand_indices & (3 << 0)) != 0) +#define DESC_MODRM_IDX(desc) ((((desc)->operand_indices >> 0) & 3) ^ 3) +#define DESC_HAS_MODREG(desc) (((desc)->operand_indices & (3 << 2)) != 0) +#define DESC_MODREG_IDX(desc) ((((desc)->operand_indices >> 2) & 3) ^ 3) +#define DESC_HAS_VEXREG(desc) (((desc)->operand_indices & (3 << 4)) != 0) +#define DESC_VEXREG_IDX(desc) ((((desc)->operand_indices >> 4) & 3) ^ 3) +#define DESC_HAS_IMPLICIT(desc) (((desc)->operand_indices & (3 << 6)) != 0) +#define DESC_IMPLICIT_IDX(desc) ((((desc)->operand_indices >> 6) & 3) ^ 3) +#define DESC_IMM_CONTROL(desc) (((desc)->immediate >> 4) & 0x7) +#define DESC_IMM_IDX(desc) (((desc)->immediate & 3) ^ 3) +#define DESC_IMM_BYTE(desc) (((desc)->immediate >> 7) & 1) + +int +decode(const uint8_t* buffer, int len, Instr* instr) +{ + int retval; + int off = 0; + uint8_t vex_operand = 0; + PrefixSet prefixes = 0; + + __builtin_memset(instr->operands, 0, sizeof(instr->operands)); + + retval = decode_prefixes(buffer + off, len - off, &prefixes, &vex_operand); + if (UNLIKELY(retval < 0 || off + retval >= len)) + { + return -1; + } + off += retval; + + uint16_t* table = (uint16_t*) _decode_table; + uint32_t kind = ENTRY_TABLE256; + + if (UNLIKELY(prefixes & PREFIX_ESC_MASK)) + { + uint32_t escape = prefixes & PREFIX_ESC_MASK; + table = (uint16_t*) &_decode_table[table[0x0F] & ~7]; + if (escape == PREFIX_ESC_0F38) + { + table = (uint16_t*) &_decode_table[table[0x38] & ~7]; + } + else if (escape == PREFIX_ESC_0F3A) + { + table = (uint16_t*) &_decode_table[table[0x3A] & ~7]; + } + } + + do + { + uint16_t entry = 0; + if (kind == ENTRY_TABLE256) + { + entry = table[buffer[off++]]; + } + else if (kind == ENTRY_TABLE8) + { + entry = table[(buffer[off] >> 3) & 7]; + } + else if (kind == ENTRY_TABLE72) + { + if ((buffer[off] & 0xc0) == 0xc0) + { + entry = table[buffer[off] - 0xb8]; + if ((entry & ENTRY_MASK) != ENTRY_NONE) + { + off++; + } + else + { + entry = table[(buffer[off] >> 3) & 7]; + } + } + else + { + entry = table[(buffer[off] >> 3) & 7]; + } + } + else if (kind == ENTRY_TABLE_PREFIX) + { + uint8_t index = 0; + if (prefixes & PREFIX_OPSZ) + { + index = 1; + } + else if (prefixes & PREFIX_REP) + { + index = 2; + } + else if (prefixes & PREFIX_REPNZ) + { + index = 3; + } +#if defined(ARCH_X86_64) + index |= prefixes & PREFIX_REXW ? (1 << 2) : 0; +#endif + index |= prefixes & PREFIX_VEX ? (1 << 3) : 0; + // If a prefix is mandatory and used as opcode extension, it has no + // further effect on the instruction. This is especially important + // for the 0x66 prefix, which could otherwise override the operand + // size of general purpose registers. + prefixes &= ~(PREFIX_OPSZ | PREFIX_REPNZ | PREFIX_REP); + entry = table[index]; + } + else + { + break; + } + + kind = entry & ENTRY_MASK; + table = (uint16_t*) &_decode_table[entry & ~7]; + } while (LIKELY(off < len)); + + if (UNLIKELY(kind != ENTRY_INSTR)) + { + return -1; + } + + struct InstrDesc* desc = (struct InstrDesc*) table; + + instr->type = desc->type; + instr->prefixes = prefixes; + instr->address = (uintptr_t) buffer; + + if (prefixes & PREFIX_SEG_FS) + { + instr->segment = RI_FS; + } + else if (prefixes & PREFIX_SEG_GS) + { + instr->segment = RI_GS; + } + else + { + instr->segment = RI_DS; + } + + uint8_t op_size = 0; + if (desc->gp_size_8) + { + op_size = 1; + } +#if defined(ARCH_X86_64) + else if (prefixes & PREFIX_REXW) + { + op_size = 8; + } +#endif + else if (prefixes & PREFIX_OPSZ) + { + op_size = 2; + } +#if defined(ARCH_X86_64) + else if (desc->gp_size_def64) + { + op_size = 8; + } +#endif + else + { + op_size = 4; + } + + if (UNLIKELY(desc->gp_instr_width)) + { + instr->width = op_size; + } + else + { + instr->width = 0; + } + + uint8_t vec_size = 16; + if (prefixes & PREFIX_VEXL) + { + vec_size = 32; + } + + uint8_t operand_sizes[4] = { + 0, 1 << desc->gp_fixed_operand_size, op_size, vec_size + }; + + for (int i = 0; i < 4; i++) + { + uint8_t enc_size = (desc->operand_sizes >> 2 * i) & 3; + instr->operands[i].size = operand_sizes[enc_size]; + } + + if (UNLIKELY(DESC_HAS_IMPLICIT(desc))) + { + struct Operand* operand = &instr->operands[DESC_IMPLICIT_IDX(desc)]; + operand->type = OT_REG; + operand->reg = 0; + } + + if (DESC_HAS_MODRM(desc)) + { + struct Operand* operand1 = &instr->operands[DESC_MODRM_IDX(desc)]; + + struct Operand* operand2 = NULL; + if (DESC_HAS_MODREG(desc)) + { + operand2 = &instr->operands[DESC_MODREG_IDX(desc)]; + } + retval = decode_modrm(buffer + off, len - off, instr, + operand1, operand2); + + if (UNLIKELY(retval < 0)) + { + return -1; + } + + off += retval; + } + else if (UNLIKELY(DESC_HAS_MODREG(desc))) + { + // If there is no ModRM, but a Mod-Reg, its opcode-encoded. + struct Operand* operand = &instr->operands[DESC_MODREG_IDX(desc)]; + uint8_t reg_idx = buffer[off - 1] & 7; +#if defined(ARCH_X86_64) + reg_idx += prefixes & PREFIX_REXB ? 8 : 0; +#endif + operand->type = OT_REG; + operand->reg = reg_idx; + } + + if (UNLIKELY(DESC_HAS_VEXREG(desc))) + { + struct Operand* operand = &instr->operands[DESC_VEXREG_IDX(desc)]; + operand->type = OT_REG; + operand->reg = vex_operand; + } + + uint32_t imm_control = DESC_IMM_CONTROL(desc); + if (UNLIKELY(imm_control == 1)) + { + struct Operand* operand = &instr->operands[DESC_IMM_IDX(desc)]; + operand->type = OT_IMM; + operand->size = 1; + instr->immediate = 1; + } + else if (UNLIKELY(imm_control == 2)) + { + struct Operand* operand = &instr->operands[DESC_IMM_IDX(desc)]; + operand->type = OT_MEM; + operand->reg = REG_NONE; + operand->size = op_size; + instr->scale = 0; + // TODO: Address size overrides +#if defined(ARCH_386) + if (UNLIKELY(off + 4 > len)) + { + return -1; + } + instr->disp = LOAD_LE_4(&buffer[off]); + off += 4; +#else + if (UNLIKELY(off + 8 > len)) + { + return -1; + } + instr->disp = LOAD_LE_8(&buffer[off]); + off += 8; +#endif + } + else if (UNLIKELY(imm_control != 0)) + { + uint8_t imm_size; + if (DESC_IMM_BYTE(desc)) + { + imm_size = 1; + } + else if (UNLIKELY(instr->type == IT_RET_IMM)) + { + imm_size = 2; + } + else if (UNLIKELY(instr->type == IT_ENTER)) + { + imm_size = 3; + } + else if (prefixes & PREFIX_OPSZ) + { + imm_size = 2; + } +#if defined(ARCH_X86_64) + else if (prefixes & PREFIX_REXW && instr->type == IT_MOVABS_IMM) + { + imm_size = 8; + } +#endif + else + { + imm_size = 4; + } + + if (UNLIKELY(off + imm_size > len)) + { + return -1; + } + + if (imm_size == 1) + { + instr->immediate = (int8_t) LOAD_LE_1(&buffer[off]); + } + else if (imm_size == 2) + { + instr->immediate = (int16_t) LOAD_LE_2(&buffer[off]); + } + else if (imm_size == 3) + { + instr->immediate = LOAD_LE_2(&buffer[off]); + instr->immediate |= LOAD_LE_1(&buffer[off + 2]) << 16; + } + else if (imm_size == 4) + { + instr->immediate = (int32_t) LOAD_LE_4(&buffer[off]); + } +#if defined(ARCH_X86_64) + else if (imm_size == 8) + { + instr->immediate = (int64_t) LOAD_LE_8(&buffer[off]); + } +#endif + off += imm_size; + + if (imm_control == 4) + { + instr->immediate += (uintptr_t) buffer + off; + } + + struct Operand* operand = &instr->operands[DESC_IMM_IDX(desc)]; + if (UNLIKELY(imm_control == 5)) + { + operand->type = OT_REG; + operand->reg = (instr->immediate & 0xf0) >> 4; + } + else + { + operand->type = OT_IMM; + } + } + + instr->size = off; + + return off; +} diff --git a/decode.h b/decode.h new file mode 100644 index 0000000..6f9abec --- /dev/null +++ b/decode.h @@ -0,0 +1,150 @@ + +#ifndef ARMX86_DECODE_H +#define ARMX86_DECODE_H + +#include +#include + +#ifndef ssize_t +#define ssize_t intptr_t +#endif + +#define DECODE_TABLE_MNEMONICS +#define MNEMONIC(name,value) IT_ ## name = value, +enum +{ +#include +}; +#undef DECODE_TABLE_MNEMONICS +#undef MNEMONIC + +enum RegIndex { + RI_AL = 0, + RI_CL, + RI_DL, + RI_BL, + RI_AH, + RI_CH, + RI_DH, + RI_BH, + + RI_AX = 0, + RI_CX, + RI_DX, + RI_BX, + RI_SP, + RI_BP, + RI_SI, + RI_DI, +#if defined(ARCH_X86_64) + RI_R8, + RI_R9, + RI_R10, + RI_R11, + RI_R12, + RI_R13, + RI_R14, + RI_R15, +#endif + + // EIP cannot be encoded in Protected/Compatibility Mode +#if defined(ARCH_X86_64) + RI_IP = 0x10, +#endif + + RI_ES = 0, + RI_CS, + RI_SS, + RI_DS, + RI_FS, + RI_GS, +}; + +typedef uint8_t Reg; + +#define reg_index(reg) (reg) +#define reg_is_none(reg) ((reg) == REG_NONE) +#define REG_NONE (0x3f) + +enum PrefixSet +{ + PREFIX_SEG_FS = 1 << 0, + PREFIX_SEG_GS = 1 << 1, + PREFIX_SEG_CS = 1 << 12, + PREFIX_OPSZ = 1 << 2, + PREFIX_ADDRSZ = 1 << 3, + PREFIX_LOCK = 1 << 4, + PREFIX_REPNZ = 1 << 5, + PREFIX_REP = 1 << 6, +#if defined(ARCH_X86_64) + PREFIX_REX = 1 << 7, + PREFIX_REXB = 1 << 8, + PREFIX_REXX = 1 << 9, + PREFIX_REXR = 1 << 10, + PREFIX_REXW = 1 << 11, +#endif + PREFIX_ESC_NONE = 0 << 13, + PREFIX_ESC_0F = 1 << 13, + PREFIX_ESC_0F38 = 2 << 13, + PREFIX_ESC_0F3A = 3 << 13, + PREFIX_ESC_MASK = 3 << 13, + PREFIX_VEX = 1 << 15, + PREFIX_VEXL = 1 << 16, +}; + +typedef enum PrefixSet PrefixSet; + +enum OperandType +{ + OT_NONE = 0, + OT_REG = 1, + OT_IMM = 2, + OT_MEM = 3, +}; + +struct Operand +{ + uint8_t type : 2; + uint8_t reg : 6; + uint8_t size; +}; + +struct Instr +{ + uint16_t type; + struct Operand operands[4]; + uint8_t segment : 3; + uint8_t width : 5; + + /** + * Encoded as 1 << (scale - 1) **or** no scaled register at all if zero. + **/ + uint8_t scale : 3; + uint8_t sreg : 5; + + PrefixSet prefixes; + size_t immediate; + intptr_t disp; + + uintptr_t address; + uint32_t size : 4; +}; + +typedef struct Instr Instr; + +#define INSTR_SEGMENT(instr) ((instr)->segment) +#define INSTR_WIDTH(instr) ((instr)->width) +#define INSTR_HAS_REP(instr) ((instr)->prefixes & PREFIX_REP) +#define INSTR_HAS_REPNZ(instr) ((instr)->prefixes & PREFIX_REPNZ) +#define INSTR_HAS_LOCK(instr) ((instr)->prefixes & PREFIX_LOCK) +#define INSTR_HAS_ADDRSZ(instr) ((instr)->prefixes & PREFIX_ADDRSZ) + +#if defined(ARCH_X86_64) +#define INSTR_HAS_REX(instr) ((instr)->prefixes & PREFIX_REX) +#endif + +int decode(const uint8_t* buffer, int len, Instr* out_instr); +void instr_format(const Instr* instr, char buffer[128]); +void instr_print(const Instr* instr) __attribute__((deprecated)); + +#endif diff --git a/format.c b/format.c new file mode 100644 index 0000000..79325ad --- /dev/null +++ b/format.c @@ -0,0 +1,168 @@ + +#include +#include + +#include + + +#define DECODE_TABLE_STRTAB1 +static const char* _mnemonic_str = +#include +; +#undef DECODE_TABLE_STRTAB1 + +#define DECODE_TABLE_STRTAB2 +static const uint16_t _mnemonic_offs[] = { +#include +}; +#undef DECODE_TABLE_STRTAB2 + +static +void +instr_format_decimal(char** cur, uint32_t value) +{ + char buffer[32]; + size_t buf_idx = sizeof(buffer) - 1; + if (value == 0) + { + buffer[buf_idx] = '0'; + } + else + { + while (value > 0) + { + uint32_t digit = value % 10; + buffer[buf_idx--] = '0' + digit; + value /= 10; + } + buf_idx++; + } + + size_t length = sizeof(buffer) - buf_idx; + __builtin_memcpy(*cur, buffer + buf_idx, length); + *cur += length; +} + +static +void +instr_format_hex(char** cur, size_t value) +{ + char buffer[32]; + size_t buf_idx = sizeof(buffer) - 1; + if (value == 0) + { + buffer[buf_idx] = '0'; + } + else + { + while (value > 0) + { + uint32_t nibble = value & 0xf; + buffer[buf_idx--] = "0123456789abcdef"[nibble]; + value >>= 4; + } + buf_idx++; + } + buffer[--buf_idx] = 'x'; + buffer[--buf_idx] = '0'; + + size_t length = sizeof(buffer) - buf_idx; + __builtin_memcpy(*cur, buffer + buf_idx, length); + *cur += length; +} + +void +instr_format(const Instr* instr, char buffer[128]) +{ + char* cur = buffer; + *(cur++) = '['; + + const char* mnemonic = &_mnemonic_str[_mnemonic_offs[instr->type]]; + while (*mnemonic) + { + *(cur++) = *(mnemonic++); + } + + if (instr->width != 0) + { + *(cur++) = '_'; + instr_format_decimal(&cur, instr->width); + } + + for (int i = 0; i < 4; i++) + { + const struct Operand* operand = &instr->operands[i]; + if (operand->type == OT_NONE) + { + break; + } + + __builtin_memcpy(cur, " REG IMM MEM" + operand->type * 4 - 4, 4); + cur += 4; + instr_format_decimal(&cur, operand->size); + *(cur++) = ':'; + + switch (operand->type) + { + size_t immediate; + case OT_REG: + instr_format_decimal(&cur, reg_index(operand->reg)); + break; + case OT_IMM: + immediate = instr->immediate; + if (operand->size == 1) + { + immediate &= 0xff; + } + else if (operand->size == 2) + { + immediate &= 0xffff; + } +#if defined(ARCH_X86_64) + else if (operand->size == 4) + { + immediate &= 0xffffffff; + } +#endif + instr_format_hex(&cur, immediate); + break; + case OT_MEM: + if (!reg_is_none(operand->reg)) + { + instr_format_decimal(&cur, reg_index(operand->reg)); + *(cur++) = ':'; + } + if (instr->scale != 0) + { + uint8_t scale = 1 << (instr->scale - 1); + instr_format_decimal(&cur, scale); + *(cur++) = '*'; + instr_format_decimal(&cur, reg_index(instr->sreg)); + *(cur++) = ':'; + } + if (instr->disp < 0) + { + *(cur++) = '-'; + instr_format_hex(&cur, -instr->disp); + } + else + { + instr_format_hex(&cur, instr->disp); + } + break; + case OT_NONE: + default: + break; + } + } + + *(cur++) = ']'; + *(cur++) = '\0'; + +#ifndef NDEBUG + if (cur - buffer > 128) + { + __builtin_trap(); + } +#endif +} diff --git a/instrs.txt b/instrs.txt new file mode 100644 index 0000000..869b381 --- /dev/null +++ b/instrs.txt @@ -0,0 +1,1177 @@ +00 MR GP GP - - ADD SIZE_8 +01 MR GP GP - - ADD +02 RM GP GP - - ADD SIZE_8 +03 RM GP GP - - ADD +04 IA GP IMM - - ADD_IMM SIZE_8 IMM_8 +05 IA GP IMM - - ADD_IMM +06 NP - - - - PUSH_ES ONLY32 +07 NP - - - - POP_ES ONLY32 +08 MR GP GP - - OR SIZE_8 +09 MR GP GP - - OR +0a RM GP GP - - OR SIZE_8 +0b RM GP GP - - OR +0c IA GP IMM - - OR_IMM SIZE_8 IMM_8 +0d IA GP IMM - - OR_IMM +0e NP - - - - PUSH_CS ONLY32 +#0f escape opcode +10 MR GP GP - - ADC SIZE_8 +11 MR GP GP - - ADC +12 RM GP GP - - ADC SIZE_8 +13 RM GP GP - - ADC +14 IA GP IMM - - ADC_IMM SIZE_8 IMM_8 +15 IA GP IMM - - ADC_IMM +16 NP - - - - PUSH_SS ONLY32 +17 NP - - - - POP_SS ONLY32 +18 MR GP GP - - SBB SIZE_8 +19 MR GP GP - - SBB +1a RM GP GP - - SBB SIZE_8 +1b RM GP GP - - SBB +1c IA GP IMM - - SBB_IMM SIZE_8 IMM_8 +1d IA GP IMM - - SBB_IMM +1e NP - - - - PUSH_DS ONLY32 +1f NP - - - - POP_DS ONLY32 +20 MR GP GP - - AND SIZE_8 +21 MR GP GP - - AND +22 RM GP GP - - AND SIZE_8 +23 RM GP GP - - AND +24 IA GP IMM - - AND_IMM SIZE_8 IMM_8 +25 IA GP IMM - - AND_IMM +#26 SEG=ES prefix +27 NP - - - - DAA ONLY32 +28 MR GP GP - - SUB SIZE_8 +29 MR GP GP - - SUB +2a RM GP GP - - SUB SIZE_8 +2b RM GP GP - - SUB +2c IA GP IMM - - SUB_IMM SIZE_8 IMM_8 +2d IA GP IMM - - SUB_IMM +#2e SEG=CS prefix +2f NP - - - - DAS ONLY32 +30 MR GP GP - - XOR SIZE_8 +31 MR GP GP - - XOR +32 RM GP GP - - XOR SIZE_8 +33 RM GP GP - - XOR +34 IA GP IMM - - XOR_IMM SIZE_8 IMM_8 +35 IA GP IMM - - XOR_IMM +#36 SEG=SS prefix +37 NP - - - - AAA ONLY32 +38 MR GP GP - - CMP SIZE_8 +39 MR GP GP - - CMP +3a RM GP GP - - CMP SIZE_8 +3b RM GP GP - - CMP +3c IA GP IMM - - CMP_IMM SIZE_8 IMM_8 +3d IA GP IMM - - CMP_IMM +#3e SEG=DS prefix +3f NP - - - - AAS ONLY32 INSTR_WIDTH +40+ O GP - - - INC ONLY32 +48+ O GP - - - DEC ONLY32 +50+ O GP - - - PUSH DEF64 +58+ O GP - - - POP DEF64 +60 NP - - - - PUSHA ONLY32 INSTR_WIDTH +61 NP - - - - POPA ONLY32 INSTR_WIDTH +62 RM GP GP - - BOUND ONLY32 +63 MR GP16 GP16 - - ARPL ONLY32 +63 RM GP GP32 - - MOVSX ONLY64 +#64 SEG=FS prefix +#65 SEG=GS prefix +#66 operand size prefix +#67 address size prefix +68 I IMM - - - PUSH DEF64 +69 RMI GP GP IMM - IMUL3 +6a I IMM - - - PUSH DEF64 IMM_8 +6b RMI GP GP IMM - IMUL3 IMM_8 +6c NP - - - - INS SIZE_8 INSTR_WIDTH +6d NP - - - - INS INSTR_WIDTH +6e NP - - - - OUTS SIZE_8 INSTR_WIDTH +6f NP - - - - OUTS INSTR_WIDTH +70 D IMM - - - JO DEF64 IMM_8 +71 D IMM - - - JNO DEF64 IMM_8 +72 D IMM - - - JC DEF64 IMM_8 +73 D IMM - - - JNC DEF64 IMM_8 +74 D IMM - - - JZ DEF64 IMM_8 +75 D IMM - - - JNZ DEF64 IMM_8 +76 D IMM - - - JBE DEF64 IMM_8 +77 D IMM - - - JA DEF64 IMM_8 +78 D IMM - - - JS DEF64 IMM_8 +79 D IMM - - - JNS DEF64 IMM_8 +7a D IMM - - - JP DEF64 IMM_8 +7b D IMM - - - JNP DEF64 IMM_8 +7c D IMM - - - JL DEF64 IMM_8 +7d D IMM - - - JGE DEF64 IMM_8 +7e D IMM - - - JLE DEF64 IMM_8 +7f D IMM - - - JG DEF64 IMM_8 +80/0 MI GP IMM - - ADD_IMM IMM_8 SIZE_8 +80/1 MI GP IMM - - OR_IMM IMM_8 SIZE_8 +80/2 MI GP IMM - - ADC_IMM IMM_8 SIZE_8 +80/3 MI GP IMM - - SBB_IMM IMM_8 SIZE_8 +80/4 MI GP IMM - - AND_IMM IMM_8 SIZE_8 +80/5 MI GP IMM - - SUB_IMM IMM_8 SIZE_8 +80/6 MI GP IMM - - XOR_IMM IMM_8 SIZE_8 +80/7 MI GP IMM - - CMP_IMM IMM_8 SIZE_8 +81/0 MI GP IMM - - ADD_IMM +81/1 MI GP IMM - - OR_IMM +81/2 MI GP IMM - - ADC_IMM +81/3 MI GP IMM - - SBB_IMM +81/4 MI GP IMM - - AND_IMM +81/5 MI GP IMM - - SUB_IMM +81/6 MI GP IMM - - XOR_IMM +81/7 MI GP IMM - - CMP_IMM +82/0 MI GP IMM - - ADD_IMM ONLY32 IMM_8 SIZE_8 +82/1 MI GP IMM - - OR_IMM ONLY32 IMM_8 SIZE_8 +82/2 MI GP IMM - - ADC_IMM ONLY32 IMM_8 SIZE_8 +82/3 MI GP IMM - - SBB_IMM ONLY32 IMM_8 SIZE_8 +82/4 MI GP IMM - - AND_IMM ONLY32 IMM_8 SIZE_8 +82/5 MI GP IMM - - SUB_IMM ONLY32 IMM_8 SIZE_8 +82/6 MI GP IMM - - XOR_IMM ONLY32 IMM_8 SIZE_8 +82/7 MI GP IMM - - CMP_IMM ONLY32 IMM_8 SIZE_8 +83/0 MI GP IMM - - ADD_IMM IMM_8 +83/1 MI GP IMM - - OR_IMM IMM_8 +83/2 MI GP IMM - - ADC_IMM IMM_8 +83/3 MI GP IMM - - SBB_IMM IMM_8 +83/4 MI GP IMM - - AND_IMM IMM_8 +83/5 MI GP IMM - - SUB_IMM IMM_8 +83/6 MI GP IMM - - XOR_IMM IMM_8 +83/7 MI GP IMM - - CMP_IMM IMM_8 +84 MR GP GP - - TEST SIZE_8 +85 MR GP GP - - TEST +86 MR GP GP - - XCHG SIZE_8 +87 MR GP GP - - XCHG +88 MR GP GP - - MOV SIZE_8 +89 MR GP GP - - MOV +8a RM GP GP - - MOV SIZE_8 +8b RM GP GP - - MOV +8c MR GP SREG - - MOV_S2G +8d RM GP GP - - LEA +8e RM SREG GP - - MOV_G2S +8f/0 M GP - - - POP DEF64 +90 NP - - - - NOP +91 OA GP GP - - XCHG +92 OA GP GP - - XCHG +93 OA GP GP - - XCHG +94 OA GP GP - - XCHG +95 OA GP GP - - XCHG +96 OA GP GP - - XCHG +97 OA GP GP - - XCHG +98 NP - - - - C_EX INSTR_WIDTH +99 NP - - - - C_SEP INSTR_WIDTH +#9a CALLF TODO +9b NP - - - - FWAIT +9c NP - - - - PUSHF DEF64 INSTR_WIDTH +9d NP - - - - POPF DEF64 INSTR_WIDTH +9e NP - - - - SAHF +9f NP - - - - LAHF +a0 FD GP GP - - MOV SIZE_8 +a1 FD GP GP - - MOV +a2 TD GP GP - - MOV SIZE_8 +a3 TD GP GP - - MOV +a4 NP - - - - MOVS SIZE_8 INSTR_WIDTH +a5 NP - - - - MOVS INSTR_WIDTH +a6 NP - - - - CMPS SIZE_8 INSTR_WIDTH +a7 NP - - - - CMPS INSTR_WIDTH +a8 IA GP IMM - - TEST_IMM SIZE_8 IMM_8 +a9 IA GP IMM - - TEST_IMM +aa NP - - - - STOS SIZE_8 INSTR_WIDTH +ab NP - - - - STOS INSTR_WIDTH +ac NP - - - - LODS SIZE_8 INSTR_WIDTH +ad NP - - - - LODS INSTR_WIDTH +ae NP - - - - SCAS SIZE_8 INSTR_WIDTH +af NP - - - - SCAS INSTR_WIDTH +b0+ OI GP IMM - - MOVABS_IMM SIZE_8 IMM_8 +b8+ OI GP IMM - - MOVABS_IMM +c0/0 MI GP IMM - - ROL_IMM SIZE_8 IMM_8 +c0/1 MI GP IMM - - ROR_IMM SIZE_8 IMM_8 +c0/2 MI GP IMM - - RCL_IMM SIZE_8 IMM_8 +c0/3 MI GP IMM - - RCR_IMM SIZE_8 IMM_8 +c0/4 MI GP IMM - - SHL_IMM SIZE_8 IMM_8 +c0/5 MI GP IMM - - SHR_IMM SIZE_8 IMM_8 +c0/7 MI GP IMM - - SAR_IMM SIZE_8 IMM_8 +c1/0 MI GP IMM - - ROL_IMM IMM_8 +c1/1 MI GP IMM - - ROR_IMM IMM_8 +c1/2 MI GP IMM - - RCL_IMM IMM_8 +c1/3 MI GP IMM - - RCR_IMM IMM_8 +c1/4 MI GP IMM - - SHL_IMM IMM_8 +c1/5 MI GP IMM - - SHR_IMM IMM_8 +c1/7 MI GP IMM - - SAR_IMM IMM_8 +# RET_IMM immediate size handled in code +c2 I IMM16 - - - RET_IMM DEF64 INSTR_WIDTH +c3 NP - - - - RET DEF64 INSTR_WIDTH +c4 RM GP GP - - LES ONLY32 +c5 RM GP GP - - LDS ONLY32 +c6//0 MI GP IMM - - MOV_IMM SIZE_8 IMM_8 +c6//f8 I IMM - - - XABORT IMM_8 +c7//0 MI GP IMM - - MOV_IMM +c7//f8 D IMM - - - XBEGIN +# ENTER immediate handled in code +c8 I IMM32 - - - ENTER DEF64 INSTR_WIDTH +c9 NP - - - - LEAVE DEF64 INSTR_WIDTH +#ca RETf TODO, ONLY32 +#cb RETf TODO, ONLY32 +cc NP - - - - INT3 +cd I IMM8 - - - INT IMM_8 +ce NP - - - - INTO ONLY32 +cf NP - - - - IRET INSTR_WIDTH +d0/0 M1 GP IMM8 - - ROL_IMM SIZE_8 +d0/1 M1 GP IMM8 - - ROR_IMM SIZE_8 +d0/2 M1 GP IMM8 - - RCL_IMM SIZE_8 +d0/3 M1 GP IMM8 - - RCR_IMM SIZE_8 +d0/4 M1 GP IMM8 - - SHL_IMM SIZE_8 +d0/5 M1 GP IMM8 - - SHR_IMM SIZE_8 +d0/7 M1 GP IMM8 - - SAR_IMM SIZE_8 +d1/0 M1 GP IMM8 - - ROL_IMM +d1/1 M1 GP IMM8 - - ROR_IMM +d1/2 M1 GP IMM8 - - RCL_IMM +d1/3 M1 GP IMM8 - - RCR_IMM +d1/4 M1 GP IMM8 - - SHL_IMM +d1/5 M1 GP IMM8 - - SHR_IMM +d1/7 M1 GP IMM8 - - SAR_IMM +d2/0 M GP - - - ROL_CL SIZE_8 +d2/1 M GP - - - ROR_CL SIZE_8 +d2/2 M GP - - - RCL_CL SIZE_8 +d2/3 M GP - - - RCR_CL SIZE_8 +d2/4 M GP - - - SHL_CL SIZE_8 +d2/5 M GP - - - SHR_CL SIZE_8 +d2/7 M GP - - - SAR_CL SIZE_8 +d3/0 M GP - - - ROL_CL +d3/1 M GP - - - ROR_CL +d3/2 M GP - - - RCL_CL +d3/3 M GP - - - RCR_CL +d3/4 M GP - - - SHL_CL +d3/5 M GP - - - SHR_CL +d3/7 M GP - - - SAR_CL +d4 I IMM - - - AAM ONLY32 SIZE_8 IMM_8 +d5 I IMM - - - AAD ONLY32 SIZE_8 IMM_8 +#d6 unused +d7 NP - - - - XLATB +#d8-df FPU Escape +e0 D IMM - - - LOOPNZ DEF64 IMM_8 +e1 D IMM - - - LOOPZ DEF64 IMM_8 +e2 D IMM - - - LOOP DEF64 IMM_8 +e3 D IMM - - - JCXZ DEF64 IMM_8 +e4 IA GP IMM - - IN_IMM SIZE_8 IMM_8 +e5 IA GP IMM - - IN_IMM IMM_8 +e6 IA GP IMM - - OUT_IMM SIZE_8 IMM_8 +e7 IA GP IMM - - OUT_IMM IMM_8 +e8 D IMM - - - CALL DEF64 +e9 D IMM - - - JMP DEF64 +#ea JMPf TODO, ONLY32 +eb D IMM - - - JMP DEF64 IMM_8 +ec NP - - - - IN SIZE_8 INSTR_WIDTH +ed NP - - - - IN INSTR_WIDTH +ee NP - - - - OUT SIZE_8 INSTR_WIDTH +ef NP - - - - OUT INSTR_WIDTH +#f0 LOCK prefix +#f1 unused +#f2 REPNZ prefix +#f3 REP/REPZ prefix +f4 NP - - - - HLT +f5 NP - - - - CMC +f6/0 MI GP IMM - - TEST_IMM SIZE_8 IMM_8 +f6/2 M GP - - - NOT SIZE_8 +f6/3 M GP - - - NEG SIZE_8 +f6/4 M GP - - - MUL SIZE_8 +f6/5 M GP - - - IMUL SIZE_8 +f6/6 M GP - - - DIV SIZE_8 +f6/7 M GP - - - IDIV SIZE_8 +f7/0 MI GP IMM - - TEST_IMM +f7/2 M GP - - - NOT +f7/3 M GP - - - NEG +f7/4 M GP - - - MUL +f7/5 M GP - - - IMUL +f7/6 M GP - - - DIV +f7/7 M GP - - - IDIV +f8 NP - - - - CLC +f9 NP - - - - STC +fa NP - - - - CLI +fb NP - - - - STI +fc NP - - - - CLD +fd NP - - - - STD +fe/0 M GP - - - INC SIZE_8 +fe/1 M GP - - - DEC SIZE_8 +ff/0 M GP - - - INC +ff/1 M GP - - - DEC +ff/2 M GP - - - CALL_IND DEF64 +#ff/3 CALLf TODO +ff/4 M GP - - - JMP_IND DEF64 +#ff/5 JMPf TODO +ff/6 M GP - - - PUSH DEF64 +0f00/0 M GP - - - SLDT +0f00/1 M GP - - - STR +0f00/2 M GP - - - LLDT +0f00/3 M GP - - - LTR +0f00/4 M GP - - - VERR +0f00/5 M GP - - - VERW +0f01//0 M GP - - - SGDT +0f01//1 M GP - - - SIDT +0f01//2 M GP - - - LGDT +0f01//3 M GP - - - LIDT +0f01//4 M GP - - - SMSW +0f01//6 M GP - - - LMSW +0f01//7 M GP - - - INVLPG +0f01//c8 NP - - - - MONITOR +0f01//c9 NP - - - - MWAIT +0f01//ca NP - - - - CLAC +0f01//cb NP - - - - STAC +0f01//cf NP - - - - ENCLS +0f01//d0 NP - - - - XGETBV +0f01//d1 NP - - - - XSETBV +0f01//d5 NP - - - - XEND +0f01//d6 NP - - - - XTEST +0f01//d7 NP - - - - ENCLU +0f01//f8 NP - - - - SWAPGS ONLY64 +0f01//f9 NP - - - - RDTSCP +0f02 RM GP GP16 - - LAR +0f03 RM GP GP16 - - LSL +0f05 NP - - - - SYSCALL ONLY64 +0f06 NP - - - - CLTS +0f07 NP - - - - SYSRET ONLY64 +0f08 NP - - - - INVD +0f09 NP - - - - WBINVD +0f0b NP - - - - UD2 +0f0d/1 M GP8 - - - PREFETCHW +0f0d/2 M GP8 - - - PREFETCHWT1 +0f18/0 M GP8 - - - PREFETCHNTA +0f18/1 M GP8 - - - PREFETCH0 +0f18/2 M GP8 - - - PREFETCH1 +0f18/3 M GP8 - - - PREFETCH2 +0f1f M GP - - - NOP +# 0f20, 0f21, 0f22, 0f23 are moves to/from control/debug registers +0f30 NP - - - - WRMSR +0f31 NP - - - - RDTSC +0f32 NP - - - - RDMSR +0f33 NP - - - - RDPMC +0f34 NP - - - - SYSENTER +0f35 NP - - - - SYSEXIT +0f37 NP - - - - GETSEC +# 0f38, 0f3a are escape opcodes +0f40 RM GP GP - - CMOVO +0f41 RM GP GP - - CMOVNO +0f42 RM GP GP - - CMOVC +0f43 RM GP GP - - CMOVNC +0f44 RM GP GP - - CMOVZ +0f45 RM GP GP - - CMOVNZ +0f46 RM GP GP - - CMOVBE +0f47 RM GP GP - - CMOVA +0f48 RM GP GP - - CMOVS +0f49 RM GP GP - - CMOVNS +0f4a RM GP GP - - CMOVP +0f4b RM GP GP - - CMOVNP +0f4c RM GP GP - - CMOVL +0f4d RM GP GP - - CMOVGE +0f4e RM GP GP - - CMOVLE +0f4f RM GP GP - - CMOVG +0f80 D IMM - - - JO DEF64 +0f81 D IMM - - - JNO DEF64 +0f82 D IMM - - - JC DEF64 +0f83 D IMM - - - JNC DEF64 +0f84 D IMM - - - JZ DEF64 +0f85 D IMM - - - JNZ DEF64 +0f86 D IMM - - - JBE DEF64 +0f87 D IMM - - - JA DEF64 +0f88 D IMM - - - JS DEF64 +0f89 D IMM - - - JNS DEF64 +0f8a D IMM - - - JP DEF64 +0f8b D IMM - - - JNP DEF64 +0f8c D IMM - - - JL DEF64 +0f8d D IMM - - - JGE DEF64 +0f8e D IMM - - - JLE DEF64 +0f8f D IMM - - - JG DEF64 +0f90 M GP8 - - - SETO +0f91 M GP8 - - - SETNO +0f92 M GP8 - - - SETC +0f93 M GP8 - - - SETNC +0f94 M GP8 - - - SETZ +0f95 M GP8 - - - SETNZ +0f96 M GP8 - - - SETBE +0f97 M GP8 - - - SETA +0f98 M GP8 - - - SETS +0f99 M GP8 - - - SETNS +0f9a M GP8 - - - SETP +0f9b M GP8 - - - SETNP +0f9c M GP8 - - - SETL +0f9d M GP8 - - - SETGE +0f9e M GP8 - - - SETLE +0f9f M GP8 - - - SETG +0fa0 NP - - - - PUSH_FS DEF64 +0fa1 NP - - - - POP_FS DEF64 +0fa2 NP - - - - CPUID +0fa3 MR GP GP - - BT +0fa4 MRI GP GP IMM8 - SHLD_IMM IMM_8 +0fa5 MR GP GP - - SHLD_CL +0fa8 NP - - - - PUSH_GS DEF64 +0fa9 NP - - - - POP_GS DEF64 +# 0faa RSM +0fab MR GP GP - - BTS +0fac MRI GP GP IMM8 - SHRD_IMM IMM_8 +0fad MR GP GP - - SHRD_CL +0faf RM GP GP - - IMUL2 +0fb0 MR GP GP - - CMPXCHG SIZE_8 +0fb1 MR GP GP - - CMPXCHG +0fb3 MR GP GP - - BTR +0fb6 RM GP GP8 - - MOVZX +0fb7 RM GP GP16 - - MOVZX +F3.0fb8 RM GP GP - - POPCNT +0fb9 RM GP GP - - UD1 +0fba/4 MI GP IMM8 - - BT IMM_8 +0fba/5 MI GP IMM8 - - BTS IMM_8 +0fba/6 MI GP IMM8 - - BTR IMM_8 +0fba/7 MI GP IMM8 - - BTC IMM_8 +0fbb MR GP GP - - BTC +0fbc RM GP GP - - BSF_TZCNT +0fbd RM GP GP - - BSR_LZCNT +0fbe RM GP GP8 - - MOVSX +0fbf RM GP GP16 - - MOVSX +0fc0 MR GP GP - - XADD SIZE_8 +0fc1 MR GP GP - - XADD +NP.0fc3 MR GP GP - - MOVNTI +0fc7//1 M GP - - - CMPXCHGD +0fc8+ O GP - - - BSWAP +0fff NP - - - - UD0 +# +NP.0f38f0 RM GP GP - - MOVBE +66.0f38f0 RM GP16 GP16 - - MOVBE +NP.0f38f1 MR GP GP - - MOVBE +66.0f38f1 MR GP16 GP16 - - MOVBE +# +# SSE +NP.0f10 RM XMM XMM - - SSE_MOVUPS +66.0f10 RM XMM XMM - - SSE_MOVUPD +F3.0f10 RM XMM32 XMM32 - - SSE_MOVSS +F2.0f10 RM XMM64 XMM64 - - SSE_MOVSD +NP.0f11 MR XMM XMM - - SSE_MOVUPS +66.0f11 MR XMM XMM - - SSE_MOVUPD +F3.0f11 MR XMM32 XMM32 - - SSE_MOVSS +F2.0f11 MR XMM64 XMM64 - - SSE_MOVSD +NP.0f12 RM XMM XMM64 - - SSE_MOVLPS +66.0f12 RM XMM XMM64 - - SSE_MOVLPD +F3.0f12 RM XMM XMM - - SSE_MOVSLDUP +F2.0f12 RM XMM XMM64 - - SSE_MOVDDUP +NP.0f13 RM XMM64 XMM - - SSE_MOVLPS +66.0f13 RM XMM64 XMM - - SSE_MOVLPD +NP.0f14 RM XMM XMM - - SSE_UNPACKLPS +66.0f14 RM XMM XMM - - SSE_UNPACKLPD +NP.0f15 RM XMM XMM - - SSE_UNPACKHPS +66.0f15 RM XMM XMM - - SSE_UNPACKHPD +NP.0f16 RM XMM XMM64 - - SSE_MOVHPS +66.0f16 RM XMM XMM64 - - SSE_MOVHPD +F3.0f16 RM XMM XMM - - SSE_MOVSHDUP +NP.0f17 RM XMM64 XMM - - SSE_MOVHPS +66.0f17 RM XMM64 XMM - - SSE_MOVHPD +NP.0f28 RM XMM XMM - - SSE_MOVAPS +66.0f28 RM XMM XMM - - SSE_MOVAPD +NP.0f29 MR XMM XMM - - SSE_MOVAPS +66.0f29 MR XMM XMM - - SSE_MOVAPD +F3.0f2a RM XMM32 GP - - SSE_CVTSI2SS +F2.0f2a RM XMM64 GP - - SSE_CVTSI2SD +NP.0f2b MR XMM XMM - - SSE_MOVNTPS +66.0f2b MR XMM XMM - - SSE_MOVNTPD +F3.0f2c RM GP XMM32 - - SSE_CVTSS2SI +F2.0f2c RM GP XMM64 - - SSE_CVTSD2SI +F3.0f2d RM GP XMM32 - - SSE_CVTSS2SI +F2.0f2d RM GP XMM64 - - SSE_CVTSD2SI +NP.0f2e RM XMM32 XMM32 - - SSE_UCOMISS +66.0f2e RM XMM64 XMM64 - - SSE_UCOMISD +NP.0f2f RM XMM32 XMM32 - - SSE_COMISS +66.0f2f RM XMM64 XMM64 - - SSE_COMISD +NP.0f50 RM GP XMM - - SSE_MOVMSKPS DEF64 +66.0f50 RM GP XMM - - SSE_MOVMSKPD DEF64 +NP.0f51 RM XMM XMM - - SSE_SQRTPS +66.0f51 RM XMM XMM - - SSE_SQRTPD +F3.0f51 RM XMM32 XMM32 - - SSE_SQRTSS +F2.0f51 RM XMM64 XMM64 - - SSE_SQRTSD +NP.0f52 RM XMM XMM - - SSE_RSQRTPS +F3.0f52 RM XMM32 XMM32 - - SSE_RSQRTSS +NP.0f53 RM XMM XMM - - SSE_RCPPS +F3.0f53 RM XMM32 XMM32 - - SSE_RCPSS +NP.0f54 RM XMM XMM - - SSE_ANDPS +66.0f54 RM XMM XMM - - SSE_ANDPD +NP.0f55 RM XMM XMM - - SSE_ANDNPS +66.0f55 RM XMM XMM - - SSE_ANDNPD +NP.0f56 RM XMM XMM - - SSE_ORPS +66.0f56 RM XMM XMM - - SSE_ORPD +NP.0f57 RM XMM XMM - - SSE_XORPS +66.0f57 RM XMM XMM - - SSE_XORPD +NP.0f58 RM XMM XMM - - SSE_ADDPS +66.0f58 RM XMM XMM - - SSE_ADDPD +F3.0f58 RM XMM32 XMM32 - - SSE_ADDSS +F2.0f58 RM XMM64 XMM64 - - SSE_ADDSD +NP.0f59 RM XMM XMM - - SSE_MULPS +66.0f59 RM XMM XMM - - SSE_MULPD +F3.0f59 RM XMM32 XMM32 - - SSE_MULSS +F2.0f59 RM XMM64 XMM64 - - SSE_MULSD +NP.0f5a RM XMM XMM64 - - SSE_CVTPS2PD +66.0f5a RM XMM XMM - - SSE_CVTPD2PS +F3.0f5a RM XMM XMM32 - - SSE_CVTSS2SD +F2.0f5a RM XMM XMM64 - - SSE_CVTSD2SS +NP.0f5b RM XMM XMM - - SSE_CVTDQ2PS +66.0f5b RM XMM XMM - - SSE_CVTPS2DQ +F3.0f5b RM XMM XMM - - SSE_CVTTPS2DQ +NP.0f5c RM XMM XMM - - SSE_SUBPS +66.0f5c RM XMM XMM - - SSE_SUBPD +F3.0f5c RM XMM32 XMM32 - - SSE_SUBSS +F2.0f5c RM XMM64 XMM64 - - SSE_SUBSD +NP.0f5d RM XMM XMM - - SSE_MINPS +66.0f5d RM XMM XMM - - SSE_MINPD +F3.0f5d RM XMM32 XMM32 - - SSE_MINSS +F2.0f5d RM XMM64 XMM64 - - SSE_MINSD +NP.0f5e RM XMM XMM - - SSE_DIVPS +66.0f5e RM XMM XMM - - SSE_DIVPD +F3.0f5e RM XMM32 XMM32 - - SSE_DIVSS +F2.0f5e RM XMM64 XMM64 - - SSE_DIVSD +NP.0f5f RM XMM XMM - - SSE_MAXPS +66.0f5f RM XMM XMM - - SSE_MAXPD +F3.0f5f RM XMM32 XMM32 - - SSE_MAXSS +F2.0f5f RM XMM64 XMM64 - - SSE_MAXSD +66.0f60 RM XMM XMM - - SSE_PUNPCKLBW +66.0f61 RM XMM XMM - - SSE_PUNPCKLWD +66.0f62 RM XMM XMM - - SSE_PUNPCKLDQ +66.0f63 RM XMM XMM - - SSE_PACKSSWB +66.0f64 RM XMM XMM - - SSE_PCMPGTB +66.0f65 RM XMM XMM - - SSE_PCMPGTW +66.0f66 RM XMM XMM - - SSE_PCMPGTD +66.0f67 RM XMM XMM - - SSE_PACKUSWB +66.0f68 RM XMM XMM - - SSE_PUNPCKHBW +66.0f69 RM XMM XMM - - SSE_PUNPCKHWD +66.0f6a RM XMM XMM - - SSE_PUNPCKHDQ +66.0f6b RM XMM XMM - - SSE_PACKSSDW +66.0f6c RM XMM XMM - - SSE_PUNPCKLQDQ +66.0f6d RM XMM XMM - - SSE_PUNPCKHQDQ +66.W0.0f6e RM XMM32 GP - - SSE_MOVD_G2X +66.W1.0f6e RM XMM64 GP - - SSE_MOVQ_G2X +66.0f6f RM XMM XMM - - SSE_MOVDQA +F3.0f6f RM XMM XMM - - SSE_MOVDQU +66.0f70 RMI XMM XMM IMM8 - SSE_PSHUFD IMM_8 +F3.0f70 RMI XMM XMM IMM8 - SSE_PSHUFHW IMM_8 +F2.0f70 RMI XMM XMM IMM8 - SSE_PSHUFLW IMM_8 +66.0f71/2 MI XMM IMM8 - - SSE_PSRLW IMM_8 +66.0f71/4 MI XMM IMM8 - - SSE_PSRAW IMM_8 +66.0f71/6 MI XMM IMM8 - - SSE_PSLLW IMM_8 +66.0f72/2 MI XMM IMM8 - - SSE_PSRLD IMM_8 +66.0f72/4 MI XMM IMM8 - - SSE_PSRAD IMM_8 +66.0f72/6 MI XMM IMM8 - - SSE_PSLLD IMM_8 +66.0f73/2 MI XMM IMM8 - - SSE_PSRLQ IMM_8 +66.0f73/3 MI XMM IMM8 - - SSE_PSRLDQ IMM_8 +66.0f73/6 MI XMM IMM8 - - SSE_PSLLQ IMM_8 +66.0f73/7 MI XMM IMM8 - - SSE_PSLLDQ IMM_8 +66.0f74 RM XMM XMM - - SSE_PCMPEQB +66.0f75 RM XMM XMM - - SSE_PCMPEQW +66.0f76 RM XMM XMM - - SSE_PCMPEQD +66.0f7c RM XMM XMM - - SSE_HADDPD +F2.0f7c RM XMM XMM - - SSE_HADDPS +66.0f7d RM XMM XMM - - SSE_HSUBPD +F2.0f7d RM XMM XMM - - SSE_HSUBPS +66.W0.0f7e MR GP XMM32 - - SSE_MOVD_X2G +66.W1.0f7e MR GP XMM64 - - SSE_MOVQ_X2G +F3.0f7e RM XMM64 XMM64 - - SSE_MOVQ_X2X +66.0f7f MR XMM XMM - - SSE_MOVDQA +F3.0f7f MR XMM XMM - - SSE_MOVDQU +NP.0fae//0 M GP - - - FXSAVE +NP.0fae//1 M GP - - - FXRSTOR +NP.0fae//2 M GP - - - LDMXCSR +NP.0fae//3 M GP - - - STMXCSR +NP.0fae//e8 NP - - - - LFENCE +NP.0fae//f0 NP - - - - MFENCE +NP.0fae//f8 NP - - - - SFENCE +NP.0fc2 RMI XMM XMM IMM8 - SSE_CMPPS IMM_8 +66.0fc2 RMI XMM XMM IMM8 - SSE_CMPPD IMM_8 +F3.0fc2 RMI XMM XMM IMM8 - SSE_CMPSS IMM_8 +F2.0fc2 RMI XMM XMM IMM8 - SSE_CMPSD IMM_8 +66.0fc4 RMI XMM GP IMM8 - SSE_PINSRW IMM_8 +66.0fc5 RMI GP XMM IMM8 - SSE_PEXTRW IMM_8 +NP.0fc6 RMI XMM XMM IMM8 - SSE_SHUFPS IMM_8 +66.0fc6 RMI XMM XMM IMM8 - SSE_SHUFPD IMM_8 +NP.0fd0 RM XMM XMM - - SSE_ADDSUBPS +66.0fd0 RM XMM XMM - - SSE_ADDSUBPD +66.0fd1 RM XMM XMM - - SSE_PSRLW +66.0fd2 RM XMM XMM - - SSE_PSRLD +66.0fd3 RM XMM XMM - - SSE_PSRLQ +66.0fd4 RM XMM XMM - - SSE_PADDQ +66.0fd5 RM XMM XMM - - SSE_PMULLW +66.0fd6 MR XMM64 XMM64 - - SSE_MOVQ_X2X +66.0fd7 RM GP XMM - - SSE_PMOVMSKB DEF64 +66.0fd8 RM XMM XMM - - SSE_PSUBUSB +66.0fd9 RM XMM XMM - - SSE_PSUBUSW +66.0fda RM XMM XMM - - SSE_PMINUB +66.0fdb RM XMM XMM - - SSE_PAND +66.0fdc RM XMM XMM - - SSE_PADDUSB +66.0fdd RM XMM XMM - - SSE_PADDUSW +66.0fde RM XMM XMM - - SSE_PMAXUB +66.0fdf RM XMM XMM - - SSE_PANDN +66.0fe0 RM XMM XMM - - SSE_PAVGB +66.0fe1 RM XMM XMM - - SSE_PSRAW +66.0fe2 RM XMM XMM - - SSE_PSRAD +66.0fe3 RM XMM XMM - - SSE_PAVGW +66.0fe4 RM XMM XMM - - SSE_PMULHUW +66.0fe5 RM XMM XMM - - SSE_PMULHW +66.0fe6 RM XMM64 XMM - - SSE_CVTTPD2DQ +F3.0fe6 RM XMM XMM64 - - SSE_CVTDQ2PD +F2.0fe6 RM XMM64 XMM - - SSE_CVTPD2DQ +66.0fe7 MR XMM XMM - - SSE_MOVNTDQ +66.0fe8 RM XMM XMM - - SSE_PSUBSB +66.0fe9 RM XMM XMM - - SSE_PSUBSW +66.0feb RM XMM XMM - - SSE_POR +66.0fec RM XMM XMM - - SSE_PADDSB +66.0fea RM XMM XMM - - SSE_PMINSW +66.0fee RM XMM XMM - - SSE_PMAXSW +66.0fed RM XMM XMM - - SSE_PADDSW +66.0fef RM XMM XMM - - SSE_PXOR +F2.0ff0 RM XMM XMM - - SSE_LDDQU +66.0ff1 RM XMM XMM - - SSE_PSLLW +66.0ff2 RM XMM XMM - - SSE_PSLLD +66.0ff3 RM XMM XMM - - SSE_PSLLQ +66.0ff4 RM XMM XMM - - SSE_PMULUDQ +66.0ff5 RM XMM XMM - - SSE_PMADDWD +66.0ff6 RM XMM XMM - - SSE_PSADBW +66.0ff7 RM XMM XMM - - SSE_MASKMOVDQU +66.0ff8 RM XMM XMM - - SSE_PSUBB +66.0ff9 RM XMM XMM - - SSE_PSUBW +66.0ffa RM XMM XMM - - SSE_PSUBD +66.0ffb RM XMM XMM - - SSE_PSUBQ +66.0ffc RM XMM XMM - - SSE_PADDB +66.0ffd RM XMM XMM - - SSE_PADDW +66.0ffe RM XMM XMM - - SSE_PADDD +# +66.0f3800 RM XMM XMM - - SSE_PSHUFB +66.0f3801 RM XMM XMM - - SSE_PHADDW +66.0f3802 RM XMM XMM - - SSE_PHADDD +66.0f3803 RM XMM XMM - - SSE_PHADDSW +66.0f3804 RM XMM XMM - - SSE_PMADDUBSW +66.0f3805 RM XMM XMM - - SSE_PHSUBW +66.0f3806 RM XMM XMM - - SSE_PHSUBD +66.0f3807 RM XMM XMM - - SSE_PHSUBSW +66.0f3808 RM XMM XMM - - SSE_PSIGNB +66.0f3809 RM XMM XMM - - SSE_PSIGNW +66.0f380a RM XMM XMM - - SSE_PSIGND +66.0f380b RM XMM XMM - - SSE_PMULHRSW +66.0f3810 RM XMM XMM - - SSE_PBLENDVB +66.0f3814 RMA XMM XMM XMM - SSE_BLENDVPS +66.0f3815 RMA XMM XMM XMM - SSE_BLENDVPD +66.0f3817 RM XMM XMM - - SSE_PTEST +66.0f381c RM XMM XMM - - SSE_PABSB +66.0f381d RM XMM XMM - - SSE_PABSW +66.0f381e RM XMM XMM - - SSE_PABSD +66.0f3820 RM XMM XMM - - SSE_PMOVSXBW +66.0f3821 RM XMM XMM - - SSE_PMOVSXBD +66.0f3822 RM XMM XMM - - SSE_PMOVSXBQ +66.0f3823 RM XMM XMM - - SSE_PMOVSXWD +66.0f3824 RM XMM XMM - - SSE_PMOVSXWQ +66.0f3825 RM XMM XMM - - SSE_PMOVSXDQ +66.0f3828 RM XMM XMM - - SSE_PMULDQ +66.0f3829 RM XMM XMM - - SSE_PCMPEQQ +66.0f382a RM XMM XMM - - SSE_MOVNTDQA +66.0f382b RM XMM XMM - - SSE_PACKUSDW +66.0f3830 RM XMM XMM - - SSE_PMOVZXBW +66.0f3831 RM XMM XMM - - SSE_PMOVZXBD +66.0f3832 RM XMM XMM - - SSE_PMOVZXBQ +66.0f3833 RM XMM XMM - - SSE_PMOVZXWD +66.0f3834 RM XMM XMM - - SSE_PMOVZXWQ +66.0f3835 RM XMM XMM - - SSE_PMOVZXDQ +66.0f3837 RM XMM XMM - - SSE_PCMPGTQ +66.0f3838 RM XMM XMM - - SSE_PMINSB +66.0f3839 RM XMM XMM - - SSE_PMINSD +66.0f383a RM XMM XMM - - SSE_PMINUW +66.0f383b RM XMM XMM - - SSE_PMINUD +66.0f383c RM XMM XMM - - SSE_PMAXSB +66.0f383d RM XMM XMM - - SSE_PMAXSD +66.0f383e RM XMM XMM - - SSE_PMAXUW +66.0f383f RM XMM XMM - - SSE_PMAXUD +66.0f3840 RM XMM XMM - - SSE_PMULLD +66.0f3841 RM XMM XMM - - SSE_PHMINPOSUW +# +66.0f3a08 RMI XMM XMM IMM - SSE_ROUNDPS SIZE_8 IMM_8 +66.0f3a09 RMI XMM XMM IMM - SSE_ROUNDPD SIZE_8 IMM_8 +66.0f3a0a RMI XMM32 XMM32 IMM - SSE_ROUNDSS SIZE_8 IMM_8 +66.0f3a0b RMI XMM64 XMM64 IMM - SSE_ROUNDSD SIZE_8 IMM_8 +66.0f3a0c RMI XMM XMM IMM - SSE_BLENDPS SIZE_8 IMM_8 +66.0f3a0d RMI XMM XMM IMM - SSE_BLENDPD SIZE_8 IMM_8 +66.0f3a0e RMI XMM XMM IMM - SSE_PBLENDW SIZE_8 IMM_8 +66.0f3a0f RMI XMM XMM IMM - SSE_PALIGNR SIZE_8 IMM_8 +66.0f3a14 MRI GP8 XMM IMM - SSE_PEXTRB SIZE_8 IMM_8 +66.0f3a15 MRI GP16 XMM IMM - SSE_PEXTRW SIZE_8 IMM_8 +66.W0.0f3a16 MRI GP XMM IMM - SSE_PEXTRD SIZE_8 IMM_8 +66.W1.0f3a16 MRI GP XMM IMM - SSE_PEXTRQ SIZE_8 IMM_8 +66.0f3a17 MRI GP32 XMM IMM - SSE_EXTRACTPS SIZE_8 IMM_8 +66.0f3a20 RMI XMM GP8 IMM - SSE_PINSRB SIZE_8 IMM_8 +66.0f3a21 RMI XMM XMM32 IMM - SSE_INSERTPS SIZE_8 IMM_8 +66.W0.0f3a22 RMI XMM GP IMM - SSE_PINSRD SIZE_8 IMM_8 +66.W1.0f3a22 RMI XMM GP IMM - SSE_PINSRQ SIZE_8 IMM_8 +66.0f3a40 RMI XMM XMM IMM - SSE_DPPS SIZE_8 IMM_8 +66.0f3a41 RMI XMM XMM IMM - SSE_DPPD SIZE_8 IMM_8 +66.0f3a42 RMI XMM XMM IMM - SSE_MPSADBW SIZE_8 IMM_8 +66.0f3a44 RMI XMM XMM IMM - SSE_PCLMULQDQ SIZE_8 IMM_8 +66.0f3a60 RMI XMM XMM IMM - SSE_PCMPESTRM SIZE_8 IMM_8 +66.0f3a61 RMI XMM XMM IMM - SSE_PCMPESTRI SIZE_8 IMM_8 +66.0f3a62 RMI XMM XMM IMM - SSE_PCMPISTRM SIZE_8 IMM_8 +66.0f3a63 RMI XMM XMM IMM - SSE_PCMPISTRI SIZE_8 IMM_8 +# +66.0f38db RM XMM XMM - - AESIMC +66.0f38dc RM XMM XMM - - AESENC +66.0f38dd RM XMM XMM - - AESENCLAST +66.0f38de RM XMM XMM - - AESDEC +66.0f38df RM XMM XMM - - AESDECLAST +66.0f3adf RMI XMM XMM IMM - AESKEYGENASSIST IMM_8 +# +# AVX +VEX.NP.0f10 RM XMM XMM - - VMOVUPS +VEX.66.0f10 RM XMM XMM - - VMOVUPD +VEX.F3.0f10 RVM XMM32 XMM32 XMM32 - VMOVSS +VEX.F2.0f10 RVM XMM64 XMM64 XMM64 - VMOVSD +VEX.NP.0f11 MR XMM XMM - - VMOVUPS +VEX.66.0f11 MR XMM XMM - - VMOVUPD +VEX.F3.0f11 MVR XMM32 XMM32 XMM32 - VMOVSS +VEX.F2.0f11 MVR XMM64 XMM64 XMM64 - VMOVSD +VEX.NP.L0.0f12 RVM XMM XMM XMM64 - VMOVLPS +VEX.66.L0.0f12 RVM XMM XMM XMM64 - VMOVLPD +VEX.F2.0f12 RM XMM XMM - - VMOVDDUP +VEX.F3.0f12 RM XMM XMM - - VMOVSLDUP +VEX.NP.L0.0f13 RM XMM64 XMM - - VMOVLPS +VEX.66.L0.0f13 RM XMM64 XMM - - VMOVLPD +VEX.NP.0f14 RVM XMM XMM XMM - VUNPACKLPS +VEX.66.0f14 RVM XMM XMM XMM - VUNPACKLPD +VEX.NP.0f15 RVM XMM XMM XMM - VUNPACKHPS +VEX.66.0f15 RVM XMM XMM XMM - VUNPACKHPD +VEX.NP.L0.0f16 RVM XMM XMM XMM64 - VMOVHPS +VEX.66.L0.0f16 RVM XMM XMM XMM64 - VMOVHPD +VEX.F3.0f16 RM XMM XMM - - VMOVSHDUP +VEX.NP.L0.0f17 RM XMM64 XMM - - VMOVHPS +VEX.66.L0.0f17 RM XMM64 XMM - - VMOVHPD +VEX.NP.0f28 RM XMM XMM - - VMOVAPS +VEX.66.0f28 RM XMM XMM - - VMOVAPD +VEX.NP.0f29 MR XMM XMM - - VMOVAPS +VEX.66.0f29 MR XMM XMM - - VMOVAPD +VEX.NP.0f2b MR XMM XMM - - VMOVNTPS +VEX.66.0f2b MR XMM XMM - - VMOVNTPD +VEX.NP.0f2e RM XMM32 XMM32 - - VUCOMISS +VEX.66.0f2e RM XMM64 XMM64 - - VUCOMISD +VEX.NP.0f2f RM XMM32 XMM32 - - VCOMISS +VEX.66.0f2f RM XMM64 XMM64 - - VCOMISD +VEX.NP.0f50 RM GP XMM - - VMOVMSKPS DEF64 +VEX.66.0f50 RM GP XMM - - VMOVMSKPD DEF64 +VEX.NP.0f51 RVM XMM XMM XMM - VSQRTPS +VEX.66.0f51 RVM XMM XMM XMM - VSQRTPD +VEX.F3.0f51 RVM XMM32 XMM32 XMM32 - VSQRTSS +VEX.F2.0f51 RVM XMM64 XMM64 XMM64 - VSQRTSD +VEX.NP.0f52 RVM XMM XMM XMM - VRSQRTPS +VEX.F3.0f52 RVM XMM32 XMM32 XMM32 - VRSQRTSS +VEX.NP.0f53 RVM XMM XMM XMM - VRCPPS +VEX.F3.0f53 RVM XMM32 XMM32 XMM32 - VRCPSS +VEX.NP.0f54 RVM XMM XMM XMM - VANDPS +VEX.66.0f54 RVM XMM XMM XMM - VANDPD +VEX.NP.0f55 RVM XMM XMM XMM - VANDNPS +VEX.66.0f55 RVM XMM XMM XMM - VANDNPD +VEX.NP.0f56 RVM XMM XMM XMM - VORPS +VEX.66.0f56 RVM XMM XMM XMM - VORPD +VEX.NP.0f57 RVM XMM XMM XMM - VXORPS +VEX.66.0f57 RVM XMM XMM XMM - VXORPD +VEX.NP.0f58 RVM XMM XMM XMM - VADDPS +VEX.66.0f58 RVM XMM XMM XMM - VADDPD +VEX.F3.0f58 RVM XMM32 XMM32 XMM32 - VADDSS +VEX.F2.0f58 RVM XMM64 XMM64 XMM64 - VADDSD +VEX.NP.0f59 RVM XMM XMM XMM - VMULPS +VEX.66.0f59 RVM XMM XMM XMM - VMULPD +VEX.F3.0f59 RVM XMM32 XMM32 XMM32 - VMULSS +VEX.F2.0f59 RVM XMM64 XMM64 XMM64 - VMULSD +VEX.NP.0f5c RVM XMM XMM XMM - VSUBPS +VEX.66.0f5c RVM XMM XMM XMM - VSUBPD +VEX.F3.0f5c RVM XMM32 XMM32 XMM32 - VSUBSS +VEX.F2.0f5c RVM XMM64 XMM64 XMM64 - VSUBSD +VEX.NP.0f5d RVM XMM XMM XMM - VMINPS +VEX.66.0f5d RVM XMM XMM XMM - VMINPD +VEX.F3.0f5d RVM XMM32 XMM32 XMM32 - VMINSS +VEX.F2.0f5d RVM XMM64 XMM64 XMM64 - VMINSD +VEX.NP.0f5e RVM XMM XMM XMM - VDIVPS +VEX.66.0f5e RVM XMM XMM XMM - VDIVPD +VEX.F3.0f5e RVM XMM32 XMM32 XMM32 - VDIVSS +VEX.F2.0f5e RVM XMM64 XMM64 XMM64 - VDIVSD +VEX.NP.0f5f RVM XMM XMM XMM - VMAXPS +VEX.66.0f5f RVM XMM XMM XMM - VMAXPD +VEX.F3.0f5f RVM XMM32 XMM32 XMM32 - VMAXSS +VEX.F2.0f5f RVM XMM64 XMM64 XMM64 - VMAXSD +VEX.66.0f60 RVM XMM XMM XMM - VPUNPCKLBW +VEX.66.0f61 RVM XMM XMM XMM - VPUNPCKLWD +VEX.66.0f62 RVM XMM XMM XMM - VPUNPCKLDQ +VEX.66.0f63 RVM XMM XMM XMM - VPACKSSWB +VEX.66.0f64 RVM XMM XMM XMM - VPCMPGTB +VEX.66.0f65 RVM XMM XMM XMM - VPCMPGTW +VEX.66.0f66 RVM XMM XMM XMM - VPCMPGTD +VEX.66.0f67 RVM XMM XMM XMM - VPACKUSWB +VEX.66.0f68 RVM XMM XMM XMM - VPUNPCKHBW +VEX.66.0f69 RVM XMM XMM XMM - VPUNPCKHWD +VEX.66.0f6a RVM XMM XMM XMM - VPUNPCKHDQ +VEX.66.0f6b RVM XMM XMM XMM - VPACKSSDW +VEX.66.0f6c RVM XMM XMM XMM - VPUNPCKLQDQ +VEX.66.0f6d RVM XMM XMM XMM - VPUNPCKHQDQ +VEX.66.W0.L0.0f6e RM XMM32 GP - - VMOVD_G2X +VEX.66.W1.L0.0f6e RM XMM64 GP - - VMOVQ_G2X ONLY64 +VEX.66.0f6f RM XMM XMM - - VMOVDQA +VEX.F3.0f6f RM XMM XMM - - VMOVDQU +VEX.66.0f70 RMI XMM XMM IMM8 - VPSHUFD IMM_8 +VEX.F3.0f70 RMI XMM XMM IMM8 - VPSHUFHW IMM_8 +VEX.F2.0f70 RMI XMM XMM IMM8 - VPSHUFLW IMM_8 +VEX.66.0f71/2 VMI XMM XMM IMM8 - VPSRLW IMM_8 +VEX.66.0f71/4 VMI XMM XMM IMM8 - VPSRAW IMM_8 +VEX.66.0f71/6 VMI XMM XMM IMM8 - VPSLLW IMM_8 +VEX.66.0f72/2 VMI XMM XMM IMM8 - VPSRLD IMM_8 +VEX.66.0f72/4 VMI XMM XMM IMM8 - VPSRAD IMM_8 +VEX.66.0f72/6 VMI XMM XMM IMM8 - VPSLLD IMM_8 +VEX.66.0f73/2 VMI XMM XMM IMM8 - VPSRLQ IMM_8 +VEX.66.0f73/3 VMI XMM XMM IMM8 - VPSRLDQ IMM_8 +VEX.66.0f73/6 VMI XMM XMM IMM8 - VPSLLQ IMM_8 +VEX.66.0f73/7 VMI XMM XMM IMM8 - VPSLLDQ IMM_8 +VEX.66.0f74 RVM XMM XMM XMM - VPCMPEQB +VEX.66.0f75 RVM XMM XMM XMM - VPCMPEQW +VEX.66.0f76 RVM XMM XMM XMM - VPCMPEQD +VEX.NP.0f77 NP - - - - VZERO +VEX.66.0f7c RVM XMM XMM XMM - VHADDPD +VEX.F2.0f7c RVM XMM XMM XMM - VHADDPS +VEX.66.0f7d RVM XMM XMM XMM - VHSUBPD +VEX.F2.0f7d RVM XMM XMM XMM - VHSUBPS +VEX.66.W0.L0.0f7e MR GP XMM32 - - VMOVD_X2G +VEX.66.W1.L0.0f7e MR GP XMM64 - - VMOVQ_X2G ONLY64 +VEX.F3.L0.0f7e RM XMM64 XMM64 - - VMOVQ_X2X +VEX.66.0f7f MR XMM XMM - - VMOVDQA +VEX.F3.0f7f MR XMM XMM - - VMOVDQU +VEX.NP.0fae//2 M GP32 - - - VLDMXCSR +VEX.NP.0fae//3 M GP32 - - - VSTMXCSR +VEX.NP.0fc2 RVMI XMM XMM XMM IMM8 VCMPPS IMM_8 +VEX.66.0fc2 RVMI XMM XMM XMM IMM8 VCMPPD IMM_8 +VEX.F3.0fc2 RVMI XMM XMM XMM IMM8 VCMPSS IMM_8 +VEX.F2.0fc2 RVMI XMM XMM XMM IMM8 VCMPSD IMM_8 +VEX.NP.0fc6 RVMI XMM XMM XMM IMM8 VSHUFPS IMM_8 +VEX.66.0fc6 RVMI XMM XMM XMM IMM8 VSHUFPD IMM_8 +VEX.NP.0fd0 RVM XMM XMM XMM - VADDSUBPS +VEX.66.0fd0 RVM XMM XMM XMM - VADDSUBPD +VEX.66.0fd1 RVM XMM XMM XMM - VPSRLW +VEX.66.0fd2 RVM XMM XMM XMM - VPSRLD +VEX.66.0fd3 RVM XMM XMM XMM - VPSRLQ +VEX.66.0fd4 RVM XMM XMM XMM - VPADDQ +VEX.66.0fd5 RVM XMM XMM XMM - VPMULLW +VEX.66.L0.0fd6 MR XMM64 XMM64 - - VMOVQ_X2X +VEX.66.0fd7 RM GP XMM - - VPMOVMSKB DEF64 +VEX.66.0fd8 RVM XMM XMM XMM - VPSUBUSB +VEX.66.0fd9 RVM XMM XMM XMM - VPSUBUSW +VEX.66.0fda RVM XMM XMM XMM - VPMINUB +VEX.66.0fdb RVM XMM XMM XMM - VPAND +VEX.66.0fdc RVM XMM XMM XMM - VPADDUSB +VEX.66.0fdd RVM XMM XMM XMM - VPADDUSW +VEX.66.0fde RVM XMM XMM XMM - VPMAXUB +VEX.66.0fdf RVM XMM XMM XMM - VPANDN +VEX.66.0fe7 MR XMM XMM - - VMOVNTDQ +VEX.66.0fe8 RVM XMM XMM XMM - VPSUBSB +VEX.66.0fe9 RVM XMM XMM XMM - VPSUBSW +VEX.66.0feb RVM XMM XMM XMM - VPOR +VEX.66.0fec RVM XMM XMM XMM - VPADDSB +VEX.66.0fea RVM XMM XMM XMM - VPMINSW +VEX.66.0fed RVM XMM XMM XMM - VPADDSW +VEX.66.0fee RVM XMM XMM XMM - VPMAXSW +VEX.66.0fef RVM XMM XMM XMM - VPXOR +VEX.F2.0ff0 RM XMM XMM - - VLDDQU +VEX.NP.L0.0ff7 RM XMM XMM - - VMASKMOVDQU +VEX.66.0ff8 RVM XMM XMM XMM - VPSUBB +VEX.66.0ff9 RVM XMM XMM XMM - VPSUBW +VEX.66.0ffa RVM XMM XMM XMM - VPSUBD +VEX.66.0ffb RVM XMM XMM XMM - VPSUBQ +VEX.66.0ffc RVM XMM XMM XMM - VPADDB +VEX.66.0ffd RVM XMM XMM XMM - VPADDW +VEX.66.0ffe RVM XMM XMM XMM - VPADDD +VEX.66.0f3800 RVM XMM XMM XMM - VPSHUFB +VEX.66.0f3801 RVM XMM XMM XMM - VPHADDW +VEX.66.0f3802 RVM XMM XMM XMM - VPHADDD +VEX.66.0f3803 RVM XMM XMM XMM - VPHADDSW +VEX.66.0f3804 RVM XMM XMM XMM - VPMADDUBSW +VEX.66.0f3805 RVM XMM XMM XMM - VPHSUBW +VEX.66.0f3806 RVM XMM XMM XMM - VPHSUBD +VEX.66.0f3807 RVM XMM XMM XMM - VPHSUBSW +VEX.66.0f3808 RVM XMM XMM XMM - VPSIGNB +VEX.66.0f3809 RVM XMM XMM XMM - VPSIGNW +VEX.66.0f380a RVM XMM XMM XMM - VPSIGND +VEX.66.0f380b RVM XMM XMM XMM - VPMULHRSW +VEX.66.W0.0f380c RVM XMM XMM XMM - VPERMILPS +VEX.66.W0.0f380d RVM XMM XMM XMM - VPERMILPD +VEX.66.W0.0f380e RM XMM XMM - - VTESTPS +VEX.66.W0.0f380f RM XMM XMM - - VTESTPD +VEX.66.W0.0f3813 RM XMM XMM - - VCVTPH2PS +VEX.66.W0.0f3814 RVMR XMM XMM XMM XMM VBLENDVPS +VEX.66.W0.0f3815 RVMR XMM XMM XMM XMM VBLENDVPD +VEX.66.W0.L1.0f3816 RVM XMM XMM XMM - VPERMPS +VEX.66.0f3817 RM XMM XMM - - VPTEST +VEX.66.W0.0f3818 RM XMM XMM32 - - VBROADCASTSS +VEX.66.W0.L1.0f3819 RM XMM XMM64 - - VBROADCASTSD +VEX.66.W0.L1.0f381a RM XMM XMM128 - - VBROADCASTF128 +VEX.66.0f381c RM XMM XMM - - VPABSB +VEX.66.0f381d RM XMM XMM - - VPABSW +VEX.66.0f381e RM XMM XMM - - VPABSD +VEX.66.0f3820 RM XMM XMM - - VPMOVSXBW +VEX.66.0f3821 RM XMM XMM - - VPMOVSXBD +VEX.66.0f3822 RM XMM XMM - - VPMOVSXBQ +VEX.66.0f3823 RM XMM XMM - - VPMOVSXWD +VEX.66.0f3824 RM XMM XMM - - VPMOVSXWQ +VEX.66.0f3825 RM XMM XMM - - VPMOVSXDQ +VEX.66.0f382a RM XMM XMM - - VMOVNTDQA +VEX.66.W0.0f382c RVM XMM XMM XMM - VMASKMOVPS +VEX.66.W0.0f382d RVM XMM XMM XMM - VMASKMOVPD +VEX.66.W0.0f382e MVR XMM XMM XMM - VMASKMOVPS +VEX.66.W0.0f382f MVR XMM XMM XMM - VMASKMOVPD +VEX.66.W0.L1.0f3836 RVM XMM XMM XMM - VPERMD +VEX.66.0f3838 RVM XMM XMM XMM - VPMINSB +VEX.66.0f3839 RVM XMM XMM XMM - VPMINSD +VEX.66.0f383a RVM XMM XMM XMM - VPMINUW +VEX.66.0f383b RVM XMM XMM XMM - VPMINUD +VEX.66.0f383c RVM XMM XMM XMM - VPMAXSB +VEX.66.0f383d RVM XMM XMM XMM - VPMAXSD +VEX.66.0f383e RVM XMM XMM XMM - VPMAXUW +VEX.66.0f383f RVM XMM XMM XMM - VPMAXUD +VEX.66.W0.0f3845 RVM XMM XMM XMM - VPSRLVD +VEX.66.W1.0f3845 RVM XMM XMM XMM - VPSRLVQ +VEX.66.W0.0f3846 RVM XMM XMM XMM - VPSRAVD +VEX.66.W1.0f3846 RVM XMM XMM XMM - VPSRAVQ +VEX.66.W0.0f3847 RVM XMM XMM XMM - VPSLLVD +VEX.66.W1.0f3847 RVM XMM XMM XMM - VPSLLVQ +VEX.66.W0.0f3858 RM XMM XMM32 - - VPBROADCASTD +VEX.66.W0.0f3859 RM XMM XMM64 - - VPBROADCASTQ +VEX.66.W0.L1.0f385a RM XMM XMM128 - - VPBROADCASTI128 +VEX.66.W0.0f3878 RM XMM XMM8 - - VPBROADCASTB +VEX.66.W0.0f3879 RM XMM XMM16 - - VPBROADCASTW +VEX.66.W0.0f388c RVM XMM XMM XMM - VPMASKMOVD +VEX.66.W1.0f388c RVM XMM XMM XMM - VPMASKMOVQ +VEX.66.W0.0f388e MVR XMM XMM XMM - VPMASKMOVD +VEX.66.W1.0f388e MVR XMM XMM XMM - VPMASKMOVQ +# TODO: VSIB encoding +#VEX.66.W0.0f3890 RMV XMM XMM XMM - VPGATHERDD VSIB +#VEX.66.W1.0f3890 RMV XMM XMM XMM - VPGATHERDQ VSIB +#VEX.66.W0.0f3891 RMV XMM XMM XMM - VPGATHERQD VSIB +#VEX.66.W1.0f3891 RMV XMM XMM XMM - VPGATHERQQ VSIB +#VEX.66.W0.0f3892 RMV XMM XMM XMM - VGATHERDPS VSIB +#VEX.66.W1.0f3892 RMV XMM XMM XMM - VGATHERDPD VSIB +#VEX.66.W0.0f3893 RMV XMM XMM XMM - VGATHERQPS VSIB +#VEX.66.W1.0f3893 RMV XMM XMM XMM - VGATHERQPD VSIB +VEX.66.W0.0f3896 RVM XMM XMM XMM - VFMADDADD132PS +VEX.66.W1.0f3896 RVM XMM XMM XMM - VFMADDADD132PD +VEX.66.W0.0f3897 RVM XMM XMM XMM - VFMSUBADD132PS +VEX.66.W1.0f3897 RVM XMM XMM XMM - VFMSUBADD132PD +VEX.66.W0.0f3898 RVM XMM XMM XMM - VFMADD132PS +VEX.66.W1.0f3898 RVM XMM XMM XMM - VFMADD132PD +VEX.66.W0.0f3899 RVM XMM32 XMM32 XMM32 - VFMADD132SS +VEX.66.W1.0f3899 RVM XMM64 XMM64 XMM64 - VFMADD132SD +VEX.66.W0.0f389a RVM XMM XMM XMM - VFMSUB132PS +VEX.66.W1.0f389a RVM XMM XMM XMM - VFMSUB132PD +VEX.66.W0.0f389b RVM XMM32 XMM32 XMM32 - VFMSUB132SS +VEX.66.W1.0f389b RVM XMM64 XMM64 XMM64 - VFMSUB132SD +VEX.66.W0.0f389c RVM XMM XMM XMM - VFNMADD132PS +VEX.66.W1.0f389c RVM XMM XMM XMM - VFNMADD132PD +VEX.66.W0.0f389d RVM XMM32 XMM32 XMM32 - VFNMADD132SS +VEX.66.W1.0f389d RVM XMM64 XMM64 XMM64 - VFNMADD132SD +VEX.66.W0.0f389e RVM XMM XMM XMM - VFNMSUB132PS +VEX.66.W1.0f389e RVM XMM XMM XMM - VFNMSUB132PD +VEX.66.W0.0f389f RVM XMM32 XMM32 XMM32 - VFNMSUB132SS +VEX.66.W1.0f389f RVM XMM64 XMM64 XMM64 - VFNMSUB132SD +VEX.66.W0.0f38a6 RVM XMM XMM XMM - VFMADDADD213PS +VEX.66.W1.0f38a6 RVM XMM XMM XMM - VFMADDADD213PD +VEX.66.W0.0f38a7 RVM XMM XMM XMM - VFMSUBADD213PS +VEX.66.W1.0f38a7 RVM XMM XMM XMM - VFMSUBADD213PD +VEX.66.W0.0f38a8 RVM XMM XMM XMM - VFMADD213PS +VEX.66.W1.0f38a8 RVM XMM XMM XMM - VFMADD213PD +VEX.66.W0.0f38a9 RVM XMM32 XMM32 XMM32 - VFMADD213SS +VEX.66.W1.0f38a9 RVM XMM64 XMM64 XMM64 - VFMADD213SD +VEX.66.W0.0f38aa RVM XMM XMM XMM - VFMSUB213PS +VEX.66.W1.0f38aa RVM XMM XMM XMM - VFMSUB213PD +VEX.66.W0.0f38ab RVM XMM32 XMM32 XMM32 - VFMSUB213SS +VEX.66.W1.0f38ab RVM XMM64 XMM64 XMM64 - VFMSUB213SD +VEX.66.W0.0f38ac RVM XMM XMM XMM - VFNMADD213PS +VEX.66.W1.0f38ac RVM XMM XMM XMM - VFNMADD213PD +VEX.66.W0.0f38ad RVM XMM32 XMM32 XMM32 - VFNMADD213SS +VEX.66.W1.0f38ad RVM XMM64 XMM64 XMM64 - VFNMADD213SD +VEX.66.W0.0f38ae RVM XMM XMM XMM - VFNMSUB213PS +VEX.66.W1.0f38ae RVM XMM XMM XMM - VFNMSUB213PD +VEX.66.W0.0f38af RVM XMM32 XMM32 XMM32 - VFNMSUB213SS +VEX.66.W1.0f38af RVM XMM64 XMM64 XMM64 - VFNMSUB213SD +VEX.66.W0.0f38b6 RVM XMM XMM XMM - VFMADDADD231PS +VEX.66.W1.0f38b6 RVM XMM XMM XMM - VFMADDADD231PD +VEX.66.W0.0f38b7 RVM XMM XMM XMM - VFMSUBADD231PS +VEX.66.W1.0f38b7 RVM XMM XMM XMM - VFMSUBADD231PD +VEX.66.W0.0f38b8 RVM XMM XMM XMM - VFMADD231PS +VEX.66.W1.0f38b8 RVM XMM XMM XMM - VFMADD231PD +VEX.66.W0.0f38b9 RVM XMM32 XMM32 XMM32 - VFMADD231SS +VEX.66.W1.0f38b9 RVM XMM64 XMM64 XMM64 - VFMADD231SD +VEX.66.W0.0f38ba RVM XMM XMM XMM - VFMSUB231PS +VEX.66.W1.0f38ba RVM XMM XMM XMM - VFMSUB231PD +VEX.66.W0.0f38bb RVM XMM32 XMM32 XMM32 - VFMSUB231SS +VEX.66.W1.0f38bb RVM XMM64 XMM64 XMM64 - VFMSUB231SD +VEX.66.W0.0f38bc RVM XMM XMM XMM - VFNMADD231PS +VEX.66.W1.0f38bc RVM XMM XMM XMM - VFNMADD231PD +VEX.66.W0.0f38bd RVM XMM32 XMM32 XMM32 - VFNMADD231SS +VEX.66.W1.0f38bd RVM XMM64 XMM64 XMM64 - VFNMADD231SD +VEX.66.W0.0f38be RVM XMM XMM XMM - VFNMSUB231PS +VEX.66.W1.0f38be RVM XMM XMM XMM - VFNMSUB231PD +VEX.66.W0.0f38bf RVM XMM32 XMM32 XMM32 - VFNMSUB231SS +VEX.66.W1.0f38bf RVM XMM64 XMM64 XMM64 - VFNMSUB231SD +VEX.66.W1.L1.0f3a00 VMI XMM XMM IMM8 - VPERMQ IMM_8 +VEX.66.W1.L1.0f3a01 VMI XMM XMM IMM8 - VPERMPD IMM_8 +VEX.66.W0.0f3a02 RVMI XMM XMM XMM IMM8 VPBLENDD IMM_8 +VEX.66.W0.0f3a04 RMI XMM XMM IMM8 - VPERMILPS IMM_8 +VEX.66.W0.0f3a05 RMI XMM XMM IMM8 - VPERMILPD IMM_8 +VEX.66.W0.L1.0f3a06 RVMI XMM XMM XMM IMM8 VPERM2F128 IMM_8 +VEX.66.0f3a08 RVMI XMM XMM XMM IMM VROUNDPS SIZE_8 IMM_8 +VEX.66.0f3a09 RVMI XMM XMM XMM IMM VROUNDPD SIZE_8 IMM_8 +VEX.66.0f3a0a RVMI XMM32 XMM32 XMM32 IMM VROUNDSS SIZE_8 IMM_8 +VEX.66.0f3a0b RVMI XMM64 XMM64 XMM64 IMM VROUNDSD SIZE_8 IMM_8 +VEX.66.0f3a0c RVMI XMM XMM XMM IMM VBLENDPS SIZE_8 IMM_8 +VEX.66.0f3a0d RVMI XMM XMM XMM IMM VBLENDPD SIZE_8 IMM_8 +VEX.66.0f3a0e RVMI XMM XMM XMM IMM VPBLENDW SIZE_8 IMM_8 +VEX.66.0f3a0f RVMI XMM XMM XMM IMM VPALIGNR SIZE_8 IMM_8 +VEX.66.L0.0f3a17 MRI GP32 XMM IMM - VEXTRACTPS SIZE_8 IMM_8 +VEX.66.W0.L1.0f3a18 RVMI XMM XMM XMM IMM8 VINSERTF128 IMM_8 +VEX.66.W0.L1.0f3a19 MRI XMM XMM IMM8 - VEXTRACTF128 IMM_8 +VEX.66.W0.L1.0f3a1d MRI XMM XMM IMM8 - VCVTPS2PH IMM_8 +VEX.66.L0.0f3a21 RVMI XMM XMM XMM32 IMM VINSERTPS SIZE_8 IMM_8 +VEX.66.W0.L1.0f3a38 RVMI XMM XMM XMM IMM8 VINSERTI128 IMM_8 +VEX.66.W0.L1.0f3a39 MRI XMM XMM IMM8 - VEXTRACTI128 IMM_8 +VEX.66.0f3a40 RVMI XMM XMM XMM IMM VDPPS SIZE_8 IMM_8 +VEX.66.0f3a41 RVMI XMM XMM XMM IMM VDPPD SIZE_8 IMM_8 +VEX.66.0f3a42 RVMI XMM XMM XMM IMM VMPSADBW SIZE_8 IMM_8 +VEX.66.W0.L1.0f3a46 RVMI XMM XMM XMM IMM8 VPERM2I128 IMM_8 +VEX.66.0f3a60 RMI XMM XMM IMM - VPCMPESTRM SIZE_8 IMM_8 +VEX.66.0f3a61 RMI XMM XMM IMM - VPCMPESTRI SIZE_8 IMM_8 +VEX.66.0f3a62 RMI XMM XMM IMM - VPCMPISTRM SIZE_8 IMM_8 +VEX.66.0f3a63 RMI XMM XMM IMM - VPCMPISTRI SIZE_8 IMM_8 +# +# BMI1 +VEX.NP.L0.0f38f2 RVM GP GP GP - ANDN +VEX.NP.L0.0f38f3/1 VM GP GP - - BLSR +VEX.NP.L0.0f38f3/2 VM GP GP - - BLSMSK +VEX.NP.L0.0f38f3/3 VM GP GP - - BLSI +VEX.NP.L0.0f38f7 RMV GP GP GP - BEXTR +# BMI2 +VEX.F2.L0.0f3af0 RMI GP GP IMM8 - RORX IMM_8 +VEX.NP.L0.0f38f5 RMV GP GP GP - BZHI +VEX.F2.L0.0f38f6 RVM GP GP GP - MULX +VEX.66.L0.0f38f7 RMV GP GP GP - SHLX +VEX.F2.L0.0f38f7 RMV GP GP GP - SHRX +VEX.F3.L0.0f38f7 RMV GP GP GP - SARX +# +# FPU +d8//0 M FPU - - - FADD_F32 +d8//1 M FPU - - - FMUL_F32 +d8//2 M FPU - - - FCOM_F32 +d8//3 M FPU - - - FCOMP_F32 +d8//4 M FPU - - - FSUB_F32 +d8//5 M FPU - - - FSUBR_F32 +d8//6 M FPU - - - FDIV_F32 +d8//7 M FPU - - - FDIVR_F32 +d8//c0+ AO FPU FPU - - FADD +d8//c8+ AO FPU FPU - - FMUL +d8//d0+ AO FPU FPU - - FCOM +d8//d8+ AO FPU FPU - - FCOMP +d8//e0+ AO FPU FPU - - FSUB +d8//e8+ AO FPU FPU - - FSUBR +d8//f0+ AO FPU FPU - - FDIV +d8//f8+ AO FPU FPU - - FDIVR +d9//0 M FPU - - - FLD_F32 +d9//2 M FPU - - - FST_F32 +d9//3 M FPU - - - FSTP_F32 +d9//4 M GP - - - FLDENV +d9//5 M GP - - - FLDCW +d9//6 M GP - - - FSTENV +d9//7 M GP - - - FSTCW +d9//c8+ O FPU - - - FXCH +d9//d0 NP - - - - FNOP +d9//e0 NP - - - - FCHS +d9//e1 NP - - - - FABS +d9//e4 NP - - - - FTST +d9//e5 NP - - - - FXAM +d9//e8 NP - - - - FLD1 +d9//e9 NP - - - - FLDL2T +d9//ea NP - - - - FLDL2E +d9//eb NP - - - - FLDPI +d9//ec NP - - - - FLDLG2 +d9//ed NP - - - - FLDLN2 +d9//ee NP - - - - FLDZ +d9//f0 NP - - - - F2XM1 +d9//f1 NP - - - - FYL2X +d9//f2 NP - - - - FPTAN +d9//f3 NP - - - - FPATAN +d9//f4 NP - - - - FXTRACT +d9//f5 NP - - - - FPREM1 +d9//f6 NP - - - - FDECSTP +d9//f7 NP - - - - FINCSTP +d9//f8 NP - - - - FPREM +d9//f9 NP - - - - FYL2XP1 +d9//fa NP - - - - FSQRT +d9//fb NP - - - - FSINCOS +d9//fc NP - - - - FRNDINT +d9//fd NP - - - - FSCALE +d9//fe NP - - - - FSIN +d9//ff NP - - - - FCOS +da//0 M FPU - - - FIADD_I32 +da//1 M FPU - - - FIMUL_I32 +da//2 M FPU - - - FICOM_I32 +da//3 M FPU - - - FICOMP_I32 +da//4 M FPU - - - FISUB_I32 +da//5 M FPU - - - FISUBR_I32 +da//6 M FPU - - - FIDIV_I32 +da//7 M FPU - - - FIDIVR_I32 +da//c0+ O FPU - - - FCMOVB +da//c8+ O FPU - - - FCMOVE +da//d0+ O FPU - - - FCMOVBE +da//d8+ O FPU - - - FCMOVU +da//e9 NP - - - - FUCOMPP +db//0+ M FPU - - - FILD_I32 +db//c0+ O FPU - - - FCMOVNB +db//c8+ O FPU - - - FCMOVNE +db//d0+ O FPU - - - FCMOVNBE +db//d8+ O FPU - - - FCMOVNU +db//e2 NP - - - - FCLEX +db//e3 NP - - - - FINIT +db//e8+ O FPU - - - FUCOMI +db//f0+ O FPU - - - FCOMI +dc//0 M FPU - - - FADD_F64 +dc//1 M FPU - - - FMUL_F64 +dc//2 M FPU - - - FCOM_F64 +dc//3 M FPU - - - FCOMP_F64 +dc//4 M FPU - - - FSUB_F64 +dc//5 M FPU - - - FSUBR_F64 +dc//6 M FPU - - - FDIV_F64 +dc//7 M FPU - - - FDIVR_F64 +dc//c0+ OA FPU FPU - - FADD +dc//c8+ OA FPU FPU - - FMUL +dc//e0+ OA FPU FPU - - FSUBR +dc//e8+ OA FPU FPU - - FSUB +dc//f0+ OA FPU FPU - - FDIVR +dc//f8+ OA FPU FPU - - FDIV +dd//0 M FPU - - - FLD_F64 +dd//1 M FPU - - - FISTTP_I64 +dd//2 M FPU - - - FST_F64 +dd//3 M FPU - - - FSTP_F64 +dd//4 M GP - - - FRSTOR +dd//6 M GP - - - FSAVE +dd//7 M GP - - - FSTSW +dd//c0+ O FPU - - - FFREE +dd//d0+ O FPU - - - FST +dd//d8+ O FPU - - - FSTP +dd//e0+ O FPU - - - FUCOM +dd//e8+ O FPU - - - FUCOMP +de//0 M FPU - - - FIADD_I16 +de//1 M FPU - - - FIMUL_I16 +de//2 M FPU - - - FICOM_I16 +de//3 M FPU - - - FICOMP_I16 +de//4 M FPU - - - FISUB_I16 +de//5 M FPU - - - FISUBR_I16 +de//6 M FPU - - - FIDIV_I16 +de//7 M FPU - - - FIDIVR_I16 +de//c0+ OA FPU FPU - - FADDP +de//c8+ OA FPU FPU - - FMULP +de//d9 NP - - - - FCOMPP +de//e0+ OA FPU FPU - - FSUBRP +de//e8+ OA FPU FPU - - FSUBP +de//f0+ OA FPU FPU - - FDIVRP +de//f8+ OA FPU FPU - - FDIVP +df//0 M FPU - - - FILD_I16 +df//1 M FPU - - - FISTTP_I16 +df//2 M FPU - - - FIST_I16 +df//3 M FPU - - - FISTP_I16 +df//4 M GP - - - FBLD +df//5 M GP - - - FILD_I64 +df//6 M GP - - - FBSTP +df//7 M GP - - - FISTP_I64 +# FSTSW AX +df//e0 O GP16 - - - FSTSW +df//f0+ AO FPU FPU - - FCOMIP +df//f8+ AO FPU FPU - - FUCOMIP diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..d23c1b1 --- /dev/null +++ b/meson.build @@ -0,0 +1,52 @@ +project('libx86decode', ['c'], default_options: ['warning_level=3', 'c_std=c99']) + +python3 = find_program('python3') + +if get_option('warning_level').to_int() >= 3 + add_project_arguments(['-Wmissing-field-initializers', + '-Wunused-parameter', + '-Wold-style-definition', + '-Wmissing-declarations', + '-Wmissing-prototypes', + '-Wmissing-noreturn', + '-Wshadow', + '-Wpointer-arith', + '-Wcast-align', + '-Wwrite-strings', + '-Winline', + '-Wformat-nonliteral', + '-Wformat-security', + '-Wswitch-default', + '-Winit-self', + '-Wnested-externs', + '-Wstrict-prototypes', + '-Wmissing-include-dirs', + '-Wundef', + '-Waggregate-return', + '-Wredundant-decls', + '-Wno-overlength-strings', + '-Wmissing-format-attribute'], + language: 'c') +endif + +c_compiler = meson.get_compiler('c') +pointer_size = c_compiler.sizeof('void*') +if pointer_size == 4 + add_project_arguments(['-DARCH_386'], language: 'c') +elif pointer_size == 8 + add_project_arguments(['-DARCH_X86_64'], language: 'c') +else + error('Invalid pointer size') +endif + +instr_data = custom_target('tables', + command: [python3, '@INPUT0@', '@INPUT1@', '@OUTPUT@'], + input: files('parseinstrs.py', 'instrs.txt'), + output: ['decode-table.inc']) + +libdecode = static_library('x86decode', 'decode.c', 'format.c', instr_data) +libx86decode = declare_dependency(link_with: libdecode, + include_directories: include_directories('.'), + sources: instr_data) + +subdir('tests') diff --git a/parseinstrs.py b/parseinstrs.py new file mode 100644 index 0000000..d5cfae8 --- /dev/null +++ b/parseinstrs.py @@ -0,0 +1,316 @@ +#!/usr/bin/python3 + +from binascii import unhexlify +from collections import OrderedDict, defaultdict +from copy import copy +from enum import Enum, IntEnum +from itertools import accumulate +import struct +import sys + +def bitstruct(name, fields): + names, sizes = zip(*(field.split(":") for field in fields)) + sizes = tuple(map(int, sizes)) + offsets = (0,) + tuple(accumulate(sizes)) + class __class: + def __init__(self, **kwargs): + for name in names: + setattr(self, name, kwargs.get(name, 0)) + def _encode(self): + return sum((getattr(self, name) & ((1 << size) - 1)) << offset + for name, size, offset in zip(names, sizes, offsets)) + __class.__name__ = name + __class._encode_size = offsets[-1] + return __class + +InstrFlags = bitstruct("InstrFlags", [ + "modrm_idx:2", + "modreg_idx:2", + "vexreg_idx:2", + "zeroreg_idx:2", + "operand_sizes:8", + "imm_idx:2", + "imm_size:2", + "imm_control:3", + "imm_byte:1", + "gp_size_8:1", + "gp_size_def64:1", + "gp_instr_width:1", + "gp_fixed_operand_size:3", +]) +assert InstrFlags._encode_size <= 32 + +ENCODINGS = { + "NP": InstrFlags(), + "M": InstrFlags(modrm_idx=0^3), + "M1": InstrFlags(modrm_idx=0^3, imm_idx=1^3, imm_control=1), + "MI": InstrFlags(modrm_idx=0^3, imm_idx=1^3, imm_control=3), + "MR": InstrFlags(modrm_idx=0^3, modreg_idx=1^3), + "RM": InstrFlags(modrm_idx=1^3, modreg_idx=0^3), + "RMA": InstrFlags(modrm_idx=1^3, modreg_idx=0^3, zeroreg_idx=2^3), + "MRI": InstrFlags(modrm_idx=0^3, modreg_idx=1^3, imm_idx=2^3, imm_control=3), + "RMI": InstrFlags(modrm_idx=1^3, modreg_idx=0^3, imm_idx=2^3, imm_control=3), + "I": InstrFlags(imm_idx=0^3, imm_control=3), + "IA": InstrFlags(zeroreg_idx=0^3, imm_idx=1^3, imm_control=3), + "O": InstrFlags(modreg_idx=0^3), + "OI": InstrFlags(modreg_idx=0^3, imm_idx=1^3, imm_control=3), + "OA": InstrFlags(modreg_idx=0^3, zeroreg_idx=1^3), + "AO": InstrFlags(modreg_idx=1^3, zeroreg_idx=0^3), + "D": InstrFlags(imm_idx=0^3, imm_control=4), + "FD": InstrFlags(zeroreg_idx=0^3, imm_idx=1^3, imm_control=2), + "TD": InstrFlags(zeroreg_idx=1^3, imm_idx=0^3, imm_control=2), + + "RVM": InstrFlags(modrm_idx=2^3, modreg_idx=0^3, vexreg_idx=1^3), + "RVMI": InstrFlags(modrm_idx=2^3, modreg_idx=0^3, vexreg_idx=1^3, imm_idx=3^3, imm_control=3, imm_byte=1), + "RVMR": InstrFlags(modrm_idx=2^3, modreg_idx=0^3, vexreg_idx=1^3, imm_idx=3^3, imm_control=5, imm_byte=1), + "RMV": InstrFlags(modrm_idx=1^3, modreg_idx=0^3, vexreg_idx=2^3), + "VM": InstrFlags(modrm_idx=1^3, vexreg_idx=0^3), + "VMI": InstrFlags(modrm_idx=1^3, vexreg_idx=0^3, imm_idx=2^3, imm_control=3, imm_byte=1), + "MVR": InstrFlags(modrm_idx=0^3, modreg_idx=2^3, vexreg_idx=1^3), +} + +OPKIND_LOOKUP = { + "-": (0, 0), + "IMM": (2, 0), + "IMM8": (1, 0), + "IMM16": (1, 1), + "IMM32": (1, 2), + "GP": (2, 0), + "GP8": (1, 0), + "GP16": (1, 1), + "GP32": (1, 2), + "GP64": (1, 3), + "XMM": (3, 0), + "XMM8": (1, 0), + "XMM16": (1, 1), + "XMM32": (1, 2), + "XMM64": (1, 3), + "XMM128": (1, 4), + "XMM256": (1, 5), + "SREG": (0, 0), + "FPU": (0, 0), +} + +def parse_desc(desc, ignore_flag): + desc = desc.split() + if ignore_flag in desc[6:]: + return None + + fixed_opsz = set() + opsizes = 0 + for i, opkind in enumerate(desc[1:5]): + enc_size, fixed_size = OPKIND_LOOKUP[opkind] + if enc_size == 1: fixed_opsz.add(fixed_size) + opsizes |= enc_size << 2 * i + + flags = copy(ENCODINGS[desc[0]]) + flags.operand_sizes = opsizes + if fixed_opsz: flags.gp_fixed_operand_size = next(iter(fixed_opsz)) + + # Miscellaneous Flags + if "DEF64" in desc[6:]: flags.gp_size_def64 = 1 + if "SIZE_8" in desc[6:]: flags.gp_size_8 = 1 + if "INSTR_WIDTH" in desc[6:]: flags.gp_instr_width = 1 + if "IMM_8" in desc[6:]: flags.imm_byte = 1 + + return desc[5], flags._encode() + +class EntryKind(Enum): + NONE = 0 + INSTR = 1 + TABLE256 = 2 + TABLE8 = 3 + TABLE72 = 4 + TABLE_PREFIX = 5 + + @property + def table_length(self): + return { + EntryKind.INSTR: 0, + EntryKind.TABLE256: 256, + EntryKind.TABLE8: 8, + EntryKind.TABLE72: 72, + EntryKind.TABLE_PREFIX: 16 + }[self] + +import re +opcode_regex = re.compile(r"^(?P(?PVEX\.)?(?PNP|66|F2|F3)\.(?PW[01]\.)?(?PL[01]\.)?)?(?P(?:[0-9a-f]{2})+)(?P//?[0-7]|//[c-f][0-9a-f])?(?P\+)?$") + +def parse_opcode(opcode_string): + """ + Parse opcode string into list of type-index tuples. + """ + match = opcode_regex.match(opcode_string) + if match is None: + raise Exception("invalid opcode: '%s'" % opcode_string) + + extended = match.group("extended") is not None + + opcode = [(EntryKind.TABLE256, x) for x in unhexlify(match.group("opcode"))] + + opcext = match.group("modrm") + if opcext: + if opcext[1] == "/": + opcext = int(opcext[2:], 16) + assert (0 <= opcext <= 7) or (0xc0 <= opcext <= 0xff) + if opcext >= 0xc0: + opcext -= 0xb8 + opcode.append((EntryKind.TABLE72, opcext)) + else: + opcode.append((EntryKind.TABLE8, int(opcext[1:], 16))) + + if match.group("prefixes"): + assert not extended + + legacy = {"NP": 0, "66": 1, "F3": 2, "F2": 3}[match.group("legacy")] + entry = legacy | ((1 << 3) if match.group("vex") else 0) + + if match.group("vexl"): + print("ignored mandatory VEX.L prefix for:", opcode_string) + + rexw = match.group("rexw") + if not rexw: + return [tuple(opcode) + ((EntryKind.TABLE_PREFIX, entry),), + tuple(opcode) + ((EntryKind.TABLE_PREFIX, entry | (1 << 2)),)] + + entry |= (1 << 2) if "W1" in rexw else 0 + return [tuple(opcode) + ((EntryKind.TABLE_PREFIX, entry),)] + + if not extended: + return [tuple(opcode)] + + last_type, last_index = opcode[-1] + assert last_type in (EntryKind.TABLE256, EntryKind.TABLE72) + assert last_index & 7 == 0 + + common_prefix = tuple(opcode[:-1]) + return [common_prefix + ((last_type, last_index + i),) for i in range(8)] + +class Table: + def __init__(self): + self.data = OrderedDict() + self.data["root"] = (EntryKind.TABLE256, [None] * 256) + self.mnemonics = set() + self.instrs = {} + + def compile(self): + mnemonics = sorted(list(self.mnemonics)) + offsets = {} + currentOffset = 0 + stats = defaultdict(int) + for name, (kind, _) in self.data.items(): + offsets[name] = currentOffset + stats[kind] += 1 + if kind.table_length: + currentOffset += kind.table_length * 2 + else: + currentOffset += 6 + currentOffset = (currentOffset + 7) & ~7 + assert currentOffset < 0x10000 + + data = b"" + for name, (kind, value) in self.data.items(): + if len(data) < offsets[name]: + data += b"\0" * (offsets[name] - len(data)) + assert len(data) == offsets[name] + if kind == EntryKind.INSTR: + mnemonicIdx = mnemonics.index(value[0]) + data += struct.pack(" +#include +#include + +#include + + +static +uint8_t +parse_nibble(const char nibble) +{ + if (nibble >= '0' && nibble <= '9') + { + return nibble - '0'; + } + else if (nibble >= 'a' && nibble <= 'f') + { + return nibble - 'a' + 10; + } + else if (nibble >= 'A' && nibble <= 'F') + { + return nibble - 'A' + 10; + } + else + { + printf("Invalid hexadecimal number: %x\n", nibble); + exit(1); + return 0; + } +} + +int +main(int argc, char** argv) +{ + if (argc != 2) + { + printf("usage: %s [instruction bytes]\n", argv[0]); + return -1; + } + + void* code = mmap((void*) 0x1238000, 0x2000, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); + + uint8_t* current_code = code; + char* hex = argv[1]; + for (; *hex && *(hex + 1); hex += 2, current_code++) + { + *current_code = (parse_nibble(hex[0]) << 4) | parse_nibble(hex[1]); + } + + size_t length = (size_t) current_code - (size_t) code; + + Instr instr; + int result = decode(code, length, &instr); + if (result < 0) + { + puts("Decode failed."); + return -1; + } + else if ((size_t) result != length) + { + printf("Decode used %u bytes, not %u.\n", (unsigned int) result, (unsigned int) length); + return -1; + } + + char buffer[128]; + instr_format(&instr, buffer); + puts(buffer); + + return 0; +} diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..de7edb9 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,22 @@ + +sh = find_program('sh') + +cases = [ + ['enter', 'decode-enter.sh'], + ['imul', 'decode-imul.sh'], + ['inc', 'decode-inc.sh'], + ['movsx', 'decode-movsx.sh'], + ['ret', 'decode-ret.sh'], + + ['sse-shufpd', 'decode-sse-shufpd.sh'], + ['sse-movq', 'decode-sse-movq.sh'], +] + +test_driver = executable('test_driver', 'driver.c', + dependencies: libx86decode, + c_args: ['-D_GNU_SOURCE']) +test_args = files('common.sh') + [test_driver.full_path(), '@0@'.format(pointer_size * 8)] + +foreach case : cases + test(case[0], sh, args: test_args + files(case[1])) +endforeach