diff options
Diffstat (limited to 'opcodes/i386-dis.c')
-rw-r--r-- | opcodes/i386-dis.c | 478 |
1 files changed, 455 insertions, 23 deletions
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index d69078c..715c315 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -93,10 +93,14 @@ static void OP_MS (int, int); static void OP_XS (int, int); static void OP_M (int, int); static void OP_VEX (int, int); +static void OP_VEX_FMA (int, int); static void OP_EX_Vex (int, int); +static void OP_EX_VexW (int, int); static void OP_XMM_Vex (int, int); +static void OP_XMM_VexW (int, int); static void OP_REG_VexI4 (int, int); static void PCLMUL_Fixup (int, int); +static void VEXI4_Fixup (int, int); static void VZERO_Fixup (int, int); static void VCMP_Fixup (int, int); static void OP_0f07 (int, int); @@ -358,11 +362,18 @@ fetch_data (struct disassemble_info *info, bfd_byte *addr) #define Vex { OP_VEX, vex_mode } #define Vex128 { OP_VEX, vex128_mode } #define Vex256 { OP_VEX, vex256_mode } +#define VexI4 { VEXI4_Fixup, 0} +#define VexFMA { OP_VEX_FMA, vex_mode } +#define Vex128FMA { OP_VEX_FMA, vex128_mode } #define EXdVex { OP_EX_Vex, d_mode } #define EXdVexS { OP_EX_Vex, d_swap_mode } #define EXqVex { OP_EX_Vex, q_mode } #define EXqVexS { OP_EX_Vex, q_swap_mode } +#define EXVexW { OP_EX_VexW, x_mode } +#define EXdVexW { OP_EX_VexW, d_mode } +#define EXqVexW { OP_EX_VexW, q_mode } #define XMVex { OP_XMM_Vex, 0 } +#define XMVexW { OP_XMM_VexW, 0 } #define XMVexI4 { OP_REG_VexI4, x_mode } #define PCLMUL { PCLMUL_Fixup, 0 } #define VZERO { VZERO_Fixup, 0 } @@ -980,11 +991,31 @@ fetch_data (struct disassemble_info *info, bfd_byte *addr) #define PREFIX_VEX_3A4A (PREFIX_VEX_3A44 + 1) #define PREFIX_VEX_3A4B (PREFIX_VEX_3A4A + 1) #define PREFIX_VEX_3A4C (PREFIX_VEX_3A4B + 1) -#define PREFIX_VEX_3A60 (PREFIX_VEX_3A4C + 1) +#define PREFIX_VEX_3A5C (PREFIX_VEX_3A4C + 1) +#define PREFIX_VEX_3A5D (PREFIX_VEX_3A5C + 1) +#define PREFIX_VEX_3A5E (PREFIX_VEX_3A5D + 1) +#define PREFIX_VEX_3A5F (PREFIX_VEX_3A5E + 1) +#define PREFIX_VEX_3A60 (PREFIX_VEX_3A5F + 1) #define PREFIX_VEX_3A61 (PREFIX_VEX_3A60 + 1) #define PREFIX_VEX_3A62 (PREFIX_VEX_3A61 + 1) #define PREFIX_VEX_3A63 (PREFIX_VEX_3A62 + 1) -#define PREFIX_VEX_3ADF (PREFIX_VEX_3A63 + 1) +#define PREFIX_VEX_3A68 (PREFIX_VEX_3A63 + 1) +#define PREFIX_VEX_3A69 (PREFIX_VEX_3A68 + 1) +#define PREFIX_VEX_3A6A (PREFIX_VEX_3A69 + 1) +#define PREFIX_VEX_3A6B (PREFIX_VEX_3A6A + 1) +#define PREFIX_VEX_3A6C (PREFIX_VEX_3A6B + 1) +#define PREFIX_VEX_3A6D (PREFIX_VEX_3A6C + 1) +#define PREFIX_VEX_3A6E (PREFIX_VEX_3A6D + 1) +#define PREFIX_VEX_3A6F (PREFIX_VEX_3A6E + 1) +#define PREFIX_VEX_3A78 (PREFIX_VEX_3A6F + 1) +#define PREFIX_VEX_3A79 (PREFIX_VEX_3A78 + 1) +#define PREFIX_VEX_3A7A (PREFIX_VEX_3A79 + 1) +#define PREFIX_VEX_3A7B (PREFIX_VEX_3A7A + 1) +#define PREFIX_VEX_3A7C (PREFIX_VEX_3A7B + 1) +#define PREFIX_VEX_3A7D (PREFIX_VEX_3A7C + 1) +#define PREFIX_VEX_3A7E (PREFIX_VEX_3A7D + 1) +#define PREFIX_VEX_3A7F (PREFIX_VEX_3A7E + 1) +#define PREFIX_VEX_3ADF (PREFIX_VEX_3A7F + 1) #define X86_64_06 0 #define X86_64_07 (X86_64_06 + 1) @@ -1216,7 +1247,15 @@ fetch_data (struct disassemble_info *info, bfd_byte *addr) #define VEX_LEN_3A61_P_2 (VEX_LEN_3A60_P_2 + 1) #define VEX_LEN_3A62_P_2 (VEX_LEN_3A61_P_2 + 1) #define VEX_LEN_3A63_P_2 (VEX_LEN_3A62_P_2 + 1) -#define VEX_LEN_3ADF_P_2 (VEX_LEN_3A63_P_2 + 1) +#define VEX_LEN_3A6A_P_2 (VEX_LEN_3A63_P_2 + 1) +#define VEX_LEN_3A6B_P_2 (VEX_LEN_3A6A_P_2 + 1) +#define VEX_LEN_3A6E_P_2 (VEX_LEN_3A6B_P_2 + 1) +#define VEX_LEN_3A6F_P_2 (VEX_LEN_3A6E_P_2 + 1) +#define VEX_LEN_3A7A_P_2 (VEX_LEN_3A6F_P_2 + 1) +#define VEX_LEN_3A7B_P_2 (VEX_LEN_3A7A_P_2 + 1) +#define VEX_LEN_3A7E_P_2 (VEX_LEN_3A7B_P_2 + 1) +#define VEX_LEN_3A7F_P_2 (VEX_LEN_3A7E_P_2 + 1) +#define VEX_LEN_3ADF_P_2 (VEX_LEN_3A7F_P_2 + 1) typedef void (*op_rtn) (int bytemode, int sizeflag); @@ -5028,6 +5067,38 @@ static const struct dis386 prefix_table[][4] = { { "(bad)", { XX } }, }, + /* PREFIX_VEX_3A5C */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfmaddsubps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A5D */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfmaddsubpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A5E */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfmsubaddps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A5F */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfmsubaddpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + /* PREFIX_VEX_3A60 */ { { "(bad)", { XX } }, @@ -5060,6 +5131,134 @@ static const struct dis386 prefix_table[][4] = { { "(bad)", { XX } }, }, + /* PREFIX_VEX_3A68 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfmaddps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A69 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfmaddpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A6A */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { VEX_LEN_TABLE (VEX_LEN_3A6A_P_2) }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A6B */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { VEX_LEN_TABLE (VEX_LEN_3A6B_P_2) }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A6C */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfmsubps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A6D */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfmsubpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A6E */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { VEX_LEN_TABLE (VEX_LEN_3A6E_P_2) }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A6F */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { VEX_LEN_TABLE (VEX_LEN_3A6F_P_2) }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A78 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfnmaddps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A79 */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfnmaddpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A7A */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { VEX_LEN_TABLE (VEX_LEN_3A7A_P_2) }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A7B */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { VEX_LEN_TABLE (VEX_LEN_3A7B_P_2) }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A7C */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfnmsubps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A7D */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { "vfnmsubpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A7E */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { VEX_LEN_TABLE (VEX_LEN_3A7E_P_2) }, + { "(bad)", { XX } }, + }, + + /* PREFIX_VEX_3A7F */ + { + { "(bad)", { XX } }, + { "(bad)", { XX } }, + { VEX_LEN_TABLE (VEX_LEN_3A7F_P_2) }, + { "(bad)", { XX } }, + }, + /* PREFIX_VEX_3ADF */ { { "(bad)", { XX } }, @@ -6807,10 +7006,10 @@ static const struct dis386 vex_table[][256] = { { "(bad)", { XX } }, { "(bad)", { XX } }, { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, + { PREFIX_TABLE (PREFIX_VEX_3A5C) }, + { PREFIX_TABLE (PREFIX_VEX_3A5D) }, + { PREFIX_TABLE (PREFIX_VEX_3A5E) }, + { PREFIX_TABLE (PREFIX_VEX_3A5F) }, /* 60 */ { PREFIX_TABLE (PREFIX_VEX_3A60) }, { PREFIX_TABLE (PREFIX_VEX_3A61) }, @@ -6821,14 +7020,14 @@ static const struct dis386 vex_table[][256] = { { "(bad)", { XX } }, { "(bad)", { XX } }, /* 68 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, + { PREFIX_TABLE (PREFIX_VEX_3A68) }, + { PREFIX_TABLE (PREFIX_VEX_3A69) }, + { PREFIX_TABLE (PREFIX_VEX_3A6A) }, + { PREFIX_TABLE (PREFIX_VEX_3A6B) }, + { PREFIX_TABLE (PREFIX_VEX_3A6C) }, + { PREFIX_TABLE (PREFIX_VEX_3A6D) }, + { PREFIX_TABLE (PREFIX_VEX_3A6E) }, + { PREFIX_TABLE (PREFIX_VEX_3A6F) }, /* 70 */ { "(bad)", { XX } }, { "(bad)", { XX } }, @@ -6839,14 +7038,14 @@ static const struct dis386 vex_table[][256] = { { "(bad)", { XX } }, { "(bad)", { XX } }, /* 78 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, + { PREFIX_TABLE (PREFIX_VEX_3A78) }, + { PREFIX_TABLE (PREFIX_VEX_3A79) }, + { PREFIX_TABLE (PREFIX_VEX_3A7A) }, + { PREFIX_TABLE (PREFIX_VEX_3A7B) }, + { PREFIX_TABLE (PREFIX_VEX_3A7C) }, + { PREFIX_TABLE (PREFIX_VEX_3A7D) }, + { PREFIX_TABLE (PREFIX_VEX_3A7E) }, + { PREFIX_TABLE (PREFIX_VEX_3A7F) }, /* 80 */ { "(bad)", { XX } }, { "(bad)", { XX } }, @@ -8153,6 +8352,54 @@ static const struct dis386 vex_len_table[][2] = { { "(bad)", { XX } }, }, + /* VEX_LEN_3A6A_P_2 */ + { + { "vfmaddss", { XMVexW, Vex128FMA, EXdVexW, EXdVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* VEX_LEN_3A6B_P_2 */ + { + { "vfmaddsd", { XMVexW, Vex128FMA, EXqVexW, EXqVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* VEX_LEN_3A6E_P_2 */ + { + { "vfmsubss", { XMVexW, Vex128FMA, EXdVexW, EXdVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* VEX_LEN_3A6F_P_2 */ + { + { "vfmsubsd", { XMVexW, Vex128FMA, EXqVexW, EXqVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* VEX_LEN_3A7A_P_2 */ + { + { "vfnmaddss", { XMVexW, Vex128FMA, EXdVexW, EXdVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* VEX_LEN_3A7B_P_2 */ + { + { "vfnmaddsd", { XMVexW, Vex128FMA, EXqVexW, EXqVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* VEX_LEN_3A7E_P_2 */ + { + { "vfnmsubss", { XMVexW, Vex128FMA, EXdVexW, EXdVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + + /* VEX_LEN_3A7F_P_2 */ + { + { "vfnmsubsd", { XMVexW, Vex128FMA, EXqVexW, EXqVexW, VexI4 } }, + { "(bad)", { XX } }, + }, + /* VEX_LEN_3ADF_P_2 */ { { "vaeskeygenassist", { XM, EXx, Ib } }, @@ -12242,6 +12489,182 @@ OP_VEX (int bytemode, int sizeflag ATTRIBUTE_UNUSED) oappend (scratchbuf + intel_syntax); } +/* Get the VEX immediate byte without moving codep. */ + +static unsigned char +get_vex_imm8 (int sizeflag) +{ + int bytes_before_imm = 0; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + if (modrm.mod != 3) + { + /* There are SIB/displacement bytes. */ + if ((sizeflag & AFLAG) || address_mode == mode_64bit) + { + /* 32/64 bit address mode */ + int base = modrm.rm; + + /* Check SIB byte. */ + if (base == 4) + { + FETCH_DATA (the_info, codep + 1); + base = *codep & 7; + bytes_before_imm++; + } + + switch (modrm.mod) + { + case 0: + /* When modrm.rm == 5 or modrm.rm == 4 and base in + SIB == 5, there is a 4 byte displacement. */ + if (base != 5) + /* No displacement. */ + break; + case 2: + /* 4 byte displacement. */ + bytes_before_imm += 4; + break; + case 1: + /* 1 byte displacement. */ + bytes_before_imm++; + break; + } + } + else + { /* 16 bit address mode */ + switch (modrm.mod) + { + case 0: + /* When modrm.rm == 6, there is a 2 byte displacement. */ + if (modrm.rm != 6) + /* No displacement. */ + break; + case 2: + /* 2 byte displacement. */ + bytes_before_imm += 2; + break; + case 1: + /* 1 byte displacement. */ + bytes_before_imm++; + break; + } + } + } + + FETCH_DATA (the_info, codep + bytes_before_imm + 1); + return codep [bytes_before_imm]; +} + +static void +OP_EX_VexReg (int bytemode, int sizeflag, int reg) +{ + if (reg == -1 && modrm.mod != 3) + { + OP_E_memory (bytemode, sizeflag); + return; + } + else + { + if (reg == -1) + { + reg = modrm.rm; + USED_REX (REX_B); + if (rex & REX_B) + reg += 8; + } + else if (reg > 7 && address_mode != mode_64bit) + BadOp (); + } + + switch (vex.length) + { + case 128: + sprintf (scratchbuf, "%%xmm%d", reg); + break; + case 256: + sprintf (scratchbuf, "%%ymm%d", reg); + break; + default: + abort (); + } + oappend (scratchbuf + intel_syntax); +} + +static void +OP_EX_VexW (int bytemode, int sizeflag) +{ + int reg = -1; + + if (!vex_w_done) + { + vex_w_done = 1; + if (vex.w) + reg = vex.register_specifier; + } + else + { + if (!vex.w) + reg = vex.register_specifier; + } + + OP_EX_VexReg (bytemode, sizeflag, reg); +} + +static void +OP_VEX_FMA (int bytemode, int sizeflag) +{ + int reg = get_vex_imm8 (sizeflag) >> 4; + + if (reg > 7 && address_mode != mode_64bit) + BadOp (); + + switch (vex.length) + { + case 128: + switch (bytemode) + { + case vex_mode: + case vex128_mode: + break; + default: + abort (); + return; + } + + sprintf (scratchbuf, "%%xmm%d", reg); + break; + case 256: + switch (bytemode) + { + case vex_mode: + break; + default: + abort (); + return; + } + + sprintf (scratchbuf, "%%ymm%d", reg); + break; + default: + abort (); + } + oappend (scratchbuf + intel_syntax); +} + +static void +VEXI4_Fixup (int bytemode ATTRIBUTE_UNUSED, + int sizeflag ATTRIBUTE_UNUSED) +{ + /* Skip the immediate byte and check for invalid bits. */ + FETCH_DATA (the_info, codep + 1); + if (*codep++ & 0xf) + BadOp (); +} + static void OP_REG_VexI4 (int bytemode, int sizeflag ATTRIBUTE_UNUSED) { @@ -12274,6 +12697,15 @@ OP_REG_VexI4 (int bytemode, int sizeflag ATTRIBUTE_UNUSED) } static void +OP_XMM_VexW (int bytemode, int sizeflag) +{ + /* Turn off the REX.W bit since it is used for swapping operands + now. */ + rex &= ~REX_W; + OP_XMM (bytemode, sizeflag); +} + +static void OP_EX_Vex (int bytemode, int sizeflag) { if (modrm.mod != 3) |