diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2018-02-17 05:20:42 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2018-02-17 05:20:57 -0800 |
commit | 62a02d25b6e5d9f92c205260daa11355d0c62532 (patch) | |
tree | 9fa0855fa0acd81d5d855b01a865cdfb3456254a /gas/config | |
parent | bb57c12e551e7b66db9d5d8623e2f294091f03c1 (diff) | |
download | gdb-62a02d25b6e5d9f92c205260daa11355d0c62532.zip gdb-62a02d25b6e5d9f92c205260daa11355d0c62532.tar.gz gdb-62a02d25b6e5d9f92c205260daa11355d0c62532.tar.bz2 |
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.
* NEWS: Mention .nop directive.
* 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.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-i386.c | 272 | ||||
-rw-r--r-- | gas/config/tc-i386.h | 5 |
2 files changed, 171 insertions, 106 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 1a5be1b..c67ea1f 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 6e4f440..1250bc2 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 |