* 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>
* archures.c (bfd_mach_fr450): New.

View File

@ -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;