x86: Apply standalone prefixes to the following instruction

Message ID CAMe9rOohqV49DVBVRr_kNTyT6ruNYJZgTCWkq4B-Bmh+VRAM=Q@mail.gmail.com
State New
Headers show
Series
  • x86: Apply standalone prefixes to the following instruction
Related show

Commit Message

H.J. Lu July 18, 2019, 10:26 p.m.
Standalone prefixes should be applied to the following instruction,
instead of being treated as regular instructions.  An error should be
issued when a standalone prefix is at the end of source or isn't
followed by an instruction in the same section.

PR gas/24821
* config/tc-i386.c (_i386_insn): Add prev.
(check_hle): Also check i.prev.name for prefix name.
(i386_md_end): New function.
(md_assemble): Apply the standalone prefix to the current
instruction.  Issue an error if a standalone prefix isn't
followed by an instruction in the same section.
(output_insn): Remember the standalone prefix and add it to the
following instruction.
* config/tc-i386.h (i386_md_end): New.
(md_end): Likewise.
* testsuite/gas/i386/i386.exp: Run prefix-2, prefix-3 and
x86-64-prefix-3.
* testsuite/gas/i386/ilp32/rex.d: Updated.
* testsuite/gas/i386/omit-lock-no.d: Likewise.
* testsuite/gas/i386/omit-lock-yes.d: Likewise.
* testsuite/gas/i386/rex.d: Likewise.
* testsuite/gas/i386/white.l: Likewise.
* testsuite/gas/i386/omit-lock.s: Replace standalone lock
with ds.
* testsuite/gas/i386/prefix-2.l: New file.
* testsuite/gas/i386/prefix-2.s: Likewise.
* testsuite/gas/i386/prefix-3.d: Likewise.
* testsuite/gas/i386/prefix-3.s: Likewise.
* testsuite/gas/i386/x86-64-prefix-3.d: Likewise.
* testsuite/gas/i386/rex.s: Add nop after REX prefixes.

-- 
H.J.

Comments

Jan Beulich July 19, 2019, 8:45 a.m. | #1
On 19.07.2019 00:26,  H.J. Lu  wrote:
> Standalone prefixes should be applied to the following instruction,

> instead of being treated as regular instructions.  An error should be

> issued when a standalone prefix is at the end of source or isn't

> followed by an instruction in the same section.


Commenting here, because commenting on the actual code fragments is
not easily possible with the patch sent as attachment.

For one, I don't agree that errors should be issued when switching
sections. Clever assembly programming can easily result in the
actual section later getting resumed, and an appropriate insn being
there.

And then I'm getting the impression that the change here is going
to break things like

static inline unsigned int find_first_set_bit(unsigned long word)
{
     asm ( "rep; bsf %1,%0" : "=r" (word) : "rm" (word) );
     return (unsigned int)word;
}

(quoted from Xen sources), being a backwards compatible
representation of tzcnt. Just like such have shown up in the past,
REP prefixes could easily obtain meaning for other insns going
forward, so tagging individual templates with RepPrefixOk is not
going to help. WBNOINVD is a pretty recent example.

Jan
Florian Weimer July 19, 2019, 9:31 a.m. | #2
* H. J. Lu:

> Standalone prefixes should be applied to the following instruction,

> instead of being treated as regular instructions.  An error should be

> issued when a standalone prefix is at the end of source or isn't

> followed by an instruction in the same section.


glibc used to do this:

| #define __arch_c_compare_and_exchange_val_8_acq(mem, newval, oldval) \
|   ({ __typeof (*mem) ret;                                                    \
|     __asm __volatile ("cmpl $0, %%fs:%P5\n\t"                                \
|                      "je 0f\n\t"                                             \
|                      "lock\n"                                                \
|                       "0:\tcmpxchgb %b2, %1"                                 \
|                       : "=a" (ret), "=m" (*mem)                              \
|                       : "q" (newval), "m" (*mem), "0" (oldval),              \
|                         "i" (offsetof (tcbhead_t, multiple_threads)));       \
|      ret; })

Will this still work?

Thanks,
Florian
H.J. Lu July 19, 2019, 3:01 p.m. | #3
On Fri, Jul 19, 2019 at 1:46 AM Jan Beulich <JBeulich@suse.com> wrote:
>

> On 19.07.2019 00:26,  H.J. Lu  wrote:

> > Standalone prefixes should be applied to the following instruction,

> > instead of being treated as regular instructions.  An error should be

> > issued when a standalone prefix is at the end of source or isn't

> > followed by an instruction in the same section.

>

> Commenting here, because commenting on the actual code fragments is

> not easily possible with the patch sent as attachment.

>

> For one, I don't agree that errors should be issued when switching

> sections. Clever assembly programming can easily result in the

> actual section later getting resumed, and an appropriate insn being

> there.


Yes, you will get an error which can be easily fixed.

> And then I'm getting the impression that the change here is going

> to break things like

>

> static inline unsigned int find_first_set_bit(unsigned long word)

> {

>      asm ( "rep; bsf %1,%0" : "=r" (word) : "rm" (word) );

>      return (unsigned int)word;

> }


"rep; bsf" works like "rep bsf".

> (quoted from Xen sources), being a backwards compatible

> representation of tzcnt. Just like such have shown up in the past,

> REP prefixes could easily obtain meaning for other insns going

> forward, so tagging individual templates with RepPrefixOk is not

> going to help. WBNOINVD is a pretty recent example.

>


Since adding REP to random instructions may lead to different instructions,
RepPrefixOk is used to prevent that.  If one really wants different
instructions,
".byte 0xf3" can be used.

-- 
H.J.
Jan Beulich July 19, 2019, 4:24 p.m. | #4
On 19.07.2019 17:01,  H.J. Lu  wrote:
> On Fri, Jul 19, 2019 at 1:46 AM Jan Beulich <JBeulich@suse.com> wrote:

>>

>> On 19.07.2019 00:26,  H.J. Lu  wrote:

>>> Standalone prefixes should be applied to the following instruction,

>>> instead of being treated as regular instructions.  An error should be

>>> issued when a standalone prefix is at the end of source or isn't

>>> followed by an instruction in the same section.

>>

>> Commenting here, because commenting on the actual code fragments is

>> not easily possible with the patch sent as attachment.

>>

>> For one, I don't agree that errors should be issued when switching

>> sections. Clever assembly programming can easily result in the

>> actual section later getting resumed, and an appropriate insn being

>> there.

> 

> Yes, you will get an error which can be easily fixed.


For both this and ...

>> And then I'm getting the impression that the change here is going

>> to break things like

>>

>> static inline unsigned int find_first_set_bit(unsigned long word)

>> {

>>       asm ( "rep; bsf %1,%0" : "=r" (word) : "rm" (word) );

>>       return (unsigned int)word;

>> }

> 

> "rep; bsf" works like "rep bsf".

> 

>> (quoted from Xen sources), being a backwards compatible

>> representation of tzcnt. Just like such have shown up in the past,

>> REP prefixes could easily obtain meaning for other insns going

>> forward, so tagging individual templates with RepPrefixOk is not

>> going to help. WBNOINVD is a pretty recent example.

>>

> 

> Since adding REP to random instructions may lead to different instructions,

> RepPrefixOk is used to prevent that.  If one really wants different

> instructions,

> ".byte 0xf3" can be used.


... this you realize that breaking existing code is bad? It doesn't
matter how "easy" it is to fix such. Taking Xen (again) as the example,
older trees are supposed to not be touched anymore except for security
fixes. Now if people upgrade their underlying distros, builds of these
older trees will suddenly start to fail.

Furthermore, with your ".byte 0xf3" suggestion, what "protection" do
you achieve when disallowing "rep", but allowing ".byte 0xf3"? Plus
personally I consider the .byte variant quite a bit worse.

Finally, with a number of changes of mine (including the still pending
operand size default changes which I'm slowly making progress with)
you've been demanding that the Linux build not be broken. But just
like Xen, Linux too uses "rep; bsf".

Jan
H.J. Lu July 19, 2019, 5:11 p.m. | #5
On Fri, Jul 19, 2019 at 9:25 AM Jan Beulich <JBeulich@suse.com> wrote:
>

> On 19.07.2019 17:01,  H.J. Lu  wrote:

> > On Fri, Jul 19, 2019 at 1:46 AM Jan Beulich <JBeulich@suse.com> wrote:

> >>

> >> On 19.07.2019 00:26,  H.J. Lu  wrote:

> >>> Standalone prefixes should be applied to the following instruction,

> >>> instead of being treated as regular instructions.  An error should be

> >>> issued when a standalone prefix is at the end of source or isn't

> >>> followed by an instruction in the same section.

> >>

> >> Commenting here, because commenting on the actual code fragments is

> >> not easily possible with the patch sent as attachment.

> >>

> >> For one, I don't agree that errors should be issued when switching

> >> sections. Clever assembly programming can easily result in the

> >> actual section later getting resumed, and an appropriate insn being

> >> there.

> >

> > Yes, you will get an error which can be easily fixed.

>

> For both this and ...

>

> >> And then I'm getting the impression that the change here is going

> >> to break things like

> >>

> >> static inline unsigned int find_first_set_bit(unsigned long word)

> >> {

> >>       asm ( "rep; bsf %1,%0" : "=r" (word) : "rm" (word) );

> >>       return (unsigned int)word;

> >> }

> >

> > "rep; bsf" works like "rep bsf".

> >

> >> (quoted from Xen sources), being a backwards compatible

> >> representation of tzcnt. Just like such have shown up in the past,

> >> REP prefixes could easily obtain meaning for other insns going

> >> forward, so tagging individual templates with RepPrefixOk is not

> >> going to help. WBNOINVD is a pretty recent example.

> >>

> >

> > Since adding REP to random instructions may lead to different instructions,

> > RepPrefixOk is used to prevent that.  If one really wants different

> > instructions,

> > ".byte 0xf3" can be used.

>

> ... this you realize that breaking existing code is bad? It doesn't

> matter how "easy" it is to fix such. Taking Xen (again) as the example,

> older trees are supposed to not be touched anymore except for security

> fixes. Now if people upgrade their underlying distros, builds of these

> older trees will suddenly start to fail.

>

> Furthermore, with your ".byte 0xf3" suggestion, what "protection" do

> you achieve when disallowing "rep", but allowing ".byte 0xf3"? Plus

> personally I consider the .byte variant quite a bit worse.


It will discourage using old assembler for new instructions.  Of course,
one can use ".byte" for anything.

> Finally, with a number of changes of mine (including the still pending

> operand size default changes which I'm slowly making progress with)

> you've been demanding that the Linux build not be broken. But just

> like Xen, Linux too uses "rep; bsf".

>


"rep; bsf" works fine since bsf has RepPrefixOk.  If REP should be
allowed for any instructions, shouldn't RepPrefixOk be removed?

-- 
H.J.
H.J. Lu July 19, 2019, 5:17 p.m. | #6
On Fri, Jul 19, 2019 at 2:31 AM Florian Weimer <fweimer@redhat.com> wrote:
>

> * H. J. Lu:

>

> > Standalone prefixes should be applied to the following instruction,

> > instead of being treated as regular instructions.  An error should be

> > issued when a standalone prefix is at the end of source or isn't

> > followed by an instruction in the same section.

>

> glibc used to do this:

>

> | #define __arch_c_compare_and_exchange_val_8_acq(mem, newval, oldval) \

> |   ({ __typeof (*mem) ret;                                                    \

> |     __asm __volatile ("cmpl $0, %%fs:%P5\n\t"                                \

> |                      "je 0f\n\t"                                             \

> |                      "lock\n"                                                \

> |                       "0:\tcmpxchgb %b2, %1"                                 \

> |                       : "=a" (ret), "=m" (*mem)                              \

> |                       : "q" (newval), "m" (*mem), "0" (oldval),              \

> |                         "i" (offsetof (tcbhead_t, multiple_threads)));       \

> |      ret; })

>

> Will this still work?

>


":" between prefixes and instruction is a special case.   Here is the updated
patch to add i386_frob_colon so that i386 can output all pending stand-alone
prefixes when seeing a colon in the same frag.

-- 
H.J.
From e72df470f74cd3f716eb7a0fb78979faccc27c69 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 18 Jul 2019 14:57:37 -0700
Subject: [PATCH] x86: Apply standalone prefixes to the following instruction

Standalone prefixes should be applied to the following instruction,
instead of being treated as regular instructions.  An error should be
issued when a standalone prefix is at the end of source or isn't
followed by an instruction in the same section.  tc_frob_colon is
added to colon so that i386 can output all pending stand-alone prefixes
when seeing a colon in the same frag.

	PR gas/24821
	* symbols.c (colon): Call tc_frob_colon if defined.
	* config/tc-i386.c (_i386_insn): Add prev.
	(check_hle): Also check i.prev.name for prefix name.
	(i386_frob_colon): New function.
	(i386_md_end): Likewise.
	(md_assemble): Apply the standalone prefix to the current
	instruction.  Issue an error if a standalone prefix isn't
	followed by an instruction in the same section.
	(output_insn): Remember the standalone prefix and add it to the
	following instruction.
	* config/tc-i386.h (i386_md_end): New.
	(md_end): Likewise.
	(i386_frob_colon): Likewise.
	(tc_frob_colon): Likewise.
	* testsuite/gas/i386/i386.exp: Run prefix-2, prefix-3, prefix-4,
	x86-64-prefix-3 and x86-64-prefix-4.
	* testsuite/gas/i386/ilp32/rex.d: Updated.
	* testsuite/gas/i386/omit-lock-no.d: Likewise.
	* testsuite/gas/i386/omit-lock-yes.d: Likewise.
	* testsuite/gas/i386/rex.d: Likewise.
	* testsuite/gas/i386/white.l: Likewise.
	* testsuite/gas/i386/omit-lock.s: Replace standalone lock
	with ds.
	* testsuite/gas/i386/prefix-2.l: New file.
	* testsuite/gas/i386/prefix-2.s: Likewise.
	* testsuite/gas/i386/prefix-3.d: Likewise.
	* testsuite/gas/i386/prefix-4.s: Likewise.
	* testsuite/gas/i386/prefix-4.d: Likewise.
	* testsuite/gas/i386/prefix-3.s: Likewise.
	* testsuite/gas/i386/x86-64-prefix-3.d: Likewise.
	* testsuite/gas/i386/x86-64-prefix-4.d: Likewise.
	* testsuite/gas/i386/rex.s: Add nop after REX prefixes.
---
 gas/config/tc-i386.c                     | 140 +++++++++++++++++++++--
 gas/config/tc-i386.h                     |   6 +
 gas/symbols.c                            |   4 +
 gas/testsuite/gas/i386/i386.exp          |   8 ++
 gas/testsuite/gas/i386/ilp32/rex.d       |  32 +++---
 gas/testsuite/gas/i386/omit-lock-no.d    |   2 +-
 gas/testsuite/gas/i386/omit-lock-yes.d   |   2 +-
 gas/testsuite/gas/i386/omit-lock.s       |   2 +-
 gas/testsuite/gas/i386/prefix-2.l        |   7 ++
 gas/testsuite/gas/i386/prefix-2.s        |  16 +++
 gas/testsuite/gas/i386/prefix-3.d        |  13 +++
 gas/testsuite/gas/i386/prefix-3.s        |  20 ++++
 gas/testsuite/gas/i386/prefix-4.d        |  12 ++
 gas/testsuite/gas/i386/prefix-4.s        |  13 +++
 gas/testsuite/gas/i386/rex.d             |  32 +++---
 gas/testsuite/gas/i386/rex.s             |  19 ++-
 gas/testsuite/gas/i386/white.l           |   4 +-
 gas/testsuite/gas/i386/x86-64-prefix-3.d |  17 +++
 gas/testsuite/gas/i386/x86-64-prefix-4.d |  15 +++
 19 files changed, 318 insertions(+), 46 deletions(-)
 create mode 100644 gas/testsuite/gas/i386/prefix-2.l
 create mode 100644 gas/testsuite/gas/i386/prefix-2.s
 create mode 100644 gas/testsuite/gas/i386/prefix-3.d
 create mode 100644 gas/testsuite/gas/i386/prefix-3.s
 create mode 100644 gas/testsuite/gas/i386/prefix-4.d
 create mode 100644 gas/testsuite/gas/i386/prefix-4.s
 create mode 100644 gas/testsuite/gas/i386/x86-64-prefix-3.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-prefix-4.d

diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 2710dcec72..31200b11cb 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -431,6 +431,25 @@ struct _i386_insn
 
     /* Error message.  */
     enum i386_error error;
+
+    /* Information of previous instruction.  */
+    struct
+      {
+	fragS *frag;
+	const char *name;
+	const char *file;
+	unsigned int line;
+	int error_count;
+	enum
+	  {
+	    insn_unknown,
+	    prefix_notrack,
+	    prefix_hle,
+	    prefix_bnd,
+	    prefix_rep,
+	    prefix_other
+	  } type;
+      } prev;
   };
 
 typedef struct _i386_insn i386_insn;
@@ -3902,7 +3921,8 @@ check_hle (void)
       abort ();
     case HLEPrefixNone:
       as_bad (_("invalid instruction `%s' after `%s'"),
-	      i.tm.name, i.hle_prefix);
+	      i.tm.name,
+	      i.hle_prefix ? i.hle_prefix : i.prev.name);
       return 0;
     case HLEPrefixLock:
       if (i.prefix[LOCK_PREFIX])
@@ -4230,6 +4250,39 @@ optimize_encoding (void)
     }
 }
 
+/* Additioanl processing for colon.  */
+
+void
+i386_frob_colon (const char *name ATTRIBUTE_UNUSED)
+{
+  if (i.prev.name
+      && i.prev.type != insn_unknown
+      && i.prev.frag == frag_now)
+    {
+      /* Output all pending stand-alone prefixes when seeing a colon in
+	 the same frag.  */
+      unsigned char *q;
+      unsigned int j;
+      for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++)
+	if (*q)
+	  FRAG_APPEND_1_CHAR (*q);
+      i.prev.name = NULL;
+    }
+}
+
+/* Issue an error if there is a stand-alone prefix at the end of
+   source.  */
+
+void
+i386_md_end (void)
+{
+  if (i.prev.name
+      && i.prev.type != insn_unknown
+      && i.prev.error_count == had_errors ())
+    as_bad_where (i.prev.file, i.prev.line,
+		  _("stand-alone `%s' prefix"), i.prev.name);
+}
+
 /* This is the guts of the machine-dependent assembler.  LINE points to a
    machine dependent instruction.  This function is supposed to emit
    the frags/bytes it assembles to.  */
@@ -4242,7 +4295,30 @@ md_assemble (char *line)
   const insn_template *t;
 
   /* Initialize globals.  */
-  memset (&i, '\0', sizeof (i));
+  if (i.prev.name
+      && i.prev.type != insn_unknown
+      && i.prev.error_count == had_errors ())
+    {
+      /* If there are no new errors since the previous stand-alone
+	 prefix, add prefix to the current instruction.  */
+      const fragS *fr;
+
+      for (fr = i.prev.frag; fr && fr != frag_now; fr = fr->fr_next)
+	;
+
+      if (fr != frag_now)
+	{
+	  /* Issue an error if the current instruction isn't in the
+	     same section.  */
+	  as_bad_where (i.prev.file, i.prev.line,
+			_("stand-alone `%s' prefix"),
+			i.prev.name);
+	  /* Discard the previous stand-alone prefix.  */
+	  memset (&i, '\0', sizeof (i));
+	}
+    }
+  else
+    memset (&i, '\0', sizeof (i));
   for (j = 0; j < MAX_OPERANDS; j++)
     i.reloc[j] = NO_RELOC;
   memset (disp_expressions, '\0', sizeof (disp_expressions));
@@ -4344,16 +4420,22 @@ md_assemble (char *line)
       return;
 
   /* Check if REP prefix is OK.  */
-  if (i.rep_prefix && !i.tm.opcode_modifier.repprefixok)
+  if ((i.rep_prefix
+       || (i.prev.name
+	   && i.prev.type == prefix_rep
+	   && !i.tm.opcode_modifier.isprefix))
+      && !i.tm.opcode_modifier.repprefixok)
     {
       as_bad (_("invalid instruction `%s' after `%s'"),
-		i.tm.name, i.rep_prefix);
+		i.tm.name,
+		i.rep_prefix ? i.rep_prefix : i.prev.name);
       return;
     }
 
   /* Check for lock without a lockable instruction.  Destination operand
      must be memory unless it is xchg (0x86).  */
   if (i.prefix[LOCK_PREFIX]
+      && !i.tm.opcode_modifier.isprefix
       && (!i.tm.opcode_modifier.islockable
 	  || i.mem_operands == 0
 	  || (i.tm.base_opcode != 0x86
@@ -4371,15 +4453,25 @@ md_assemble (char *line)
     }
 
   /* Check if HLE prefix is OK.  */
-  if (i.hle_prefix && !check_hle ())
+  if ((i.hle_prefix
+       || (i.prev.name
+	   && i.prev.type == prefix_hle
+	   && !i.tm.opcode_modifier.isprefix))
+      && !check_hle ())
     return;
 
   /* Check BND prefix.  */
-  if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok)
+  if ((i.bnd_prefix
+       || (i.prev.name
+	   && i.prev.type == prefix_bnd
+	   && !i.tm.opcode_modifier.isprefix))
+      && !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)
+  if ((i.notrack_prefix
+       || (i.prev.name && i.prev.type == prefix_notrack))
+      && !i.tm.opcode_modifier.notrackprefixok)
     as_bad (_("expecting indirect branch instruction after `notrack'"));
 
   if (i.tm.cpu_flags.bitfield.cpumpx)
@@ -8314,6 +8406,40 @@ output_insn (void)
   insn_start_frag = frag_now;
   insn_start_off = frag_now_fix ();
 
+  if (i.tm.opcode_modifier.isprefix && i.tm.opcode_length == 1)
+    {
+      /* Remember the stand-alone prefix.  */
+      i.prev.name = i.tm.name;
+      i.prev.frag = insn_start_frag;
+      i.prev.file = as_where (&i.prev.line);
+
+      /* Save the current error count.  */
+      i.prev.error_count = had_errors ();
+
+      /* Add the prefix to the following instruction.  */
+      i.prev.type = prefix_other;
+      switch (add_prefix (i.tm.base_opcode))
+	{
+	case PREFIX_DS:
+	  if (i.tm.cpu_flags.bitfield.cpuibt)
+	    i.prev.type = prefix_notrack;
+	  break;
+	case PREFIX_REP:
+	  if (i.tm.cpu_flags.bitfield.cpuhle)
+	    i.prev.type = prefix_hle;
+	  else if (i.tm.cpu_flags.bitfield.cpumpx)
+	    i.prev.type = prefix_bnd;
+	  else
+	    i.prev.type = prefix_rep;
+	  break;
+	default:
+	  break;
+	}
+      return;
+    }
+  else
+    i.prev.name = NULL;
+
   /* Output jumps.  */
   if (i.tm.opcode_modifier.jump)
     output_branch ();
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index b02a25671f..8d1a4d09cf 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -194,6 +194,12 @@ extern int i386_need_index_operator (void);
 extern const struct relax_type md_relax_table[];
 #define TC_GENERIC_RELAX_TABLE md_relax_table
 
+extern void i386_md_end (void);
+#define md_end() i386_md_end ()
+
+extern void i386_frob_colon (const char *);
+#define tc_frob_colon(name) i386_frob_colon (name)
+
 extern int optimize_align_code;
 
 #define md_do_align(n, fill, len, max, around)				\
diff --git a/gas/symbols.c b/gas/symbols.c
index 918028f875..2a3efd7ee0 100644
--- a/gas/symbols.c
+++ b/gas/symbols.c
@@ -458,6 +458,10 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
   obj_frob_colon (sym_name);
 #endif
 
+#ifdef tc_frob_colon
+  tc_frob_colon (sym_name);
+#endif
+
   if ((symbolP = symbol_find (sym_name)) != 0)
     {
       S_CLEAR_WEAKREFR (symbolP);
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index 988f3fffb2..2d5c147471 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -567,6 +567,10 @@ if [expr ([istarget "i*86-*-*"] ||  [istarget "x86_64-*-*"]) && [gas_32_check]]
 	run_dump_test "property-1"
 	run_dump_test "property-2"
 
+	run_list_test "prefix-2"
+	run_dump_test "prefix-3"
+	run_dump_test "prefix-4"
+
 	if { [gas_64_check] } then {
 	    run_dump_test "att-regs"
 	    run_dump_test "intel-regs"
@@ -1088,6 +1092,10 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
 	run_dump_test "evex-no-scale-64"
 	run_dump_test "x86-64-property-1"
 	run_dump_test "x86-64-property-2"
+
+	run_list_test "prefix-2"
+	run_dump_test "x86-64-prefix-3"
+	run_dump_test "x86-64-prefix-4"
     }
 
     set ASFLAGS "$old_ASFLAGS"
diff --git a/gas/testsuite/gas/i386/ilp32/rex.d b/gas/testsuite/gas/i386/ilp32/rex.d
index d8bc1b528c..189461961a 100644
--- a/gas/testsuite/gas/i386/ilp32/rex.d
+++ b/gas/testsuite/gas/i386/ilp32/rex.d
@@ -28,20 +28,20 @@ Disassembly of section .text:
 [	 ]*[0-9a-f]+:[	 ]+9b dd 30\s+fsave\s+\(%rax\)
 [	 ]*[0-9a-f]+:[	 ]+9b 41 dd 30\s+fsave\s+\(%r8\)
 [	 ]*[0-9a-f]+:[	 ]+40 c5 f9 28 00[	 ]+rex vmovapd \(%rax\),%xmm0
-[	 ]*[0-9a-f]+:[	 ]+40[	 ]+rex
-[	 ]*[0-9a-f]+:[	 ]+41[	 ]+rex.B
-[	 ]*[0-9a-f]+:[	 ]+42[	 ]+rex.X
-[	 ]*[0-9a-f]+:[	 ]+43[	 ]+rex.XB
-[	 ]*[0-9a-f]+:[	 ]+44[	 ]+rex.R
-[	 ]*[0-9a-f]+:[	 ]+45[	 ]+rex.RB
-[	 ]*[0-9a-f]+:[	 ]+46[	 ]+rex.RX
-[	 ]*[0-9a-f]+:[	 ]+47[	 ]+rex.RXB
-[	 ]*[0-9a-f]+:[	 ]+48[	 ]+rex.W
-[	 ]*[0-9a-f]+:[	 ]+49[	 ]+rex.WB
-[	 ]*[0-9a-f]+:[	 ]+4a[	 ]+rex.WX
-[	 ]*[0-9a-f]+:[	 ]+4b[	 ]+rex.WXB
-[	 ]*[0-9a-f]+:[	 ]+4c[	 ]+rex.WR
-[	 ]*[0-9a-f]+:[	 ]+4d[	 ]+rex.WRB
-[	 ]*[0-9a-f]+:[	 ]+4e[	 ]+rex.WRX
-[	 ]*[0-9a-f]+:[	 ]+4f[	 ]+rex.WRXB
+[	 ]*[0-9a-f]+:[	 ]+40 90[	 ]+rex xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+41 90[	 ]+xchg[ ]+%eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+42 90[	 ]+rex.X xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+43 90[	 ]+rex.XB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+44 90[	 ]+rex.R xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+45 90[	 ]+rex.RB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+46 90[	 ]+rex.RX xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+47 90[	 ]+rex.RXB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+48 90[	 ]+rex.W nop
+[	 ]*[0-9a-f]+:[	 ]+49 90[	 ]+xchg[ ]+%rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4a 90[	 ]+rex.WX xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4b 90[	 ]+rex.WXB xchg %rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4c 90[	 ]+rex.WR xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4d 90[	 ]+rex.WRB xchg %rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4e 90[	 ]+rex.WRX xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4f 90[	 ]+rex.WRXB xchg %rax,%r8
 #pass
diff --git a/gas/testsuite/gas/i386/omit-lock-no.d b/gas/testsuite/gas/i386/omit-lock-no.d
index 87f796f3a8..a35dfe7cd2 100644
--- a/gas/testsuite/gas/i386/omit-lock-no.d
+++ b/gas/testsuite/gas/i386/omit-lock-no.d
@@ -8,5 +8,5 @@
 Disassembly of section .text:
 
 0+ <main>:
-   0:	f0 f0 83 00 01       	lock lock addl \$0x1,\(%eax\)
+   0:	3e f0 83 00 01       	lock addl \$0x1,%ds:\(%eax\)
 #pass
diff --git a/gas/testsuite/gas/i386/omit-lock-yes.d b/gas/testsuite/gas/i386/omit-lock-yes.d
index 67f0ef196e..1e17e52a24 100644
--- a/gas/testsuite/gas/i386/omit-lock-yes.d
+++ b/gas/testsuite/gas/i386/omit-lock-yes.d
@@ -8,5 +8,5 @@
 Disassembly of section .text:
 
 0+ <main>:
-   0:	83 00 01             	addl   \$0x1,\(%eax\)
+   0:	3e 83 00 01          	addl   \$0x1,%ds:\(%eax\)
 #pass
diff --git a/gas/testsuite/gas/i386/omit-lock.s b/gas/testsuite/gas/i386/omit-lock.s
index 248a9be1fe..1e52498399 100644
--- a/gas/testsuite/gas/i386/omit-lock.s
+++ b/gas/testsuite/gas/i386/omit-lock.s
@@ -1,5 +1,5 @@
 	.text
 .globl main
 main:
-	lock
+	ds
         lock addl $0x1,(%eax)
diff --git a/gas/testsuite/gas/i386/prefix-2.l b/gas/testsuite/gas/i386/prefix-2.l
new file mode 100644
index 0000000000..5dd3a6cd38
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-2.l
@@ -0,0 +1,7 @@
+.*.s: Assembler messages:
+.*.s:3: Error: same type of prefix used twice
+.*.s:6: Error: invalid instruction `movups' after `rep'
+.*.s:8: Error: expecting valid branch instruction after `bnd'
+.*.s:9: Error: stand-alone `rep' prefix
+.*.s:12: Error: invalid instruction `movups' after `repz'
+.*.s:16: Error: stand-alone `lock' prefix
diff --git a/gas/testsuite/gas/i386/prefix-2.s b/gas/testsuite/gas/i386/prefix-2.s
new file mode 100644
index 0000000000..74977772b1
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-2.s
@@ -0,0 +1,16 @@
+	.text
+	rep
+	rep
+	repz stosb
+	rep
+	movups foo, %xmm0
+	bnd
+	movups foo, %xmm0
+	rep
+	.pushsection .foo,"ax",@progbits
+	repz
+	movups foo, %xmm0
+	.popsection
+	movups foo, %xmm1
+	bnd
+	lock
diff --git a/gas/testsuite/gas/i386/prefix-3.d b/gas/testsuite/gas/i386/prefix-3.d
new file mode 100644
index 0000000000..4647730307
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-3.d
@@ -0,0 +1,13 @@
+#objdump: -dw
+#name: i386 prefix 3
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+ <test>:
+ +[a-f0-9]+:	65 f3 f0 0f c1 05 00 00 00 00 	xrelease lock xadd %eax,%gs:0x0
+ +[a-f0-9]+:	f3 aa                	rep stos %al,%es:\(%edi\)
+ +[a-f0-9]+:	f2 e9 fc ff ff ff    	bnd jmp [a-f0-9]+ <test\+0x[a-f0-9]+>
+ +[a-f0-9]+:	f3 c3                	repz ret 
+#pass
diff --git a/gas/testsuite/gas/i386/prefix-3.s b/gas/testsuite/gas/i386/prefix-3.s
new file mode 100644
index 0000000000..7bf48746cf
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-3.s
@@ -0,0 +1,20 @@
+	.text
+test:
+	gs
+	lock
+	xrelease
+	.p2align 4
+	xaddl %eax, foo
+	rep
+
+
+	stosb
+	bnd
+
+	jmp foo
+	rep
+	ret
+.ifdef __64_bit__
+	rex64
+	call foo
+.endif
diff --git a/gas/testsuite/gas/i386/prefix-4.d b/gas/testsuite/gas/i386/prefix-4.d
new file mode 100644
index 0000000000..f297ebce64
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-4.d
@@ -0,0 +1,12 @@
+#objdump: -dw
+#name: i386 prefix 4
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+ <test>:
+ +[a-f0-9]+:	74 03                	je     5 <test\+0x5>
+ +[a-f0-9]+:	77 02                	ja     6 <test\+0x6>
+ +[a-f0-9]+:	f0 f3 0f b0 0d 00 00 00 00 	lock xrelease cmpxchg %cl,0x0
+#pass
diff --git a/gas/testsuite/gas/i386/prefix-4.s b/gas/testsuite/gas/i386/prefix-4.s
new file mode 100644
index 0000000000..943d28cc11
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-4.s
@@ -0,0 +1,13 @@
+	.text
+test:
+	je 0f
+	ja 1f
+	lock
+0:
+	xrelease
+	.data
+foo:
+	.byte 0
+	.text
+1:
+	cmpxchgb %cl, foo
diff --git a/gas/testsuite/gas/i386/rex.d b/gas/testsuite/gas/i386/rex.d
index 22c0c7f30a..79111c8158 100644
--- a/gas/testsuite/gas/i386/rex.d
+++ b/gas/testsuite/gas/i386/rex.d
@@ -27,20 +27,20 @@ Disassembly of section .text:
 [	 ]*[0-9a-f]+:[	 ]+9b dd 30\s+fsave\s+\(%rax\)
 [	 ]*[0-9a-f]+:[	 ]+9b 41 dd 30\s+fsave\s+\(%r8\)
 [	 ]*[0-9a-f]+:[	 ]+40 c5 f9 28 00[	 ]+rex vmovapd \(%rax\),%xmm0
-[	 ]*[0-9a-f]+:[	 ]+40[	 ]+rex
-[	 ]*[0-9a-f]+:[	 ]+41[	 ]+rex.B
-[	 ]*[0-9a-f]+:[	 ]+42[	 ]+rex.X
-[	 ]*[0-9a-f]+:[	 ]+43[	 ]+rex.XB
-[	 ]*[0-9a-f]+:[	 ]+44[	 ]+rex.R
-[	 ]*[0-9a-f]+:[	 ]+45[	 ]+rex.RB
-[	 ]*[0-9a-f]+:[	 ]+46[	 ]+rex.RX
-[	 ]*[0-9a-f]+:[	 ]+47[	 ]+rex.RXB
-[	 ]*[0-9a-f]+:[	 ]+48[	 ]+rex.W
-[	 ]*[0-9a-f]+:[	 ]+49[	 ]+rex.WB
-[	 ]*[0-9a-f]+:[	 ]+4a[	 ]+rex.WX
-[	 ]*[0-9a-f]+:[	 ]+4b[	 ]+rex.WXB
-[	 ]*[0-9a-f]+:[	 ]+4c[	 ]+rex.WR
-[	 ]*[0-9a-f]+:[	 ]+4d[	 ]+rex.WRB
-[	 ]*[0-9a-f]+:[	 ]+4e[	 ]+rex.WRX
-[	 ]*[0-9a-f]+:[	 ]+4f[	 ]+rex.WRXB
+[	 ]*[0-9a-f]+:[	 ]+40 90[	 ]+rex xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+41 90[	 ]+xchg[ ]+%eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+42 90[	 ]+rex.X xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+43 90[	 ]+rex.XB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+44 90[	 ]+rex.R xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+45 90[	 ]+rex.RB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+46 90[	 ]+rex.RX xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+47 90[	 ]+rex.RXB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+48 90[	 ]+rex.W nop
+[	 ]*[0-9a-f]+:[	 ]+49 90[	 ]+xchg[ ]+%rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4a 90[	 ]+rex.WX xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4b 90[	 ]+rex.WXB xchg %rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4c 90[	 ]+rex.WR xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4d 90[	 ]+rex.WRB xchg %rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4e 90[	 ]+rex.WRX xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4f 90[	 ]+rex.WRXB xchg %rax,%r8
 #pass
diff --git a/gas/testsuite/gas/i386/rex.s b/gas/testsuite/gas/i386/rex.s
index c1490ccdee..c33e538686 100644
--- a/gas/testsuite/gas/i386/rex.s
+++ b/gas/testsuite/gas/i386/rex.s
@@ -28,21 +28,36 @@ _start:
 
 # Test prefixes family.
 	rex
+	nop
 	rex.B
+	nop
 	rex.X
+	nop
 	rex.XB
+	nop
 	rex.R
+	nop
 	rex.RB
+	nop
 	rex.RX
+	nop
 	rex.RXB
+	nop
 	rex.W
+	nop
 	rex.WB
+	nop
 	rex.WX
+	nop
 	rex.WXB
+	nop
 	rex.WR
+	nop
 	rex.WRB
+	nop
 	rex.WRX
+	nop
 	rex.WRXB
-# Make sure that the above rex prefix won't become the rex prefix for
-# the padding.
+	nop
 	rex
+	nop
diff --git a/gas/testsuite/gas/i386/white.l b/gas/testsuite/gas/i386/white.l
index 876c9d525f..c0ab623a09 100644
--- a/gas/testsuite/gas/i386/white.l
+++ b/gas/testsuite/gas/i386/white.l
@@ -3,8 +3,8 @@ GAS LISTING .*
 
    1                                	# test handling of whitespace, and upper-case
    2                                	.TeXt 
-   3 0000 36                         		ss 
-   4 0001 8803                       		mov % al , \( % ebx \) 
+   3                                		ss 
+   4 0000 368803                     		mov % al , \( % ebx \) 
    5 0003 C705D711 00007B00 0000     	        mOvl \$ 123 , 4567 
    6 000d 678A787B                   	 ADDr16	mov 123 \( % bx , % si , 1 \) , % bh 
    7 0011 FFE0                       		jmp \* % eax 
diff --git a/gas/testsuite/gas/i386/x86-64-prefix-3.d b/gas/testsuite/gas/i386/x86-64-prefix-3.d
new file mode 100644
index 0000000000..2c29e3651a
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-prefix-3.d
@@ -0,0 +1,17 @@
+#name: x86-64 prefix 3
+#source: prefix-3.s
+#as: -defsym __64_bit__=1
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <test>:
+ +[a-f0-9]+:	65 f3 f0 0f c1 04 25 00 00 00 00 	xrelease lock xadd %eax,%gs:0x0
+ +[a-f0-9]+:	f3 aa                	rep stos %al,%es:\(%rdi\)
+ +[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq [a-f0-9]+ <test\+0x[a-f0-9]+>
+ +[a-f0-9]+:	f3 c3                	repz retq 
+ +[a-f0-9]+:	48 e8 00 00 00 00    	callq  [a-f0-9]+ <test\+0x[a-f0-9]+>
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-prefix-4.d b/gas/testsuite/gas/i386/x86-64-prefix-4.d
new file mode 100644
index 0000000000..555a6d740b
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-prefix-4.d
@@ -0,0 +1,15 @@
+#name: x86-64 prefix 4
+#source: prefix-4.s
+#as: -defsym __64_bit__=1
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <test>:
+ +[a-f0-9]+:	74 03                	je     5 <test\+0x5>
+ +[a-f0-9]+:	77 02                	ja     6 <test\+0x6>
+ +[a-f0-9]+:	f0 f3 0f b0 0c 25 00 00 00 00 	lock xrelease cmpxchg %cl,0x0
+#pass
H.J. Lu July 19, 2019, 5:23 p.m. | #7
On Fri, Jul 19, 2019 at 10:11 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> On Fri, Jul 19, 2019 at 9:25 AM Jan Beulich <JBeulich@suse.com> wrote:

> >

> > On 19.07.2019 17:01,  H.J. Lu  wrote:

> > > On Fri, Jul 19, 2019 at 1:46 AM Jan Beulich <JBeulich@suse.com> wrote:

> > >>

> > >> On 19.07.2019 00:26,  H.J. Lu  wrote:

> > >>> Standalone prefixes should be applied to the following instruction,

> > >>> instead of being treated as regular instructions.  An error should be

> > >>> issued when a standalone prefix is at the end of source or isn't

> > >>> followed by an instruction in the same section.

> > >>

> > >> Commenting here, because commenting on the actual code fragments is

> > >> not easily possible with the patch sent as attachment.

> > >>

> > >> For one, I don't agree that errors should be issued when switching

> > >> sections. Clever assembly programming can easily result in the

> > >> actual section later getting resumed, and an appropriate insn being

> > >> there.

> > >

> > > Yes, you will get an error which can be easily fixed.

> >

> > For both this and ...

> >

> > >> And then I'm getting the impression that the change here is going

> > >> to break things like

> > >>

> > >> static inline unsigned int find_first_set_bit(unsigned long word)

> > >> {

> > >>       asm ( "rep; bsf %1,%0" : "=r" (word) : "rm" (word) );

> > >>       return (unsigned int)word;

> > >> }

> > >

> > > "rep; bsf" works like "rep bsf".

> > >

> > >> (quoted from Xen sources), being a backwards compatible

> > >> representation of tzcnt. Just like such have shown up in the past,

> > >> REP prefixes could easily obtain meaning for other insns going

> > >> forward, so tagging individual templates with RepPrefixOk is not

> > >> going to help. WBNOINVD is a pretty recent example.

> > >>

> > >

> > > Since adding REP to random instructions may lead to different instructions,

> > > RepPrefixOk is used to prevent that.  If one really wants different

> > > instructions,

> > > ".byte 0xf3" can be used.

> >

> > ... this you realize that breaking existing code is bad? It doesn't

> > matter how "easy" it is to fix such. Taking Xen (again) as the example,

> > older trees are supposed to not be touched anymore except for security

> > fixes. Now if people upgrade their underlying distros, builds of these

> > older trees will suddenly start to fail.

> >

> > Furthermore, with your ".byte 0xf3" suggestion, what "protection" do

> > you achieve when disallowing "rep", but allowing ".byte 0xf3"? Plus

> > personally I consider the .byte variant quite a bit worse.

>

> It will discourage using old assembler for new instructions.  Of course,

> one can use ".byte" for anything.

>

> > Finally, with a number of changes of mine (including the still pending

> > operand size default changes which I'm slowly making progress with)

> > you've been demanding that the Linux build not be broken. But just

> > like Xen, Linux too uses "rep; bsf".

> >

>

> "rep; bsf" works fine since bsf has RepPrefixOk.  If REP should be

> allowed for any instructions, shouldn't RepPrefixOk be removed?

>


RepPrefixOk was added by

commit 29c048b696d4e93fe9f595d59fcb6239270e5a29
Author: Roland McGrath <roland@gnu.org>
Date:   Fri Jun 22 16:42:08 2012 +0000

    gas/
            * config/tc-i386.c (parse_insn): Don't complain about REP prefix
            when the template has opcode_modifier.repprefixok set.
            * NEWS: Mention the change.

    gas/testsuite/
            * gas/i386/rep-bsf.d: New file.
            * gas/i386/rep-bsf.s: New file.
            * gas/i386/i386.exp: Add the new test.

    opcodes/
            * i386-opc.h (RepPrefixOk): New enum constant.
            (i386_opcode_modifier): New bitfield 'repprefixok'.
            * i386-gen.c (opcode_modifiers): Add RepPrefixOk.
            * i386-opc.tbl: Add RepPrefixOk to bsf, bsr, and to all
            instructions that have IsString.
            * i386-tbl.h: Regenerate.

We can either remove RepPrefixOk or add it to any instructions
which can have REP.

-- 
H.J.
H.J. Lu July 19, 2019, 5:37 p.m. | #8
On Fri, Jul 19, 2019 at 10:23 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> On Fri, Jul 19, 2019 at 10:11 AM H.J. Lu <hjl.tools@gmail.com> wrote:

> >

> > On Fri, Jul 19, 2019 at 9:25 AM Jan Beulich <JBeulich@suse.com> wrote:

> > >

> > > On 19.07.2019 17:01,  H.J. Lu  wrote:

> > > > On Fri, Jul 19, 2019 at 1:46 AM Jan Beulich <JBeulich@suse.com> wrote:

> > > >>

> > > >> On 19.07.2019 00:26,  H.J. Lu  wrote:

> > > >>> Standalone prefixes should be applied to the following instruction,

> > > >>> instead of being treated as regular instructions.  An error should be

> > > >>> issued when a standalone prefix is at the end of source or isn't

> > > >>> followed by an instruction in the same section.

> > > >>

> > > >> Commenting here, because commenting on the actual code fragments is

> > > >> not easily possible with the patch sent as attachment.

> > > >>

> > > >> For one, I don't agree that errors should be issued when switching

> > > >> sections. Clever assembly programming can easily result in the

> > > >> actual section later getting resumed, and an appropriate insn being

> > > >> there.

> > > >

> > > > Yes, you will get an error which can be easily fixed.

> > >

> > > For both this and ...

> > >

> > > >> And then I'm getting the impression that the change here is going

> > > >> to break things like

> > > >>

> > > >> static inline unsigned int find_first_set_bit(unsigned long word)

> > > >> {

> > > >>       asm ( "rep; bsf %1,%0" : "=r" (word) : "rm" (word) );

> > > >>       return (unsigned int)word;

> > > >> }

> > > >

> > > > "rep; bsf" works like "rep bsf".

> > > >

> > > >> (quoted from Xen sources), being a backwards compatible

> > > >> representation of tzcnt. Just like such have shown up in the past,

> > > >> REP prefixes could easily obtain meaning for other insns going

> > > >> forward, so tagging individual templates with RepPrefixOk is not

> > > >> going to help. WBNOINVD is a pretty recent example.

> > > >>

> > > >

> > > > Since adding REP to random instructions may lead to different instructions,

> > > > RepPrefixOk is used to prevent that.  If one really wants different

> > > > instructions,

> > > > ".byte 0xf3" can be used.

> > >

> > > ... this you realize that breaking existing code is bad? It doesn't

> > > matter how "easy" it is to fix such. Taking Xen (again) as the example,

> > > older trees are supposed to not be touched anymore except for security

> > > fixes. Now if people upgrade their underlying distros, builds of these

> > > older trees will suddenly start to fail.

> > >

> > > Furthermore, with your ".byte 0xf3" suggestion, what "protection" do

> > > you achieve when disallowing "rep", but allowing ".byte 0xf3"? Plus

> > > personally I consider the .byte variant quite a bit worse.

> >

> > It will discourage using old assembler for new instructions.  Of course,

> > one can use ".byte" for anything.

> >

> > > Finally, with a number of changes of mine (including the still pending

> > > operand size default changes which I'm slowly making progress with)

> > > you've been demanding that the Linux build not be broken. But just

> > > like Xen, Linux too uses "rep; bsf".

> > >

> >

> > "rep; bsf" works fine since bsf has RepPrefixOk.  If REP should be

> > allowed for any instructions, shouldn't RepPrefixOk be removed?

> >

>

> RepPrefixOk was added by

>

> commit 29c048b696d4e93fe9f595d59fcb6239270e5a29

> Author: Roland McGrath <roland@gnu.org>

> Date:   Fri Jun 22 16:42:08 2012 +0000

>

>     gas/

>             * config/tc-i386.c (parse_insn): Don't complain about REP prefix

>             when the template has opcode_modifier.repprefixok set.

>             * NEWS: Mention the change.

>

>     gas/testsuite/

>             * gas/i386/rep-bsf.d: New file.

>             * gas/i386/rep-bsf.s: New file.

>             * gas/i386/i386.exp: Add the new test.

>

>     opcodes/

>             * i386-opc.h (RepPrefixOk): New enum constant.

>             (i386_opcode_modifier): New bitfield 'repprefixok'.

>             * i386-gen.c (opcode_modifiers): Add RepPrefixOk.

>             * i386-opc.tbl: Add RepPrefixOk to bsf, bsr, and to all

>             instructions that have IsString.

>             * i386-tbl.h: Regenerate.

>

> We can either remove RepPrefixOk or add it to any instructions

> which can have REP.

>


Gas tried to favor "REP INSN" over "REP; INSN":

https://sourceware.org/ml/binutils/2012-06/msg00180.html
https://sourceware.org/ml/binutils/2012-06/msg00193.html

We can add RepPrefixOk if needed.

-- 
H.J.
Jan Beulich July 22, 2019, 7:52 a.m. | #9
On 19.07.2019 19:37,  H.J. Lu  wrote:
> Gas tried to favor "REP INSN" over "REP; INSN":

> 

> https://sourceware.org/ml/binutils/2012-06/msg00180.html

> https://sourceware.org/ml/binutils/2012-06/msg00193.html

> 

> We can add RepPrefixOk if needed.


And this is the whole point: The form without line separator
should be accepted for templates with RepPrefixOk only. The
one with line separator should (by default) not complain.
I don't mind you adding an option to this effect, but it
ought to be off by default.

As to BSF/BSR having RepPrefixOk - this is exactly what I've
been mentioning before: Recognizing the desire to have it
can't possibly happen early enough. At the point the assembler
supports such insns with the extra attribute, it'll quite
obviously also accept the real mnemonics (TZCNT/LZCNT in this
case). WBNOINVD is a pretty good recent example, as mentioned
before (and I think I did point out that in Xen we already use
"rep; wbinvd" to generate that insn).

IMO BSF/BSR should never have had the attribute added to them.

Jan

Patch

From 34f719635dc6fd820b6b95af4ba938a03f2e95a6 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 18 Jul 2019 14:57:37 -0700
Subject: [PATCH] x86: Apply standalone prefixes to the following instruction

Standalone prefixes should be applied to the following instruction,
instead of being treated as regular instructions.  An error should be
issued when a standalone prefix is at the end of source or isn't
followed by an instruction in the same section.

	PR gas/24821
	* config/tc-i386.c (_i386_insn): Add prev.
	(check_hle): Also check i.prev.name for prefix name.
	(i386_md_end): New function.
	(md_assemble): Apply the standalone prefix to the current
	instruction.  Issue an error if a standalone prefix isn't
	followed by an instruction in the same section.
	(output_insn): Remember the standalone prefix and add it to the
	following instruction.
	* config/tc-i386.h (i386_md_end): New.
	(md_end): Likewise.
	* testsuite/gas/i386/i386.exp: Run prefix-2, prefix-3 and
	x86-64-prefix-3.
	* testsuite/gas/i386/ilp32/rex.d: Updated.
	* testsuite/gas/i386/omit-lock-no.d: Likewise.
	* testsuite/gas/i386/omit-lock-yes.d: Likewise.
	* testsuite/gas/i386/rex.d: Likewise.
	* testsuite/gas/i386/white.l: Likewise.
	* testsuite/gas/i386/omit-lock.s: Replace standalone lock
	with ds.
	* testsuite/gas/i386/prefix-2.l: New file.
	* testsuite/gas/i386/prefix-2.s: Likewise.
	* testsuite/gas/i386/prefix-3.d: Likewise.
	* testsuite/gas/i386/prefix-3.s: Likewise.
	* testsuite/gas/i386/x86-64-prefix-3.d: Likewise.
	* testsuite/gas/i386/rex.s: Add nop after REX prefixes.
---
 gas/config/tc-i386.c                     | 120 +++++++++++++++++++++--
 gas/config/tc-i386.h                     |   3 +
 gas/testsuite/gas/i386/i386.exp          |   6 ++
 gas/testsuite/gas/i386/ilp32/rex.d       |  32 +++---
 gas/testsuite/gas/i386/omit-lock-no.d    |   2 +-
 gas/testsuite/gas/i386/omit-lock-yes.d   |   2 +-
 gas/testsuite/gas/i386/omit-lock.s       |   2 +-
 gas/testsuite/gas/i386/prefix-2.l        |   7 ++
 gas/testsuite/gas/i386/prefix-2.s        |  16 +++
 gas/testsuite/gas/i386/prefix-3.d        |  13 +++
 gas/testsuite/gas/i386/prefix-3.s        |  20 ++++
 gas/testsuite/gas/i386/rex.d             |  32 +++---
 gas/testsuite/gas/i386/rex.s             |  19 +++-
 gas/testsuite/gas/i386/white.l           |   4 +-
 gas/testsuite/gas/i386/x86-64-prefix-3.d |  17 ++++
 15 files changed, 249 insertions(+), 46 deletions(-)
 create mode 100644 gas/testsuite/gas/i386/prefix-2.l
 create mode 100644 gas/testsuite/gas/i386/prefix-2.s
 create mode 100644 gas/testsuite/gas/i386/prefix-3.d
 create mode 100644 gas/testsuite/gas/i386/prefix-3.s
 create mode 100644 gas/testsuite/gas/i386/x86-64-prefix-3.d

diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 2710dcec72..3551cfcde0 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -431,6 +431,25 @@  struct _i386_insn
 
     /* Error message.  */
     enum i386_error error;
+
+    /* Information of previous instruction.  */
+    struct
+      {
+	fragS *frag;
+	const char *name;
+	const char *file;
+	unsigned int line;
+	int error_count;
+	enum
+	  {
+	    insn_unknown,
+	    prefix_notrack,
+	    prefix_hle,
+	    prefix_bnd,
+	    prefix_rep,
+	    prefix_other
+	  } type;
+      } prev;
   };
 
 typedef struct _i386_insn i386_insn;
@@ -3902,7 +3921,8 @@  check_hle (void)
       abort ();
     case HLEPrefixNone:
       as_bad (_("invalid instruction `%s' after `%s'"),
-	      i.tm.name, i.hle_prefix);
+	      i.tm.name,
+	      i.hle_prefix ? i.hle_prefix : i.prev.name);
       return 0;
     case HLEPrefixLock:
       if (i.prefix[LOCK_PREFIX])
@@ -4230,6 +4250,19 @@  optimize_encoding (void)
     }
 }
 
+/* Issue an error if there is a stand-alone prefix at the end of
+   source.  */
+
+void
+i386_md_end (void)
+{
+  if (i.prev.name
+      && i.prev.type != insn_unknown
+      && i.prev.error_count == had_errors ())
+    as_bad_where (i.prev.file, i.prev.line,
+		  _("stand-alone `%s' prefix"), i.prev.name);
+}
+
 /* This is the guts of the machine-dependent assembler.  LINE points to a
    machine dependent instruction.  This function is supposed to emit
    the frags/bytes it assembles to.  */
@@ -4242,7 +4275,30 @@  md_assemble (char *line)
   const insn_template *t;
 
   /* Initialize globals.  */
-  memset (&i, '\0', sizeof (i));
+  if (i.prev.name
+      && i.prev.type != insn_unknown
+      && i.prev.error_count == had_errors ())
+    {
+      /* If there are no new errors since the previous stand-alone
+	 prefix, add prefix to the current instruction.  */
+      const fragS *fr;
+
+      for (fr = i.prev.frag; fr && fr != frag_now; fr = fr->fr_next)
+	;
+
+      if (fr != frag_now)
+	{
+	  /* Issue an error if the current instruction isn't in the
+	     same section.  */
+	  as_bad_where (i.prev.file, i.prev.line,
+			_("stand-alone `%s' prefix"),
+			i.prev.name);
+	  /* Discard the previous stand-alone prefix.  */
+	  memset (&i, '\0', sizeof (i));
+	}
+    }
+  else
+    memset (&i, '\0', sizeof (i));
   for (j = 0; j < MAX_OPERANDS; j++)
     i.reloc[j] = NO_RELOC;
   memset (disp_expressions, '\0', sizeof (disp_expressions));
@@ -4344,16 +4400,22 @@  md_assemble (char *line)
       return;
 
   /* Check if REP prefix is OK.  */
-  if (i.rep_prefix && !i.tm.opcode_modifier.repprefixok)
+  if ((i.rep_prefix
+       || (i.prev.name
+	   && i.prev.type == prefix_rep
+	   && !i.tm.opcode_modifier.isprefix))
+      && !i.tm.opcode_modifier.repprefixok)
     {
       as_bad (_("invalid instruction `%s' after `%s'"),
-		i.tm.name, i.rep_prefix);
+		i.tm.name,
+		i.rep_prefix ? i.rep_prefix : i.prev.name);
       return;
     }
 
   /* Check for lock without a lockable instruction.  Destination operand
      must be memory unless it is xchg (0x86).  */
   if (i.prefix[LOCK_PREFIX]
+      && !i.tm.opcode_modifier.isprefix
       && (!i.tm.opcode_modifier.islockable
 	  || i.mem_operands == 0
 	  || (i.tm.base_opcode != 0x86
@@ -4371,15 +4433,25 @@  md_assemble (char *line)
     }
 
   /* Check if HLE prefix is OK.  */
-  if (i.hle_prefix && !check_hle ())
+  if ((i.hle_prefix
+       || (i.prev.name
+	   && i.prev.type == prefix_hle
+	   && !i.tm.opcode_modifier.isprefix))
+      && !check_hle ())
     return;
 
   /* Check BND prefix.  */
-  if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok)
+  if ((i.bnd_prefix
+       || (i.prev.name
+	   && i.prev.type == prefix_bnd
+	   && !i.tm.opcode_modifier.isprefix))
+      && !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)
+  if ((i.notrack_prefix
+       || (i.prev.name && i.prev.type == prefix_notrack))
+      && !i.tm.opcode_modifier.notrackprefixok)
     as_bad (_("expecting indirect branch instruction after `notrack'"));
 
   if (i.tm.cpu_flags.bitfield.cpumpx)
@@ -8314,6 +8386,40 @@  output_insn (void)
   insn_start_frag = frag_now;
   insn_start_off = frag_now_fix ();
 
+  if (i.tm.opcode_modifier.isprefix && i.tm.opcode_length == 1)
+    {
+      /* Remember the stand-alone prefix.  */
+      i.prev.name = i.tm.name;
+      i.prev.frag = insn_start_frag;
+      i.prev.file = as_where (&i.prev.line);
+
+      /* Save the current error count.  */
+      i.prev.error_count = had_errors ();
+
+      /* Add the prefix to the following instruction.  */
+      i.prev.type = prefix_other;
+      switch (add_prefix (i.tm.base_opcode))
+	{
+	case PREFIX_DS:
+	  if (i.tm.cpu_flags.bitfield.cpuibt)
+	    i.prev.type = prefix_notrack;
+	  break;
+	case PREFIX_REP:
+	  if (i.tm.cpu_flags.bitfield.cpuhle)
+	    i.prev.type = prefix_hle;
+	  else if (i.tm.cpu_flags.bitfield.cpumpx)
+	    i.prev.type = prefix_bnd;
+	  else
+	    i.prev.type = prefix_rep;
+	  break;
+	default:
+	  break;
+	}
+      return;
+    }
+  else
+    i.prev.name = NULL;
+
   /* Output jumps.  */
   if (i.tm.opcode_modifier.jump)
     output_branch ();
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index b02a25671f..44b68acaac 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -194,6 +194,9 @@  extern int i386_need_index_operator (void);
 extern const struct relax_type md_relax_table[];
 #define TC_GENERIC_RELAX_TABLE md_relax_table
 
+extern void i386_md_end (void);
+#define md_end() i386_md_end ();
+
 extern int optimize_align_code;
 
 #define md_do_align(n, fill, len, max, around)				\
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index 988f3fffb2..eaf40f6dda 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -567,6 +567,9 @@  if [expr ([istarget "i*86-*-*"] ||  [istarget "x86_64-*-*"]) && [gas_32_check]]
 	run_dump_test "property-1"
 	run_dump_test "property-2"
 
+	run_list_test "prefix-2"
+	run_dump_test "prefix-3"
+
 	if { [gas_64_check] } then {
 	    run_dump_test "att-regs"
 	    run_dump_test "intel-regs"
@@ -1088,6 +1091,9 @@  if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
 	run_dump_test "evex-no-scale-64"
 	run_dump_test "x86-64-property-1"
 	run_dump_test "x86-64-property-2"
+
+	run_list_test "prefix-2"
+	run_dump_test "x86-64-prefix-3"
     }
 
     set ASFLAGS "$old_ASFLAGS"
diff --git a/gas/testsuite/gas/i386/ilp32/rex.d b/gas/testsuite/gas/i386/ilp32/rex.d
index d8bc1b528c..189461961a 100644
--- a/gas/testsuite/gas/i386/ilp32/rex.d
+++ b/gas/testsuite/gas/i386/ilp32/rex.d
@@ -28,20 +28,20 @@  Disassembly of section .text:
 [	 ]*[0-9a-f]+:[	 ]+9b dd 30\s+fsave\s+\(%rax\)
 [	 ]*[0-9a-f]+:[	 ]+9b 41 dd 30\s+fsave\s+\(%r8\)
 [	 ]*[0-9a-f]+:[	 ]+40 c5 f9 28 00[	 ]+rex vmovapd \(%rax\),%xmm0
-[	 ]*[0-9a-f]+:[	 ]+40[	 ]+rex
-[	 ]*[0-9a-f]+:[	 ]+41[	 ]+rex.B
-[	 ]*[0-9a-f]+:[	 ]+42[	 ]+rex.X
-[	 ]*[0-9a-f]+:[	 ]+43[	 ]+rex.XB
-[	 ]*[0-9a-f]+:[	 ]+44[	 ]+rex.R
-[	 ]*[0-9a-f]+:[	 ]+45[	 ]+rex.RB
-[	 ]*[0-9a-f]+:[	 ]+46[	 ]+rex.RX
-[	 ]*[0-9a-f]+:[	 ]+47[	 ]+rex.RXB
-[	 ]*[0-9a-f]+:[	 ]+48[	 ]+rex.W
-[	 ]*[0-9a-f]+:[	 ]+49[	 ]+rex.WB
-[	 ]*[0-9a-f]+:[	 ]+4a[	 ]+rex.WX
-[	 ]*[0-9a-f]+:[	 ]+4b[	 ]+rex.WXB
-[	 ]*[0-9a-f]+:[	 ]+4c[	 ]+rex.WR
-[	 ]*[0-9a-f]+:[	 ]+4d[	 ]+rex.WRB
-[	 ]*[0-9a-f]+:[	 ]+4e[	 ]+rex.WRX
-[	 ]*[0-9a-f]+:[	 ]+4f[	 ]+rex.WRXB
+[	 ]*[0-9a-f]+:[	 ]+40 90[	 ]+rex xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+41 90[	 ]+xchg[ ]+%eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+42 90[	 ]+rex.X xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+43 90[	 ]+rex.XB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+44 90[	 ]+rex.R xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+45 90[	 ]+rex.RB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+46 90[	 ]+rex.RX xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+47 90[	 ]+rex.RXB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+48 90[	 ]+rex.W nop
+[	 ]*[0-9a-f]+:[	 ]+49 90[	 ]+xchg[ ]+%rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4a 90[	 ]+rex.WX xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4b 90[	 ]+rex.WXB xchg %rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4c 90[	 ]+rex.WR xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4d 90[	 ]+rex.WRB xchg %rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4e 90[	 ]+rex.WRX xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4f 90[	 ]+rex.WRXB xchg %rax,%r8
 #pass
diff --git a/gas/testsuite/gas/i386/omit-lock-no.d b/gas/testsuite/gas/i386/omit-lock-no.d
index 87f796f3a8..a35dfe7cd2 100644
--- a/gas/testsuite/gas/i386/omit-lock-no.d
+++ b/gas/testsuite/gas/i386/omit-lock-no.d
@@ -8,5 +8,5 @@ 
 Disassembly of section .text:
 
 0+ <main>:
-   0:	f0 f0 83 00 01       	lock lock addl \$0x1,\(%eax\)
+   0:	3e f0 83 00 01       	lock addl \$0x1,%ds:\(%eax\)
 #pass
diff --git a/gas/testsuite/gas/i386/omit-lock-yes.d b/gas/testsuite/gas/i386/omit-lock-yes.d
index 67f0ef196e..1e17e52a24 100644
--- a/gas/testsuite/gas/i386/omit-lock-yes.d
+++ b/gas/testsuite/gas/i386/omit-lock-yes.d
@@ -8,5 +8,5 @@ 
 Disassembly of section .text:
 
 0+ <main>:
-   0:	83 00 01             	addl   \$0x1,\(%eax\)
+   0:	3e 83 00 01          	addl   \$0x1,%ds:\(%eax\)
 #pass
diff --git a/gas/testsuite/gas/i386/omit-lock.s b/gas/testsuite/gas/i386/omit-lock.s
index 248a9be1fe..1e52498399 100644
--- a/gas/testsuite/gas/i386/omit-lock.s
+++ b/gas/testsuite/gas/i386/omit-lock.s
@@ -1,5 +1,5 @@ 
 	.text
 .globl main
 main:
-	lock
+	ds
         lock addl $0x1,(%eax)
diff --git a/gas/testsuite/gas/i386/prefix-2.l b/gas/testsuite/gas/i386/prefix-2.l
new file mode 100644
index 0000000000..5dd3a6cd38
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-2.l
@@ -0,0 +1,7 @@ 
+.*.s: Assembler messages:
+.*.s:3: Error: same type of prefix used twice
+.*.s:6: Error: invalid instruction `movups' after `rep'
+.*.s:8: Error: expecting valid branch instruction after `bnd'
+.*.s:9: Error: stand-alone `rep' prefix
+.*.s:12: Error: invalid instruction `movups' after `repz'
+.*.s:16: Error: stand-alone `lock' prefix
diff --git a/gas/testsuite/gas/i386/prefix-2.s b/gas/testsuite/gas/i386/prefix-2.s
new file mode 100644
index 0000000000..74977772b1
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-2.s
@@ -0,0 +1,16 @@ 
+	.text
+	rep
+	rep
+	repz stosb
+	rep
+	movups foo, %xmm0
+	bnd
+	movups foo, %xmm0
+	rep
+	.pushsection .foo,"ax",@progbits
+	repz
+	movups foo, %xmm0
+	.popsection
+	movups foo, %xmm1
+	bnd
+	lock
diff --git a/gas/testsuite/gas/i386/prefix-3.d b/gas/testsuite/gas/i386/prefix-3.d
new file mode 100644
index 0000000000..4647730307
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-3.d
@@ -0,0 +1,13 @@ 
+#objdump: -dw
+#name: i386 prefix 3
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+ <test>:
+ +[a-f0-9]+:	65 f3 f0 0f c1 05 00 00 00 00 	xrelease lock xadd %eax,%gs:0x0
+ +[a-f0-9]+:	f3 aa                	rep stos %al,%es:\(%edi\)
+ +[a-f0-9]+:	f2 e9 fc ff ff ff    	bnd jmp [a-f0-9]+ <test\+0x[a-f0-9]+>
+ +[a-f0-9]+:	f3 c3                	repz ret 
+#pass
diff --git a/gas/testsuite/gas/i386/prefix-3.s b/gas/testsuite/gas/i386/prefix-3.s
new file mode 100644
index 0000000000..7bf48746cf
--- /dev/null
+++ b/gas/testsuite/gas/i386/prefix-3.s
@@ -0,0 +1,20 @@ 
+	.text
+test:
+	gs
+	lock
+	xrelease
+	.p2align 4
+	xaddl %eax, foo
+	rep
+
+
+	stosb
+	bnd
+
+	jmp foo
+	rep
+	ret
+.ifdef __64_bit__
+	rex64
+	call foo
+.endif
diff --git a/gas/testsuite/gas/i386/rex.d b/gas/testsuite/gas/i386/rex.d
index 22c0c7f30a..79111c8158 100644
--- a/gas/testsuite/gas/i386/rex.d
+++ b/gas/testsuite/gas/i386/rex.d
@@ -27,20 +27,20 @@  Disassembly of section .text:
 [	 ]*[0-9a-f]+:[	 ]+9b dd 30\s+fsave\s+\(%rax\)
 [	 ]*[0-9a-f]+:[	 ]+9b 41 dd 30\s+fsave\s+\(%r8\)
 [	 ]*[0-9a-f]+:[	 ]+40 c5 f9 28 00[	 ]+rex vmovapd \(%rax\),%xmm0
-[	 ]*[0-9a-f]+:[	 ]+40[	 ]+rex
-[	 ]*[0-9a-f]+:[	 ]+41[	 ]+rex.B
-[	 ]*[0-9a-f]+:[	 ]+42[	 ]+rex.X
-[	 ]*[0-9a-f]+:[	 ]+43[	 ]+rex.XB
-[	 ]*[0-9a-f]+:[	 ]+44[	 ]+rex.R
-[	 ]*[0-9a-f]+:[	 ]+45[	 ]+rex.RB
-[	 ]*[0-9a-f]+:[	 ]+46[	 ]+rex.RX
-[	 ]*[0-9a-f]+:[	 ]+47[	 ]+rex.RXB
-[	 ]*[0-9a-f]+:[	 ]+48[	 ]+rex.W
-[	 ]*[0-9a-f]+:[	 ]+49[	 ]+rex.WB
-[	 ]*[0-9a-f]+:[	 ]+4a[	 ]+rex.WX
-[	 ]*[0-9a-f]+:[	 ]+4b[	 ]+rex.WXB
-[	 ]*[0-9a-f]+:[	 ]+4c[	 ]+rex.WR
-[	 ]*[0-9a-f]+:[	 ]+4d[	 ]+rex.WRB
-[	 ]*[0-9a-f]+:[	 ]+4e[	 ]+rex.WRX
-[	 ]*[0-9a-f]+:[	 ]+4f[	 ]+rex.WRXB
+[	 ]*[0-9a-f]+:[	 ]+40 90[	 ]+rex xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+41 90[	 ]+xchg[ ]+%eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+42 90[	 ]+rex.X xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+43 90[	 ]+rex.XB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+44 90[	 ]+rex.R xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+45 90[	 ]+rex.RB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+46 90[	 ]+rex.RX xchg %eax,%eax
+[	 ]*[0-9a-f]+:[	 ]+47 90[	 ]+rex.RXB xchg %eax,%r8d
+[	 ]*[0-9a-f]+:[	 ]+48 90[	 ]+rex.W nop
+[	 ]*[0-9a-f]+:[	 ]+49 90[	 ]+xchg[ ]+%rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4a 90[	 ]+rex.WX xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4b 90[	 ]+rex.WXB xchg %rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4c 90[	 ]+rex.WR xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4d 90[	 ]+rex.WRB xchg %rax,%r8
+[	 ]*[0-9a-f]+:[	 ]+4e 90[	 ]+rex.WRX xchg %rax,%rax
+[	 ]*[0-9a-f]+:[	 ]+4f 90[	 ]+rex.WRXB xchg %rax,%r8
 #pass
diff --git a/gas/testsuite/gas/i386/rex.s b/gas/testsuite/gas/i386/rex.s
index c1490ccdee..c33e538686 100644
--- a/gas/testsuite/gas/i386/rex.s
+++ b/gas/testsuite/gas/i386/rex.s
@@ -28,21 +28,36 @@  _start:
 
 # Test prefixes family.
 	rex
+	nop
 	rex.B
+	nop
 	rex.X
+	nop
 	rex.XB
+	nop
 	rex.R
+	nop
 	rex.RB
+	nop
 	rex.RX
+	nop
 	rex.RXB
+	nop
 	rex.W
+	nop
 	rex.WB
+	nop
 	rex.WX
+	nop
 	rex.WXB
+	nop
 	rex.WR
+	nop
 	rex.WRB
+	nop
 	rex.WRX
+	nop
 	rex.WRXB
-# Make sure that the above rex prefix won't become the rex prefix for
-# the padding.
+	nop
 	rex
+	nop
diff --git a/gas/testsuite/gas/i386/white.l b/gas/testsuite/gas/i386/white.l
index 876c9d525f..c0ab623a09 100644
--- a/gas/testsuite/gas/i386/white.l
+++ b/gas/testsuite/gas/i386/white.l
@@ -3,8 +3,8 @@  GAS LISTING .*
 
    1                                	# test handling of whitespace, and upper-case
    2                                	.TeXt 
-   3 0000 36                         		ss 
-   4 0001 8803                       		mov % al , \( % ebx \) 
+   3                                		ss 
+   4 0000 368803                     		mov % al , \( % ebx \) 
    5 0003 C705D711 00007B00 0000     	        mOvl \$ 123 , 4567 
    6 000d 678A787B                   	 ADDr16	mov 123 \( % bx , % si , 1 \) , % bh 
    7 0011 FFE0                       		jmp \* % eax 
diff --git a/gas/testsuite/gas/i386/x86-64-prefix-3.d b/gas/testsuite/gas/i386/x86-64-prefix-3.d
new file mode 100644
index 0000000000..2c29e3651a
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-prefix-3.d
@@ -0,0 +1,17 @@ 
+#name: x86-64 prefix 3
+#source: prefix-3.s
+#as: -defsym __64_bit__=1
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <test>:
+ +[a-f0-9]+:	65 f3 f0 0f c1 04 25 00 00 00 00 	xrelease lock xadd %eax,%gs:0x0
+ +[a-f0-9]+:	f3 aa                	rep stos %al,%es:\(%rdi\)
+ +[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq [a-f0-9]+ <test\+0x[a-f0-9]+>
+ +[a-f0-9]+:	f3 c3                	repz retq 
+ +[a-f0-9]+:	48 e8 00 00 00 00    	callq  [a-f0-9]+ <test\+0x[a-f0-9]+>
+#pass
-- 
2.20.1