diff options
-rw-r--r-- | gas/ChangeLog | 8 | ||||
-rw-r--r-- | gas/write.c | 121 |
2 files changed, 90 insertions, 39 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 3ae1eaf..081bb80 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,11 @@ +2011-08-18 Alan Modra <amodra@gmail.com> + + * 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. + 2011-08-10 Maciej W. Rozycki <macro@codesourcery.com> * config/tc-mips.c (can_swap_branch_p): Update the comment on diff --git a/gas/write.c b/gas/write.c index 5eb4b56..cf59d7d 100644 --- a/gas/write.c +++ b/gas/write.c @@ -1,7 +1,7 @@ /* write.c - emit .o file Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010 Free Software Foundation, Inc. + 2010, 2011 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -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 *reloc, fragS *fragp, } } +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, void *xxx ATTRIBUTE_UNUSED) 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, void *xxx ATTRIBUTE_UNUSED) _("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, void *xxx ATTRIBUTE_UNUSED) } #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); |