aboutsummaryrefslogtreecommitdiff
path: root/gas/write.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-02-17 05:20:42 -0800
committerH.J. Lu <hjl.tools@gmail.com>2018-02-17 05:20:57 -0800
commit62a02d25b6e5d9f92c205260daa11355d0c62532 (patch)
tree9fa0855fa0acd81d5d855b01a865cdfb3456254a /gas/write.c
parentbb57c12e551e7b66db9d5d8623e2f294091f03c1 (diff)
downloadfsf-binutils-gdb-62a02d25b6e5d9f92c205260daa11355d0c62532.zip
fsf-binutils-gdb-62a02d25b6e5d9f92c205260daa11355d0c62532.tar.gz
fsf-binutils-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.c59
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