return TRUE;
}
+/* Follow indirect and warning symbol links. */
+
+static inline struct bfd_link_hash_entry *
+follow_link (struct bfd_link_hash_entry *h)
+{
+ while (h->type == bfd_link_hash_indirect
+ || h->type == bfd_link_hash_warning)
+ h = h->u.i.link;
+ return h;
+}
+
+static inline struct elf_link_hash_entry *
+elf_follow_link (struct elf_link_hash_entry *h)
+{
+ return (struct elf_link_hash_entry *) follow_link (&h->root);
+}
+
+static inline struct ppc_link_hash_entry *
+ppc_follow_link (struct ppc_link_hash_entry *h)
+{
+ return (struct ppc_link_hash_entry *) follow_link (&h->elf.root);
+}
+
/* Merge PLT info on FROM with that on TO. */
static void
edir->is_func |= eind->is_func;
edir->is_func_descriptor |= eind->is_func_descriptor;
edir->tls_mask |= eind->tls_mask;
+ if (eind->oh != NULL)
+ edir->oh = ppc_follow_link (eind->oh);
/* If called to transfer flags for a weakdef during processing
of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF.
hash entry FH. Link the entries via their OH fields. */
static struct ppc_link_hash_entry *
-get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
+lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
{
struct ppc_link_hash_entry *fdh = fh->oh;
fdh = (struct ppc_link_hash_entry *)
elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
- if (fdh != NULL)
- {
- fdh->is_func_descriptor = 1;
- fdh->oh = fh;
- fh->is_func = 1;
- fh->oh = fdh;
- }
+ if (fdh == NULL)
+ return fdh;
+
+ fdh->is_func_descriptor = 1;
+ fdh->oh = fh;
+ fh->is_func = 1;
+ fh->oh = fdh;
}
- return fdh;
+ return ppc_follow_link (fdh);
}
/* Make a fake function descriptor sym for the code sym FH. */
abort ();
htab = ppc_hash_table (info);
- fdh = get_fdh (eh, htab);
- if (fdh == NULL
- && !info->relocatable
- && (eh->elf.root.type == bfd_link_hash_undefined
- || eh->elf.root.type == bfd_link_hash_undefweak)
- && eh->elf.ref_regular)
- {
- /* Make an undefweak function descriptor sym, which is enough to
- pull in an --as-needed shared lib, but won't cause link
- errors. Archives are handled elsewhere. */
- fdh = make_fdh (info, eh);
- if (fdh == NULL)
- return FALSE;
- else
- fdh->elf.ref_regular = 1;
+ fdh = lookup_fdh (eh, htab);
+ if (fdh == NULL)
+ {
+ if (!info->relocatable
+ && (eh->elf.root.type == bfd_link_hash_undefined
+ || eh->elf.root.type == bfd_link_hash_undefweak)
+ && eh->elf.ref_regular)
+ {
+ /* Make an undefweak function descriptor sym, which is enough to
+ pull in an --as-needed shared lib, but won't cause link
+ errors. Archives are handled elsewhere. */
+ fdh = make_fdh (info, eh);
+ if (fdh == NULL)
+ return FALSE;
+ fdh->elf.ref_regular = 1;
+ }
}
- else if (fdh != NULL)
+ else
{
unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
else
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ h = elf_follow_link (h);
}
tls_type = 0;
{
if (h->root.root.string[0] == '.'
&& h->root.root.string[1] != 0
- && get_fdh ((struct ppc_link_hash_entry *) h, htab))
+ && lookup_fdh ((struct ppc_link_hash_entry *) h, htab))
;
else
((struct ppc_link_hash_entry *) h)->is_func = 1;
sym_hashes = elf_sym_hashes (opd_bfd);
rh = sym_hashes[symndx - symtab_hdr->sh_info];
- while (rh->root.type == bfd_link_hash_indirect
- || rh->root.type == bfd_link_hash_warning)
- rh = ((struct elf_link_hash_entry *) rh->root.u.i.link);
+ rh = elf_follow_link (rh);
BFD_ASSERT (rh->root.type == bfd_link_hash_defined
|| rh->root.type == bfd_link_hash_defweak);
val = rh->root.u.def.value;
return val;
}
+/* If FDH is a function descriptor symbol, return the associated code
+ entry symbol if it is defined. Return NULL otherwise. */
+
+static struct ppc_link_hash_entry *
+defined_code_entry (struct ppc_link_hash_entry *fdh)
+{
+ if (fdh->is_func_descriptor)
+ {
+ struct ppc_link_hash_entry *fh = ppc_follow_link (fdh->oh);
+ if (fh->elf.root.type == bfd_link_hash_defined
+ || fh->elf.root.type == bfd_link_hash_defweak)
+ return fh;
+ }
+ return NULL;
+}
+
+/* If FH is a function code entry symbol, return the associated
+ function descriptor symbol if it is defined. Return NULL otherwise. */
+
+static struct ppc_link_hash_entry *
+defined_func_desc (struct ppc_link_hash_entry *fh)
+{
+ if (fh->oh != NULL
+ && fh->oh->is_func_descriptor)
+ {
+ struct ppc_link_hash_entry *fdh = ppc_follow_link (fh->oh);
+ if (fdh->elf.root.type == bfd_link_hash_defined
+ || fdh->elf.root.type == bfd_link_hash_defweak)
+ return fdh;
+ }
+ return NULL;
+}
+
/* Mark all our entry sym sections, both opd and code section. */
static void
for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
{
- struct ppc_link_hash_entry *eh;
+ struct ppc_link_hash_entry *eh, *fh;
asection *sec;
eh = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, FALSE);
+ elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, TRUE);
if (eh == NULL)
continue;
if (eh->elf.root.type != bfd_link_hash_defined
&& eh->elf.root.type != bfd_link_hash_defweak)
continue;
- if (eh->is_func_descriptor
- && (eh->oh->elf.root.type == bfd_link_hash_defined
- || eh->oh->elf.root.type == bfd_link_hash_defweak))
+ fh = defined_code_entry (eh);
+ if (fh != NULL)
{
- sec = eh->oh->elf.root.u.def.section;
+ sec = fh->elf.root.u.def.section;
sec->flags |= SEC_KEEP;
}
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
{
struct bfd_link_info *info = (struct bfd_link_info *) inf;
struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
+ struct ppc_link_hash_entry *fdh;
if (eh->elf.root.type == bfd_link_hash_warning)
eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
/* Dynamic linking info is on the func descriptor sym. */
- if (eh->oh != NULL
- && eh->oh->is_func_descriptor
- && (eh->oh->elf.root.type == bfd_link_hash_defined
- || eh->oh->elf.root.type == bfd_link_hash_defweak))
- eh = eh->oh;
+ fdh = defined_func_desc (eh);
+ if (fdh != NULL)
+ eh = fdh;
if ((eh->elf.root.type == bfd_link_hash_defined
|| eh->elf.root.type == bfd_link_hash_defweak)
&& ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN)))
{
asection *code_sec;
+ struct ppc_link_hash_entry *fh;
eh->elf.root.u.def.section->flags |= SEC_KEEP;
/* Function descriptor syms cause the associated
function code sym section to be marked. */
- if (eh->is_func_descriptor
- && (eh->oh->elf.root.type == bfd_link_hash_defined
- || eh->oh->elf.root.type == bfd_link_hash_defweak))
- eh->oh->elf.root.u.def.section->flags |= SEC_KEEP;
+ fh = defined_code_entry (eh);
+ if (fh != NULL)
+ {
+ code_sec = fh->elf.root.u.def.section;
+ code_sec->flags |= SEC_KEEP;
+ }
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
&& opd_entry_value (eh->elf.root.u.def.section,
eh->elf.root.u.def.value,
if (h != NULL)
{
enum elf_ppc64_reloc_type r_type;
- struct ppc_link_hash_entry *eh;
+ struct ppc_link_hash_entry *eh, *fh, *fdh;
r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
eh = (struct ppc_link_hash_entry *) h;
- if (eh->oh != NULL
- && eh->oh->is_func_descriptor
- && (eh->oh->elf.root.type == bfd_link_hash_defined
- || eh->oh->elf.root.type == bfd_link_hash_defweak))
- eh = eh->oh;
+ fdh = defined_func_desc (eh);
+ if (fdh != NULL)
+ eh = fdh;
/* Function descriptor syms cause the associated
function code sym section to be marked. */
- if (eh->is_func_descriptor
- && (eh->oh->elf.root.type == bfd_link_hash_defined
- || eh->oh->elf.root.type == bfd_link_hash_defweak))
+ fh = defined_code_entry (eh);
+ if (fh != NULL)
{
/* They also mark their opd section. */
eh->elf.root.u.def.section->gc_mark = 1;
- rsec = eh->oh->elf.root.u.def.section;
+ rsec = fh->elf.root.u.def.section;
}
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
&& opd_entry_value (eh->elf.root.u.def.section,
struct ppc_dyn_relocs *p;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ h = elf_follow_link (h);
eh = (struct ppc_link_hash_entry *) h;
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
in dynamic objects are handled elsewhere. */
if (fh->elf.root.type == bfd_link_hash_undefweak
&& fh->was_undefined
- && (fh->oh->elf.root.type == bfd_link_hash_defined
- || fh->oh->elf.root.type == bfd_link_hash_defweak)
- && get_opd_info (fh->oh->elf.root.u.def.section) != NULL
- && opd_entry_value (fh->oh->elf.root.u.def.section,
- fh->oh->elf.root.u.def.value,
+ && (fdh = defined_func_desc (fh)) != NULL
+ && get_opd_info (fdh->elf.root.u.def.section) != NULL
+ && opd_entry_value (fdh->elf.root.u.def.section,
+ fdh->elf.root.u.def.value,
&fh->elf.root.u.def.section,
&fh->elf.root.u.def.value) != (bfd_vma) -1)
{
- fh->elf.root.type = fh->oh->elf.root.type;
+ fh->elf.root.type = fdh->elf.root.type;
fh->elf.forced_local = 1;
- fh->elf.def_regular = fh->oh->elf.def_regular;
- fh->elf.def_dynamic = fh->oh->elf.def_dynamic;
+ fh->elf.def_regular = fdh->elf.def_regular;
+ fh->elf.def_dynamic = fdh->elf.def_dynamic;
}
/* If this is a function code symbol, transfer dynamic linking
/* Find the corresponding function descriptor symbol. Create it
as undefined if necessary. */
- fdh = get_fdh (fh, htab);
- if (fdh != NULL)
- while (fdh->elf.root.type == bfd_link_hash_indirect
- || fdh->elf.root.type == bfd_link_hash_warning)
- fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link;
-
+ fdh = lookup_fdh (fh, htab);
if (fdh == NULL
&& !info->executable
&& (fh->elf.root.type == bfd_link_hash_undefined
struct elf_link_hash_entry *h;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ h = elf_follow_link (h);
if (hp != NULL)
*hp = h;
if (h != NULL
&& h->root.root.string[0] == '.')
{
- fdh = get_fdh ((struct ppc_link_hash_entry *) h,
- ppc_hash_table (info));
+ fdh = lookup_fdh ((struct ppc_link_hash_entry *) h,
+ ppc_hash_table (info));
if (fdh != NULL
&& fdh->elf.root.type != bfd_link_hash_defined
&& fdh->elf.root.type != bfd_link_hash_defweak)
struct elf_link_hash_entry *h;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ h = elf_follow_link (h);
if (h == &hash1->elf || h == &hash2->elf)
return TRUE;
}
{
struct plt_entry *ent;
struct ppc_link_hash_entry *fdh = h;
- if (fdh->oh != NULL
- && fdh->oh->is_func_descriptor)
- fdh = fdh->oh;
+ if (h->oh != NULL
+ && h->oh->is_func_descriptor)
+ fdh = ppc_follow_link (h->oh);
for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
hashes[symndx] = &h->elf;
r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24);
if (h->oh != NULL && h->oh->is_func)
- h = h->oh;
+ h = ppc_follow_link (h->oh);
if (h->elf.root.u.def.section != stub_entry->target_section)
/* H is an opd symbol. The addend must be zero. */
r->r_addend = 0;
break;
case ppc_stub_plt_call:
- /* Do the best we can for shared libraries built without
- exporting ".foo" for each "foo". This can happen when symbol
- versioning scripts strip all bar a subset of symbols. */
if (stub_entry->h != NULL
- && stub_entry->h->oh != NULL
- && stub_entry->h->oh->elf.root.type != bfd_link_hash_defined
- && stub_entry->h->oh->elf.root.type != bfd_link_hash_defweak)
+ && stub_entry->h->is_func_descriptor
+ && stub_entry->h->oh != NULL)
{
- /* Point the symbol at the stub. There may be multiple stubs,
- we don't really care; The main thing is to make this sym
- defined somewhere. Maybe defining the symbol in the stub
- section is a silly idea. If we didn't do this, htab->top_id
- could disappear. */
- stub_entry->h->oh->elf.root.type = bfd_link_hash_defined;
- stub_entry->h->oh->elf.root.u.def.section = stub_entry->stub_sec;
- stub_entry->h->oh->elf.root.u.def.value = stub_entry->stub_offset;
+ struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh);
+
+ /* If the old-ABI "dot-symbol" is undefined make it weak so
+ we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL.
+ FIXME: We used to define the symbol on one of the call
+ stubs instead, which is why we test symbol section id
+ against htab->top_id in various places. Likely all
+ these checks could now disappear. */
+ if (fh->elf.root.type == bfd_link_hash_undefined)
+ fh->elf.root.type = bfd_link_hash_undefweak;
}
/* Now build the stub. */
if (eh != NULL
&& (eh->elf.plt.plist != NULL
|| (eh->oh != NULL
- && eh->oh->elf.plt.plist != NULL)))
+ && ppc_follow_link (eh->oh)->elf.plt.plist != NULL)))
{
ret = 1;
break;
use the func descriptor sym instead if it is
defined. */
if (hash->elf.root.root.string[0] == '.'
- && (fdh = get_fdh (hash, htab)) != NULL)
+ && (fdh = lookup_fdh (hash, htab)) != NULL)
{
if (fdh->elf.root.type == bfd_link_hash_defined
|| fdh->elf.root.type == bfd_link_hash_defweak)
base pointer. */
stub_entry = NULL;
fdh = h;
- if (((h != NULL
- && (((fdh = h->oh) != NULL
- && fdh->elf.plt.plist != NULL)
- || (fdh = h)->elf.plt.plist != NULL))
+ if (h != NULL
+ && h->oh != NULL
+ && h->oh->is_func_descriptor)
+ fdh = ppc_follow_link (h->oh);
+ if (((fdh != NULL
+ && fdh->elf.plt.plist != NULL)
|| (sec != NULL
&& sec->output_section != NULL
&& sec->id <= htab->top_id