summaryrefslogtreecommitdiff
path: root/bfd/elf32-frv.c
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2004-03-02 23:01:18 +0000
committerAlexandre Oliva <aoliva@redhat.com>2004-03-02 23:01:18 +0000
commit3b712a1afc40e81696c1c0e9e97742070691d9fa (patch)
tree9c51c0ab76862e960494d06d6f29d7b2b15a8db4 /bfd/elf32-frv.c
parentabc523ed9f53c57e12fa92bc14523ae6ddf3c48c (diff)
* 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.
Diffstat (limited to 'bfd/elf32-frv.c')
-rw-r--r--bfd/elf32-frv.c177
1 files changed, 140 insertions, 37 deletions
diff --git a/bfd/elf32-frv.c b/bfd/elf32-frv.c
index 4a84addb65..de7a113216 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;