aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2025-05-19 16:07:20 +0930
committerAlan Modra <amodra@gmail.com>2025-05-23 08:26:08 +0930
commit689f3edfb8fb7fbe5432bfdba9f79347a6649dbf (patch)
treeb6cd920e7dd050f6992a1c6d295f38f0011a7e22
parent0c951ab895a5b3977dad6718e6571774db1237c6 (diff)
downloadbinutils-689f3edfb8fb7fbe5432bfdba9f79347a6649dbf.zip
binutils-689f3edfb8fb7fbe5432bfdba9f79347a6649dbf.tar.gz
binutils-689f3edfb8fb7fbe5432bfdba9f79347a6649dbf.tar.bz2
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.
-rw-r--r--gas/as.h4
-rw-r--r--gas/config/tc-i386.c2
-rw-r--r--gas/config/tc-i386.h1
-rw-r--r--gas/listing.c23
-rw-r--r--gas/read.c10
-rw-r--r--gas/write.c46
6 files changed, 25 insertions, 61 deletions
diff --git a/gas/as.h b/gas/as.h
index 826d88d..4b5f78b 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 1669d43..73d552e 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 2119d71..9137d84 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 c47a43d..0d1f4e8 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 de26d4b..832a196 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 c725841..8ccd996 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)