This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] x86: Add .nop directive to assembler


On Fri, Feb 16, 2018 at 4:49 PM, Alan Modra <amodra@gmail.com> wrote:
> On Fri, Feb 16, 2018 at 08:07:50AM -0800, H.J. Lu wrote:
>> Good points.  Here is the updated patch.   OK for master?
>
> OK, except for one quibble with the default md_generate_nops.  I think
> that should error rather than filling with zeros (which is likely to
> be an illegal instruction or trap).
>

Fixed.  This is the patch I will check in tomorrow.

Thanks.

-- 
H.J.
From 2fe9da0602ad115c02a1164b3237f12df3d5b130 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 9 Feb 2018 03:46:06 -0800
Subject: [PATCH] Add .nop assembler directive

Implement the '.nop SIZE[, CONTROL]' assembler directive, which emits
SIZE bytes filled with no-op instructions.  SIZE is absolute expression.
The optional CONTROL byte controls how no-op instructions should be
generated.  If the comma and @var{control} are omitted, CONTROL is
assumed to be zero.

For Intel 80386 and AMD x86-64 targets, CONTROL byte specifies the size
limit of a single no-op instruction.  The valid values of CONTROL byte
are between 0 and 8 for 16-bit mode, between 0 and 10 for 32-bit mode,
between 0 and 11 for 64-bit mode.  When 0 is used, the no-op size limit
is set to the maximum supported size.

2 new relax states, rs_space_nop and rs_fill_nop, are added to enum
_relax_state, which are similar to rs_space and rs_fill, respectively,
but they fill with no-op instructions, instead of a single byte.  A
target backend must override the default md_generate_nops to generate
proper no-op instructions.  Otherwise, an error of unimplemented .nop
directive will be issued whenever .nop directive is used.

gas/

	* as.h (_relax_state): Add rs_space_nop and rs_fill_nop.
	* read.c (potable): Add .nop.
	(s_nop): New function.
	* read.h (s_nop): New prototype.
	* write.c (cvt_frag_to_fill): Handle rs_space_nop and
	rs_fill_nop.
	(md_generate_nops): New function.
	(relax_segment): Likewise.
	(write_contents): Use md_generate_nops for rs_fill_nop.
	* config/tc-i386.c (alt64_11): New.
	(alt64_patt): Likewise.
	(md_convert_frag): Handle rs_space_nop.
	(i386_output_nops): New function.
	(i386_generate_nops): Likewise.
	(i386_align_code): Call i386_output_nops.
	* config/tc-i386.h (i386_generate_nops): New.
	(md_generate_nops): Likewise.
	* doc/as.texinfo: Document .nop directive.
	* testsuite/gas/i386/i386.exp: Run .nop directive tests.
	* testsuite/gas/i386/nop-1.d: New file.
	* testsuite/gas/i386/nop-1.s: Likewise.
	* testsuite/gas/i386/nop-2.d: Likewise.
	* testsuite/gas/i386/nop-2.s: Likewise.
	* testsuite/gas/i386/nop-3.d: Likewise.
	* testsuite/gas/i386/nop-3.s: Likewise.
	* testsuite/gas/i386/nop-4.d: Likewise.
	* testsuite/gas/i386/nop-4.s: Likewise.
	* testsuite/gas/i386/nop-5.d: Likewise.
	* testsuite/gas/i386/nop-5.s: Likewise.
	* testsuite/gas/i386/nop-6.d: Likewise.
	* testsuite/gas/i386/nop-6.s: Likewise.
	* testsuite/gas/i386/nop-bad-1.l: Likewise.
	* testsuite/gas/i386/nop-bad-1.s: Likewise.
	* testsuite/gas/i386/x86-64-nop-1.d: Likewise.
	* testsuite/gas/i386/x86-64-nop-2.d: Likewise.
	* testsuite/gas/i386/x86-64-nop-3.d: Likewise.
	* testsuite/gas/i386/x86-64-nop-4.d: Likewise.
	* testsuite/gas/i386/x86-64-nop-5.d: Likewise.
	* testsuite/gas/i386/x86-64-nop-6.d: Likewise.
---
 gas/as.h                              |  10 ++
 gas/config/tc-i386.c                  | 272 +++++++++++++++++++++-------------
 gas/config/tc-i386.h                  |   5 +
 gas/doc/as.texinfo                    |  18 +++
 gas/read.c                            |  53 +++++++
 gas/read.h                            |   1 +
 gas/testsuite/gas/i386/i386.exp       |  13 ++
 gas/testsuite/gas/i386/nop-1.d        |  31 ++++
 gas/testsuite/gas/i386/nop-1.s        |  21 +++
 gas/testsuite/gas/i386/nop-2.d        |  40 +++++
 gas/testsuite/gas/i386/nop-2.s        |  22 +++
 gas/testsuite/gas/i386/nop-3.d        |  20 +++
 gas/testsuite/gas/i386/nop-3.s        |  15 ++
 gas/testsuite/gas/i386/nop-4.d        |  23 +++
 gas/testsuite/gas/i386/nop-4.s        |  18 +++
 gas/testsuite/gas/i386/nop-5.d        |  25 ++++
 gas/testsuite/gas/i386/nop-5.s        |  19 +++
 gas/testsuite/gas/i386/nop-6.d        |  17 +++
 gas/testsuite/gas/i386/nop-6.s        |  25 ++++
 gas/testsuite/gas/i386/nop-bad-1.l    |   4 +
 gas/testsuite/gas/i386/nop-bad-1.s    |   4 +
 gas/testsuite/gas/i386/x86-64-nop-1.d |  32 ++++
 gas/testsuite/gas/i386/x86-64-nop-2.d |  41 +++++
 gas/testsuite/gas/i386/x86-64-nop-3.d |  21 +++
 gas/testsuite/gas/i386/x86-64-nop-4.d |  24 +++
 gas/testsuite/gas/i386/x86-64-nop-5.d |  26 ++++
 gas/testsuite/gas/i386/x86-64-nop-6.d |  18 +++
 gas/write.c                           |  59 +++++++-
 28 files changed, 766 insertions(+), 111 deletions(-)
 create mode 100644 gas/testsuite/gas/i386/nop-1.d
 create mode 100644 gas/testsuite/gas/i386/nop-1.s
 create mode 100644 gas/testsuite/gas/i386/nop-2.d
 create mode 100644 gas/testsuite/gas/i386/nop-2.s
 create mode 100644 gas/testsuite/gas/i386/nop-3.d
 create mode 100644 gas/testsuite/gas/i386/nop-3.s
 create mode 100644 gas/testsuite/gas/i386/nop-4.d
 create mode 100644 gas/testsuite/gas/i386/nop-4.s
 create mode 100644 gas/testsuite/gas/i386/nop-5.d
 create mode 100644 gas/testsuite/gas/i386/nop-5.s
 create mode 100644 gas/testsuite/gas/i386/nop-6.d
 create mode 100644 gas/testsuite/gas/i386/nop-6.s
 create mode 100644 gas/testsuite/gas/i386/nop-bad-1.l
 create mode 100644 gas/testsuite/gas/i386/nop-bad-1.s
 create mode 100644 gas/testsuite/gas/i386/x86-64-nop-1.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-nop-2.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-nop-3.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-nop-4.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-nop-5.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-nop-6.d

diff --git a/gas/as.h b/gas/as.h
index c33353a9c5..d75ff42523 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -279,6 +279,16 @@ enum _relax_state
      1 variable char: fill character  */
   rs_space,
 
+  /* .nop directive with expression operand that needs to be computed
+     later.  Similar to rs_space, but different.  It fills with no-op
+     instructions.
+     fr_symbol: operand
+     1 constant byte: no-op fill control byte.  */
+  rs_space_nop,
+
+  /* Similar to rs_fill.  It is used to implement .nop directive .  */
+  rs_fill_nop,
+
   /* A DWARF leb128 value; only ELF uses this.  The subtype is 0 for
      unsigned, 1 for signed.  */
   rs_leb128,
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 1a5be1bcda..c67ea1f224 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -1146,105 +1146,174 @@ static struct hash_control *op_hash;
 /* Hash table for register lookup.  */
 static struct hash_control *reg_hash;
 
-void
-i386_align_code (fragS *fragP, int count)
-{
   /* Various efficient no-op patterns for aligning code labels.
      Note: Don't try to assemble the instructions in the comments.
      0L and 0w are not legal.  */
-  static const unsigned char f32_1[] =
-    {0x90};					/* nop			*/
-  static const unsigned char f32_2[] =
-    {0x66,0x90};				/* xchg %ax,%ax */
-  static const unsigned char f32_3[] =
-    {0x8d,0x76,0x00};				/* leal 0(%esi),%esi	*/
-  static const unsigned char f32_4[] =
-    {0x8d,0x74,0x26,0x00};			/* leal 0(%esi,1),%esi	*/
-  static const unsigned char f32_5[] =
-    {0x90,					/* nop			*/
-     0x8d,0x74,0x26,0x00};			/* leal 0(%esi,1),%esi	*/
-  static const unsigned char f32_6[] =
-    {0x8d,0xb6,0x00,0x00,0x00,0x00};		/* leal 0L(%esi),%esi	*/
-  static const unsigned char f32_7[] =
-    {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};	/* leal 0L(%esi,1),%esi */
-  static const unsigned char f32_8[] =
-    {0x90,					/* nop			*/
-     0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};	/* leal 0L(%esi,1),%esi */
-  static const unsigned char f32_9[] =
-    {0x89,0xf6,					/* movl %esi,%esi	*/
-     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
-  static const unsigned char f32_10[] =
-    {0x8d,0x76,0x00,				/* leal 0(%esi),%esi	*/
-     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
-  static const unsigned char f32_11[] =
-    {0x8d,0x74,0x26,0x00,			/* leal 0(%esi,1),%esi	*/
-     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
-  static const unsigned char f32_12[] =
-    {0x8d,0xb6,0x00,0x00,0x00,0x00,		/* leal 0L(%esi),%esi	*/
-     0x8d,0xbf,0x00,0x00,0x00,0x00};		/* leal 0L(%edi),%edi	*/
-  static const unsigned char f32_13[] =
-    {0x8d,0xb6,0x00,0x00,0x00,0x00,		/* leal 0L(%esi),%esi	*/
-     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
-  static const unsigned char f32_14[] =
-    {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00,	/* leal 0L(%esi,1),%esi */
-     0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
-  static const unsigned char f16_3[] =
-    {0x8d,0x74,0x00};				/* lea 0(%esi),%esi	*/
-  static const unsigned char f16_4[] =
-    {0x8d,0xb4,0x00,0x00};			/* lea 0w(%si),%si	*/
-  static const unsigned char f16_5[] =
-    {0x90,					/* nop			*/
-     0x8d,0xb4,0x00,0x00};			/* lea 0w(%si),%si	*/
-  static const unsigned char f16_6[] =
-    {0x89,0xf6,					/* mov %si,%si		*/
-     0x8d,0xbd,0x00,0x00};			/* lea 0w(%di),%di	*/
-  static const unsigned char f16_7[] =
-    {0x8d,0x74,0x00,				/* lea 0(%si),%si	*/
-     0x8d,0xbd,0x00,0x00};			/* lea 0w(%di),%di	*/
-  static const unsigned char f16_8[] =
-    {0x8d,0xb4,0x00,0x00,			/* lea 0w(%si),%si	*/
-     0x8d,0xbd,0x00,0x00};			/* lea 0w(%di),%di	*/
-  static const unsigned char jump_31[] =
-    {0xeb,0x1d,0x90,0x90,0x90,0x90,0x90,	/* jmp .+31; lotsa nops	*/
-     0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
-     0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
-     0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
-  static const unsigned char *const f32_patt[] = {
-    f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8,
-    f32_9, f32_10, f32_11, f32_12, f32_13, f32_14
-  };
-  static const unsigned char *const f16_patt[] = {
-    f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8
-  };
-  /* nopl (%[re]ax) */
-  static const unsigned char alt_3[] =
-    {0x0f,0x1f,0x00};
-  /* nopl 0(%[re]ax) */
-  static const unsigned char alt_4[] =
-    {0x0f,0x1f,0x40,0x00};
-  /* nopl 0(%[re]ax,%[re]ax,1) */
-  static const unsigned char alt_5[] =
-    {0x0f,0x1f,0x44,0x00,0x00};
-  /* nopw 0(%[re]ax,%[re]ax,1) */
-  static const unsigned char alt_6[] =
-    {0x66,0x0f,0x1f,0x44,0x00,0x00};
-  /* nopl 0L(%[re]ax) */
-  static const unsigned char alt_7[] =
-    {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
-  /* nopl 0L(%[re]ax,%[re]ax,1) */
-  static const unsigned char alt_8[] =
-    {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
-  /* nopw 0L(%[re]ax,%[re]ax,1) */
-  static const unsigned char alt_9[] =
-    {0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
-  /* nopw %cs:0L(%[re]ax,%[re]ax,1) */
-  static const unsigned char alt_10[] =
-    {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
-  static const unsigned char *const alt_patt[] = {
-    f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8,
-    alt_9, alt_10
-  };
+static const unsigned char f32_1[] =
+  {0x90};				/* nop			*/
+static const unsigned char f32_2[] =
+  {0x66,0x90};				/* xchg %ax,%ax		*/
+static const unsigned char f32_3[] =
+  {0x8d,0x76,0x00};			/* leal 0(%esi),%esi	*/
+static const unsigned char f32_4[] =
+  {0x8d,0x74,0x26,0x00};		/* leal 0(%esi,1),%esi	*/
+static const unsigned char f32_5[] =
+  {0x90,				/* nop			*/
+   0x8d,0x74,0x26,0x00};		/* leal 0(%esi,1),%esi	*/
+static const unsigned char f32_6[] =
+  {0x8d,0xb6,0x00,0x00,0x00,0x00};	/* leal 0L(%esi),%esi	*/
+static const unsigned char f32_7[] =
+  {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};	/* leal 0L(%esi,1),%esi */
+static const unsigned char f32_8[] =
+  {0x90,				/* nop			*/
+   0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};	/* leal 0L(%esi,1),%esi */
+static const unsigned char f32_9[] =
+  {0x89,0xf6,				/* movl %esi,%esi	*/
+   0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
+static const unsigned char f32_10[] =
+  {0x8d,0x76,0x00,			/* leal 0(%esi),%esi	*/
+   0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
+static const unsigned char f32_11[] =
+  {0x8d,0x74,0x26,0x00,			/* leal 0(%esi,1),%esi	*/
+   0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
+static const unsigned char f32_12[] =
+  {0x8d,0xb6,0x00,0x00,0x00,0x00,	/* leal 0L(%esi),%esi	*/
+   0x8d,0xbf,0x00,0x00,0x00,0x00};	/* leal 0L(%edi),%edi	*/
+static const unsigned char f32_13[] =
+  {0x8d,0xb6,0x00,0x00,0x00,0x00,	/* leal 0L(%esi),%esi	*/
+   0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
+static const unsigned char f32_14[] =
+  {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00,	/* leal 0L(%esi,1),%esi */
+   0x8d,0xbc,0x27,0x00,0x00,0x00,0x00};	/* leal 0L(%edi,1),%edi */
+static const unsigned char f16_3[] =
+  {0x8d,0x74,0x00};			/* lea 0(%esi),%esi	*/
+static const unsigned char f16_4[] =
+  {0x8d,0xb4,0x00,0x00};		/* lea 0w(%si),%si	*/
+static const unsigned char f16_5[] =
+  {0x90,				/* nop			*/
+   0x8d,0xb4,0x00,0x00};		/* lea 0w(%si),%si	*/
+static const unsigned char f16_6[] =
+  {0x89,0xf6,				/* mov %si,%si		*/
+   0x8d,0xbd,0x00,0x00};		/* lea 0w(%di),%di	*/
+static const unsigned char f16_7[] =
+  {0x8d,0x74,0x00,			/* lea 0(%si),%si	*/
+   0x8d,0xbd,0x00,0x00};		/* lea 0w(%di),%di	*/
+static const unsigned char f16_8[] =
+  {0x8d,0xb4,0x00,0x00,			/* lea 0w(%si),%si	*/
+   0x8d,0xbd,0x00,0x00};		/* lea 0w(%di),%di	*/
+static const unsigned char jump_31[] =
+  {0xeb,0x1d,0x90,0x90,0x90,0x90,0x90,	/* jmp .+31; lotsa nops	*/
+   0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
+   0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
+   0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
+/* 32-bit NOPs patterns.  */
+static const unsigned char *const f32_patt[] = {
+  f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8,
+  f32_9, f32_10, f32_11, f32_12, f32_13, f32_14
+};
+/* 16-bit NOPs patterns.  */
+static const unsigned char *const f16_patt[] = {
+  f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8
+};
+/* nopl (%[re]ax) */
+static const unsigned char alt_3[] =
+  {0x0f,0x1f,0x00};
+/* nopl 0(%[re]ax) */
+static const unsigned char alt_4[] =
+  {0x0f,0x1f,0x40,0x00};
+/* nopl 0(%[re]ax,%[re]ax,1) */
+static const unsigned char alt_5[] =
+  {0x0f,0x1f,0x44,0x00,0x00};
+/* nopw 0(%[re]ax,%[re]ax,1) */
+static const unsigned char alt_6[] =
+  {0x66,0x0f,0x1f,0x44,0x00,0x00};
+/* nopl 0L(%[re]ax) */
+static const unsigned char alt_7[] =
+  {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
+/* nopl 0L(%[re]ax,%[re]ax,1) */
+static const unsigned char alt_8[] =
+  {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
+/* nopw 0L(%[re]ax,%[re]ax,1) */
+static const unsigned char alt_9[] =
+  {0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
+/* nopw %cs:0L(%[re]ax,%[re]ax,1) */
+static const unsigned char alt_10[] =
+  {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
+/* 32-bit and 64-bit NOPs patterns.  */
+static const unsigned char *const alt_patt[] = {
+  f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8,
+  alt_9, alt_10
+};
+/* 64-bit only: nopw %cs:0L(%eax,%eax,1) */
+static const unsigned char alt64_11[] =
+  {0x67,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
+/* 64-bit NOPs patterns.  */
+static const unsigned char *const alt64_patt[] = {
+  f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8,
+  alt_9, alt_10, alt64_11
+};
+
+/* Genenerate COUNT bytes of NOPs to WHERE from PATT with the maximum
+   size of a single NOP instruction MAX_SINGLE_NOP_SIZE.  */
 
+static void
+i386_output_nops (char *where, const unsigned char *const *patt,
+		  int count, int max_single_nop_size)
+
+{
+  while (count > max_single_nop_size)
+    {
+      count -= max_single_nop_size;
+      memcpy (where + count, patt[max_single_nop_size - 1],
+	      max_single_nop_size);
+    }
+
+  if (count)
+    memcpy (where, patt[count - 1], count);
+}
+
+
+/* Genenerate COUNT bytes of NOPs to WHERE with the maximum size of a
+   single NOP instruction LIMIT.  */
+
+void
+i386_generate_nops (fragS *f, char *where, offsetT count, int limit)
+{
+  /* Output NOPs for .nop directive.  */
+  int max_single_nop_size;
+  const unsigned char *const *patt;
+
+  if (flag_code == CODE_16BIT)
+    {
+      patt = f16_patt;
+      max_single_nop_size = sizeof (f16_patt) / sizeof (f16_patt[0]);
+    }
+  else if (flag_code == CODE_64BIT)
+    {
+      patt = alt64_patt;
+      max_single_nop_size = sizeof (alt64_patt) / sizeof (alt64_patt[0]);
+    }
+  else
+    {
+      patt = alt_patt;
+      max_single_nop_size = sizeof (alt_patt) / sizeof (alt_patt[0]);
+    }
+  if (limit == 0)
+    limit = max_single_nop_size;
+  else if (limit > max_single_nop_size)
+    {
+      as_bad_where (f->fr_file, f->fr_line,
+		    _("invalide single nop size: %d (expect within [0, %d])"),
+		    limit, max_single_nop_size);
+      return;
+    }
+
+  i386_output_nops (where, patt, count, limit);
+}
+
+void
+i386_align_code (fragS *fragP, int count)
+{
   /* Only align for at least a positive non-zero boundary. */
   if (count <= 0 || count > MAX_MEM_FOR_RS_ALIGN_CODE)
     return;
@@ -1397,17 +1466,8 @@ i386_align_code (fragS *fragP, int count)
 	  /* Maximum length of an instruction is 10 byte.  If the
 	     padding is greater than 10 bytes and we don't use jump,
 	     we have to break it into smaller pieces.  */
-	  int padding = count;
-	  while (padding > 10)
-	    {
-	      padding -= 10;
-	      memcpy (fragP->fr_literal + fragP->fr_fix + padding,
-		      patt [9], 10);
-	    }
-
-	  if (padding)
-	    memcpy (fragP->fr_literal + fragP->fr_fix,
-		    patt [padding - 1], padding);
+	  i386_output_nops (fragP->fr_literal + fragP->fr_fix,
+			    patt, count, 10);
 	}
     }
   fragP->fr_var = count;
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index 6e4f440c09..1250bc25f5 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -281,6 +281,11 @@ extern void sco_id (void);
 
 #define WORKING_DOT_WORD 1
 
+/* How to generate NOPs for .nop direct directive.  */
+extern void i386_generate_nops (fragS *, char *, offsetT, int);
+#define md_generate_nops(frag, where, amount, control) \
+  i386_generate_nops ((frag), (where), (amount), (control))
+
 /* We want .cfi_* pseudo-ops for generating unwind info.  */
 #define TARGET_USE_CFIPOP 1
 
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index f4e0fddefb..3084bcb871 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -4479,6 +4479,7 @@ Some machine configurations provide additional directives.
 * MRI::				@code{.mri @var{val}}
 * Noaltmacro::                  @code{.noaltmacro}
 * Nolist::                      @code{.nolist}
+* Nop::                         @code{.nop @var{size}[, @var{control}]}
 * Octa::                        @code{.octa @var{bignums}}
 * Offset::			@code{.offset @var{loc}}
 * Org::                         @code{.org @var{new-lc}, @var{fill}}
@@ -6101,6 +6102,23 @@ internal counter (which is zero initially).   @code{.list} increments the
 counter, and @code{.nolist} decrements it.  Assembly listings are
 generated whenever the counter is greater than zero.
 
+@node Nop
+@section @code{.nop @var{size}[, @var{control}]}
+
+@cindex @code{nop} directive
+@cindex filling memory with no-op instructions
+This directive emits @var{size} bytes filled with no-op instructions.
+@var{size} is absolute expression, which must be a positve value.
+@var{control} controls how no-op instructions should be generated.  If
+the comma and @var{control} are omitted, @var{control} is assumed to be
+zero.
+
+Note: For Intel 80386 and AMD x86-64 targets, @var{control} specifies
+the size limit of a no-op instruction.  The valid values of @var{control}
+are between 0 and 8 for 16-bit mode, between 0 and 10 for 32-bit mode,
+between 0 and 11 for 64-bit mode.  When 0 is used, the no-op instruction
+size limit is set to the maximum supported size.
+
 @node Octa
 @section @code{.octa @var{bignums}}
 
diff --git a/gas/read.c b/gas/read.c
index 7bf52f1121..9ab88f8962 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -442,6 +442,7 @@ static const pseudo_typeS potable[] = {
 /* size  */
   {"space", s_space, 0},
   {"skip", s_space, 0},
+  {"nop", s_nop, 0},
   {"sleb128", s_leb128, 1},
   {"spc", s_ignore, 0},
   {"stabd", s_stab, 'd'},
@@ -3508,6 +3509,58 @@ s_space (int mult)
     mri_comment_end (stop, stopc);
 }
 
+void
+s_nop (int ignore ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+  expressionS val;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+#ifdef md_cons_align
+  md_cons_align (1);
+#endif
+
+  expression (&exp);
+
+  if (*input_line_pointer == ',')
+    {
+      ++input_line_pointer;
+      expression (&val);
+    }
+  else
+    {
+      val.X_op = O_constant;
+      val.X_add_number = 0;
+    }
+
+  if (val.X_op == O_constant)
+    {
+      if (val.X_add_number < 0)
+	{
+	  as_warn (_("negative nop control byte, ignored"));
+	  val.X_add_number = 0;
+	}
+
+      if (!need_pass_2)
+	{
+	  /* Store the no-op instruction control byte in the first byte
+	     of frag.  */
+	  char *p;
+	  symbolS *sym = make_expr_symbol (&exp);
+	  p = frag_var (rs_space_nop, 1, 1, (relax_substateT) 0,
+			sym, (offsetT) 0, (char *) 0);
+	  *p = val.X_add_number;
+	}
+    }
+  else
+    as_bad (_("unsupported variable nop control in .nop directive"));
+
+  demand_empty_rest_of_line ();
+}
+
 /* This is like s_space, but the value is a floating point number with
    the given precision.  This is for the MRI dcb.s pseudo-op and
    friends.  */
diff --git a/gas/read.h b/gas/read.h
index eebdc4e745..3f0927bc9e 100644
--- a/gas/read.h
+++ b/gas/read.h
@@ -206,6 +206,7 @@ extern void s_purgem (int);
 extern void s_rept (int);
 extern void s_set (int);
 extern void s_space (int mult);
+extern void s_nop (int);
 extern void s_stab (int what);
 extern void s_struct (int);
 extern void s_text (int);
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index a21ef84997..0ca49ea46f 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -431,6 +431,8 @@ if [expr ([istarget "i*86-*-*"] ||  [istarget "x86_64-*-*"]) && [gas_32_check]]
     run_dump_test "align-1a"
     run_dump_test "align-1b"
     run_list_test "inval-pseudo" "-al"
+    run_dump_test "nop-1"
+    run_dump_test "nop-2"
 
     # These tests require support for 8 and 16 bit relocs,
     # so we only run them for ELF and COFF targets.
@@ -494,6 +496,10 @@ if [expr ([istarget "i*86-*-*"] ||  [istarget "x86_64-*-*"]) && [gas_32_check]]
 	run_dump_test "got-no-relax"
 
 	run_dump_test "addend"
+	run_dump_test "nop-3"
+	run_dump_test "nop-4"
+	run_dump_test "nop-5"
+	run_dump_test "nop-6"
 
 	if { [gas_64_check] } then {
 	    run_dump_test "att-regs"
@@ -538,6 +544,7 @@ if [expr [istarget "i*86-*-*"] || [istarget "x86_64-*-*"]] then {
     run_list_test "space1" "-al"
     run_dump_test rept
     run_dump_test pr19498
+    run_list_test "nop-bad-1" ""
     if [is_elf_format] then {
 	run_list_test_stdin "list-1" "-al"
 	run_list_test_stdin "list-2" "-al"
@@ -904,6 +911,8 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
     run_list_test "x86-64-notrackbad" "-al"
     run_dump_test "x86-64-movd"
     run_dump_test "x86-64-movd-intel"
+    run_dump_test "x86-64-nop-1"
+    run_dump_test "x86-64-nop-2"
 
     if { ![istarget "*-*-aix*"]
       && ![istarget "*-*-beos*"]
@@ -961,6 +970,10 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
 	run_dump_test "x86-64-gotpcrel-no-relax"
 
 	run_dump_test "x86-64-addend"
+	run_dump_test "x86-64-nop-3"
+	run_dump_test "x86-64-nop-4"
+	run_dump_test "x86-64-nop-5"
+	run_dump_test "x86-64-nop-6"
     }
 
     set ASFLAGS "$old_ASFLAGS"
diff --git a/gas/testsuite/gas/i386/nop-1.d b/gas/testsuite/gas/i386/nop-1.d
new file mode 100644
index 0000000000..46422c88db
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-1.d
@@ -0,0 +1,31 @@
+#objdump: -drw
+#name: i386 .nop 1
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <single>:
+ +[a-f0-9]+:	90                   	nop
+
+0+1 <pseudo_1>:
+ +[a-f0-9]+:	90                   	nop
+
+0+2 <pseudo_8>:
+ +[a-f0-9]+:	0f 1f 84 00 00 00 00 00 	nopl   0x0\(%eax,%eax,1\)
+
+0+a <pseudo_8_4>:
+ +[a-f0-9]+:	0f 1f 40 00          	nopl   0x0\(%eax\)
+ +[a-f0-9]+:	0f 1f 40 00          	nopl   0x0\(%eax\)
+
+0+12 <pseudo_20>:
+ +[a-f0-9]+:	66 2e 0f 1f 84 00 00 00 00 00 	nopw   %cs:0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	66 2e 0f 1f 84 00 00 00 00 00 	nopw   %cs:0x0\(%eax,%eax,1\)
+
+0+26 <pseudo_30>:
+ +[a-f0-9]+:	66 2e 0f 1f 84 00 00 00 00 00 	nopw   %cs:0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	66 2e 0f 1f 84 00 00 00 00 00 	nopw   %cs:0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	66 2e 0f 1f 84 00 00 00 00 00 	nopw   %cs:0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+#pass
diff --git a/gas/testsuite/gas/i386/nop-1.s b/gas/testsuite/gas/i386/nop-1.s
new file mode 100644
index 0000000000..891783dce8
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-1.s
@@ -0,0 +1,21 @@
+       .text
+single:
+	.nop 0
+	nop
+
+pseudo_1:
+	.nop 1
+
+pseudo_8:
+	.nop 8
+
+pseudo_8_4:
+	.nop 8, 4
+
+pseudo_20:
+	.nop 20
+
+pseudo_30:
+	.nop 30
+
+	xor %eax, %eax
diff --git a/gas/testsuite/gas/i386/nop-2.d b/gas/testsuite/gas/i386/nop-2.d
new file mode 100644
index 0000000000..332b990a97
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-2.d
@@ -0,0 +1,40 @@
+#objdump: -drw -Mi8086
+#name: i386 .nop 2
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <single>:
+ +[a-f0-9]+:	90                   	nop
+
+0+1 <pseudo_1>:
+ +[a-f0-9]+:	90                   	nop
+
+0+2 <pseudo_8>:
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+
+0+a <pseudo_8_4>:
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+
+0+12 <pseudo_20>:
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+
+0+26 <pseudo_30>:
+ +[a-f0-9]+:	89 f6                	mov    %si,%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	66 31 c0             	xor    %eax,%eax
+#pass
diff --git a/gas/testsuite/gas/i386/nop-2.s b/gas/testsuite/gas/i386/nop-2.s
new file mode 100644
index 0000000000..2b71b9786d
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-2.s
@@ -0,0 +1,22 @@
+       .text
+       .code16
+single:
+	.nop 0
+	nop
+
+pseudo_1:
+	.nop 1
+
+pseudo_8:
+	.nop 8
+
+pseudo_8_4:
+	.nop 8, 4
+
+pseudo_20:
+	.nop 20
+
+pseudo_30:
+	.nop 30
+
+	xor %eax, %eax
diff --git a/gas/testsuite/gas/i386/nop-3.d b/gas/testsuite/gas/i386/nop-3.d
new file mode 100644
index 0000000000..bebd24bc08
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-3.d
@@ -0,0 +1,20 @@
+#objdump: -drw
+#name: i386 .nop 3
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	85 c0                	test   %eax,%eax
+ +[a-f0-9]+:	0f 1f 00             	nopl   \(%eax\)
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+
+Disassembly of section .altinstr_replacement:
+
+0+ <.altinstr_replacement>:
+ +[a-f0-9]+:	e9 fc ff ff ff       	jmp    1 <.altinstr_replacement\+0x1>	1: (R_386_PC)?(DISP)?32	foo
+#pass
diff --git a/gas/testsuite/gas/i386/nop-3.s b/gas/testsuite/gas/i386/nop-3.s
new file mode 100644
index 0000000000..57370ff579
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-3.s
@@ -0,0 +1,15 @@
+	.text
+_start:
+	xor %eax, %eax
+140:
+	testl %eax, %eax
+141:
+	.nop -(((144f-143f)-(141b-140b)) > 0)*((144f-143f)-(141b-140b)),7
+142:
+	xor %eax, %eax
+	.pushsection .altinstr_replacement,"ax"
+143:
+	jmp foo
+144:
+	.popsection
+	xor %eax, %eax
diff --git a/gas/testsuite/gas/i386/nop-4.d b/gas/testsuite/gas/i386/nop-4.d
new file mode 100644
index 0000000000..99ddcd3994
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-4.d
@@ -0,0 +1,23 @@
+#objdump: -drw
+#name: i386 .nop 4
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	85 c0                	test   %eax,%eax
+ +[a-f0-9]+:	66 0f 1f 84 00 00 00 00 00 	nopw   0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+
+Disassembly of section .altinstr_replacement:
+
+0+ <.altinstr_replacement>:
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	e9 fc ff ff ff       	jmp    7 <.altinstr_replacement\+0x7>	7: (R_386_PC)?(DISP)?32	foo
+#pass
diff --git a/gas/testsuite/gas/i386/nop-4.s b/gas/testsuite/gas/i386/nop-4.s
new file mode 100644
index 0000000000..f7aa11187e
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-4.s
@@ -0,0 +1,18 @@
+	.text
+_start:
+	xor %eax, %eax
+140:
+	testl %eax, %eax
+141:
+	.nop -(((144f-143f)-(141b-140b)) > 0)*((144f-143f)-(141b-140b))
+142:
+	xor %eax, %eax
+	.pushsection .altinstr_replacement,"ax"
+143:
+	mov %eax, %eax
+	mov %eax, %eax
+	mov %eax, %eax
+	jmp foo
+144:
+	.popsection
+	xor %eax, %eax
diff --git a/gas/testsuite/gas/i386/nop-5.d b/gas/testsuite/gas/i386/nop-5.d
new file mode 100644
index 0000000000..aab4258b19
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-5.d
@@ -0,0 +1,25 @@
+#objdump: -drw
+#name: i386 .nop 5
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	85 c0                	test   %eax,%eax
+ +[a-f0-9]+:	0f 1f 44 00 00       	nopl   0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	66 0f 1f 44 00 00    	nopw   0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+
+Disassembly of section .altinstr_replacement:
+
+0+ <.altinstr_replacement>:
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	e9 fc ff ff ff       	jmp    9 <.altinstr_replacement\+0x9>	9: (R_386_PC)?(DISP)?32	foo
+#pass
diff --git a/gas/testsuite/gas/i386/nop-5.s b/gas/testsuite/gas/i386/nop-5.s
new file mode 100644
index 0000000000..4f563ce82f
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-5.s
@@ -0,0 +1,19 @@
+	.text
+_start:
+	xor %eax, %eax
+140:
+	testl %eax, %eax
+141:
+	.nop -(((144f-143f)-(141b-140b)) > 0)*((144f-143f)-(141b-140b)),6
+142:
+	xor %eax, %eax
+	.pushsection .altinstr_replacement,"ax"
+143:
+	mov %eax, %eax
+	mov %eax, %eax
+	mov %eax, %eax
+	mov %eax, %eax
+	jmp foo
+144:
+	.popsection
+	xor %eax, %eax
diff --git a/gas/testsuite/gas/i386/nop-6.d b/gas/testsuite/gas/i386/nop-6.d
new file mode 100644
index 0000000000..93ee8def03
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-6.d
@@ -0,0 +1,17 @@
+#objdump: -drw
+#name: i386 .nop 6
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+:	0f 1f 40 00          	nopl   0x0\(%eax\)
+
+Disassembly of section .altinstr_replacement:
+
+0+ <.altinstr_replacement>:
+ +[a-f0-9]+:	75 fe                	jne    0 <_start>
+ +[a-f0-9]+:	89 c4                	mov    %eax,%esp
+#pass
diff --git a/gas/testsuite/gas/i386/nop-6.s b/gas/testsuite/gas/i386/nop-6.s
new file mode 100644
index 0000000000..c7b1e2cbf0
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-6.s
@@ -0,0 +1,25 @@
+.macro mknops nr_bytes
+    .nop \nr_bytes, 9
+.endm
+
+.macro ALTERNATIVE
+.L\@_orig_s:
+.L\@_orig_e:
+     mknops (-(((.L\@_repl_e\()1 - .L\@_repl_s\()1) - (.L\@_orig_e - .L\@_orig_s)) > 0) * ((.L\@_repl_e\()1 - .L\@_repl_s\()1) - (.L\@_orig_e - .L\@_orig_s)))
+.L\@_orig_p:
+
+    .section .discard, "a", @progbits
+    .byte (.L\@_orig_p - .L\@_orig_s)
+    .byte 0xff + (.L\@_repl_e\()1 - .L\@_repl_s\()1) - (.L\@_orig_p - .L\@_orig_s)
+
+    .section .altinstr_replacement, "ax", @progbits
+.L\@_repl_s\()1:
+.L\@_fill_rsb_loop:
+    jnz .L\@_fill_rsb_loop
+    mov %eax, %esp
+.L\@_repl_e\()1:
+.endm
+
+	.text
+_start:
+ALTERNATIVE
diff --git a/gas/testsuite/gas/i386/nop-bad-1.l b/gas/testsuite/gas/i386/nop-bad-1.l
new file mode 100644
index 0000000000..34be496b4b
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-bad-1.l
@@ -0,0 +1,4 @@
+.*: Assembler messages:
+.*:2: Warning: negative nop control byte, ignored
+.*:4: Warning: \.space, \.nop or \.fill with negative value, ignored
+.*:3: Error: invalide single nop size: 20 \(expect within \[0, [0-9]+\]\)
diff --git a/gas/testsuite/gas/i386/nop-bad-1.s b/gas/testsuite/gas/i386/nop-bad-1.s
new file mode 100644
index 0000000000..53cc7d554a
--- /dev/null
+++ b/gas/testsuite/gas/i386/nop-bad-1.s
@@ -0,0 +1,4 @@
+	.text
+        .nop 100, -2
+        .nop 100, 20
+        .nop -1
diff --git a/gas/testsuite/gas/i386/x86-64-nop-1.d b/gas/testsuite/gas/i386/x86-64-nop-1.d
new file mode 100644
index 0000000000..f3edc7d346
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-nop-1.d
@@ -0,0 +1,32 @@
+#source: nop-1.s
+#objdump: -drw
+#name: x86-64 .nop 1
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <single>:
+ +[a-f0-9]+:	90                   	nop
+
+0+1 <pseudo_1>:
+ +[a-f0-9]+:	90                   	nop
+
+0+2 <pseudo_8>:
+ +[a-f0-9]+:	0f 1f 84 00 00 00 00 00 	nopl   0x0\(%rax,%rax,1\)
+
+0+a <pseudo_8_4>:
+ +[a-f0-9]+:	0f 1f 40 00          	nopl   0x0\(%rax\)
+ +[a-f0-9]+:	0f 1f 40 00          	nopl   0x0\(%rax\)
+
+0+12 <pseudo_20>:
+ +[a-f0-9]+:	66 0f 1f 84 00 00 00 00 00 	nopw   0x0\(%rax,%rax,1\)
+ +[a-f0-9]+:	67 66 2e 0f 1f 84 00 00 00 00 00 	nopw   %cs:0x0\(%eax,%eax,1\)
+
+0+26 <pseudo_30>:
+ +[a-f0-9]+:	0f 1f 84 00 00 00 00 00 	nopl   0x0\(%rax,%rax,1\)
+ +[a-f0-9]+:	67 66 2e 0f 1f 84 00 00 00 00 00 	nopw   %cs:0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	67 66 2e 0f 1f 84 00 00 00 00 00 	nopw   %cs:0x0\(%eax,%eax,1\)
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-nop-2.d b/gas/testsuite/gas/i386/x86-64-nop-2.d
new file mode 100644
index 0000000000..e894d2c7bf
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-nop-2.d
@@ -0,0 +1,41 @@
+#source: nop-2.s
+#objdump: -drw -Mi8086
+#name: x86-64 .nop 2
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <single>:
+ +[a-f0-9]+:	90                   	nop
+
+0+1 <pseudo_1>:
+ +[a-f0-9]+:	90                   	nop
+
+0+2 <pseudo_8>:
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+
+0+a <pseudo_8_4>:
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+
+0+12 <pseudo_20>:
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+
+0+26 <pseudo_30>:
+ +[a-f0-9]+:	89 f6                	mov    %si,%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	8d b4 00 00          	lea    0x0\(%si\),%si
+ +[a-f0-9]+:	8d bd 00 00          	lea    0x0\(%di\),%di
+ +[a-f0-9]+:	66 31 c0             	xor    %eax,%eax
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-nop-3.d b/gas/testsuite/gas/i386/x86-64-nop-3.d
new file mode 100644
index 0000000000..b43239af6f
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-nop-3.d
@@ -0,0 +1,21 @@
+#source: nop-3.s
+#objdump: -drw
+#name: x86-64 .nop 3
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	85 c0                	test   %eax,%eax
+ +[a-f0-9]+:	0f 1f 00             	nopl   \(%rax\)
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+
+Disassembly of section .altinstr_replacement:
+
+0+ <.altinstr_replacement>:
+ +[a-f0-9]+:	e9 00 00 00 00       	jmpq   5 <_start\+0x5>	1: R_X86_64_PLT32	foo-0x4
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-nop-4.d b/gas/testsuite/gas/i386/x86-64-nop-4.d
new file mode 100644
index 0000000000..a910171303
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-nop-4.d
@@ -0,0 +1,24 @@
+#source: nop-4.s
+#objdump: -drw
+#name: x86-64 .nop 4
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	85 c0                	test   %eax,%eax
+ +[a-f0-9]+:	66 0f 1f 84 00 00 00 00 00 	nopw   0x0\(%rax,%rax,1\)
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+
+Disassembly of section .altinstr_replacement:
+
+0+ <.altinstr_replacement>:
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	e9 00 00 00 00       	jmpq   b <_start\+0xb>	7: R_X86_64_PLT32	foo-0x4
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-nop-5.d b/gas/testsuite/gas/i386/x86-64-nop-5.d
new file mode 100644
index 0000000000..57493cf6dc
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-nop-5.d
@@ -0,0 +1,26 @@
+#source: nop-5.s
+#objdump: -drw
+#name: x86-64 .nop 5
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	85 c0                	test   %eax,%eax
+ +[a-f0-9]+:	0f 1f 44 00 00       	nopl   0x0\(%rax,%rax,1\)
+ +[a-f0-9]+:	66 0f 1f 44 00 00    	nopw   0x0\(%rax,%rax,1\)
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+ +[a-f0-9]+:	31 c0                	xor    %eax,%eax
+
+Disassembly of section .altinstr_replacement:
+
+0+ <.altinstr_replacement>:
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	89 c0                	mov    %eax,%eax
+ +[a-f0-9]+:	e9 00 00 00 00       	jmpq   d <_start\+0xd>	9: R_X86_64_PLT32	foo-0x4
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-nop-6.d b/gas/testsuite/gas/i386/x86-64-nop-6.d
new file mode 100644
index 0000000000..520f590945
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-nop-6.d
@@ -0,0 +1,18 @@
+#source: nop-6.s
+#objdump: -drw
+#name: x86-64 .nop 6
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+:	0f 1f 40 00          	nopl   0x0\(%rax\)
+
+Disassembly of section .altinstr_replacement:
+
+0+ <.altinstr_replacement>:
+ +[a-f0-9]+:	75 fe                	jne    0 <_start>
+ +[a-f0-9]+:	89 c4                	mov    %eax,%esp
+#pass
diff --git a/gas/write.c b/gas/write.c
index 2869660cfe..9b14fda156 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -435,6 +435,8 @@ cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP)
 {
   switch (fragP->fr_type)
     {
+    case rs_space_nop:
+      goto skip_align;
     case rs_align:
     case rs_align_code:
     case rs_align_test:
@@ -443,6 +445,7 @@ cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP)
 #ifdef HANDLE_ALIGN
       HANDLE_ALIGN (fragP);
 #endif
+skip_align:
       know (fragP->fr_next != NULL);
       fragP->fr_offset = (fragP->fr_next->fr_address
 			  - fragP->fr_address
@@ -450,14 +453,18 @@ cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP)
       if (fragP->fr_offset < 0)
 	{
 	  as_bad_where (fragP->fr_file, fragP->fr_line,
-			_("attempt to .org/.space backwards? (%ld)"),
+			_("attempt to .org/.space/.nop backwards? (%ld)"),
 			(long) fragP->fr_offset);
 	  fragP->fr_offset = 0;
 	}
-      fragP->fr_type = rs_fill;
+      if (fragP->fr_type == rs_space_nop)
+	fragP->fr_type = rs_fill_nop;
+      else
+	fragP->fr_type = rs_fill;
       break;
 
     case rs_fill:
+    case rs_fill_nop:
       break;
 
     case rs_leb128:
@@ -1570,6 +1577,20 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
     }
 }
 
+#ifndef md_generate_nops
+/* Genenerate COUNT bytes of no-op instructions to WHERE.  A target
+   backend must override this with proper no-op instructions.   */
+
+static void
+md_generate_nops (fragS *f ATTRIBUTE_UNUSED,
+		  char *where ATTRIBUTE_UNUSED,
+		  offsetT count ATTRIBUTE_UNUSED,
+		  int control ATTRIBUTE_UNUSED)
+{
+  as_bad (_("unimplemented .nop directive"));
+}
+#endif
+
 static void
 write_contents (bfd *abfd ATTRIBUTE_UNUSED,
 		asection *sec,
@@ -1593,7 +1614,7 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
       char *fill_literal;
       offsetT count;
 
-      gas_assert (f->fr_type == rs_fill);
+      gas_assert (f->fr_type == rs_fill || f->fr_type == rs_fill_nop);
       if (f->fr_fix)
 	{
 	  x = bfd_set_section_contents (stdoutput, sec,
@@ -1610,9 +1631,35 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
 		      bfd_errmsg (bfd_get_error ()));
 	  offset += f->fr_fix;
 	}
-      fill_literal = f->fr_literal + f->fr_fix;
+
       fill_size = f->fr_var;
       count = f->fr_offset;
+      fill_literal = f->fr_literal + f->fr_fix;
+
+      if (f->fr_type == rs_fill_nop)
+	{
+	  gas_assert (count >= 0 && fill_size == 1);
+	  if (count > 0)
+	    {
+	      char *buf = xmalloc (count);
+	      md_generate_nops (f, buf, count, *fill_literal);
+	      x = bfd_set_section_contents
+		(stdoutput, sec, buf, (file_ptr) offset,
+		 (bfd_size_type) count);
+	      if (!x)
+		as_fatal (ngettext ("can't fill %ld byte "
+				    "in section %s of %s: '%s'",
+				    "can't fill %ld bytes "
+				    "in section %s of %s: '%s'",
+				    (long) count), (long) count,
+				    sec->name, stdoutput->filename,
+				    bfd_errmsg (bfd_get_error ()));
+	      offset += count;
+	      free (buf);
+	    }
+	  continue;
+	}
+
       gas_assert (count >= 0);
       if (fill_size && count)
 	{
@@ -2461,6 +2508,7 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 	  break;
 
 	case rs_space:
+	case rs_space_nop:
 	  break;
 
 	case rs_machine_dependent:
@@ -2765,6 +2813,7 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 		break;
 
 	      case rs_space:
+	      case rs_space_nop:
 		growth = 0;
 		if (symbolP)
 		  {
@@ -2791,7 +2840,7 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 			  }
 
 			as_warn_where (fragP->fr_file, fragP->fr_line,
-				       _(".space or .fill with negative value, ignored"));
+				       _(".space, .nop or .fill with negative value, ignored"));
 			fragP->fr_symbol = 0;
 		      }
 		    else
-- 
2.14.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]