* 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.
This commit is contained in:
Alexandre Oliva
2004-03-02 23:01:18 +00:00
parent abc523ed9f
commit 3b712a1afc
2 changed files with 159 additions and 37 deletions

View File

@ -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> 2004-03-01 Richard Sandiford <rsandifo@redhat.com>
* archures.c (bfd_mach_fr450): New. * archures.c (bfd_mach_fr450): New.

View File

@ -748,6 +748,10 @@ struct frv_pic_relocs_info
relocations referencing the symbol. */ relocations referencing the symbol. */
unsigned relocs32, relocsfd, relocsfdv; 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 /* The offsets of the GOT entries assigned to symbol+addend, to the
function descriptor's address, and to a function descriptor, function descriptor's address, and to a function descriptor,
respectively. Should be zero if unassigned. The offsets are 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 * static struct frv_pic_relocs_info *
frv_pic_relocs_info_find (struct htab *ht, frv_pic_relocs_info_find (struct htab *ht,
bfd *abfd, 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 **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) if (*loc)
return *loc; return *loc;
@ -818,7 +826,8 @@ inline static struct frv_pic_relocs_info *
frv_pic_relocs_info_for_global (struct htab *ht, frv_pic_relocs_info_for_global (struct htab *ht,
bfd *abfd, bfd *abfd,
struct elf_link_hash_entry *h, struct elf_link_hash_entry *h,
bfd_vma addend) bfd_vma addend,
enum insert_option insert)
{ {
struct frv_pic_relocs_info entry; struct frv_pic_relocs_info entry;
@ -826,7 +835,7 @@ frv_pic_relocs_info_for_global (struct htab *ht,
entry.d.h = h; entry.d.h = h;
entry.addend = addend; 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 /* 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, frv_pic_relocs_info_for_local (struct htab *ht,
bfd *abfd, bfd *abfd,
long symndx, long symndx,
bfd_vma addend) bfd_vma addend,
enum insert_option insert)
{ {
struct frv_pic_relocs_info entry; struct frv_pic_relocs_info entry;
@ -844,7 +854,59 @@ frv_pic_relocs_info_for_local (struct htab *ht,
entry.d.abfd = abfd; entry.d.abfd = abfd;
entry.addend = addend; 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 /* 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 inline static bfd_vma
_frv_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, _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; Elf_Internal_Rela outrel;
bfd_vma reloc_offset; 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->contents + reloc_offset);
sreloc->reloc_count++; sreloc->reloc_count++;
BFD_ASSERT (entry->dynrelocs > 0);
entry->dynrelocs--;
return reloc_offset; return reloc_offset;
} }
/* Add a fixup to the ROFIXUP section. */ /* Add a fixup to the ROFIXUP section. */
static bfd_vma 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; bfd_vma fixup_offset;
@ -895,6 +962,12 @@ _frv_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset)
} }
rofixup->reloc_count++; rofixup->reloc_count++;
if (entry)
{
BFD_ASSERT (entry->fixups > 0);
entry->fixups--;
}
return fixup_offset; return fixup_offset;
} }
@ -999,13 +1072,13 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry,
{ {
if (sec) if (sec)
ad += sec->output_section->vma; ad += sec->output_section->vma;
if (entry->symndx != -1 || if (entry->symndx != -1
entry->d.h->root.type != bfd_link_hash_undefweak) || entry->d.h->root.type != bfd_link_hash_undefweak)
_frv_add_rofixup (output_bfd, frv_gotfixup_section (info), _frv_add_rofixup (output_bfd, frv_gotfixup_section (info),
frv_got_section (info)->output_section->vma frv_got_section (info)->output_section->vma
+ frv_got_section (info)->output_offset + frv_got_section (info)->output_offset
+ frv_got_initial_offset (info) + frv_got_initial_offset (info)
+ entry->got_entry); + entry->got_entry, entry);
} }
else else
_frv_add_dyn_reloc (output_bfd, frv_gotrel_section (info), _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) + entry->got_entry)
+ frv_got_section (info)->output_section->vma + frv_got_section (info)->output_section->vma
+ frv_got_section (info)->output_offset, + frv_got_section (info)->output_offset,
R_FRV_32, idx, ad); R_FRV_32, idx, ad, entry);
bfd_put_32 (output_bfd, ad, bfd_put_32 (output_bfd, ad,
frv_got_section (info)->contents 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_section->vma
+ frv_got_section (info)->output_offset + frv_got_section (info)->output_offset
+ frv_got_initial_offset (info) + frv_got_initial_offset (info)
+ entry->fdgot_entry); + entry->fdgot_entry, entry);
} }
else else
_frv_add_dyn_reloc (output_bfd, frv_gotrel_section (info), _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) + entry->fdgot_entry)
+ frv_got_section (info)->output_section->vma + frv_got_section (info)->output_section->vma
+ frv_got_section (info)->output_offset, + frv_got_section (info)->output_offset,
reloc, idx, ad); reloc, idx, ad, entry);
} }
bfd_put_32 (output_bfd, ad, bfd_put_32 (output_bfd, ad,
@ -1142,19 +1215,19 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry,
if (sec) if (sec)
ad += sec->output_section->vma; ad += sec->output_section->vma;
ofst = 0; ofst = 0;
if (entry->symndx != -1 || if (entry->symndx != -1
entry->d.h->root.type != bfd_link_hash_undefweak) || entry->d.h->root.type != bfd_link_hash_undefweak)
{ {
_frv_add_rofixup (output_bfd, frv_gotfixup_section (info), _frv_add_rofixup (output_bfd, frv_gotfixup_section (info),
frv_got_section (info)->output_section->vma frv_got_section (info)->output_section->vma
+ frv_got_section (info)->output_offset + frv_got_section (info)->output_offset
+ frv_got_initial_offset (info) + frv_got_initial_offset (info)
+ entry->fd_entry); + entry->fd_entry, entry);
_frv_add_rofixup (output_bfd, frv_gotfixup_section (info), _frv_add_rofixup (output_bfd, frv_gotfixup_section (info),
frv_got_section (info)->output_section->vma frv_got_section (info)->output_section->vma
+ frv_got_section (info)->output_offset + frv_got_section (info)->output_offset
+ frv_got_initial_offset (info) + frv_got_initial_offset (info)
+ entry->fd_entry + 4); + entry->fd_entry + 4, entry);
} }
} }
else else
@ -1170,7 +1243,7 @@ _frv_emit_got_relocs_plt_entries (struct frv_pic_relocs_info *entry,
+ entry->fd_entry) + entry->fd_entry)
+ frv_got_section (info)->output_section->vma + frv_got_section (info)->output_section->vma
+ frv_got_section (info)->output_offset, + 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 /* 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) if (h != NULL)
picrel = frv_pic_relocs_info_for_global (frv_relocs_info (info), picrel = frv_pic_relocs_info_for_global (frv_relocs_info (info),
input_bfd, h, input_bfd, h,
orig_addend); orig_addend, INSERT);
else else
/* In order to find the entry we created before, we must /* In order to find the entry we created before, we must
use the original addend, not the one that may have been use the original addend, not the one that may have been
modified by _bfd_elf_rela_local_sym(). */ modified by _bfd_elf_rela_local_sym(). */
picrel = frv_pic_relocs_info_for_local (frv_relocs_info (info), picrel = frv_pic_relocs_info_for_local (frv_relocs_info (info),
input_bfd, r_symndx, input_bfd, r_symndx,
orig_addend); orig_addend, INSERT);
if (! picrel) if (! picrel)
return FALSE; return FALSE;
@ -2092,7 +2165,8 @@ elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section,
(output_bfd, info, (output_bfd, info,
input_section, rel->r_offset) input_section, rel->r_offset)
+ input_section->output_section->vma + input_section->output_section->vma
+ input_section->output_offset); + input_section->output_offset,
picrel);
} }
} }
else if ((bfd_get_section_flags (output_bfd, 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, rel->r_offset)
+ input_section->output_section->vma + input_section->output_section->vma
+ input_section->output_offset, + 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, (output_bfd, info,
input_section, rel->r_offset) input_section, rel->r_offset)
+ input_section->output_section->vma + input_section->output_section->vma
+ input_section->output_offset); + input_section->output_offset,
picrel);
if (r_type == R_FRV_FUNCDESC_VALUE) if (r_type == R_FRV_FUNCDESC_VALUE)
_frv_add_rofixup _frv_add_rofixup
(output_bfd, (output_bfd,
@ -2201,7 +2276,7 @@ elf32_frv_relocate_section (output_bfd, info, input_bfd, input_section,
(output_bfd, info, (output_bfd, info,
input_section, rel->r_offset) input_section, rel->r_offset)
+ input_section->output_section->vma + 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, rel->r_offset)
+ input_section->output_section->vma + input_section->output_section->vma
+ input_section->output_offset, + input_section->output_offset,
r_type, dynindx, addend); r_type, dynindx, addend, picrel);
} }
/* We want the addend in-place because dynamic /* We want the addend in-place because dynamic
relocations are REL. Setting relocation to it 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_pic_relocs_info *entry = *entryp;
struct _frv_dynamic_got_info *dinfo = dinfo_; struct _frv_dynamic_got_info *dinfo = dinfo_;
unsigned relocs = 0, fixups = 0;
/* Allocate space for a GOT entry pointing to the symbol. */ /* Allocate space for a GOT entry pointing to the symbol. */
if (entry->got12) if (entry->got12)
@ -2862,27 +2938,33 @@ _frv_count_got_plt_entries (void **entryp, void *dinfo_)
dinfo->lzplt += 8; dinfo->lzplt += 8;
if (!dinfo->info->executable || dinfo->info->pie) if (!dinfo->info->executable || dinfo->info->pie)
dinfo->relocs += entry->relocs32 + entry->relocsfd + entry->relocsfdv; relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
else else
{ {
if (entry->symndx != -1 || FRV_SYM_LOCAL (dinfo->info, entry->d.h)) if (entry->symndx != -1 || FRV_SYM_LOCAL (dinfo->info, entry->d.h))
{ {
if (entry->symndx != -1 if (entry->symndx != -1
|| entry->d.h->root.type != bfd_link_hash_undefweak) || entry->d.h->root.type != bfd_link_hash_undefweak)
dinfo->fixups += entry->relocs32 + 2 * entry->relocsfdv; fixups += entry->relocs32 + 2 * entry->relocsfdv;
} }
else 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 || FRV_FUNCDESC_LOCAL (dinfo->info, entry->d.h))
{ {
if (entry->symndx != -1 if (entry->symndx != -1
|| entry->d.h->root.type != bfd_link_hash_undefweak) || entry->d.h->root.type != bfd_link_hash_undefweak)
dinfo->fixups += entry->relocsfd; fixups += entry->relocsfd;
} }
else else
dinfo->relocs += entry->relocsfd; relocs += entry->relocsfd;
} }
entry->dynrelocs += relocs;
entry->fixups += fixups;
dinfo->relocs += relocs;
dinfo->fixups += fixups;
return 1; return 1;
} }
@ -3210,6 +3292,7 @@ _frv_resolve_final_relocs_info (void **entryp, void *p)
if (entry->symndx == -1) if (entry->symndx == -1)
{ {
struct elf_link_hash_entry *h = entry->d.h; struct elf_link_hash_entry *h = entry->d.h;
struct frv_pic_relocs_info *oentry;
while (h->root.type == bfd_link_hash_indirect while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning) || 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) if (entry->d.h == h)
return 1; 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; entry->d.h = h;
/* If we can't find this entry with the new bfd hash, re-insert /* 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; + hgot->root.u.def.section->output_offset;
_frv_add_rofixup (output_bfd, frv_gotfixup_section (info), _frv_add_rofixup (output_bfd, frv_gotfixup_section (info),
got_value); got_value, 0);
} }
if (frv_gotfixup_section (info)->_raw_size if (frv_gotfixup_section (info)->_raw_size
!= (frv_gotfixup_section (info)->reloc_count * 4)) != (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->callbacks->warning
(info, "no dynamic sections, missing -melf32frvfd?", (info, "no dynamic sections, missing -melf32frvfd?",
@ -3931,12 +4034,12 @@ elf32_frv_check_relocs (abfd, info, sec, relocs)
picrel picrel
= frv_pic_relocs_info_for_global (frv_relocs_info (info), = frv_pic_relocs_info_for_global (frv_relocs_info (info),
abfd, h, abfd, h,
rel->r_addend); rel->r_addend, INSERT);
} }
else else
picrel = frv_pic_relocs_info_for_local (frv_relocs_info (info), picrel = frv_pic_relocs_info_for_local (frv_relocs_info (info),
abfd, r_symndx, abfd, r_symndx,
rel->r_addend); rel->r_addend, INSERT);
if (! picrel) if (! picrel)
return FALSE; return FALSE;
break; break;