diff options
Diffstat (limited to 'opcodes/i386-dis.c')
-rw-r--r-- | opcodes/i386-dis.c | 272 |
1 files changed, 177 insertions, 95 deletions
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index a9b1027..087c449 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -92,8 +92,10 @@ 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_EX_VexImmW (int, int); static void OP_XMM_Vex (int, int); static void OP_XMM_VexW (int, int); static void OP_REG_VexI4 (int, int); @@ -371,11 +373,14 @@ fetch_data (struct disassemble_info *info, bfd_byte *addr) #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 EXqVex { OP_EX_Vex, q_mode } #define EXVexW { OP_EX_VexW, x_mode } #define EXdVexW { OP_EX_VexW, d_mode } #define EXqVexW { OP_EX_VexW, q_mode } +#define EXVexImmW { OP_EX_VexImmW, x_mode } #define XMVex { OP_XMM_Vex, 0 } #define XMVexW { OP_XMM_VexW, 0 } #define XMVexI4 { OP_REG_VexI4, x_mode } @@ -1937,7 +1942,7 @@ static struct vex; static unsigned char need_vex; static unsigned char need_vex_reg; -static unsigned char vex_i4_done; +static unsigned char vex_w_done; /* If we are accessing mod/rm/reg without need_modrm set, then the values are stale. Hitting this abort likely indicates that you @@ -4698,7 +4703,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vpermil2ps", { XMVexW, Vex, EXVexW, EXVexW, VPERMIL2 } }, + { "vpermil2ps", { XMVexW, Vex, EXVexImmW, EXVexImmW, VPERMIL2 } }, { "(bad)", { XX } }, }, @@ -4706,7 +4711,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vpermil2pd", { XMVexW, Vex, EXVexW, EXVexW, VPERMIL2 } }, + { "vpermil2pd", { XMVexW, Vex, EXVexImmW, EXVexImmW, VPERMIL2 } }, { "(bad)", { XX } }, }, @@ -4738,7 +4743,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfmaddsubps", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfmaddsubps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4746,7 +4751,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfmaddsubpd", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfmaddsubpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4754,7 +4759,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfmsubaddps", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfmsubaddps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4762,7 +4767,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfmsubaddpd", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfmsubaddpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4802,7 +4807,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfmaddps", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfmaddps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4810,7 +4815,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfmaddpd", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfmaddpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4834,7 +4839,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfmsubps", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfmsubps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4842,7 +4847,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfmsubpd", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfmsubpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4866,7 +4871,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfnmaddps", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfnmaddps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4874,7 +4879,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfnmaddpd", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfnmaddpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4898,7 +4903,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfnmsubps", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfnmsubps", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -4906,7 +4911,7 @@ static const struct dis386 prefix_table[][4] = { { { "(bad)", { XX } }, { "(bad)", { XX } }, - { "vfnmsubpd", { XMVexW, Vex, EXVexW, EXVexW, VexI4 } }, + { "vfnmsubpd", { XMVexW, VexFMA, EXVexW, EXVexW, VexI4 } }, { "(bad)", { XX } }, }, @@ -8859,49 +8864,49 @@ static const struct dis386 vex_len_table[][2] = { /* VEX_LEN_3A6A_P_2 */ { - { "vfmaddss", { XMVexW, Vex128, EXdVexW, EXdVexW, VexI4 } }, + { "vfmaddss", { XMVexW, Vex128FMA, EXdVexW, EXdVexW, VexI4 } }, { "(bad)", { XX } }, }, /* VEX_LEN_3A6B_P_2 */ { - { "vfmaddsd", { XMVexW, Vex128, EXqVexW, EXqVexW, VexI4 } }, + { "vfmaddsd", { XMVexW, Vex128FMA, EXqVexW, EXqVexW, VexI4 } }, { "(bad)", { XX } }, }, /* VEX_LEN_3A6E_P_2 */ { - { "vfmsubss", { XMVexW, Vex128, EXdVexW, EXdVexW, VexI4 } }, + { "vfmsubss", { XMVexW, Vex128FMA, EXdVexW, EXdVexW, VexI4 } }, { "(bad)", { XX } }, }, /* VEX_LEN_3A6F_P_2 */ { - { "vfmsubsd", { XMVexW, Vex128, EXqVexW, EXqVexW, VexI4 } }, + { "vfmsubsd", { XMVexW, Vex128FMA, EXqVexW, EXqVexW, VexI4 } }, { "(bad)", { XX } }, }, /* VEX_LEN_3A7A_P_2 */ { - { "vfnmaddss", { XMVexW, Vex128, EXdVexW, EXdVexW, VexI4 } }, + { "vfnmaddss", { XMVexW, Vex128FMA, EXdVexW, EXdVexW, VexI4 } }, { "(bad)", { XX } }, }, /* VEX_LEN_3A7B_P_2 */ { - { "vfnmaddsd", { XMVexW, Vex128, EXqVexW, EXqVexW, VexI4 } }, + { "vfnmaddsd", { XMVexW, Vex128FMA, EXqVexW, EXqVexW, VexI4 } }, { "(bad)", { XX } }, }, /* VEX_LEN_3A7E_P_2 */ { - { "vfnmsubss", { XMVexW, Vex128, EXdVexW, EXdVexW, VexI4 } }, + { "vfnmsubss", { XMVexW, Vex128FMA, EXdVexW, EXdVexW, VexI4 } }, { "(bad)", { XX } }, }, /* VEX_LEN_3A7F_P_2 */ { - { "vfnmsubsd", { XMVexW, Vex128, EXqVexW, EXqVexW, VexI4 } }, + { "vfnmsubsd", { XMVexW, Vex128FMA, EXqVexW, EXqVexW, VexI4 } }, { "(bad)", { XX } }, }, }; @@ -10184,7 +10189,7 @@ print_insn (bfd_vma pc, disassemble_info *info) { need_vex = 0; need_vex_reg = 0; - vex_i4_done = 0; + vex_w_done = 0; dp = get_valid_dis386 (dp, info); if (dp != NULL && putop (dp->name, sizeflag) == 0) { @@ -13276,88 +13281,79 @@ OP_VEX (int bytemode, int sizeflag ATTRIBUTE_UNUSED) oappend (scratchbuf + intel_syntax); } -static void -OP_EX_VexW (int bytemode, int sizeflag) -{ - int reg = -1; - static unsigned char vex_i4; +/* Get the VEX immediate byte without moving codep. */ - if (!vex_i4_done) - { - int bytes_before_imm = 0; +static unsigned char +get_vex_imm8 (int sizeflag) +{ + int bytes_before_imm = 0; - /* Skip mod/rm byte once. We will be called twice. */ - MODRM_CHECK; - codep++; + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; - if (modrm.mod != 3) + if (modrm.mod != 3) + { + /* There are SIB/displacement bytes. */ + if ((sizeflag & AFLAG) || address_mode == mode_64bit) { - /* There are SIB/displacement bytes. */ - if ((sizeflag & AFLAG) || address_mode == mode_64bit) - { - /* 32/64 bit address mode */ - int base = modrm.rm; + /* 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++; - } + /* 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; - } + 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; - } + } + 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); - vex_i4 = codep [bytes_before_imm]; - vex_i4_done = 1; - if (vex.w) - reg = vex_i4 >> 4; - } - else - { - if (!vex.w) - reg = vex_i4 >> 4; } + 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, 0); @@ -13391,6 +13387,89 @@ OP_EX_VexW (int bytemode, int sizeflag) } static void +OP_EX_VexImmW (int bytemode, int sizeflag) +{ + int reg = -1; + static unsigned char vex_imm8; + + if (!vex_w_done) + { + vex_imm8 = get_vex_imm8 (sizeflag); + if (vex.w) + reg = vex_imm8 >> 4; + vex_w_done = 1; + } + else + { + if (!vex.w) + reg = vex_imm8 >> 4; + } + + OP_EX_VexReg (bytemode, sizeflag, reg); +} + +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) { @@ -13414,6 +13493,9 @@ OP_REG_VexI4 (int bytemode, int sizeflag ATTRIBUTE_UNUSED) BadOp (); reg >>= 4; + if (reg > 7 && address_mode != mode_64bit) + BadOp (); + switch (vex.length) { case 128: |