Add a new ".nop" directive to the assembler to allow the creation of no-op instructions in an architeture neutral manner.

* 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-s12z.c (md_assemble): Preserve the input line pointer,
	rather than corrupting it.
	* 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.
This commit is contained in:
Nick Clifton 2020-09-14 16:14:24 +01:00
parent 04f5bab24b
commit b1766e7ce8
18 changed files with 164 additions and 38 deletions

View File

@ -1,3 +1,29 @@
2020-09-14 Nick Clifton <nickc@redhat.com>
* 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-s12z.c (md_assemble): Preserve the input line pointer,
rather than corrupting it.
* 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-07 Mark Wielaard <mark@klomp.org>
* as.texi (-g): Explicitly mention when .debug_info and .debug_line

View File

@ -1,5 +1,9 @@
-*- text -*-
* Added a .nop directive to generate a single no-op instruction in a target
neutral manner. This instruction does have an effect on DWARF line number
generation, if that is active.
* Removed --reduce-memory-overheads and --hash-size as gas now
uses hash tables that can be expand and shrink automatically.

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -3807,6 +3807,7 @@ md_assemble (char *str)
return;
}
char * saved_ilp = input_line_pointer;
input_line_pointer = skip_whites (op_end);
size_t i;
@ -3816,15 +3817,17 @@ md_assemble (char *str)
if (0 == strcmp (name, opc->name))
{
if (opc->parse_operands (opc))
return;
{
input_line_pointer = saved_ilp;
return;
}
continue;
}
}
as_bad (_("Invalid instruction: \"%s\""), str);
as_bad (_("First invalid token: \"%s\""), fail_line_pointer);
while (*input_line_pointer++)
;
input_line_pointer = saved_ilp;
}

View File

@ -4446,6 +4446,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}}
@ -6157,22 +6158,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.
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.
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
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

View File

@ -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

View File

@ -465,6 +465,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},
@ -3502,6 +3503,38 @@ s_space (int mult)
mri_comment_end (stop, stopc);
}
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));
md_assemble (nop);
free (nop);
#endif
}
void
s_nops (int ignore ATTRIBUTE_UNUSED)
{
@ -3516,8 +3549,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;
@ -3529,29 +3566,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

View File

@ -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);

View File

@ -443,6 +443,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
@ -470,3 +471,5 @@ run_dump_test "org-6"
run_dump_test "fill-1"
gas_test "pr23938.s" "" "" ".xstabs"
run_dump_test "nop"

View File

@ -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

View File

@ -0,0 +1,2 @@
.text
.nop

View File

@ -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

View File

@ -0,0 +1,3 @@
.text
.nop
.nop

View File

@ -279,6 +279,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"

View File

@ -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 .*

View File

@ -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;
}