This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] x86: Add NOTRACK prefix support
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: binutils at sourceware dot org
- Date: Mon, 22 May 2017 10:51:43 -0700
- Subject: [PATCH] x86: Add NOTRACK prefix support
- Authentication-results: sourceware.org; auth=none
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
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.
I will check it in shortly.
H.J.
---
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.
---
gas/config/tc-i386.c | 75 +-
gas/testsuite/gas/i386/i386.exp | 6 +
gas/testsuite/gas/i386/notrack-intel.d | 29 +
gas/testsuite/gas/i386/notrack.d | 28 +
gas/testsuite/gas/i386/notrack.s | 35 +
gas/testsuite/gas/i386/notrackbad.l | 52 +
gas/testsuite/gas/i386/notrackbad.s | 22 +
gas/testsuite/gas/i386/x86-64-notrack-intel.d | 30 +
gas/testsuite/gas/i386/x86-64-notrack.d | 29 +
gas/testsuite/gas/i386/x86-64-notrack.s | 40 +
gas/testsuite/gas/i386/x86-64-notrackbad.l | 52 +
gas/testsuite/gas/i386/x86-64-notrackbad.s | 22 +
include/opcode/i386.h | 1 +
opcodes/i386-dis.c | 44 +-
opcodes/i386-gen.c | 1 +
opcodes/i386-opc.h | 3 +
opcodes/i386-opc.tbl | 15 +-
opcodes/i386-tbl.h | 21299 ++++++++++++------------
18 files changed, 11114 insertions(+), 10669 deletions(-)
create mode 100644 gas/testsuite/gas/i386/notrack-intel.d
create mode 100644 gas/testsuite/gas/i386/notrack.d
create mode 100644 gas/testsuite/gas/i386/notrack.s
create mode 100644 gas/testsuite/gas/i386/notrackbad.l
create mode 100644 gas/testsuite/gas/i386/notrackbad.s
create mode 100644 gas/testsuite/gas/i386/x86-64-notrack-intel.d
create mode 100644 gas/testsuite/gas/i386/x86-64-notrack.d
create mode 100644 gas/testsuite/gas/i386/x86-64-notrack.s
create mode 100644 gas/testsuite/gas/i386/x86-64-notrackbad.l
create mode 100644 gas/testsuite/gas/i386/x86-64-notrackbad.s
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 6250793..6c1091e 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -66,8 +66,11 @@
#define HLE_PREFIX REP_PREFIX
#define BND_PREFIX REP_PREFIX
#define LOCK_PREFIX 5
-#define REX_PREFIX 6 /* must come last. */
-#define MAX_PREFIXES 7 /* max prefixes per opcode */
+/* Only one of NOTRACK_PREFIX and SEG_PREFIX can be used at the same
+ time. */
+#define NOTRACK_PREFIX 6
+#define REX_PREFIX 7 /* must come last. */
+#define MAX_PREFIXES 8 /* max prefixes per opcode */
/* we define the syntax here (modulo base,index,scale syntax) */
#define REGISTER_PREFIX '%'
@@ -388,6 +391,9 @@ struct _i386_insn
/* Have BND prefix. */
const char *bnd_prefix;
+ /* Have NOTRACK prefix. */
+ const char *notrack_prefix;
+
/* Error message. */
enum i386_error error;
};
@@ -2144,6 +2150,7 @@ enum PREFIX_GROUP
PREFIX_EXIST = 0,
PREFIX_LOCK,
PREFIX_REP,
+ PREFIX_DS,
PREFIX_OTHER
};
@@ -2152,7 +2159,8 @@ enum PREFIX_GROUP
same class already exists.
b. PREFIX_LOCK if lock prefix is added.
c. PREFIX_REP if rep/repne prefix is added.
- d. PREFIX_OTHER if other prefix is added.
+ d. PREFIX_DS if ds prefix is added.
+ e. PREFIX_OTHER if other prefix is added.
*/
static enum PREFIX_GROUP
@@ -2177,8 +2185,10 @@ add_prefix (unsigned int prefix)
default:
abort ();
- case CS_PREFIX_OPCODE:
case DS_PREFIX_OPCODE:
+ ret = PREFIX_DS;
+ /* Fall through. */
+ case CS_PREFIX_OPCODE:
case ES_PREFIX_OPCODE:
case FS_PREFIX_OPCODE:
case GS_PREFIX_OPCODE:
@@ -3702,6 +3712,15 @@ md_assemble (char *line)
if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok)
as_bad (_("expecting valid branch instruction after `bnd'"));
+ /* Check NOTRACK prefix. */
+ if (i.notrack_prefix
+ && (!i.tm.opcode_modifier.notrackprefixok
+ || i.reg_operands != 1
+ || i.disp_operands != 0
+ || i.mem_operands != 0
+ || i.imm_operands != 0))
+ as_bad (_("expecting register indirect branch instruction after `notrack'"));
+
if (i.tm.cpu_flags.bitfield.cpumpx)
{
if (flag_code == CODE_64BIT && i.prefix[ADDR_PREFIX])
@@ -3964,20 +3983,42 @@ parse_insn (char *line, char *mnemonic)
else
{
/* Add prefix, checking for repeated prefixes. */
- switch (add_prefix (current_templates->start->base_opcode))
+ enum PREFIX_GROUP p
+ = add_prefix (current_templates->start->base_opcode);
+ if (p == PREFIX_DS
+ && current_templates->start->cpu_flags.bitfield.cpucet)
{
- case PREFIX_EXIST:
- return NULL;
- case PREFIX_REP:
- if (current_templates->start->cpu_flags.bitfield.cpuhle)
- i.hle_prefix = current_templates->start->name;
- else if (current_templates->start->cpu_flags.bitfield.cpumpx)
- i.bnd_prefix = current_templates->start->name;
- else
- i.rep_prefix = current_templates->start->name;
- break;
- default:
- break;
+ i.notrack_prefix = current_templates->start->name;
+ /* Move NOTRACK_PREFIX_OPCODE to NOTRACK_PREFIX slot so
+ that it is placed before others. */
+ i.prefix[SEG_PREFIX] = 0;
+ i.prefix[NOTRACK_PREFIX] = NOTRACK_PREFIX_OPCODE;
+ }
+ else
+ {
+ switch (p)
+ {
+ case PREFIX_EXIST:
+ return NULL;
+ case PREFIX_REP:
+ if (current_templates->start->cpu_flags.bitfield.cpuhle)
+ i.hle_prefix = current_templates->start->name;
+ else if (current_templates->start->cpu_flags.bitfield.cpumpx)
+ i.bnd_prefix = current_templates->start->name;
+ else
+ i.rep_prefix = current_templates->start->name;
+ break;
+ default:
+ break;
+ }
+
+ if (i.notrack_prefix != NULL)
+ {
+ /* There must be no other prefixes after NOTRACK
+ prefix. */
+ as_bad (_("expecting no other prefixes after `notrack'"));
+ return NULL;
+ }
}
}
/* Skip past PREFIX_SEPARATOR and reset token_start. */
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index c1d6af7..67a7a13 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -385,6 +385,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_32_check]]
run_dump_test "cet"
run_dump_test "cet-intel"
run_dump_test "pseudos"
+ run_dump_test "notrack"
+ run_dump_test "notrack-intel"
+ run_list_test "notrackbad" "-al"
# These tests require support for 8 and 16 bit relocs,
# so we only run them for ELF and COFF targets.
@@ -805,6 +808,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
run_dump_test "x86-64-cet"
run_dump_test "x86-64-cet-intel"
run_dump_test "x86-64-pseudos"
+ run_dump_test "x86-64-notrack"
+ run_dump_test "x86-64-notrack-intel"
+ run_list_test "x86-64-notrackbad" "-al"
if { ![istarget "*-*-aix*"]
&& ![istarget "*-*-beos*"]
diff --git a/gas/testsuite/gas/i386/notrack-intel.d b/gas/testsuite/gas/i386/notrack-intel.d
new file mode 100644
index 0000000..b99e194
--- /dev/null
+++ b/gas/testsuite/gas/i386/notrack-intel.d
@@ -0,0 +1,29 @@
+#source: notrack.s
+#objdump: -dw -Mintel
+#name: i386 NOTRACK prefix (Intel disassembly)
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+[ ]*[a-f0-9]+: 3e ff d0 notrack call eax
+[ ]*[a-f0-9]+: 66 3e ff d0 notrack call ax
+[ ]*[a-f0-9]+: 3e ff e0 notrack jmp eax
+[ ]*[a-f0-9]+: 66 3e ff e0 notrack jmp ax
+[ ]*[a-f0-9]+: f2 3e ff d0 bnd notrack call eax
+[ ]*[a-f0-9]+: 66 f2 3e ff d0 bnd notrack call ax
+[ ]*[a-f0-9]+: f2 3e ff e0 bnd notrack jmp eax
+[ ]*[a-f0-9]+: 66 f2 3e ff e0 bnd notrack jmp ax
+[ ]*[a-f0-9]+: 3e ff d0 notrack call eax
+[ ]*[a-f0-9]+: 66 3e ff d0 notrack call ax
+[ ]*[a-f0-9]+: 3e ff e0 notrack jmp eax
+[ ]*[a-f0-9]+: 66 3e ff e0 notrack jmp ax
+[ ]*[a-f0-9]+: f2 3e ff d0 bnd notrack call eax
+[ ]*[a-f0-9]+: 66 f2 3e ff d0 bnd notrack call ax
+[ ]*[a-f0-9]+: f2 3e ff e0 bnd notrack jmp eax
+[ ]*[a-f0-9]+: 66 f2 3e ff e0 bnd notrack jmp ax
+[ ]*[a-f0-9]+: 3e f2 ff d0 ds bnd call eax
+[ ]*[a-f0-9]+: 3e 66 ff d0 ds call ax
+#pass
diff --git a/gas/testsuite/gas/i386/notrack.d b/gas/testsuite/gas/i386/notrack.d
new file mode 100644
index 0000000..eda09eb
--- /dev/null
+++ b/gas/testsuite/gas/i386/notrack.d
@@ -0,0 +1,28 @@
+#objdump: -dw
+#name: i386 NOTRACK prefix
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+[ ]*[a-f0-9]+: 3e ff d0 notrack call \*%eax
+[ ]*[a-f0-9]+: 66 3e ff d0 notrack callw \*%ax
+[ ]*[a-f0-9]+: 3e ff e0 notrack jmp \*%eax
+[ ]*[a-f0-9]+: 66 3e ff e0 notrack jmpw \*%ax
+[ ]*[a-f0-9]+: f2 3e ff d0 bnd notrack call \*%eax
+[ ]*[a-f0-9]+: 66 f2 3e ff d0 bnd notrack callw \*%ax
+[ ]*[a-f0-9]+: f2 3e ff e0 bnd notrack jmp \*%eax
+[ ]*[a-f0-9]+: 66 f2 3e ff e0 bnd notrack jmpw \*%ax
+[ ]*[a-f0-9]+: 3e ff d0 notrack call \*%eax
+[ ]*[a-f0-9]+: 66 3e ff d0 notrack callw \*%ax
+[ ]*[a-f0-9]+: 3e ff e0 notrack jmp \*%eax
+[ ]*[a-f0-9]+: 66 3e ff e0 notrack jmpw \*%ax
+[ ]*[a-f0-9]+: f2 3e ff d0 bnd notrack call \*%eax
+[ ]*[a-f0-9]+: 66 f2 3e ff d0 bnd notrack callw \*%ax
+[ ]*[a-f0-9]+: f2 3e ff e0 bnd notrack jmp \*%eax
+[ ]*[a-f0-9]+: 66 f2 3e ff e0 bnd notrack jmpw \*%ax
+[ ]*[a-f0-9]+: 3e f2 ff d0 ds bnd call \*%eax
+[ ]*[a-f0-9]+: 3e 66 ff d0 ds callw \*%ax
+#pass
diff --git a/gas/testsuite/gas/i386/notrack.s b/gas/testsuite/gas/i386/notrack.s
new file mode 100644
index 0000000..3b8b210
--- /dev/null
+++ b/gas/testsuite/gas/i386/notrack.s
@@ -0,0 +1,35 @@
+# Check 32bit NOTRACK prefix
+
+ .allow_index_reg
+ .text
+_start:
+ notrack call *%eax
+ notrack call *%ax
+ notrack jmp *%eax
+ notrack jmp *%ax
+
+ bnd notrack call *%eax
+ bnd notrack call *%ax
+ bnd notrack jmp *%eax
+ bnd notrack jmp *%ax
+
+ .intel_syntax noprefix
+ notrack call eax
+ notrack call ax
+ notrack jmp eax
+ notrack jmp ax
+
+ bnd notrack call eax
+ bnd notrack call ax
+ bnd notrack jmp eax
+ bnd notrack jmp ax
+
+ .byte 0x3e
+ .byte 0xf2
+ .byte 0xff
+ .byte 0xd0
+
+ .byte 0x3e
+ .byte 0x66
+ .byte 0xff
+ .byte 0xd0
diff --git a/gas/testsuite/gas/i386/notrackbad.l b/gas/testsuite/gas/i386/notrackbad.l
new file mode 100644
index 0000000..b092ab2
--- /dev/null
+++ b/gas/testsuite/gas/i386/notrackbad.l
@@ -0,0 +1,52 @@
+.*: Assembler messages:
+.*:6: Error: expecting register indirect branch instruction after `notrack'
+.*:6: Warning: skipping prefixes on this instruction
+.*:7: Error: expecting register indirect branch instruction after `notrack'
+.*:7: Warning: skipping prefixes on this instruction
+.*:9: Error: expecting register indirect branch instruction after `notrack'
+.*:10: Error: expecting register indirect branch instruction after `notrack'
+.*:11: Error: same type of prefix used twice
+.*:12: Error: expecting no other prefixes after `notrack'
+.*:13: Error: expecting no other prefixes after `notrack'
+.*:14: Error: expecting no other prefixes after `notrack'
+.*:17: Error: expecting register indirect branch instruction after `notrack'
+.*:18: Error: expecting register indirect branch instruction after `notrack'
+.*:19: Error: same type of prefix used twice
+.*:20: Error: expecting no other prefixes after `notrack'
+.*:21: Error: expecting no other prefixes after `notrack'
+.*:22: Error: expecting no other prefixes after `notrack'
+GAS LISTING .*
+
+
+[ ]*1[ ]+\# Check 32bit unsupported NOTRACK prefix
+[ ]*2[ ]+
+[ ]*3[ ]+\.allow_index_reg
+[ ]*4[ ]+\.text
+[ ]*5[ ]+_start:
+[ ]*6[ ]+\?\?\?\? E8FCFFFF notrack call foo
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+\*\*\*\* Warning: skipping prefixes on this instruction
+[ ]*6[ ]+FF
+[ ]*7[ ]+\?\?\?\? E9FCFFFF notrack jmp foo
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+\*\*\*\* Warning: skipping prefixes on this instruction
+[ ]*7[ ]+FF
+[ ]*8[ ]+
+[ ]*9[ ]+\?\?\?\? 3EFF10 notrack call \*\(%eax\)
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+[ ]*10[ ]+\?\?\?\? 3EFF20 notrack jmp \*\(%eax\)
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+[ ]*11[ ]+fs notrack call \*%eax
+[ ]*12[ ]+notrack fs call \*%eax
+[ ]*13[ ]+notrack bnd call \*%eax
+[ ]*14[ ]+notrack data16 call \*%eax
+[ ]*15[ ]+
+[ ]*16[ ]+\.intel_syntax noprefix
+[ ]*17[ ]+\?\?\?\? 3EFF10 notrack call \[eax\]
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+[ ]*18[ ]+\?\?\?\? 3EFF20 notrack jmp \[eax\]
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+[ ]*19[ ]+fs notrack call eax
+[ ]*20[ ]+notrack fs call eax
+[ ]*21[ ]+notrack bnd call eax
+[ ]*22[ ]+notrack data16 call eax
diff --git a/gas/testsuite/gas/i386/notrackbad.s b/gas/testsuite/gas/i386/notrackbad.s
new file mode 100644
index 0000000..c7eae50
--- /dev/null
+++ b/gas/testsuite/gas/i386/notrackbad.s
@@ -0,0 +1,22 @@
+# Check 32bit unsupported NOTRACK prefix
+
+ .allow_index_reg
+ .text
+_start:
+ notrack call foo
+ notrack jmp foo
+
+ notrack call *(%eax)
+ notrack jmp *(%eax)
+ fs notrack call *%eax
+ notrack fs call *%eax
+ notrack bnd call *%eax
+ notrack data16 call *%eax
+
+ .intel_syntax noprefix
+ notrack call [eax]
+ notrack jmp [eax]
+ fs notrack call eax
+ notrack fs call eax
+ notrack bnd call eax
+ notrack data16 call eax
diff --git a/gas/testsuite/gas/i386/x86-64-notrack-intel.d b/gas/testsuite/gas/i386/x86-64-notrack-intel.d
new file mode 100644
index 0000000..6e0cfdb
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-notrack-intel.d
@@ -0,0 +1,30 @@
+#source: x86-64-notrack.s
+#objdump: -dw -Mintel
+#name: x86-64 NOTRACK prefix (Intel disassembly)
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+[ ]*[a-f0-9]+: 3e ff d0 notrack call rax
+[ ]*[a-f0-9]+: 3e 41 ff d0 notrack call r8
+[ ]*[a-f0-9]+: 3e ff e0 notrack jmp rax
+[ ]*[a-f0-9]+: 3e 41 ff e0 notrack jmp r8
+[ ]*[a-f0-9]+: f2 3e ff d0 bnd notrack call rax
+[ ]*[a-f0-9]+: f2 3e 41 ff d0 bnd notrack call r8
+[ ]*[a-f0-9]+: f2 3e ff e0 bnd notrack jmp rax
+[ ]*[a-f0-9]+: f2 3e 41 ff e0 bnd notrack jmp r8
+[ ]*[a-f0-9]+: 3e ff d0 notrack call rax
+[ ]*[a-f0-9]+: 3e 41 ff d0 notrack call r8
+[ ]*[a-f0-9]+: 3e ff e0 notrack jmp rax
+[ ]*[a-f0-9]+: 3e 41 ff e0 notrack jmp r8
+[ ]*[a-f0-9]+: f2 3e ff d0 bnd notrack call rax
+[ ]*[a-f0-9]+: f2 3e 41 ff d0 bnd notrack call r8
+[ ]*[a-f0-9]+: f2 3e ff e0 bnd notrack jmp rax
+[ ]*[a-f0-9]+: f2 3e 41 ff e0 bnd notrack jmp r8
+[ ]*[a-f0-9]+: 3e f2 ff d0 ds bnd call rax
+[ ]*[a-f0-9]+: 3e 66 ff d0 ds call ax
+[ ]*[a-f0-9]+: 66 3e ff d0 ds call ax
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-notrack.d b/gas/testsuite/gas/i386/x86-64-notrack.d
new file mode 100644
index 0000000..0f63f12
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-notrack.d
@@ -0,0 +1,29 @@
+#objdump: -dw
+#name: x86-64 NOTRACK prefix
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+[ ]*[a-f0-9]+: 3e ff d0 notrack callq \*%rax
+[ ]*[a-f0-9]+: 3e 41 ff d0 notrack callq \*%r8
+[ ]*[a-f0-9]+: 3e ff e0 notrack jmpq \*%rax
+[ ]*[a-f0-9]+: 3e 41 ff e0 notrack jmpq \*%r8
+[ ]*[a-f0-9]+: f2 3e ff d0 bnd notrack callq \*%rax
+[ ]*[a-f0-9]+: f2 3e 41 ff d0 bnd notrack callq \*%r8
+[ ]*[a-f0-9]+: f2 3e ff e0 bnd notrack jmpq \*%rax
+[ ]*[a-f0-9]+: f2 3e 41 ff e0 bnd notrack jmpq \*%r8
+[ ]*[a-f0-9]+: 3e ff d0 notrack callq \*%rax
+[ ]*[a-f0-9]+: 3e 41 ff d0 notrack callq \*%r8
+[ ]*[a-f0-9]+: 3e ff e0 notrack jmpq \*%rax
+[ ]*[a-f0-9]+: 3e 41 ff e0 notrack jmpq \*%r8
+[ ]*[a-f0-9]+: f2 3e ff d0 bnd notrack callq \*%rax
+[ ]*[a-f0-9]+: f2 3e 41 ff d0 bnd notrack callq \*%r8
+[ ]*[a-f0-9]+: f2 3e ff e0 bnd notrack jmpq \*%rax
+[ ]*[a-f0-9]+: f2 3e 41 ff e0 bnd notrack jmpq \*%r8
+[ ]*[a-f0-9]+: 3e f2 ff d0 ds bnd callq \*%rax
+[ ]*[a-f0-9]+: 3e 66 ff d0 ds callw \*%ax
+[ ]*[a-f0-9]+: 66 3e ff d0 ds callw \*%ax
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-notrack.s b/gas/testsuite/gas/i386/x86-64-notrack.s
new file mode 100644
index 0000000..f90a870
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-notrack.s
@@ -0,0 +1,40 @@
+# Check 64bit NOTRACK prefix
+
+ .allow_index_reg
+ .text
+_start:
+ notrack call *%rax
+ notrack call *%r8
+ notrack jmp *%rax
+ notrack jmp *%r8
+
+ bnd notrack call *%rax
+ bnd notrack call *%r8
+ bnd notrack jmp *%rax
+ bnd notrack jmp *%r8
+
+ .intel_syntax noprefix
+ notrack call rax
+ notrack call r8
+ notrack jmp rax
+ notrack jmp r8
+
+ bnd notrack call rax
+ bnd notrack call r8
+ bnd notrack jmp rax
+ bnd notrack jmp r8
+
+ .byte 0x3e
+ .byte 0xf2
+ .byte 0xff
+ .byte 0xd0
+
+ .byte 0x3e
+ .byte 0x66
+ .byte 0xff
+ .byte 0xd0
+
+ .byte 0x66
+ .byte 0x3e
+ .byte 0xff
+ .byte 0xd0
diff --git a/gas/testsuite/gas/i386/x86-64-notrackbad.l b/gas/testsuite/gas/i386/x86-64-notrackbad.l
new file mode 100644
index 0000000..a72e37d
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-notrackbad.l
@@ -0,0 +1,52 @@
+.*: Assembler messages:
+.*:6: Error: expecting register indirect branch instruction after `notrack'
+.*:6: Warning: skipping prefixes on this instruction
+.*:7: Error: expecting register indirect branch instruction after `notrack'
+.*:7: Warning: skipping prefixes on this instruction
+.*:9: Error: expecting register indirect branch instruction after `notrack'
+.*:10: Error: expecting register indirect branch instruction after `notrack'
+.*:11: Error: same type of prefix used twice
+.*:12: Error: expecting no other prefixes after `notrack'
+.*:13: Error: expecting no other prefixes after `notrack'
+.*:14: Error: expecting no other prefixes after `notrack'
+.*:17: Error: expecting register indirect branch instruction after `notrack'
+.*:18: Error: expecting register indirect branch instruction after `notrack'
+.*:19: Error: same type of prefix used twice
+.*:20: Error: expecting no other prefixes after `notrack'
+.*:21: Error: expecting no other prefixes after `notrack'
+.*:22: Error: expecting no other prefixes after `notrack'
+GAS LISTING .*
+
+
+[ ]*1[ ]+\# Check 64bit unsupported NOTRACK prefix
+[ ]*2[ ]+
+[ ]*3[ ]+\.allow_index_reg
+[ ]*4[ ]+\.text
+[ ]*5[ ]+_start:
+[ ]*6[ ]+\?\?\?\? E8000000 notrack call foo
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+\*\*\*\* Warning: skipping prefixes on this instruction
+[ ]*6[ ]+00
+[ ]*7[ ]+\?\?\?\? E9000000 notrack jmp foo
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+\*\*\*\* Warning: skipping prefixes on this instruction
+[ ]*7[ ]+00
+[ ]*8[ ]+
+[ ]*9[ ]+\?\?\?\? 3EFF10 notrack call \*\(%rax\)
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+[ ]*10[ ]+\?\?\?\? 3EFF20 notrack jmp \*\(%rax\)
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+[ ]*11[ ]+fs notrack call \*%rax
+[ ]*12[ ]+notrack fs call \*%rax
+[ ]*13[ ]+notrack bnd call \*%rax
+[ ]*14[ ]+notrack data16 call \*%rax
+[ ]*15[ ]+
+[ ]*16[ ]+\.intel_syntax noprefix
+[ ]*17[ ]+\?\?\?\? 3EFF10 notrack call \[rax\]
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+[ ]*18[ ]+\?\?\?\? 3EFF20 notrack jmp \[rax\]
+\*\*\*\* Error: expecting register indirect branch instruction after `notrack'
+[ ]*19[ ]+fs notrack call rax
+[ ]*20[ ]+notrack fs call rax
+[ ]*21[ ]+notrack bnd call rax
+[ ]*22[ ]+notrack data16 call rax
diff --git a/gas/testsuite/gas/i386/x86-64-notrackbad.s b/gas/testsuite/gas/i386/x86-64-notrackbad.s
new file mode 100644
index 0000000..59d6248
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-notrackbad.s
@@ -0,0 +1,22 @@
+# Check 64bit unsupported NOTRACK prefix
+
+ .allow_index_reg
+ .text
+_start:
+ notrack call foo
+ notrack jmp foo
+
+ notrack call *(%rax)
+ notrack jmp *(%rax)
+ fs notrack call *%rax
+ notrack fs call *%rax
+ notrack bnd call *%rax
+ notrack data16 call *%rax
+
+ .intel_syntax noprefix
+ notrack call [rax]
+ notrack jmp [rax]
+ fs notrack call rax
+ notrack fs call rax
+ notrack bnd call rax
+ notrack data16 call rax
diff --git a/include/opcode/i386.h b/include/opcode/i386.h
index 58cbf06..8d271be 100644
--- a/include/opcode/i386.h
+++ b/include/opcode/i386.h
@@ -77,6 +77,7 @@
#define XACQUIRE_PREFIX_OPCODE 0xf2
#define XRELEASE_PREFIX_OPCODE 0xf3
#define BND_PREFIX_OPCODE 0xf2
+#define NOTRACK_PREFIX_OPCODE 0x3e
#define TWO_BYTE_OPCODE_ESCAPE 0x0f
#define NOP_OPCODE (char) 0x90
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.
*/
diff --git a/opcodes/i386-gen.c b/opcodes/i386-gen.c
index 8d7941c..eacdb4f 100644
--- a/opcodes/i386-gen.c
+++ b/opcodes/i386-gen.c
@@ -566,6 +566,7 @@ static bitfield opcode_modifiers[] =
BITFIELD (FWait),
BITFIELD (IsString),
BITFIELD (BNDPrefixOk),
+ BITFIELD (NoTrackPrefixOk),
BITFIELD (IsLockable),
BITFIELD (RegKludge),
BITFIELD (FirstXmm0),
diff --git a/opcodes/i386-opc.h b/opcodes/i386-opc.h
index d1a6a45..ccc774a 100644
--- a/opcodes/i386-opc.h
+++ b/opcodes/i386-opc.h
@@ -407,6 +407,8 @@ enum
IsString,
/* quick test if branch instruction is MPX supported */
BNDPrefixOk,
+ /* quick test if NOTRACK prefix is supported */
+ NoTrackPrefixOk,
/* quick test for lockable instructions */
IsLockable,
/* fake an extra reg operand for clr, imul and special register
@@ -622,6 +624,7 @@ typedef struct i386_opcode_modifier
unsigned int fwait:1;
unsigned int isstring:1;
unsigned int bndprefixok:1;
+ unsigned int notrackprefixok:1;
unsigned int islockable:1;
unsigned int regkludge:1;
unsigned int firstxmm0:1;
diff --git a/opcodes/i386-opc.tbl b/opcodes/i386-opc.tbl
index 242bbf5..5b1a4fd 100644
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -312,9 +312,9 @@ shrd, 2, 0xfad, None, 2, Cpu386, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, {
call, 1, 0xe8, None, 1, CpuNo64, JumpDword|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp16|Disp32 }
call, 1, 0xe8, None, 1, Cpu64, AMD64|JumpDword|DefaultSize|No_bSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk, { Disp16|Disp32S }
call, 1, 0xe8, None, 1, Cpu64, Intel64|JumpDword|DefaultSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk, { Disp32S }
-call, 1, 0xff, 0x2, 1, CpuNo64, Modrm|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Reg16|Reg32|Word|Dword|Unspecified|BaseIndex|Disp8|Disp16|Disp32|JumpAbsolute }
-call, 1, 0xff, 0x2, 1, Cpu64, AMD64|Modrm|DefaultSize|No_bSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk, { Reg16|Reg64|Word|Qword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|JumpAbsolute }
-call, 1, 0xff, 0x2, 1, Cpu64, Intel64|Modrm|DefaultSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk, { Reg64|Qword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|JumpAbsolute }
+call, 1, 0xff, 0x2, 1, CpuNo64, Modrm|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk|NoTrackPrefixOk, { Reg16|Reg32|Word|Dword|Unspecified|BaseIndex|Disp8|Disp16|Disp32|JumpAbsolute }
+call, 1, 0xff, 0x2, 1, Cpu64, AMD64|Modrm|DefaultSize|No_bSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk|NoTrackPrefixOk, { Reg16|Reg64|Word|Qword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|JumpAbsolute }
+call, 1, 0xff, 0x2, 1, Cpu64, Intel64|Modrm|DefaultSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk|NoTrackPrefixOk, { Reg64|Qword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|JumpAbsolute }
// Intel Syntax
call, 2, 0x9a, None, 1, CpuNo64, JumpInterSegment|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Imm16, Imm16|Imm32 }
// Intel Syntax
@@ -325,9 +325,9 @@ lcall, 1, 0xff, 0x3, 1, 0, Modrm|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, {
jmp, 1, 0xeb, None, 1, CpuNo64, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32 }
jmp, 1, 0xeb, None, 1, Cpu64, AMD64|Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32S }
jmp, 1, 0xeb, None, 1, Cpu64, Intel64|Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp32S }
-jmp, 1, 0xff, 0x4, 1, CpuNo64, Modrm|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Reg16|Reg32|Word|Dword|Unspecified|BaseIndex|Disp8|Disp16|Disp32|JumpAbsolute }
-jmp, 1, 0xff, 0x4, 1, Cpu64, AMD64|Modrm|No_bSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk, { Reg16|Reg64|Word|Qword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|JumpAbsolute }
-jmp, 1, 0xff, 0x4, 1, Cpu64, Intel64|Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk, { Reg64|Qword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|JumpAbsolute }
+jmp, 1, 0xff, 0x4, 1, CpuNo64, Modrm|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk|NoTrackPrefixOk, { Reg16|Reg32|Word|Dword|Unspecified|BaseIndex|Disp8|Disp16|Disp32|JumpAbsolute }
+jmp, 1, 0xff, 0x4, 1, Cpu64, AMD64|Modrm|No_bSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk|NoTrackPrefixOk, { Reg16|Reg64|Word|Qword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|JumpAbsolute }
+jmp, 1, 0xff, 0x4, 1, Cpu64, Intel64|Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk|NoTrackPrefixOk, { Reg64|Qword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|JumpAbsolute }
// Intel Syntax.
jmp, 2, 0xea, None, 1, CpuNo64, JumpInterSegment|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Imm16, Imm16|Imm32 }
// Intel Syntax.
@@ -6024,4 +6024,7 @@ clrssbsy, 1, 0xf30fae, 0x6, 2, CpuCET, Modrm|IgnoreSize|No_bSuf|No_wSuf|No_lSuf|
endbr64, 0, 0xf30f1efa, None, 3, CpuCET, IgnoreSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { 0 }
endbr32, 0, 0xf30f1efb, None, 3, CpuCET, IgnoreSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { 0 }
+// notrack prefix
+notrack, 0, 0x3e, None, 1, CpuCET, No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|IsPrefix, { 0 }
+
// CET instructions end.