From a3f77dbf49cf137410a7d987e4a599162279f40f Mon Sep 17 00:00:00 2001 From: Alexis Engelke Date: Sun, 8 Apr 2018 13:16:49 +0000 Subject: [PATCH] Initial commit --- .gitignore | 1 + LICENSE | 28 + README.md | 18 + decode.c | 727 ++++++++++++++++++++++ decode.h | 150 +++++ format.c | 168 +++++ instrs.txt | 1177 ++++++++++++++++++++++++++++++++++++ meson.build | 52 ++ parseinstrs.py | 316 ++++++++++ tests/common.sh | 31 + tests/decode-enter.sh | 9 + tests/decode-imul.sh | 2 + tests/decode-inc.sh | 12 + tests/decode-movsx.sh | 5 + tests/decode-ret.sh | 12 + tests/decode-sse-movq.sh | 1 + tests/decode-sse-shufpd.sh | 1 + tests/driver.c | 72 +++ tests/meson.build | 22 + 19 files changed, 2804 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 decode.c create mode 100644 decode.h create mode 100644 format.c create mode 100644 instrs.txt create mode 100644 meson.build create mode 100644 parseinstrs.py create mode 100644 tests/common.sh create mode 100644 tests/decode-enter.sh create mode 100644 tests/decode-imul.sh create mode 100644 tests/decode-inc.sh create mode 100644 tests/decode-movsx.sh create mode 100644 tests/decode-ret.sh create mode 100644 tests/decode-sse-movq.sh create mode 100644 tests/decode-sse-shufpd.sh create mode 100644 tests/driver.c create mode 100644 tests/meson.build 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