/* A copy of relocs before they are modified for --emit-relocs. */
Elf_Internal_Rela *opd_relocs;
+
+ /* Nonzero if this bfd has small toc/got relocs, ie. that expect
+ the reloc to be in the range -32768 to 32767. */
+ unsigned int has_small_toc_reloc;
};
#define ppc64_elf_tdata(bfd) \
/* Nonzero if this section has any toc or got relocs. */
#define has_toc_reloc sec_flg2
-/* Nonzero if this section has small toc/got relocs, ie. that expect
- the reloc to be in the range -32768 to 32767. */
-#define has_small_toc_reloc sec_flg3
-
/* Nonzero if this section has a call to another section that uses
the toc or got. */
-#define makes_toc_func_call sec_flg4
+#define makes_toc_func_call sec_flg3
/* Recursion protection when determining above flag. */
-#define call_check_in_progress sec_flg5
+#define call_check_in_progress sec_flg4
/* Get the ppc64 ELF linker hash table from a link_info structure. */
function type. */
static bfd_boolean
-ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
+ppc64_elf_add_symbol_hook (bfd *ibfd,
struct bfd_link_info *info,
Elf_Internal_Sym *isym,
const char **name ATTRIBUTE_UNUSED,
bfd_vma *value ATTRIBUTE_UNUSED)
{
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ {
+ if ((ibfd->flags & DYNAMIC) == 0)
+ elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ }
else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
;
else if (*sec != NULL
|| r_type == R_PPC64_GOT16_DS)
{
htab->do_multi_toc = 1;
- sec->has_small_toc_reloc = 1;
+ ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
}
if (ppc64_elf_tdata (abfd)->got == NULL
case R_PPC64_TOC16:
case R_PPC64_TOC16_DS:
htab->do_multi_toc = 1;
- sec->has_small_toc_reloc = 1;
+ ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_HI:
case R_PPC64_TOC16_HA:
}
}
+/* This function merges got entries in the same toc group. */
+
+static void
+merge_got_entries (struct got_entry **pent)
+{
+ struct got_entry *ent, *ent2;
+
+ for (ent = *pent; ent != NULL; ent = ent->next)
+ if (!ent->is_indirect)
+ for (ent2 = ent->next; ent2 != NULL; ent2 = ent2->next)
+ if (!ent2->is_indirect
+ && ent2->addend == ent->addend
+ && ent2->tls_type == ent->tls_type
+ && elf_gp (ent2->owner) == elf_gp (ent->owner))
+ {
+ ent2->is_indirect = TRUE;
+ ent2->got.ent = ent;
+ }
+}
+
/* Allocate space in .plt, .got and associated reloc sections for
dynamic relocs. */
gent->tls_type = TLS_TLS | TLS_TPREL;
}
+ /* Remove any list entry that won't generate a word in the GOT before
+ we call merge_got_entries. Otherwise we risk merging to empty
+ entries. */
pgent = &h->got.glist;
while ((gent = *pgent) != NULL)
if (gent->got.refcount > 0)
+ {
+ if ((gent->tls_type & TLS_LD) != 0
+ && !h->def_dynamic)
+ {
+ ppc64_tlsld_got (gent->owner)->got.refcount += 1;
+ *pgent = gent->next;
+ }
+ else
+ pgent = &gent->next;
+ }
+ else
+ *pgent = gent->next;
+
+ if (!htab->do_multi_toc)
+ merge_got_entries (&h->got.glist);
+
+ for (gent = h->got.glist; gent != NULL; gent = gent->next)
+ if (!gent->is_indirect)
{
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic,
return FALSE;
}
- if ((gent->tls_type & TLS_LD) != 0
- && !h->def_dynamic)
- {
- ppc64_tlsld_got (gent->owner)->got.refcount += 1;
- *pgent = gent->next;
- continue;
- }
-
if (!is_ppc64_elf (gent->owner))
abort ();
allocate_got (h, info, gent);
- pgent = &gent->next;
}
- else
- *pgent = gent->next;
if (eh->dyn_relocs == NULL
|| (!htab->elf.dynamic_sections_created
asection *s;
bfd_boolean relocs;
bfd *ibfd;
+ struct got_entry *first_tlsld;
htab = ppc_hash_table (info);
if (htab == NULL)
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
+ first_tlsld = NULL;
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
+ struct got_entry *ent;
+
if (!is_ppc64_elf (ibfd))
continue;
- if (ppc64_tlsld_got (ibfd)->got.refcount > 0)
+ ent = ppc64_tlsld_got (ibfd);
+ if (ent->got.refcount > 0)
{
- s = ppc64_elf_tdata (ibfd)->got;
- ppc64_tlsld_got (ibfd)->got.offset = s->size;
- ppc64_tlsld_got (ibfd)->owner = ibfd;
- s->size += 16;
- if (info->shared)
+ if (!htab->do_multi_toc && first_tlsld != NULL)
{
- asection *srel = ppc64_elf_tdata (ibfd)->relgot;
- srel->size += sizeof (Elf64_External_Rela);
+ ent->is_indirect = TRUE;
+ ent->got.ent = first_tlsld;
+ }
+ else
+ {
+ if (first_tlsld == NULL)
+ first_tlsld = ent;
+ s = ppc64_elf_tdata (ibfd)->got;
+ ent->got.offset = s->size;
+ ent->owner = ibfd;
+ s->size += 16;
+ if (info->shared)
+ {
+ asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+ srel->size += sizeof (Elf64_External_Rela);
+ }
}
}
else
- ppc64_tlsld_got (ibfd)->got.offset = (bfd_vma) -1;
+ ent->got.offset = (bfd_vma) -1;
}
/* We now have determined the sizes of the various dynamic sections.
ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
{
struct ppc_link_hash_table *htab = ppc_hash_table (info);
- bfd_vma addr, off;
+ bfd_vma addr, off, limit;
if (htab == NULL)
return FALSE;
addr = isec->output_offset + isec->output_section->vma;
off = addr - htab->toc_curr;
- if (off + isec->size > 0x10000)
+ limit = 0x80008000;
+ if (ppc64_elf_tdata (isec->owner)->has_small_toc_reloc)
+ limit = 0x10000;
+ if (off + isec->size > limit)
{
addr = (htab->toc_first_sec->output_offset
+ htab->toc_first_sec->output_section->vma);
return TRUE;
}
-/* This function merges got entries in the same toc group. */
-
-static void
-merge_got_entries (struct got_entry **pent)
-{
- struct got_entry *ent, *ent2;
-
- for (ent = *pent; ent != NULL; ent = ent->next)
- if (!ent->is_indirect)
- for (ent2 = ent->next; ent2 != NULL; ent2 = ent2->next)
- if (!ent2->is_indirect
- && ent2->addend == ent->addend
- && ent2->tls_type == ent->tls_type
- && elf_gp (ent2->owner) == elf_gp (ent->owner))
- {
- ent2->is_indirect = TRUE;
- ent2->got.ent = ent;
- }
-}
-
/* Called via elf_link_hash_traverse to merge GOT entries for global
symbol H. */
htab->multi_toc_needed = htab->toc_curr != elf_gp (info->output_bfd);
+ if (!htab->do_multi_toc)
+ return FALSE;
+
/* Merge global sym got entries within a toc group. */
elf_link_hash_traverse (&htab->elf, merge_global_got, info);