aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2003-07-10 00:37:27 +0000
committerAlan Modra <amodra@gmail.com>2003-07-10 00:37:27 +0000
commite717da7ead54704139ab3c160e95ed3db479d871 (patch)
tree894d27d29db547fc787ec15d3d799e13c004c2e7 /bfd/elf64-ppc.c
parent149ebfb1debe345ddcb167ba88f1bff0b92c56db (diff)
downloadgdb-e717da7ead54704139ab3c160e95ed3db479d871.zip
gdb-e717da7ead54704139ab3c160e95ed3db479d871.tar.gz
gdb-e717da7ead54704139ab3c160e95ed3db479d871.tar.bz2
* elf64-ppc.c (bfd_elf64_mkobject): Define.
(struct ppc64_elf_obj_tdata): New. (ppc64_elf_tdata, ppc64_tlsld_got): Define. (ppc64_elf_mkobject): New function. (struct got_entry): Add "owner". Move "tls_type". (struct ppc_link_hash_table): Delete "relgot", "tlsld_got". (ppc64_elf_init_stub_bfd): New function. (create_got_section): Create header .got in dynobj. Create .got and .rela.got in each bfd. Stash pointers in ppc64_elf_obj_tdata. (ppc64_elf_create_dynamic_sections): Don't call create_got_section. Look for dynobj .got, and test it. (ppc64_elf_copy_indirect_symbol): Adjust for changed got. (update_local_sym_info): Likewise. (ppc64_elf_check_relocs): Likewise. (ppc64_elf_gc_sweep_hook): Likewise. (ppc64_elf_tls_optimize): Likewise. (allocate_dynrelocs): Likewise. (ppc64_elf_size_dynamic_sections): Likewise. (ppc64_elf_relocate_section): Likewise. (ppc64_elf_next_toc_section): Update comment. (toc_adjusting_stub_needed): Remove unneeded cast. (ppc64_elf_build_stubs): Check for stub sections in stub bfd by testing section flags. (ppc64_elf_build_stubs): Likewise. (ppc64_elf_size_stubs): Likewise. Remove stub_bfd param. (ppc64_elf_finish_dynamic_sections): Write out got sections. (func_desc_adjust): Copy over dynamic info for undef weaks. * elf64-ppc.h (ppc64_elf_init_stub_bfd): Declare. (ppc64_elf_size_stubs): Update prototype. * elflink.h (elf_link_sort_relocs): Use link_orders to find reldyn input sections rather than scanning dynobj.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r--bfd/elf64-ppc.c361
1 files changed, 247 insertions, 114 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index ab2f45a3..0334d84 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -69,6 +69,7 @@ static bfd_reloc_status_type ppc64_elf_unhandled_reloc
#define elf_backend_can_refcount 1
#define elf_backend_rela_normal 1
+#define bfd_elf64_mkobject ppc64_elf_mkobject
#define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup
#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data
#define bfd_elf64_new_section_hook ppc64_elf_new_section_hook
@@ -2316,6 +2317,40 @@ ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
return bfd_reloc_dangerous;
}
+struct ppc64_elf_obj_tdata
+{
+ struct elf_obj_tdata elf;
+
+ /* Shortcuts to dynamic linker sections. */
+ asection *got;
+ asection *relgot;
+
+ /* TLS local dynamic got entry handling. Suppose for multiple GOT
+ sections means we potentially need one of these for each input bfd. */
+ union {
+ bfd_signed_vma refcount;
+ bfd_vma offset;
+ } tlsld_got;
+};
+
+#define ppc64_elf_tdata(bfd) \
+ ((struct ppc64_elf_obj_tdata *) (bfd)->tdata.any)
+
+#define ppc64_tlsld_got(bfd) \
+ (&ppc64_elf_tdata (bfd)->tlsld_got)
+
+/* Override the generic function because we store some extras. */
+
+static bfd_boolean
+ppc64_elf_mkobject (bfd *abfd)
+{
+ bfd_size_type amt = sizeof (struct ppc64_elf_obj_tdata);
+ abfd->tdata.any = bfd_zalloc (abfd, amt);
+ if (abfd->tdata.any == NULL)
+ return FALSE;
+ return TRUE;
+}
+
/* Fix bad default arch selected for a 64 bit input bfd when the
default is 32 bit. */
@@ -2497,16 +2532,24 @@ struct got_entry
/* The symbol addend that we'll be placing in the GOT. */
bfd_vma addend;
+ /* Unlike other ELF targets, we use separate GOT entries for the same
+ symbol referenced from different input files. This is to support
+ automatic multiple TOC/GOT sections, where the TOC base can vary
+ from one input file to another.
+
+ Point to the BFD owning this GOT entry. */
+ bfd *owner;
+
+ /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD,
+ TLS_TPREL or TLS_DTPREL for tls entries. */
+ char tls_type;
+
/* Reference count until size_dynamic_sections, GOT offset thereafter. */
union
{
bfd_signed_vma refcount;
bfd_vma offset;
} got;
-
- /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD,
- TLS_TPREL or TLS_DTPREL for tls entries. */
- char tls_type;
};
/* The same for PLT. */
@@ -2719,7 +2762,6 @@ struct ppc_link_hash_table
/* Short-cuts to get to dynamic linker sections. */
asection *got;
- asection *relgot;
asection *plt;
asection *relplt;
asection *dynbss;
@@ -2735,12 +2777,6 @@ struct ppc_link_hash_table
/* Shortcut to .__tls_get_addr. */
struct elf_link_hash_entry *tls_get_addr;
- /* TLS local dynamic got entry handling. */
- union {
- bfd_signed_vma refcount;
- bfd_vma offset;
- } tlsld_got;
-
/* Statistics. */
unsigned long stub_count[ppc_stub_plt_call];
@@ -2928,6 +2964,23 @@ ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
_bfd_generic_link_hash_table_free (hash);
}
+/* Satisfy the ELF linker by filling in some fields in our fake bfd. */
+
+void
+ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
+{
+ struct ppc_link_hash_table *htab;
+
+ elf_elfheader (abfd)->e_ident[EI_CLASS] = ELFCLASS64;
+
+/* Always hook our dynamic sections into the first bfd, which is the
+ linker created stub bfd. This ensures that the GOT header is at
+ the start of the output TOC section. */
+ htab = ppc_hash_table (info);
+ htab->stub_bfd = abfd;
+ htab->elf.dynobj = abfd;
+}
+
/* Build a name for an entry in the stub hash table. */
static char *
@@ -3122,30 +3175,43 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
return TRUE;
}
-/* Create .got and .rela.got sections in DYNOBJ, and set up
- shortcuts to them in our hash table. */
+/* Create .got and .rela.got sections in ABFD, and .got in dynobj if
+ not already done. */
static bfd_boolean
-create_got_section (bfd *dynobj, struct bfd_link_info *info)
+create_got_section (bfd *abfd, struct bfd_link_info *info)
{
- struct ppc_link_hash_table *htab;
-
- if (! _bfd_elf_create_got_section (dynobj, info))
- return FALSE;
+ asection *got, *relgot;
+ flagword flags;
+ struct ppc_link_hash_table *htab = ppc_hash_table (info);
- htab = ppc_hash_table (info);
- htab->got = bfd_get_section_by_name (dynobj, ".got");
if (!htab->got)
- abort ();
+ {
+ if (! _bfd_elf_create_got_section (htab->elf.dynobj, info))
+ return FALSE;
+
+ htab->got = bfd_get_section_by_name (htab->elf.dynobj, ".got");
+ if (!htab->got)
+ abort ();
+ }
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
+
+ got = bfd_make_section (abfd, ".got");
+ if (!got
+ || !bfd_set_section_flags (abfd, got, flags)
+ || !bfd_set_section_alignment (abfd, got, 3))
+ return FALSE;
- htab->relgot = bfd_make_section (dynobj, ".rela.got");
- if (!htab->relgot
- || ! bfd_set_section_flags (dynobj, htab->relgot,
- (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY | SEC_LINKER_CREATED
- | SEC_READONLY))
- || ! bfd_set_section_alignment (dynobj, htab->relgot, 3))
+ relgot = bfd_make_section (abfd, ".rela.got");
+ if (!relgot
+ || ! bfd_set_section_flags (abfd, relgot, flags | SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, relgot, 3))
return FALSE;
+
+ ppc64_elf_tdata (abfd)->got = got;
+ ppc64_elf_tdata (abfd)->relgot = relgot;
return TRUE;
}
@@ -3156,20 +3222,19 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
- htab = ppc_hash_table (info);
- if (!htab->got && !create_got_section (dynobj, info))
- return FALSE;
-
if (!_bfd_elf_create_dynamic_sections (dynobj, info))
return FALSE;
+ htab = ppc_hash_table (info);
+ if (!htab->got)
+ htab->got = bfd_get_section_by_name (dynobj, ".got");
htab->plt = bfd_get_section_by_name (dynobj, ".plt");
htab->relplt = bfd_get_section_by_name (dynobj, ".rela.plt");
htab->dynbss = bfd_get_section_by_name (dynobj, ".dynbss");
if (!info->shared)
htab->relbss = bfd_get_section_by_name (dynobj, ".rela.bss");
- if (!htab->plt || !htab->relplt || !htab->dynbss
+ if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss
|| (!info->shared && !htab->relbss))
abort ();
@@ -3260,6 +3325,7 @@ ppc64_elf_copy_indirect_symbol (struct elf_backend_data *bed ATTRIBUTE_UNUSED,
for (dent = edir->elf.got.glist; dent != NULL; dent = dent->next)
if (dent->addend == ent->addend
+ && dent->owner == ent->owner
&& dent->tls_type == ent->tls_type)
{
dent->got.refcount += ent->got.refcount;
@@ -3360,7 +3426,9 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
struct got_entry *ent;
for (ent = local_got_ents[r_symndx]; ent != NULL; ent = ent->next)
- if (ent->addend == r_addend && ent->tls_type == tls_type)
+ if (ent->addend == r_addend
+ && ent->owner == abfd
+ && ent->tls_type == tls_type)
break;
if (ent == NULL)
{
@@ -3370,6 +3438,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
return FALSE;
ent->next = local_got_ents[r_symndx];
ent->addend = r_addend;
+ ent->owner = abfd;
ent->tls_type = tls_type;
ent->got.refcount = 0;
local_got_ents[r_symndx] = ent;
@@ -3460,8 +3529,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
ppc64_elf_section_data (sec)->opd.func_sec = opd_sym_map;
}
- if (htab->elf.dynobj == NULL)
- htab->elf.dynobj = abfd;
if (htab->sfpr == NULL
&& !create_linkage_sections (htab->elf.dynobj, info))
return FALSE;
@@ -3487,7 +3554,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
- htab->tlsld_got.refcount += 1;
+ ppc64_tlsld_got (abfd)->refcount += 1;
tls_type = TLS_TLS | TLS_LD;
goto dogottls;
@@ -3524,8 +3591,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT16_LO_DS:
/* This symbol requires a global offset table entry. */
sec->has_gp_reloc = 1;
- if (htab->got == NULL
- && !create_got_section (htab->elf.dynobj, info))
+ if (ppc64_elf_tdata (abfd)->got == NULL
+ && !create_got_section (abfd, info))
return FALSE;
if (h != NULL)
@@ -3536,6 +3603,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
eh = (struct ppc_link_hash_entry *) h;
for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
+ && ent->owner == abfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
@@ -3546,6 +3614,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
return FALSE;
ent->next = eh->elf.got.glist;
ent->addend = rel->r_addend;
+ ent->owner = abfd;
ent->tls_type = tls_type;
ent->got.refcount = 0;
eh->elf.got.glist = ent;
@@ -4054,7 +4123,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
- htab->tlsld_got.refcount -= 1;
+ ppc64_tlsld_got (abfd)->refcount -= 1;
tls_type = TLS_TLS | TLS_LD;
goto dogot;
@@ -4096,6 +4165,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
for (; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
+ && ent->owner == abfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
@@ -4213,7 +4283,9 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
&& (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
&& (info->shared
|| (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+ || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
+ || (fdh->root.type == bfd_link_hash_undefweak
+ && ELF_ST_VISIBILITY (fdh->other) == STV_DEFAULT)))
{
if (fdh->dynindx == -1)
if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
@@ -5138,7 +5210,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
/* These relocs should never be against a symbol
defined in a shared lib. Leave them alone if
that turns out to be the case. */
- htab->tlsld_got.refcount -= 1;
+ ppc64_tlsld_got (ibfd)->refcount -= 1;
if (!is_local)
continue;
@@ -5276,6 +5348,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
for (; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
+ && ent->owner == ibfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
@@ -5431,7 +5504,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
for (ent = h->got.glist; ent != NULL; ent = ent->next)
if (ent->got.refcount > 0
&& (ent->tls_type & TLS_TPREL) != 0
- && ent->addend == gent->addend)
+ && ent->addend == gent->addend
+ && ent->owner == gent->owner)
{
gent->got.refcount = 0;
break;
@@ -5460,11 +5534,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if ((gent->tls_type & TLS_LD) != 0
&& !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))
{
- gent->got.offset = htab->tlsld_got.offset;
+ gent->got.offset = ppc64_tlsld_got (gent->owner)->offset;
continue;
}
- s = htab->got;
+ s = ppc64_elf_tdata (gent->owner)->got;
gent->got.offset = s->_raw_size;
s->_raw_size
+= (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8;
@@ -5473,7 +5547,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
- htab->relgot->_raw_size
+ ppc64_elf_tdata (gent->owner)->relgot->_raw_size
+= (gent->tls_type & eh->tls_mask & TLS_GD
? 2 * sizeof (Elf64_External_Rela)
: sizeof (Elf64_External_Rela));
@@ -5618,16 +5692,6 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
}
}
- if (htab->tlsld_got.refcount > 0)
- {
- htab->tlsld_got.offset = htab->got->_raw_size;
- htab->got->_raw_size += 16;
- if (info->shared)
- htab->relgot->_raw_size += sizeof (Elf64_External_Rela);
- }
- else
- htab->tlsld_got.offset = (bfd_vma) -1;
-
/* Set up .got offsets for local syms, and space for local dynamic
relocs. */
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
@@ -5642,6 +5706,20 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
continue;
+ if (ppc64_tlsld_got (ibfd)->refcount > 0)
+ {
+ s = ppc64_elf_tdata (ibfd)->got;
+ ppc64_tlsld_got (ibfd)->offset = s->_raw_size;
+ s->_raw_size += 16;
+ if (info->shared)
+ {
+ srel = ppc64_elf_tdata (ibfd)->relgot;
+ srel->_raw_size += sizeof (Elf64_External_Rela);
+ }
+ }
+ else
+ ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1;
+
for (s = ibfd->sections; s != NULL; s = s->next)
{
struct ppc_dyn_relocs *p;
@@ -5677,8 +5755,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
locsymcount = symtab_hdr->sh_info;
end_lgot_ents = lgot_ents + locsymcount;
lgot_masks = (char *) end_lgot_ents;
- s = htab->got;
- srel = htab->relgot;
+ s = ppc64_elf_tdata (ibfd)->got;
+ srel = ppc64_elf_tdata (ibfd)->relgot;
for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
{
struct got_entry *ent;
@@ -5688,14 +5766,14 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
{
if ((ent->tls_type & *lgot_masks & TLS_LD) != 0)
{
- if (htab->tlsld_got.offset == (bfd_vma) -1)
+ if (ppc64_tlsld_got (ibfd)->offset == (bfd_vma) -1)
{
- htab->tlsld_got.offset = s->_raw_size;
+ ppc64_tlsld_got (ibfd)->offset = s->_raw_size;
s->_raw_size += 16;
if (info->shared)
srel->_raw_size += sizeof (Elf64_External_Rela);
}
- ent->got.offset = htab->tlsld_got.offset;
+ ent->got.offset = ppc64_tlsld_got (ibfd)->offset;
}
else
{
@@ -5738,16 +5816,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
if (s == htab->brlt || s == htab->relbrlt)
/* These haven't been allocated yet; don't strip. */
continue;
- else if (s == htab->got)
- {
- /* Automatic multiple tocs aren't possible if we are using the
- GOT. The GOT is accessed via r2, so we can't adjust r2.
- FIXME: There's no reason why we couldn't lay out multiple
- GOTs too. */
- if (s->_raw_size > elf_backend_got_header_size)
- htab->no_multi_toc = 1;
- }
- else if (s == htab->plt
+ else if (s == htab->got
+ || s == htab->plt
|| s == htab->glink)
{
/* Strip this section if we don't need it; see the
@@ -5805,6 +5875,38 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
return FALSE;
}
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ {
+ s = ppc64_elf_tdata (ibfd)->got;
+ if (s != NULL && s != htab->got)
+ {
+ s->_cooked_size = 0;
+ if (s->_raw_size == 0)
+ _bfd_strip_section_from_output (info, s);
+ else
+ {
+ s->contents = bfd_zalloc (ibfd, s->_raw_size);
+ if (s->contents == NULL)
+ return FALSE;
+ }
+ }
+ s = ppc64_elf_tdata (ibfd)->relgot;
+ if (s != NULL)
+ {
+ s->_cooked_size = 0;
+ if (s->_raw_size == 0)
+ _bfd_strip_section_from_output (info, s);
+ else
+ {
+ s->contents = bfd_zalloc (ibfd, s->_raw_size);
+ if (s->contents == NULL)
+ return FALSE;
+ relocs = TRUE;
+ s->reloc_count = 0;
+ }
+ }
+ }
+
if (htab->elf.dynamic_sections_created)
{
/* Add some entries to the .dynamic section. We fill in the
@@ -6323,10 +6425,10 @@ ppc64_elf_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info)
return 1;
}
-/* The linker repeatedly calls this function for each toc input
- section. Group input bfds such that the toc within a group
- is less than 64k in size. Will break with cute linker scripts
- that play games with dot in the output toc section. */
+/* The linker repeatedly calls this function for each TOC input section
+ and linker generated GOT section. Group input bfds such that the toc
+ within a group is less than 64k in size. Will break with cute linker
+ scripts that play games with dot in the output toc section. */
void
ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
@@ -6389,7 +6491,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
if (contents == NULL)
return -1;
if (! bfd_get_section_contents (isec->owner, isec, contents,
- (file_ptr) 0, isec->_raw_size))
+ 0, isec->_raw_size))
{
free (contents);
return -1;
@@ -6555,7 +6657,6 @@ group_sections (struct ppc_link_hash_table *htab,
bfd_boolean
ppc64_elf_size_stubs (bfd *output_bfd,
- bfd *stub_bfd,
struct bfd_link_info *info,
bfd_signed_vma group_size,
asection *(*add_stub_section) (const char *, asection *),
@@ -6566,7 +6667,6 @@ ppc64_elf_size_stubs (bfd *output_bfd,
struct ppc_link_hash_table *htab = ppc_hash_table (info);
/* Stash our params away. */
- htab->stub_bfd = stub_bfd;
htab->add_stub_section = add_stub_section;
htab->layout_sections_again = layout_sections_again;
stubs_always_before_branch = group_size < 0;
@@ -6820,10 +6920,11 @@ ppc64_elf_size_stubs (bfd *output_bfd,
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
- {
- stub_sec->_raw_size = 0;
- stub_sec->_cooked_size = 0;
- }
+ if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+ {
+ stub_sec->_raw_size = 0;
+ stub_sec->_cooked_size = 0;
+ }
htab->brlt->_raw_size = 0;
htab->brlt->_cooked_size = 0;
@@ -6909,24 +7010,26 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
struct ppc_link_hash_table *htab = ppc_hash_table (info);
asection *stub_sec;
bfd_byte *p;
+ int stub_sec_count = 0;
htab->emit_stub_syms = emit_stub_syms;
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
- {
- bfd_size_type size;
+ if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+ {
+ bfd_size_type size;
- /* Allocate memory to hold the linker stubs. */
- size = stub_sec->_raw_size;
- if (size != 0)
- {
- stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
- if (stub_sec->contents == NULL)
- return FALSE;
- }
- stub_sec->_cooked_size = 0;
- }
+ /* Allocate memory to hold the linker stubs. */
+ size = stub_sec->_raw_size;
+ if (size != 0)
+ {
+ stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
+ if (stub_sec->contents == NULL)
+ return FALSE;
+ }
+ stub_sec->_cooked_size = 0;
+ }
if (htab->plt != NULL)
{
@@ -7018,10 +7121,12 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
- {
- if (stub_sec->_raw_size != stub_sec->_cooked_size)
- break;
- }
+ if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+ {
+ stub_sec_count += 1;
+ if (stub_sec->_raw_size != stub_sec->_cooked_size)
+ break;
+ }
if (stub_sec != NULL
|| htab->glink->_raw_size != htab->glink->_cooked_size)
@@ -7045,7 +7150,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
" long branch %lu\n"
" long toc adj %lu\n"
" plt call %lu"),
- htab->stub_bfd->section_count,
+ stub_sec_count,
htab->stub_count[ppc_stub_long_branch - 1],
htab->stub_count[ppc_stub_long_branch_r2off - 1],
htab->stub_count[ppc_stub_plt_branch - 1],
@@ -7736,17 +7841,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
{
/* Relocation is to the entry for this symbol in the global
offset table. */
+ asection *got;
bfd_vma *offp;
bfd_vma off;
unsigned long indx = 0;
- if (htab->got == NULL)
- abort ();
-
if (tls_type == (TLS_TLS | TLS_LD)
&& (h == NULL
|| !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
- offp = &htab->tlsld_got.offset;
+ offp = &ppc64_tlsld_got (input_bfd)->offset;
else
{
struct got_entry *ent;
@@ -7778,6 +7881,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
for (; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
+ && ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
@@ -7785,6 +7889,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
offp = &ent->got.offset;
}
+ got = ppc64_elf_tdata (input_bfd)->got;
+ if (got == NULL)
+ abort ();
+
/* The offset must always be a multiple of 8. We use the
least significant bit to record whether we have already
processed this entry. */
@@ -7796,14 +7904,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Generate relocs for the dynamic linker, except in
the case of TLSLD where we'll use one entry per
module. */
+ asection *relgot = ppc64_elf_tdata (input_bfd)->relgot;
+
*offp = off | 1;
if ((info->shared || indx != 0)
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
{
- outrel.r_offset = (htab->got->output_section->vma
- + htab->got->output_offset
+ outrel.r_offset = (got->output_section->vma
+ + got->output_offset
+ off);
outrel.r_addend = rel->r_addend;
if (tls_type & (TLS_LD | TLS_GD))
@@ -7812,8 +7922,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPMOD64);
if (tls_type == (TLS_TLS | TLS_GD))
{
- loc = htab->relgot->contents;
- loc += (htab->relgot->reloc_count++
+ loc = relgot->contents;
+ loc += (relgot->reloc_count++
* sizeof (Elf64_External_Rela));
bfd_elf64_swap_reloca_out (output_bfd,
&outrel, loc);
@@ -7833,7 +7943,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Write the .got section contents for the sake
of prelink. */
- loc = htab->got->contents + off;
+ loc = got->contents + off;
bfd_put_64 (output_bfd, outrel.r_addend + relocation,
loc);
}
@@ -7846,8 +7956,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL))
outrel.r_addend -= htab->tls_sec->vma;
}
- loc = htab->relgot->contents;
- loc += (htab->relgot->reloc_count++
+ loc = relgot->contents;
+ loc += (relgot->reloc_count++
* sizeof (Elf64_External_Rela));
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
}
@@ -7868,23 +7978,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (tls_type == (TLS_TLS | TLS_GD))
{
bfd_put_64 (output_bfd, relocation,
- htab->got->contents + off + 8);
+ got->contents + off + 8);
relocation = 1;
}
}
bfd_put_64 (output_bfd, relocation,
- htab->got->contents + off);
+ got->contents + off);
}
}
if (off >= (bfd_vma) -2)
abort ();
- relocation = htab->got->output_offset + off;
+ relocation = got->output_offset + off;
/* TOC base (r2) is TOC start plus 0x8000. */
- addend = - TOC_BASE_OFF;
+ addend = -TOC_BASE_OFF;
}
break;
@@ -8626,6 +8736,29 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
= PLT_ENTRY_SIZE;
}
+ /* We need to handle writing out multiple GOT sections ourselves,
+ since we didn't add them to DYNOBJ. */
+ while ((dynobj = dynobj->link_next) != NULL)
+ {
+ asection *s;
+ s = ppc64_elf_tdata (dynobj)->got;
+ if (s != NULL
+ && s->_raw_size != 0
+ && s->output_section != bfd_abs_section_ptr
+ && !bfd_set_section_contents (output_bfd, s->output_section,
+ s->contents, s->output_offset,
+ s->_raw_size))
+ return FALSE;
+ s = ppc64_elf_tdata (dynobj)->relgot;
+ if (s != NULL
+ && s->_raw_size != 0
+ && s->output_section != bfd_abs_section_ptr
+ && !bfd_set_section_contents (output_bfd, s->output_section,
+ s->contents, s->output_offset,
+ s->_raw_size))
+ return FALSE;
+ }
+
return TRUE;
}