From 2fe9da0602ad115c02a1164b3237f12df3d5b130 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" 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+ : + +[a-f0-9]+: 90 nop + +0+1 : + +[a-f0-9]+: 90 nop + +0+2 : + +[a-f0-9]+: 0f 1f 84 00 00 00 00 00 nopl 0x0\(%eax,%eax,1\) + +0+a : + +[a-f0-9]+: 0f 1f 40 00 nopl 0x0\(%eax\) + +[a-f0-9]+: 0f 1f 40 00 nopl 0x0\(%eax\) + +0+12 : + +[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 : + +[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+ : + +[a-f0-9]+: 90 nop + +0+1 : + +[a-f0-9]+: 90 nop + +0+2 : + +[a-f0-9]+: 8d b4 00 00 lea 0x0\(%si\),%si + +[a-f0-9]+: 8d bd 00 00 lea 0x0\(%di\),%di + +0+a : + +[a-f0-9]+: 8d b4 00 00 lea 0x0\(%si\),%si + +[a-f0-9]+: 8d b4 00 00 lea 0x0\(%si\),%si + +0+12 : + +[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 : + +[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+ : + +[a-f0-9]+: 90 nop + +0+1 : + +[a-f0-9]+: 90 nop + +0+2 : + +[a-f0-9]+: 0f 1f 84 00 00 00 00 00 nopl 0x0\(%rax,%rax,1\) + +0+a : + +[a-f0-9]+: 0f 1f 40 00 nopl 0x0\(%rax\) + +[a-f0-9]+: 0f 1f 40 00 nopl 0x0\(%rax\) + +0+12 : + +[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 : + +[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+ : + +[a-f0-9]+: 90 nop + +0+1 : + +[a-f0-9]+: 90 nop + +0+2 : + +[a-f0-9]+: 8d b4 00 00 lea 0x0\(%si\),%si + +[a-f0-9]+: 8d bd 00 00 lea 0x0\(%di\),%di + +0+a : + +[a-f0-9]+: 8d b4 00 00 lea 0x0\(%si\),%si + +[a-f0-9]+: 8d b4 00 00 lea 0x0\(%si\),%si + +0+12 : + +[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 : + +[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