diff options
Diffstat (limited to 'opcodes/i386-dis.c')
-rw-r--r-- | opcodes/i386-dis.c | 83 |
1 files changed, 69 insertions, 14 deletions
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index 9c5063e..e2c7b1b 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -107,6 +107,7 @@ static bool DistinctDest_Fixup (instr_info *, int, int); static bool PREFETCHI_Fixup (instr_info *, int, int); static bool PUSH2_POP2_Fixup (instr_info *, int, int); static bool JMPABS_Fixup (instr_info *, int, int); +static bool CFCMOV_Fixup (instr_info *, int, int); static void ATTRIBUTE_PRINTF_3 i386_dis_printf (const disassemble_info *, enum disassembler_style, @@ -228,6 +229,7 @@ struct instr_info bool b; bool no_broadcast; bool nf; + bool u; } vex; @@ -4041,7 +4043,7 @@ static const struct dis386 prefix_table[][4] = { { "vbcstnebf162ps", { XM, Mw }, 0 }, { "vbcstnesh2ps", { XM, Mw }, 0 }, }, - + /* PREFIX_VEX_0F38D2_W_0 */ { { "vpdpwuud", { XM, Vex, EXx }, 0 }, @@ -9028,6 +9030,8 @@ get_valid_dis386 (const struct dis386 *dp, instr_info *ins) if (!(*ins->codep & 0x4)) ins->rex2 |= REX_X; + ins->vex.u = *ins->codep & 0x4; + switch ((*ins->codep & 0x3)) { case 0: @@ -9061,9 +9065,9 @@ get_valid_dis386 (const struct dis386 *dp, instr_info *ins) if (ins->address_mode != mode_64bit) { /* Report bad for !evex_default and when two fixed values of evex - change.. */ - if (ins->evex_type != evex_default - || (ins->rex2 & (REX_B | REX_X))) + change. */ + if (ins->evex_type != evex_default || (ins->rex2 & REX_B) + || ((ins->rex2 & REX_X) && (ins->modrm.mod != 3))) return &bad_opcode; /* In 16/32-bit mode silently ignore following bits. */ ins->rex &= ~REX_B; @@ -9085,14 +9089,22 @@ get_valid_dis386 (const struct dis386 *dp, instr_info *ins) if (!fetch_modrm (ins)) return &err_opcode; - if (ins->modrm.mod == 3 && (ins->rex2 & REX_X)) + /* When modrm.mod != 3, the U bit is used by APX for bit X4. + When modrm.mod == 3, the U bit is used by AVX10. The U bit and + the b bit should not be zero at the same time. */ + if (ins->modrm.mod == 3 && !ins->vex.u && !ins->vex.b) return &bad_opcode; /* Set vector length. For EVEX-promoted instructions, evex.ll == 0b00, which has the same encoding as vex.length == 128 and they can share the same processing with vex.length in OP_VEX. */ if (ins->modrm.mod == 3 && ins->vex.b && ins->evex_type != evex_from_legacy) - ins->vex.length = 512; + { + if (ins->vex.u) + ins->vex.length = 512; + else + ins->vex.length = 256; + } else { switch (ins->vex.ll) @@ -10248,9 +10260,21 @@ static const char *const scc_suffix[16] = { static void swap_operand (instr_info *ins) { - ins->mnemonicendp[0] = '.'; - ins->mnemonicendp[1] = 's'; - ins->mnemonicendp[2] = '\0'; + char *p = ins->mnemonicendp; + + if (p[-1] == '}') + { + while (*--p != '{') + { + if (p <= ins->obuf + 2) + abort (); + } + if (p[-1] == ' ') + --p; + } + memmove (p + 2, p, ins->mnemonicendp - p + 1); + p[0] = '.'; + p[1] = 's'; ins->mnemonicendp += 2; } @@ -10560,7 +10584,14 @@ putop (instr_info *ins, const char *in_template, int sizeflag) } } else if (l == 1 && last[0] == 'C') - break; + { + if (ins->vex.nd && !ins->vex.nf) + break; + *ins->obufp++ = 'c'; + *ins->obufp++ = 'f'; + /* Skip printing {evex} */ + evex_printed = true; + } else if (l == 1 && last[0] == 'N') { if (ins->vex.nf) @@ -12397,9 +12428,9 @@ OP_I (instr_info *ins, int bytemode, int sizeflag) break; case const_1_mode: if (ins->intel_syntax) - oappend (ins, "1"); + oappend_with_style (ins, "1", dis_style_immediate); else - oappend (ins, "$1"); + oappend_with_style (ins, "$1", dis_style_immediate); return true; default: oappend (ins, INTERNAL_DISASSEMBLER_ERROR); @@ -12981,14 +13012,15 @@ OP_EX (instr_info *ins, int bytemode, int sizeflag) USED_REX (REX_B); if (ins->rex & REX_B) reg += 8; - if (ins->rex2 & REX_B) - reg += 16; if (ins->vex.evex) { USED_REX (REX_X); if ((ins->rex & REX_X)) reg += 16; + ins->rex2_used &= ~REX_B; } + else if (ins->rex2 & REX_B) + reg += 16; if ((sizeflag & SUFFIX_ALWAYS) && (bytemode == x_swap_mode @@ -14040,3 +14072,26 @@ JMPABS_Fixup (instr_info *ins, int bytemode, int sizeflag) return OP_IMREG (ins, bytemode, sizeflag); return OP_OFF64 (ins, bytemode, sizeflag); } + +static bool +CFCMOV_Fixup (instr_info *ins, int opnd, int sizeflag) +{ + /* EVEX.NF is used as a direction bit in the 2-operand case to reverse the + source and destination operands. */ + bool dstmem = !ins->vex.nd && ins->vex.nf; + + if (opnd == 0) + { + if (dstmem) + return OP_E (ins, v_swap_mode, sizeflag); + return OP_G (ins, v_mode, sizeflag); + } + + /* These bits have been consumed and should be cleared. */ + ins->vex.nf = false; + ins->vex.mask_register_specifier = 0; + + if (dstmem) + return OP_G (ins, v_mode, sizeflag); + return OP_E (ins, v_mode, sizeflag); +} |