aboutsummaryrefslogtreecommitdiff
path: root/opcodes/i386-dis.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2017-05-22 11:02:46 -0700
committerH.J. Lu <hjl.tools@gmail.com>2017-05-22 11:02:58 -0700
commit04ef582ace91cad765d056cc95624478e0421144 (patch)
treece513249defa49cae554a37f0f532d696a6e788a /opcodes/i386-dis.c
parent25f94347373b1b6f4bfc79eeb38e79d383195779 (diff)
downloadbinutils-04ef582ace91cad765d056cc95624478e0421144.zip
binutils-04ef582ace91cad765d056cc95624478e0421144.tar.gz
binutils-04ef582ace91cad765d056cc95624478e0421144.tar.bz2
x86: Add NOTRACK prefix support
For register indirect branches, NOTRACK prefix (0x3e), which is also the DS segment register prefix, can be used to ignore the CET indirect branch track. gas/ * config/tc-i386.c (REX_PREFIX): Changed to 7. (NOTRACK_PREFIX): New. (MAX_PREFIXES): Changed to 8. (_i386_insn): Add notrack_prefix. (PREFIX_GROUP): Add PREFIX_DS. (add_prefix): Return PREFIX_DS for DS_PREFIX_OPCODE. (md_assemble): Check if NOTRACK prefix is supported. (parse_insn): Set notrack_prefix and issue an error for other prefixes after NOTRACK prefix. * testsuite/gas/i386/i386.exp: Run tests for NOTRACK prefix. * testsuite/gas/i386/notrack-intel.d: New file. * testsuite/gas/i386/notrack.d: Likewise. * testsuite/gas/i386/notrack.s: Likewise. * testsuite/gas/i386/notrackbad.l: Likewise. * testsuite/gas/i386/notrackbad.s: Likewise. * testsuite/gas/i386/x86-64-notrack-intel.d: Likewise. * testsuite/gas/i386/x86-64-notrack.d: Likewise. * testsuite/gas/i386/x86-64-notrack.s: Likewise. * testsuite/gas/i386/x86-64-notrackbad.l: Likewise. * testsuite/gas/i386/x86-64-notrackbad.s: Likewise. include/ * include/opcode/i386.h (NOTRACK_PREFIX_OPCODE): New. opcodes/ * i386-dis.c (NOTRACK_Fixup): New. (NOTRACK): Likewise. (NOTRACK_PREFIX): Likewise. (last_active_prefix): Likewise. (reg_table): Use NOTRACK on indirect call and jmp. (ckprefix): Set last_active_prefix. (prefix_name): Return "notrack" for NOTRACK_PREFIX. * i386-gen.c (opcode_modifiers): Add NoTrackPrefixOk. * i386-opc.h (NoTrackPrefixOk): New. (i386_opcode_modifier): Add notrackprefixok. * i386-opc.tbl: Add NoTrackPrefixOk to indirect call and jmp. Add notrack. * i386-tbl.h: Regenerated.
Diffstat (limited to 'opcodes/i386-dis.c')
-rw-r--r--opcodes/i386-dis.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c
index 3980c46..039768b 100644
--- a/opcodes/i386-dis.c
+++ b/opcodes/i386-dis.c
@@ -110,6 +110,7 @@ static void CMP_Fixup (int, int);
static void BadOp (void);
static void REP_Fixup (int, int);
static void BND_Fixup (int, int);
+static void NOTRACK_Fixup (int, int);
static void HLE_Fixup1 (int, int);
static void HLE_Fixup2 (int, int);
static void HLE_Fixup3 (int, int);
@@ -473,6 +474,7 @@ fetch_data (struct disassemble_info *info, bfd_byte *addr)
#define Evh3 { HLE_Fixup3, v_mode }
#define BND { BND_Fixup, 0 }
+#define NOTRACK { NOTRACK_Fixup, 0 }
#define cond_jump_flag { NULL, cond_jump_mode }
#define loop_jcxz_flag { NULL, loop_jcxz_mode }
@@ -3167,6 +3169,7 @@ static int last_data_prefix;
static int last_addr_prefix;
static int last_rex_prefix;
static int last_seg_prefix;
+static int last_active_prefix;
static int fwait_prefix;
/* The active segment register prefix. */
static int active_seg_prefix;
@@ -3549,9 +3552,9 @@ static const struct dis386 reg_table[][8] = {
{
{ "incQ", { Evh1 }, 0 },
{ "decQ", { Evh1 }, 0 },
- { "call{&|}", { indirEv, BND }, 0 },
+ { "call{&|}", { indirEv, NOTRACK, BND }, 0 },
{ MOD_TABLE (MOD_FF_REG_3) },
- { "jmp{&|}", { indirEv, BND }, 0 },
+ { "jmp{&|}", { indirEv, NOTRACK, BND }, 0 },
{ MOD_TABLE (MOD_FF_REG_5) },
{ "pushU", { stackEv }, 0 },
{ Bad_Opcode },
@@ -12281,6 +12284,7 @@ static const struct dis386 rm_table[][8] = {
#define XACQUIRE_PREFIX (0xf2 | 0x200)
#define XRELEASE_PREFIX (0xf3 | 0x400)
#define BND_PREFIX (0xf2 | 0x400)
+#define NOTRACK_PREFIX (0x3e | 0x100)
static int
ckprefix (void)
@@ -12298,6 +12302,7 @@ ckprefix (void)
last_addr_prefix = -1;
last_rex_prefix = -1;
last_seg_prefix = -1;
+ last_active_prefix = -1;
fwait_prefix = -1;
active_seg_prefix = 0;
for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++)
@@ -12410,7 +12415,10 @@ ckprefix (void)
return 1;
}
if (*codep != FWAIT_OPCODE)
- all_prefixes[i++] = *codep;
+ {
+ last_active_prefix = i;
+ all_prefixes[i++] = *codep;
+ }
rex = newrex;
codep++;
length++;
@@ -12499,6 +12507,8 @@ prefix_name (int pref, int sizeflag)
return "xrelease";
case BND_PREFIX:
return "bnd";
+ case NOTRACK_PREFIX:
+ return "notrack";
default:
return NULL;
}
@@ -16789,6 +16799,34 @@ BND_Fixup (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
all_prefixes[last_repnz_prefix] = BND_PREFIX;
}
+/* For NOTRACK-prefixed instructions, 0x3E prefix should be displayed as
+ "notrack". */
+
+static void
+NOTRACK_Fixup (int bytemode ATTRIBUTE_UNUSED,
+ int sizeflag ATTRIBUTE_UNUSED)
+{
+ if (modrm.mod == 3
+ && active_seg_prefix == PREFIX_DS
+ && (address_mode != mode_64bit || last_data_prefix < 0))
+ {
+ /* NOTRACK prefix is only valid on register indirect branch
+ instructions and it must be the last prefix before REX
+ prefix and opcode. NB: DATA prefix is unsupported for
+ Intel64. */
+ if (last_active_prefix >= 0)
+ {
+ int notrack_prefix = last_active_prefix;
+ if (last_rex_prefix == last_active_prefix)
+ notrack_prefix--;
+ if (all_prefixes[notrack_prefix] != NOTRACK_PREFIX_OPCODE)
+ return;
+ }
+ active_seg_prefix = 0;
+ all_prefixes[last_seg_prefix] = NOTRACK_PREFIX;
+ }
+}
+
/* Similar to OP_E. But the 0xf2/0xf3 prefixes should be displayed as
"xacquire"/"xrelease" for memory operand if there is a LOCK prefix.
*/