This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
.reloc improvement
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Thu, 18 Aug 2011 23:38:17 +0930
- Subject: .reloc improvement
This patch makes some improvements to relocations emitted by the
.reloc directive:
1) A symbol on these relocs is converted to section symbol plus offset
if the symbol satisifes S_IS_LOCAL and some section related
conditions. For example, forward/backward labels like "1f", and
ELF locals like .L123 will be converted. This helps keep the
symbol table tidy.
2) These relocations are merge sorted with the normal fixup relocs,
instead of being emitted after the fixup relocs. A merge sort
ought to be sufficient; If someone generates .reloc with offsets
out of order then I'd say they obviously don't care about reloc
sorting!
3) Time taken to find .reloc frags should be considerably better
than it used to be.
* write.c (resolve_reloc_expr_symbols): Convert local symbols
on relocs to section+offset.
(get_frag_for_reloc): New function.
(write_relocs): Merge sort fixup relocs with those from .reloc
directives.
Index: gas/write.c
===================================================================
RCS file: /cvs/src/src/gas/write.c,v
retrieving revision 1.144
diff -u -p -r1.144 write.c
--- gas/write.c 4 Aug 2011 20:53:58 -0000 1.144
+++ gas/write.c 18 Aug 2011 13:25:23 -0000
@@ -708,7 +708,20 @@ resolve_reloc_expr_symbols (void)
sec = NULL;
}
else if (sym != NULL)
- symbol_mark_used_in_reloc (sym);
+ {
+ if (S_IS_LOCAL (sym) && !symbol_section_p (sym))
+ {
+ asection *symsec = S_GET_SEGMENT (sym);
+ if (!(((symsec->flags & SEC_MERGE) != 0
+ && addend != 0)
+ || (symsec->flags & SEC_THREAD_LOCAL) != 0))
+ {
+ addend += S_GET_VALUE (sym);
+ sym = section_symbol (symsec);
+ }
+ }
+ symbol_mark_used_in_reloc (sym);
+ }
}
if (sym == NULL)
{
@@ -1146,15 +1159,37 @@ install_reloc (asection *sec, arelent *r
}
}
+static fragS *
+get_frag_for_reloc (fragS *last_frag,
+ const segment_info_type *seginfo,
+ const struct reloc_list *r)
+{
+ fragS *f;
+
+ for (f = last_frag; f != NULL; f = f->fr_next)
+ if (f->fr_address <= r->u.b.r.address
+ && r->u.b.r.address < f->fr_address + f->fr_fix)
+ return f;
+
+ for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next)
+ if (f->fr_address <= r->u.b.r.address
+ && r->u.b.r.address < f->fr_address + f->fr_fix)
+ return f;
+
+ as_bad_where (r->file, r->line,
+ _("reloc not within (fixed part of) section"));
+ return NULL;
+}
+
static void
write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
{
segment_info_type *seginfo = seg_info (sec);
- unsigned int i;
unsigned int n;
struct reloc_list *my_reloc_list, **rp, *r;
arelent **relocs;
fixS *fixp;
+ fragS *last_frag;
/* If seginfo is NULL, we did not create this section; don't do
anything with it. */
@@ -1188,12 +1223,19 @@ write_relocs (bfd *abfd, asection *sec,
relocs = (arelent **) xcalloc (n, sizeof (arelent *));
- i = 0;
+ n = 0;
+ r = my_reloc_list;
+ last_frag = NULL;
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
{
- int j;
int fx_size, slack;
offsetT loc;
+ arelent **reloc;
+#ifndef RELOC_EXPANSION_POSSIBLE
+ arelent *rel;
+
+ reloc = &rel;
+#endif
if (fixp->fx_done)
continue;
@@ -1208,28 +1250,46 @@ write_relocs (bfd *abfd, asection *sec,
_("internal error: fixup not contained within frag"));
#ifndef RELOC_EXPANSION_POSSIBLE
- {
- arelent *reloc = tc_gen_reloc (sec, fixp);
-
- if (!reloc)
- continue;
- relocs[i++] = reloc;
- j = 1;
- }
+ *reloc = tc_gen_reloc (sec, fixp);
#else
- {
- arelent **reloc = tc_gen_reloc (sec, fixp);
+ reloc = tc_gen_reloc (sec, fixp);
+#endif
- for (j = 0; reloc[j]; j++)
- relocs[i++] = reloc[j];
- }
+ while (*reloc)
+ {
+ while (r != NULL && r->u.b.r.address < (*reloc)->address)
+ {
+ fragS *f = get_frag_for_reloc (last_frag, seginfo, r);
+ if (f != NULL)
+ {
+ last_frag = f;
+ relocs[n++] = &r->u.b.r;
+ install_reloc (sec, &r->u.b.r, f, r->file, r->line);
+ }
+ r = r->next;
+ }
+ relocs[n++] = *reloc;
+ install_reloc (sec, *reloc, fixp->fx_frag,
+ fixp->fx_file, fixp->fx_line);
+#ifndef RELOC_EXPANSION_POSSIBLE
+ break;
+#else
+ reloc++;
#endif
+ }
+ }
- for ( ; j != 0; --j)
- install_reloc (sec, relocs[i - j], fixp->fx_frag,
- fixp->fx_file, fixp->fx_line);
+ while (r != NULL)
+ {
+ fragS *f = get_frag_for_reloc (last_frag, seginfo, r);
+ if (f != NULL)
+ {
+ last_frag = f;
+ relocs[n++] = &r->u.b.r;
+ install_reloc (sec, &r->u.b.r, f, r->file, r->line);
+ }
+ r = r->next;
}
- n = i;
#ifdef DEBUG4
{
@@ -1249,23 +1309,6 @@ write_relocs (bfd *abfd, asection *sec,
}
#endif
- for (r = my_reloc_list; r != NULL; r = r->next)
- {
- fragS *f;
- for (f = seginfo->frchainP->frch_root; f; f = f->fr_next)
- if (f->fr_address <= r->u.b.r.address
- && r->u.b.r.address < f->fr_address + f->fr_fix)
- break;
- if (f == NULL)
- as_bad_where (r->file, r->line,
- _("reloc not within (fixed part of) section"));
- else
- {
- relocs[n++] = &r->u.b.r;
- install_reloc (sec, &r->u.b.r, f, r->file, r->line);
- }
- }
-
if (n)
{
flagword flags = bfd_get_section_flags (abfd, sec);
--
Alan Modra
Australia Development Lab, IBM