diff options
Diffstat (limited to 'gas/write.c')
-rw-r--r-- | gas/write.c | 166 |
1 files changed, 58 insertions, 108 deletions
diff --git a/gas/write.c b/gas/write.c index 46549b834d..b94099b812 100644 --- a/gas/write.c +++ b/gas/write.c @@ -553,11 +553,7 @@ size_seg (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) if (size > 0 && ! seginfo->bss) flags |= SEC_HAS_CONTENTS; - /* @@ This is just an approximation. */ - if (seginfo && seginfo->fix_root) - flags |= SEC_RELOC; - else - flags &= ~SEC_RELOC; + flags &= ~SEC_RELOC; x = bfd_set_section_flags (abfd, sec, flags); assert (x); @@ -1000,6 +996,32 @@ fix_segment (bfd *abfd ATTRIBUTE_UNUSED, } static void +install_reloc (asection *sec, arelent *reloc, fragS *fragp, + char *file, unsigned int line) +{ + char *err; + bfd_reloc_status_type s; + + s = bfd_install_relocation (stdoutput, reloc, + fragp->fr_literal, fragp->fr_address, + sec, &err); + switch (s) + { + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + as_bad_where (file, line, _("relocation overflow")); + break; + case bfd_reloc_outofrange: + as_bad_where (file, line, _("relocation out of range")); + break; + default: + as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"), + file, line, s); + } +} + +static void write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) { segment_info_type *seginfo = seg_info (sec); @@ -1007,7 +1029,6 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) unsigned int n; arelent **relocs; fixS *fixp; - char *err; /* If seginfo is NULL, we did not create this section; don't do anything with it. */ @@ -1016,129 +1037,57 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) n = 0; for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) - n++; + if (!fixp->fx_done) + n++; + +#ifdef RELOC_EXPANSION_POSSIBLE + n *= MAX_RELOC_EXPANSION; +#endif -#ifndef RELOC_EXPANSION_POSSIBLE - /* Set up reloc information as well. */ relocs = xcalloc (n, sizeof (arelent *)); i = 0; for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next) { - arelent *reloc; - bfd_reloc_status_type s; + int j; int fx_size, slack; offsetT loc; if (fixp->fx_done) - { - n--; - continue; - } - - reloc = tc_gen_reloc (sec, fixp); - if (!reloc) - { - n--; - continue; - } + continue; fx_size = fixp->fx_size; slack = TC_FX_SIZE_SLACK (fixp); if (slack > 0) fx_size = fx_size > slack ? fx_size - slack : 0; loc = fixp->fx_where + fx_size; - if (slack >= 0 - && loc > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset) + if (slack >= 0 && loc > fixp->fx_frag->fr_fix) as_bad_where (fixp->fx_file, fixp->fx_line, _("internal error: fixup not contained within frag")); - s = bfd_install_relocation (stdoutput, reloc, - fixp->fx_frag->fr_literal, - fixp->fx_frag->fr_address, - sec, &err); - switch (s) - { - case bfd_reloc_ok: - break; - case bfd_reloc_overflow: - as_bad_where (fixp->fx_file, fixp->fx_line, - _("relocation overflow")); - break; - case bfd_reloc_outofrange: - as_bad_where (fixp->fx_file, fixp->fx_line, - _("relocation out of range")); - break; - default: - as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"), - fixp->fx_file, fixp->fx_line, s); - } - relocs[i++] = reloc; - } -#else - n = n * MAX_RELOC_EXPANSION; - /* Set up reloc information as well. */ - relocs = xcalloc (n, sizeof (arelent *)); - - i = 0; - for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next) - { - arelent **reloc; - bfd_reloc_status_type s; - int j; - int fx_size, slack; - offsetT loc; +#ifndef RELOC_EXPANSION_POSSIBLE + { + arelent *reloc = tc_gen_reloc (sec, fixp); - if (fixp->fx_done) - { - n--; + if (!reloc) continue; - } - - reloc = tc_gen_reloc (sec, fixp); + relocs[i++] = reloc; + j = 1; + } +#else + { + arelent **reloc = tc_gen_reloc (sec, fixp); - for (j = 0; reloc[j]; j++) - { + for (j = 0; reloc[j]; j++) relocs[i++] = reloc[j]; - assert (i <= n); - } - - fx_size = fixp->fx_size; - slack = TC_FX_SIZE_SLACK (fixp); - if (slack > 0) - fx_size = fx_size > slack ? fx_size - slack : 0; - loc = fixp->fx_where + fx_size; - if (slack >= 0 - && loc > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("internal error: fixup not contained within frag")); + } +#endif - for (j = 0; reloc[j]; j++) - { - s = bfd_install_relocation (stdoutput, reloc[j], - fixp->fx_frag->fr_literal, - fixp->fx_frag->fr_address, - sec, &err); - switch (s) - { - case bfd_reloc_ok: - break; - case bfd_reloc_overflow: - as_bad_where (fixp->fx_file, fixp->fx_line, - _("relocation overflow")); - break; - case bfd_reloc_outofrange: - as_bad_where (fixp->fx_file, fixp->fx_line, - _("relocation out of range")); - break; - default: - as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"), - fixp->fx_file, fixp->fx_line, s); - } - } + for ( ; j != 0; --j) + install_reloc (sec, relocs[i - j], fixp->fx_frag, + fixp->fx_file, fixp->fx_line); } n = i; -#endif #ifdef DEBUG4 { @@ -1159,11 +1108,12 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) #endif if (n) - bfd_set_reloc (stdoutput, sec, relocs, n); - else - bfd_set_section_flags (abfd, sec, - (bfd_get_section_flags (abfd, sec) - & (flagword) ~SEC_RELOC)); + { + flagword flags = bfd_get_section_flags (abfd, sec); + flags |= SEC_RELOC; + bfd_set_section_flags (abfd, sec, flags); + bfd_set_reloc (stdoutput, sec, relocs, n); + } #ifdef SET_SECTION_RELOCS SET_SECTION_RELOCS (sec, relocs, n); |