From 23f268a0235389c01122caf5f77f434de6cfae70 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 15 Sep 2020 10:27:50 +0100 Subject: Add support to the assembler for a ".nop" directive which inserts a single no-op instruction. Import from mainline: 2020-09-14 Nick Clifton * read.c (s_nop): New function. Handles the .nop directive. (potable): Add entry for "nop". (s_nops): Code tidy. * read.h (s_nop): Add prototype. * config/tc-bpf.h (md_single_noop_insn): Define. * config/tc-mmix.h (md_single_noop_insn): Define. * config/tc-or1k.h (md_single_noop_insn): Define. * config/tc-ia64.h (md_single_noop_insn): Define. * write.c (relax_segment): Update error message regarding non-absolute values passed to .fill and .nops. * NEWS: Mention the new directive. * doc/as.texi: Document the new directive. * doc/internals.texi: Document the new internal macros used to implement the new directive. * testsuite/gas/all/nop.s: New test. * testsuite/gas/all/nop.d: New test control file. * testsuite/gas/all/gas.exp: Run the new test. * testsuite/gas/elf/dwarf-5-nop-for-line-table.s: New test. * testsuite/gas/elf/dwarf-5-nop-for-line-table.d: New test control file. * testsuite/gas/elf/elf.exp: Run the new test. * testsuite/gas/i386/space1.l: Adjust expected output. --- gas/ChangeLog | 28 ++++++++ gas/config/tc-bpf.h | 1 + gas/config/tc-ia64.h | 2 + gas/config/tc-mmix.h | 2 + gas/config/tc-or1k.h | 2 + gas/doc/as.texi | 32 ++++++--- gas/doc/internals.texi | 10 +++ gas/read.c | 81 +++++++++++++++++----- gas/read.h | 1 + gas/testsuite/gas/all/gas.exp | 3 + gas/testsuite/gas/all/nop.d | 8 +++ gas/testsuite/gas/all/nop.s | 2 + gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.d | 12 ++++ gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.s | 3 + gas/testsuite/gas/elf/elf.exp | 1 + gas/testsuite/gas/i386/space1.l | 10 +-- gas/write.c | 2 +- 17 files changed, 164 insertions(+), 36 deletions(-) create mode 100644 gas/testsuite/gas/all/nop.d create mode 100644 gas/testsuite/gas/all/nop.s create mode 100644 gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.d create mode 100644 gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 89e2dce..ded3862 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,31 @@ +2020-09-15 Nick Clifton + + Import from mainline: + 2020-09-14 Nick Clifton + + * read.c (s_nop): New function. Handles the .nop directive. + (potable): Add entry for "nop". + (s_nops): Code tidy. + * read.h (s_nop): Add prototype. + * config/tc-bpf.h (md_single_noop_insn): Define. + * config/tc-mmix.h (md_single_noop_insn): Define. + * config/tc-or1k.h (md_single_noop_insn): Define. + * config/tc-ia64.h (md_single_noop_insn): Define. + * write.c (relax_segment): Update error message regarding + non-absolute values passed to .fill and .nops. + * NEWS: Mention the new directive. + * doc/as.texi: Document the new directive. + * doc/internals.texi: Document the new internal macros used to + implement the new directive. + * testsuite/gas/all/nop.s: New test. + * testsuite/gas/all/nop.d: New test control file. + * testsuite/gas/all/gas.exp: Run the new test. + * testsuite/gas/elf/dwarf-5-nop-for-line-table.s: New test. + * testsuite/gas/elf/dwarf-5-nop-for-line-table.d: New test + control file. + * testsuite/gas/elf/elf.exp: Run the new test. + * testsuite/gas/i386/space1.l: Adjust expected output. + 2020-09-14 Mark Wielaard Backport from mainline: diff --git a/gas/config/tc-bpf.h b/gas/config/tc-bpf.h index 5765833..cb02d6c 100644 --- a/gas/config/tc-bpf.h +++ b/gas/config/tc-bpf.h @@ -48,3 +48,4 @@ /* Values passed to md_apply_fix don't include the symbol value. */ #define MD_APPLY_SYM_VALUE(FIX) 0 +#define md_single_noop_insn "mov %r1,%r1" diff --git a/gas/config/tc-ia64.h b/gas/config/tc-ia64.h index e982e57..d187bbc 100644 --- a/gas/config/tc-ia64.h +++ b/gas/config/tc-ia64.h @@ -327,3 +327,5 @@ typedef struct unwind_record #ifdef TE_VMS #define DWARF2_VERSION (dwarf_level < 3 ? 3 : dwarf_level) #endif + +#define md_single_noop_insn "nop 0" diff --git a/gas/config/tc-mmix.h b/gas/config/tc-mmix.h index f7a54c1..2d8e226 100644 --- a/gas/config/tc-mmix.h +++ b/gas/config/tc-mmix.h @@ -228,3 +228,5 @@ extern void mmix_md_do_align (int, char *, int, int); /* MMIX has global register symbols. */ #define TC_GLOBAL_REGISTER_SYMBOL_OK + +#define md_single_noop_insn "set $0, $0" diff --git a/gas/config/tc-or1k.h b/gas/config/tc-or1k.h index 0242dd4..b9aa00c 100644 --- a/gas/config/tc-or1k.h +++ b/gas/config/tc-or1k.h @@ -74,3 +74,5 @@ void or1k_elf_final_processing (void); #define tc_cfi_frame_initial_instructions \ or1k_cfi_frame_initial_instructions extern void or1k_cfi_frame_initial_instructions (void); + +#define md_single_noop_insn "l.nop" diff --git a/gas/doc/as.texi b/gas/doc/as.texi index a3f7834..8ce9fb7 100644 --- a/gas/doc/as.texi +++ b/gas/doc/as.texi @@ -4459,6 +4459,7 @@ Some machine configurations provide additional directives. * MRI:: @code{.mri @var{val}} * Noaltmacro:: @code{.noaltmacro} * Nolist:: @code{.nolist} +* Nop:: @code{.nop} * Nops:: @code{.nops @var{size}[, @var{control}]} * Octa:: @code{.octa @var{bignums}} * Offset:: @code{.offset @var{loc}} @@ -6167,22 +6168,31 @@ 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} + +@cindex @code{nop} directive +@cindex filling memory with no-op instructions +This directive emits a single no-op instruction. It is provided on all +architectures, allowing the creation of architecture neutral tests involving +actual code. The size of the generated instruction is target specific. The +instruction does affect the generation of DWARF debug line information. + @node Nops @section @code{.nops @var{size}[, @var{control}]} @cindex @code{nops} 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 4 in 16-bit mode, between 0 and 7 when tuning for -older processors in 32-bit mode, between 0 and 11 in 64-bit mode or when -tuning for newer processors in 32-bit mode. When 0 is used, the no-op +This directive emits no-op instructions. It is specific to the Intel 80386 and +AMD x86-64 targets. It takes a @var{size} argument and generates @var{size} +bytes of no-op instructions. @var{size} must be absolute and positive. These +bytes do not affect the generation of DWARF debug line information. + +The optional @var{control} argument specifies a size limit for a single no-op +instruction. If not provided then a value of 0 is assumed. The valid values +of @var{control} are between 0 and 4 in 16-bit mode, between 0 and 7 when +tuning for older processors in 32-bit mode, between 0 and 11 in 64-bit mode or +when tuning for newer processors in 32-bit mode. When 0 is used, the no-op instruction size limit is set to the maximum supported size. @node Octa diff --git a/gas/doc/internals.texi b/gas/doc/internals.texi index 23520bd..1230ddd 100644 --- a/gas/doc/internals.texi +++ b/gas/doc/internals.texi @@ -1547,6 +1547,16 @@ The function should return the debug format that is preferred by the CPU backend. This format will be used when generating assembler specific debug information. +@item md_emit_single_noop_insn +@itemx md_single_noop_insn +These macro facilitate the @var{.nop} directive. If defined the +@var{md_emit_single_noop_insn) macro provides code to insert a single no-op +instruction into the output stream. If this involves calling @var{md_assemble} +with a fixed string then the alternative macro @var{md_single_noop_insn} can be +defined, specifying the string to pass. If neither of these macros are defined +then the @var{.nop} directive will call @var{md_assemble} with the string +@option{nop}. + @item md_allow_local_subtract (@var{left}, @var{right}, @var{section}) If defined, GAS will call this macro when evaluating an expression which is the difference of two symbols defined in the same section. It takes three diff --git a/gas/read.c b/gas/read.c index f192cc1..69eb19c 100644 --- a/gas/read.c +++ b/gas/read.c @@ -417,6 +417,7 @@ static const pseudo_typeS potable[] = { {"noformat", s_ignore, 0}, {"nolist", listing_list, 0}, /* Turn listing off. */ {"nopage", listing_nopage, 0}, + {"nop", s_nop, 0}, {"nops", s_nops, 0}, {"octa", cons, 16}, {"offset", s_struct, 0}, @@ -3438,6 +3439,43 @@ s_space (int mult) } void +s_nop (int ignore ATTRIBUTE_UNUSED) +{ +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + +#ifdef md_cons_align + md_cons_align (1); +#endif + + SKIP_WHITESPACE (); + demand_empty_rest_of_line (); + +#ifdef md_emit_single_noop + md_emit_single_noop; +#else + char * nop; + +#ifndef md_single_noop_insn +#define md_single_noop_insn "nop" +#endif + /* md_assemble might modify its argument, so + we must pass it a string that is writeable. */ + if (asprintf (&nop, "%s", md_single_noop_insn) < 0) + as_fatal ("%s", xstrerror (errno)); + + /* Some targets assume that they can update input_line_pointer inside + md_assemble, and, worse, that they can leave it assigned to the string + pointer that was provided as an argument. So preserve ilp here. */ + char * saved_ilp = input_line_pointer; + md_assemble (nop); + input_line_pointer = saved_ilp; + free (nop); +#endif +} + +void s_nops (int ignore ATTRIBUTE_UNUSED) { expressionS exp; @@ -3451,8 +3489,12 @@ s_nops (int ignore ATTRIBUTE_UNUSED) md_cons_align (1); #endif + SKIP_WHITESPACE (); expression (&exp); + /* Note - this expression is tested for an absolute value in + write.c:relax_segment(). */ + SKIP_WHITESPACE (); if (*input_line_pointer == ',') { ++input_line_pointer; @@ -3464,29 +3506,30 @@ s_nops (int ignore ATTRIBUTE_UNUSED) val.X_add_number = 0; } - if (val.X_op == O_constant) + 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; - } + as_bad (_("unsupported variable nop control in .nops directive")); + val.X_op = O_constant; + val.X_add_number = 0; + } + else if (val.X_add_number < 0) + { + as_warn (_("negative nop control byte, ignored")); + val.X_add_number = 0; } - else - as_bad (_("unsupported variable nop control in .nops directive")); demand_empty_rest_of_line (); + + if (need_pass_2) + /* Ignore this directive if we are going to perform a second pass. */ + return; + + /* 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; } /* This is like s_space, but the value is a floating point number with diff --git a/gas/read.h b/gas/read.h index ffcdbb6..b2f0d36 100644 --- a/gas/read.h +++ b/gas/read.h @@ -207,6 +207,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_nops (int); extern void s_stab (int what); extern void s_struct (int); diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp index c782955..7ecf26e 100644 --- a/gas/testsuite/gas/all/gas.exp +++ b/gas/testsuite/gas/all/gas.exp @@ -440,6 +440,7 @@ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/err-*.s $srcdir/$subdir/warn dg-finish # Set $nop_type appropriately to indicate the NOP instruction mnemonic. +# Note - this code is made obsolete by the new .nops pseudo-op. switch -glob $target_triplet { bpf-*-* { set nop_type 6 @@ -467,3 +468,5 @@ run_dump_test "org-6" run_dump_test "fill-1" gas_test "pr23938.s" "" "" ".xstabs" + +run_dump_test "nop" diff --git a/gas/testsuite/gas/all/nop.d b/gas/testsuite/gas/all/nop.d new file mode 100644 index 0000000..81ac08d --- /dev/null +++ b/gas/testsuite/gas/all/nop.d @@ -0,0 +1,8 @@ +#objdump: -s -j .text -j "\$TEXT\$" +#name: Generate NOPs in an architecture neutral manner + +.*: +file format .* + +Contents of section (\.text|\$TEXT\$): + [^ ]* .* +#pass diff --git a/gas/testsuite/gas/all/nop.s b/gas/testsuite/gas/all/nop.s new file mode 100644 index 0000000..bca3805 --- /dev/null +++ b/gas/testsuite/gas/all/nop.s @@ -0,0 +1,2 @@ + .text + .nop diff --git a/gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.d b/gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.d new file mode 100644 index 0000000..651a1a2 --- /dev/null +++ b/gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.d @@ -0,0 +1,12 @@ +#as: --gdwarf-5 +#name: Check line table is produced with .nops +#readelf: -wL + +#... +Contents of the .debug_line section: + +CU: .* +File name.* +#... +.*[ ]+[1-8][ ]+0.* +#pass diff --git a/gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.s b/gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.s new file mode 100644 index 0000000..e3712ff --- /dev/null +++ b/gas/testsuite/gas/elf/dwarf-5-nop-for-line-table.s @@ -0,0 +1,3 @@ + .text + .nop + .nop diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp index 155f78e..52c02cf 100644 --- a/gas/testsuite/gas/elf/elf.exp +++ b/gas/testsuite/gas/elf/elf.exp @@ -276,6 +276,7 @@ if { [is_elf_format] } then { run_dump_test "dwarf-5-file0" $dump_opts run_dump_test "dwarf-4-cu" $dump_opts run_dump_test "dwarf-5-cu" $dump_opts + run_dump_test "dwarf-5-nop-for-line-table" $dump_opts run_dump_test "pr25917" run_dump_test "bss" run_dump_test "bad-bss" diff --git a/gas/testsuite/gas/i386/space1.l b/gas/testsuite/gas/i386/space1.l index 5b0053e..bf446fa 100644 --- a/gas/testsuite/gas/i386/space1.l +++ b/gas/testsuite/gas/i386/space1.l @@ -1,9 +1,9 @@ .*: Assembler messages: -.*:2: Error: .space specifies non-absolute value -.*:3: Error: .space specifies non-absolute value -.*:4: Error: .space specifies non-absolute value -.*:5: Error: .space specifies non-absolute value -.*:6: Error: .space specifies non-absolute value +.*:2: Error: .space, .nops or .fill specifies non-absolute value +.*:3: Error: .space, .nops or .fill specifies non-absolute value +.*:4: Error: .space, .nops or .fill specifies non-absolute value +.*:5: Error: .space, .nops or .fill specifies non-absolute value +.*:6: Error: .space, .nops or .fill specifies non-absolute value GAS LISTING .* diff --git a/gas/write.c b/gas/write.c index 0b43063..054f279 100644 --- a/gas/write.c +++ b/gas/write.c @@ -3017,7 +3017,7 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass) || ! S_IS_DEFINED (symbolP)) { as_bad_where (fragP->fr_file, fragP->fr_line, - _(".space specifies non-absolute value")); + _(".space, .nops or .fill specifies non-absolute value")); /* Prevent repeat of this error message. */ fragP->fr_symbol = 0; } -- cgit v1.1