aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-sh.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf32-sh.c')
-rw-r--r--bfd/elf32-sh.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c
index c8bbe71..703ac40 100644
--- a/bfd/elf32-sh.c
+++ b/bfd/elf32-sh.c
@@ -3388,6 +3388,8 @@ struct elf_sh_link_hash_entry
/* Track dynamic relocs copied for this symbol. */
struct elf_sh_dyn_relocs *dyn_relocs;
+
+ bfd_signed_vma gotplt_refcount;
};
/* sh ELF linker hash table. */
@@ -3452,6 +3454,7 @@ sh_elf_link_hash_newfunc (entry, table, string)
eh = (struct elf_sh_link_hash_entry *) ret;
eh->dyn_relocs = NULL;
+ eh->gotplt_refcount = 0;
#ifdef INCLUDE_SHMEDIA
ret->datalabel_got_offset = (bfd_vma) -1;
#endif
@@ -3867,6 +3870,18 @@ allocate_dynrelocs (h, inf)
info = (struct bfd_link_info *) inf;
htab = sh_elf_hash_table (info);
+ eh = (struct elf_sh_link_hash_entry *) h;
+ if ((h->got.refcount > 0
+ || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
+ && eh->gotplt_refcount > 0)
+ {
+ /* The symbol has been forced local, or we have some direct got refs,
+ so treat all the gotplt refs as got refs. */
+ h->got.refcount += eh->gotplt_refcount;
+ if (h->plt.refcount >= eh->gotplt_refcount)
+ h->plt.refcount -= eh->gotplt_refcount;
+ }
+
if (htab->root.dynamic_sections_created
&& h->plt.refcount > 0)
{
@@ -3961,7 +3976,6 @@ allocate_dynrelocs (h, inf)
else
h->got.offset = (bfd_vma) -1;
- eh = (struct elf_sh_link_hash_entry *) h;
if (eh->dyn_relocs == NULL)
return true;
@@ -5200,6 +5214,7 @@ sh_elf_gc_sweep_hook (abfd, info, sec, relocs)
const Elf_Internal_Rela *rel, *relend;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
+ struct elf_sh_link_hash_entry *eh;
elf_section_data (sec)->local_dynrel = NULL;
@@ -5302,10 +5317,15 @@ sh_elf_gc_sweep_hook (abfd, info, sec, relocs)
if (r_symndx >= symtab_hdr->sh_info)
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (h->got.refcount > 0)
+ eh = (struct elf_sh_link_hash_entry *) h;
+ if (eh->gotplt_refcount > 0)
+ {
+ eh->gotplt_refcount -= 1;
+ if (h->plt.refcount > 0)
+ h->plt.refcount -= 1;
+ }
+ else if (h->got.refcount > 0)
h->got.refcount -= 1;
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
}
else if (local_got_refcounts != NULL)
{
@@ -5365,6 +5385,8 @@ sh_elf_copy_indirect_symbol (bed, dir, ind)
edir->dyn_relocs = eind->dyn_relocs;
eind->dyn_relocs = NULL;
}
+ edir->gotplt_refcount = eind->gotplt_refcount;
+ eind->gotplt_refcount = 0;
_bfd_elf_link_hash_copy_indirect (bed, dir, ind);
}
@@ -5539,6 +5561,7 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
h->plt.refcount += 1;
+ ((struct elf_sh_link_hash_entry *) h)->gotplt_refcount += 1;
break;