diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 19 | ||||
-rw-r--r-- | bfd/elf32-frv.c | 177 |
2 files changed, 159 insertions, 37 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 0e7dadc..ecbeaba 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2004-03-02 Alexandre Oliva <aoliva@redhat.com> + + * elf32-frv.c (struct frv_pic_relocs_info): Added fixups and + dynrelocs. + (_frv_count_got_plt_entries): Initialize them. + (frv_pic_relocs_info_find): Add insert argument. Adjust all + callers. + (frv_pic_relocs_info_for_global): Likewise. + (frv_pic_relocs_info_for_local): Likewise. + (frv_pic_merge_early_relocs_info): New. + (_frv_resolve_final_relocs_info): Use it in case one entry maps to + another. + (_frv_add_dyn_reloc): Add entry argument. Adjust all callers. + Check that we don't exceed the allocated count for entry. + (_frv_add_rofixup): Likewise. + (_frv_emit_got_relocs_plt_entries): Adjust for coding standards. + (elf32_frv_finish_dynamic_sections): Improve error message in case + we emit too few rofixup entries. + 2004-03-01 Richard Sandiford <rsandifo@redhat.com> * archures.c (bfd_mach_fr450): New. diff --git a/bfd/elf32-frv.c b/bfd/elf32-frv.c index 4a84add..de7a113 100644 --- a/bfd/elf32-frv.c +++ b/bfd/elf32-frv.c @@ -748,6 +748,10 @@ struct frv_pic_relocs_info relocations referencing the symbol. */ unsigned relocs32, relocsfd, relocsfdv; + /* The number of .rofixups entries and dynamic relocations allocated + for this symbol, minus any that might have already been used. */ + unsigned fixups, dynrelocs; + /* The offsets of the GOT entries assigned to symbol+addend, to the function descriptor's address, and to a function descriptor, respectively. Should be zero if unassigned. The offsets are @@ -789,10 +793,14 @@ frv_pic_relocs_info_eq (const void *entry1, const void *entry2) static struct frv_pic_relocs_info * frv_pic_relocs_info_find (struct htab *ht, bfd *abfd, - const struct frv_pic_relocs_info *entry) + const struct frv_pic_relocs_info *entry, + enum insert_option insert) { struct frv_pic_relocs_info **loc = - (struct frv_pic_relocs_info **) htab_find_slot (ht, entry, INSERT); + (struct frv_pic_relocs_info **) htab_find_slot (ht, entry, insert); + + if (! loc) + return NULL; if (*loc) return *loc; @@ -818,7 +826,8 @@ inline static struct frv_pic_relocs_info * frv_pic_relocs_info_for_global (struct htab *ht, bfd *abfd, struct elf_link_hash_entry *h, - bfd_vma addend) + bfd_vma addend, + enum insert_option insert) { struct frv_pic_relocs_info entry; @@ -826,7 +835,7 @@ frv_pic_relocs_info_for_global (struct htab *ht, entry.d.h = h; entry.addend = addend; - return frv_pic_relocs_info_find (ht, abfd, &entry); + return frv_pic_relocs_info_find (ht, abfd, &entry, insert); } /* Obtain the address of the entry in HT associated with the SYMNDXth @@ -836,7 +845,8 @@ inline static struct frv_pic_relocs_info * frv_pic_relocs_info_for_local (struct htab *ht, bfd *abfd, long symndx, - bfd_vma addend) + bfd_vma addend, + enum insert_option insert) { struct frv_pic_relocs_info entry; @@ -844,7 +854,59 @@ frv_pic_relocs_info_for_local (struct htab *ht, entry.d.abfd = abfd; entry.addend = addend; - return frv_pic_relocs_info_find (ht, abfd, &entry); + return frv_pic_relocs_info_find (ht, abfd, &entry, insert); +} + +/* Merge fields set by check_relocs() of two entries that end up being + mapped to the same (presumably global) symbol. */ + +inline static void +frv_pic_merge_early_relocs_info (struct frv_pic_relocs_info *e2, + struct frv_pic_relocs_info const *e1) +{ + e2->got12 |= e1->got12; + e2->gotlos |= e1->gotlos; + e2->gothilo |= e1->gothilo; + e2->fd |= e1->fd; + e2->fdgot12 |= e1->fdgot12; + e2->fdgotlos |= e1->fdgotlos; + e2->fdgothilo |= e1->fdgothilo; + e2->fdgoff12 |= e1->fdgoff12; + e2->fdgofflos |= e1->fdgofflos; + e2->fdgoffhilo |= e1->fdgoffhilo; + e2->gotoff |= e1->gotoff; + e2->call |= e1->call; + e2->sym |= e1->sym; + +#if 0 + /* These are set in _frv_count_got_plt_entries() or later, and this + function is only called in _frv_resolve_final_relocs_info(), that + runs just before it, so we don't have to worry about the fields + below. */ + + e2->plt |= e1->plt; + e2->privfd |= e1->privfd; + e2->lazyplt |= e1->lazyplt; + e2->done |= e1->done; + + e2->relocs32 += e1->relocs32; + e2->relocsfd += e1->relocsfd; + e2->relocsfdv += e1->relocsfdv; + e2->fixups += e1->fixups; + e2->dynrelocs += e1->dynrelocs; + + if (abs (e1->got_entry) < abs (e2->got_entry)) + e2->got_entry = e1->got_entry; + if (abs (e1->fdgot_entry) < abs (e2->fdgot_entry)) + e2->fdgot_entry = e1->fdgot_entry; + if (abs (e1->fd_entry) < abs (e2->fd_entry)) + e2->fd_entry = e1->fd_entry; + + if (e1->plt_entry < e2->plt_entry) + e2->plt_entry = e1->plt_entry; + if (e1->lzplt_entry < e2->lzplt_entry) + e2->lzplt_entry = e1->lzplt_entry; +#endif } /* Every block of 65535 lazy PLT entries shares a single call to the @@ -859,7 +921,8 @@ frv_pic_relocs_info_for_local (struct htab *ht, inline static bfd_vma _frv_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, - int reloc_type, long dynindx, bfd_vma addend) + int reloc_type, long dynindx, bfd_vma addend, + struct frv_pic_relocs_info *entry) { Elf_Internal_Rela outrel; bfd_vma reloc_offset; @@ -874,13 +937,17 @@ _frv_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, sreloc->contents + reloc_offset); sreloc->reloc_count++; + BFD_ASSERT (entry->dynrelocs > 0); + entry->dynrelocs--; + return reloc_offset; } /* Add a fixup to the ROFIXUP section. */ static bfd_vma -_frv_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset) +_frv_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset, + struct frv_pic_relocs_info *entry) { bfd_vma fixup_offset; @@ -894,7 +961,13 @@ _frv_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset) bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset); } rofixup->reloc_count++; - + + if (entry) + { + BFD_ASSERT (entry->fixups > 0); + entry->fixups--; + } + return fixup_offset; } @@ -999,13 +1072,13 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry, { if (sec) ad += sec->output_section->vma; - if (entry->symndx != -1 || - entry->d.h->root.type != bfd_link_hash_undefweak) + if (entry->symndx != -1 + || entry->d.h->root.type != bfd_link_hash_undefweak) _frv_add_rofixup (output_bfd, frv_gotfixup_section (info), frv_got_section (info)->output_section->vma + frv_got_section (info)->output_offset + frv_got_initial_offset (info) - + entry->got_entry); + + entry->got_entry, entry); } else _frv_add_dyn_reloc (output_bfd, frv_gotrel_section (info), @@ -1016,7 +1089,7 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry, + entry->got_entry) + frv_got_section (info)->output_section->vma + frv_got_section (info)->output_offset, - R_FRV_32, idx, ad); + R_FRV_32, idx, ad, entry); bfd_put_32 (output_bfd, ad, frv_got_section (info)->contents @@ -1089,7 +1162,7 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry, frv_got_section (info)->output_section->vma + frv_got_section (info)->output_offset + frv_got_initial_offset (info) - + entry->fdgot_entry); + + entry->fdgot_entry, entry); } else _frv_add_dyn_reloc (output_bfd, frv_gotrel_section (info), @@ -1100,7 +1173,7 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry, + entry->fdgot_entry) + frv_got_section (info)->output_section->vma + frv_got_section (info)->output_offset, - reloc, idx, ad); + reloc, idx, ad, entry); } bfd_put_32 (output_bfd, ad, @@ -1142,19 +1215,19 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry, if (sec) ad += sec->output_section->vma; ofst = 0; - if (entry->symndx != -1 || - entry->d.h->root.type != bfd_link_hash_undefweak) + if (entry->symndx != -1 + || entry->d.h->root.type != bfd_link_hash_undefweak) { _frv_add_rofixup (output_bfd, frv_gotfixup_section (info), frv_got_section (info)->output_section->vma + frv_got_section (info)->output_offset + frv_got_initial_offset (info) - + entry->fd_entry); + + entry->fd_entry, entry); _frv_add_rofixup (output_bfd, frv_gotfixup_section (info), frv_got_section (info)->output_section->vma + frv_got_section (info)->output_offset + frv_got_initial_offset (info) - + entry->fd_entry + 4); + + entry->fd_entry + 4, entry); } } else @@ -1170,7 +1243,7 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry, + entry->fd_entry) + frv_got_section (info)->output_section->vma + frv_got_section (info)->output_offset, - R_FRV_FUNCDESC_VALUE, idx, ad); + R_FRV_FUNCDESC_VALUE, idx, ad, entry); } /* If we've omitted the dynamic relocation, just emit the fixed @@ -1922,14 +1995,14 @@ elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section, if (h != NULL) picrel = frv_pic_relocs_info_for_global (frv_relocs_info (info), input_bfd, h, - orig_addend); + orig_addend, INSERT); else /* In order to find the entry we created before, we must use the original addend, not the one that may have been modified by _bfd_elf_rela_local_sym(). */ picrel = frv_pic_relocs_info_for_local (frv_relocs_info (info), input_bfd, r_symndx, - orig_addend); + orig_addend, INSERT); if (! picrel) return FALSE; @@ -2092,7 +2165,8 @@ elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section, (output_bfd, info, input_section, rel->r_offset) + input_section->output_section->vma - + input_section->output_offset); + + input_section->output_offset, + picrel); } } else if ((bfd_get_section_flags (output_bfd, @@ -2114,7 +2188,7 @@ elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section, input_section, rel->r_offset) + input_section->output_section->vma + input_section->output_offset, - r_type, dynindx, addend); + r_type, dynindx, addend, picrel); } } @@ -2192,7 +2266,8 @@ elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section, (output_bfd, info, input_section, rel->r_offset) + input_section->output_section->vma - + input_section->output_offset); + + input_section->output_offset, + picrel); if (r_type == R_FRV_FUNCDESC_VALUE) _frv_add_rofixup (output_bfd, @@ -2201,7 +2276,7 @@ elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section, (output_bfd, info, input_section, rel->r_offset) + input_section->output_section->vma - + input_section->output_offset + 4); + + input_section->output_offset + 4, picrel); } } } @@ -2226,7 +2301,7 @@ elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section, input_section, rel->r_offset) + input_section->output_section->vma + input_section->output_offset, - r_type, dynindx, addend); + r_type, dynindx, addend, picrel); } /* We want the addend in-place because dynamic relocations are REL. Setting relocation to it @@ -2806,6 +2881,7 @@ _frv_count_got_plt_entries (void **entryp, void *dinfo_) { struct frv_pic_relocs_info *entry = *entryp; struct _frv_dynamic_got_info *dinfo = dinfo_; + unsigned relocs = 0, fixups = 0; /* Allocate space for a GOT entry pointing to the symbol. */ if (entry->got12) @@ -2862,27 +2938,33 @@ _frv_count_got_plt_entries (void **entryp, void *dinfo_) dinfo->lzplt += 8; if (!dinfo->info->executable || dinfo->info->pie) - dinfo->relocs += entry->relocs32 + entry->relocsfd + entry->relocsfdv; + relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv; else { if (entry->symndx != -1 || FRV_SYM_LOCAL (dinfo->info, entry->d.h)) { if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - dinfo->fixups += entry->relocs32 + 2 * entry->relocsfdv; + || entry->d.h->root.type != bfd_link_hash_undefweak) + fixups += entry->relocs32 + 2 * entry->relocsfdv; } else - dinfo->relocs += entry->relocs32 + entry->relocsfdv; + relocs += entry->relocs32 + entry->relocsfdv; + if (entry->symndx != -1 || FRV_FUNCDESC_LOCAL (dinfo->info, entry->d.h)) { if (entry->symndx != -1 || entry->d.h->root.type != bfd_link_hash_undefweak) - dinfo->fixups += entry->relocsfd; + fixups += entry->relocsfd; } else - dinfo->relocs += entry->relocsfd; + relocs += entry->relocsfd; } + entry->dynrelocs += relocs; + entry->fixups += fixups; + dinfo->relocs += relocs; + dinfo->fixups += fixups; + return 1; } @@ -3210,6 +3292,7 @@ _frv_resolve_final_relocs_info (void **entryp, void *p) if (entry->symndx == -1) { struct elf_link_hash_entry *h = entry->d.h; + struct frv_pic_relocs_info *oentry; while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) @@ -3218,6 +3301,17 @@ _frv_resolve_final_relocs_info (void **entryp, void *p) if (entry->d.h == h) return 1; + oentry = frv_pic_relocs_info_for_global (*htab, 0, h, entry->addend, + NO_INSERT); + + if (oentry) + { + /* Merge the two entries. */ + frv_pic_merge_early_relocs_info (oentry, entry); + htab_clear_slot (*htab, entryp); + return 1; + } + entry->d.h = h; /* If we can't find this entry with the new bfd hash, re-insert @@ -3581,13 +3675,22 @@ elf32_frv_finish_dynamic_sections (bfd *output_bfd, + hgot->root.u.def.section->output_offset; _frv_add_rofixup (output_bfd, frv_gotfixup_section (info), - got_value); + got_value, 0); } if (frv_gotfixup_section (info)->_raw_size != (frv_gotfixup_section (info)->reloc_count * 4)) { - if (!elf_hash_table (info)->dynamic_sections_created) + if (frv_gotfixup_section (info)->_raw_size + < frv_gotfixup_section (info)->reloc_count * 4) + { + info->callbacks->warning + (info, "LINKER BUG: .rofixup section size mismatch", + ".rofixup", NULL, NULL, 0); + abort (); + return FALSE; + } + else if (!elf_hash_table (info)->dynamic_sections_created) { info->callbacks->warning (info, "no dynamic sections, missing -melf32frvfd?", @@ -3931,12 +4034,12 @@ elf32_frv_check_relocs (abfd, info, sec, relocs) picrel = frv_pic_relocs_info_for_global (frv_relocs_info (info), abfd, h, - rel->r_addend); + rel->r_addend, INSERT); } else picrel = frv_pic_relocs_info_for_local (frv_relocs_info (info), abfd, r_symndx, - rel->r_addend); + rel->r_addend, INSERT); if (! picrel) return FALSE; break; |