From: Alan Modra Date: Mon, 19 May 2025 06:37:20 +0000 (+0930) Subject: rs_fill_nop and md_generate_nops X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=689f3edfb8fb7fbe5432bfdba9f79347a6649dbf;p=thirdparty%2Fbinutils-gdb.git rs_fill_nop and md_generate_nops Make rs_fill_nop behave like rs_fill in using a repeat count (fr_offset) to emit fr_var length repeated nop patterns. Besides being more elegant, this reduces memory required for large .nops directives. * as.h (rs_fill_nop): Update comment. * config/tc-i386.c (i386_generate_nops): Handle rs_fill_nop as for rs_align_code. * config/tc-i386.h (MAX_MEM_FOR_RS_SPACE_NOP): Define. * listing.c (calc_hex): Handle rs_fill_nop as for rs_fill. * read.c (MAX_MEM_FOR_RS_SPACE_NOP): Define. (s_nops): Use MAX_MEM_FOR_RS_SPACE_NOP setting up frag. * write.c (write_contents): Call md_generate_nops for rs_fill_nop before the fr_fix part is written, so that rs_fill_nop can be handled as for rs_fill. --- diff --git a/gas/as.h b/gas/as.h index 826d88db013..4b5f78b53d0 100644 --- a/gas/as.h +++ b/gas/as.h @@ -247,9 +247,7 @@ enum _relax_state 1 constant byte: no-op fill control byte. */ rs_space_nop, - /* Similar to rs_fill. It is used to implement .nops directive. - When listings are enabled, fr_opcode gets the buffer assigned, once - that's available. */ + /* Similar to rs_fill. It is used to implement .nops directive. */ rs_fill_nop, /* A DWARF leb128 value; only ELF uses this. The subtype is 0 for diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 1669d432a0f..73d552edb13 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -1769,7 +1769,7 @@ i386_generate_nops (fragS *fragP, char *where, offsetT count, int limit) count -= non_repeat; } - if (fragP->fr_type == rs_align_code) + if (fragP->fr_type != rs_machine_dependent) { /* Set up the frag so that everything we have emitted so far is included in fr_fix. The repeating larger nop only needs to diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h index 2119d71c99b..9137d843096 100644 --- a/gas/config/tc-i386.h +++ b/gas/config/tc-i386.h @@ -390,6 +390,7 @@ if (fragP->fr_type == rs_align_code) \ Yes, the branch might be one byte longer in CODE_16BIT but then the largest nop is smaller. */ #define MAX_MEM_FOR_RS_ALIGN_CODE (1 + 5 + 2 * 15 - 1) +#define MAX_MEM_FOR_RS_SPACE_NOP MAX_MEM_FOR_RS_ALIGN_CODE /* We want .cfi_* pseudo-ops for generating unwind info. */ #define TARGET_USE_CFIPOP 1 diff --git a/gas/listing.c b/gas/listing.c index c47a43d3f49..0d1f4e8066a 100644 --- a/gas/listing.c +++ b/gas/listing.c @@ -826,7 +826,7 @@ calc_hex (list_info_type *list) data_buffer_size += 2; octet_in_frag++; } - if (frag_ptr->fr_type == rs_fill) + if (frag_ptr->fr_type == rs_fill || frag_ptr->fr_type == rs_fill_nop) { unsigned int var_rep_max = octet_in_frag; unsigned int var_rep_idx = octet_in_frag; @@ -851,27 +851,6 @@ calc_hex (list_info_type *list) var_rep_idx = var_rep_max; } } - else if (frag_ptr->fr_type == rs_fill_nop && frag_ptr->fr_opcode) - { - /* Print as many bytes from fr_opcode as is sensible. */ - octet_in_frag = 0; - while (octet_in_frag < (unsigned int) frag_ptr->fr_offset - && data_buffer_size < MAX_BYTES - 3) - { - if (address == ~(unsigned int) 0) - address = frag_ptr->fr_address / OCTETS_PER_BYTE; - - sprintf (data_buffer + data_buffer_size, - "%02X", - frag_ptr->fr_opcode[octet_in_frag] & 0xff); - data_buffer_size += 2; - - octet_in_frag++; - } - - free (frag_ptr->fr_opcode); - frag_ptr->fr_opcode = NULL; - } frag_ptr = frag_ptr->fr_next; } diff --git a/gas/read.c b/gas/read.c index de26d4b6460..832a19632f2 100644 --- a/gas/read.c +++ b/gas/read.c @@ -3617,6 +3617,13 @@ s_nop (int ignore ATTRIBUTE_UNUSED) && frag_off + frag_now_fix () < start_off + exp.X_add_number); } +/* Use this to specify the amount of memory allocated for representing + the nops. Needs to be large enough to hold any fixed size prologue + plus the replicating portion. */ +#ifndef MAX_MEM_FOR_RS_SPACE_NOP +# define MAX_MEM_FOR_RS_SPACE_NOP 1 +#endif + void s_nops (int ignore ATTRIBUTE_UNUSED) { @@ -3665,8 +3672,7 @@ s_nops (int ignore ATTRIBUTE_UNUSED) /* 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 = frag_var (rs_space_nop, MAX_MEM_FOR_RS_SPACE_NOP, 1, 0, sym, 0, NULL); *p = val.X_add_number; } diff --git a/gas/write.c b/gas/write.c index c725841d505..8ccd996089c 100644 --- a/gas/write.c +++ b/gas/write.c @@ -1653,6 +1653,19 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED, offsetT count; gas_assert (f->fr_type == rs_fill || f->fr_type == rs_fill_nop); + + count = f->fr_offset; + fill_literal = f->fr_literal + f->fr_fix; + if (f->fr_type == rs_fill_nop && count > 0) + { + md_generate_nops (f, fill_literal, count, *fill_literal); + /* md_generate_nops updates fr_fix and fr_var. */ + f->fr_offset = (f->fr_next->fr_address - f->fr_address + - f->fr_fix) / f->fr_var; + count = f->fr_offset; + fill_literal = f->fr_literal + f->fr_fix; + } + if (f->fr_fix) { x = bfd_set_section_contents (stdoutput, sec, @@ -1671,39 +1684,6 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED, } 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, - bfd_section_name (sec), - bfd_get_filename (stdoutput), - bfd_errmsg (bfd_get_error ())); - offset += count; -#ifndef NO_LISTING - if (listing & LISTING_LISTING) - f->fr_opcode = buf; - else -#endif - free (buf); - } - continue; - } gas_assert (count >= 0); if (fill_size && count)