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/write.c | |
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/write.c')
-rw-r--r-- | gas/write.c | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/gas/write.c b/gas/write.c index 2869660..9b14fda 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 |