return TRUE;
}
+/* Return 1 if target is one of ours. */
+
+static bfd_boolean
+is_ppc64_elf_target (const struct bfd_target *targ)
+{
+ extern const bfd_target bfd_elf64_powerpc_vec;
+ extern const bfd_target bfd_elf64_powerpcle_vec;
+
+ return targ == &bfd_elf64_powerpc_vec || targ == &bfd_elf64_powerpcle_vec;
+}
+
/* Fix bad default arch selected for a 64 bit input bfd when the
default is 32 bit. */
synthetic_opd = opd;
synthetic_relocatable = relocatable;
- qsort (syms, symcount, sizeof (asymbol *), compare_symbols);
+ qsort (syms, symcount, sizeof (*syms), compare_symbols);
if (!relocatable && symcount > 1)
{
arelent *r;
size_t size;
long relcount;
- asection *relopd;
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
- relopd = opd;
relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
if (! relcount
- || ! (*slurp_relocs) (abfd, relopd, syms, FALSE))
+ || ! (*slurp_relocs) (abfd, opd, static_syms, FALSE))
goto done;
size = 0;
- for (i = secsymend, r = relopd->relocation; i < opdsymend; ++i)
+ for (i = secsymend, r = opd->relocation; i < opdsymend; ++i)
{
asymbol *sym;
- while (r < relopd->relocation + relcount
+ while (r < opd->relocation + relcount
&& r->address < syms[i]->value + opd->vma)
++r;
- if (r == relopd->relocation + relcount)
+ if (r == opd->relocation + relcount)
break;
if (r->address != syms[i]->value + opd->vma)
names = (char *) (s + count);
- for (i = secsymend, r = relopd->relocation; i < opdsymend; ++i)
+ for (i = secsymend, r = opd->relocation; i < opdsymend; ++i)
{
asymbol *sym;
- while (r < relopd->relocation + relcount
+ while (r < opd->relocation + relcount
&& r->address < syms[i]->value + opd->vma)
++r;
- if (r == relopd->relocation + relcount)
+ if (r == opd->relocation + relcount)
break;
if (r->address != syms[i]->value + opd->vma)
unsigned int is_func:1;
unsigned int is_func_descriptor:1;
- /* Whether global opd sym has been adjusted or not.
- After ppc64_elf_edit_opd has run, this flag should be set for all
- globals defined in any opd section. */
+ /* Whether global opd/toc sym has been adjusted or not.
+ After ppc64_elf_edit_opd/ppc64_elf_edit_toc has run, this flag
+ should be set for all globals defined in any opd/toc section. */
unsigned int adjust_done:1;
/* Set if we twiddled this symbol to weak at some stage. */
/* Statistics. */
unsigned long stub_count[ppc_stub_plt_call];
+ /* Number of stubs against global syms. */
+ unsigned long stub_globals;
+
/* Set if we should emit symbols for stubs. */
unsigned int emit_stub_syms:1;
(int) rel->r_addend & 0xffffffff);
}
}
+ if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
+ stub_name[len - 2] = 0;
return stub_name;
}
|| ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
return FALSE;
- if (info->shared)
+ if (info->shared || info->emitrelocations)
{
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
struct elf_link_hash_entry *ind)
{
struct ppc_link_hash_entry *edir, *eind;
- flagword mask;
edir = (struct ppc_link_hash_entry *) dir;
eind = (struct ppc_link_hash_entry *) ind;
edir->is_func_descriptor |= eind->is_func_descriptor;
edir->tls_mask |= eind->tls_mask;
- mask = (ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK | ELF_LINK_NON_GOT_REF
- | ELF_LINK_HASH_NEEDS_PLT);
/* If called to transfer flags for a weakdef during processing
- of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF.
+ of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF.
We clear it ourselves for ELIMINATE_COPY_RELOCS. */
- if (ELIMINATE_COPY_RELOCS
- && eind->elf.root.type != bfd_link_hash_indirect
- && (edir->elf.elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0)
- mask &= ~ELF_LINK_NON_GOT_REF;
+ if (!(ELIMINATE_COPY_RELOCS
+ && eind->elf.root.type != bfd_link_hash_indirect
+ && edir->elf.dynamic_adjusted))
+ edir->elf.non_got_ref |= eind->elf.non_got_ref;
- edir->elf.elf_link_hash_flags |= eind->elf.elf_link_hash_flags & mask;
+ edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
+ edir->elf.ref_regular |= eind->elf.ref_regular;
+ edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
+ edir->elf.needs_plt |= eind->elf.needs_plt;
/* If we were called to copy over info for a weak sym, that's all. */
if (eind->elf.root.type != bfd_link_hash_indirect)
struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
- extern const bfd_target bfd_elf64_powerpc_vec;
- extern const bfd_target bfd_elf64_powerpcle_vec;
htab = ppc_hash_table (info);
- if (htab->elf.root.creator != &bfd_elf64_powerpc_vec
- && htab->elf.root.creator != &bfd_elf64_powerpcle_vec)
+ if (!is_ppc64_elf_target (htab->elf.root.creator))
return TRUE;
elf_link_hash_traverse (&htab->elf, add_symbol_adjust, info);
if (h->type != bfd_link_hash_undefined
&& h->type != bfd_link_hash_common)
{
- *pun = h->und_next;
- h->und_next = NULL;
+ *pun = h->u.undef.next;
+ h->u.undef.next = NULL;
if (h == htab->elf.root.undefs_tail)
{
if (pun == &htab->elf.root.undefs)
htab->elf.root.undefs_tail = NULL;
else
- /* pun points at an und_next field. Go back to
+ /* pun points at an u.undef.next field. Go back to
the start of the link_hash_entry. */
htab->elf.root.undefs_tail = (struct bfd_link_hash_entry *)
- ((char *) pun - ((char *) &h->und_next - (char *) h));
+ ((char *) pun - ((char *) &h->u.undef.next - (char *) h));
break;
}
}
else
- pun = &h->und_next;
+ pun = &h->u.undef.next;
}
htab->twiddled_syms = 0;
eh->elf.plt.plist = ent;
}
ent->plt.refcount += 1;
- eh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ eh->elf.needs_plt = 1;
eh->is_func = 1;
return TRUE;
}
case R_PPC64_TOC:
if (h != NULL && !info->shared)
/* We may need a copy reloc. */
- h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+ h->non_got_ref = 1;
/* Don't propagate .opd relocs. */
if (NO_OPD_RELOCS && opd_sym_map != NULL)
|| (h != NULL
&& (! info->symbolic
|| h->root.type == bfd_link_hash_defweak
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))))
+ || !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+ || !h->def_regular)))
{
struct ppc_dyn_relocs *p;
struct ppc_dyn_relocs **head;
bfd *opd_bfd = opd_sec->owner;
Elf_Internal_Rela *lo, *hi, *look;
+ /* No relocs implies we are linking a --just-symbols object. */
+ if (opd_sec->reloc_count == 0)
+ {
+ bfd_vma val;
+
+ if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8))
+ return (bfd_vma) -1;
+
+ if (code_sec != NULL)
+ {
+ asection *sec, *likely = NULL;
+ for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
+ if (sec->vma <= val
+ && (sec->flags & SEC_LOAD) != 0
+ && (sec->flags & SEC_ALLOC) != 0)
+ likely = sec;
+ if (likely != NULL)
+ {
+ *code_sec = likely;
+ if (code_off != NULL)
+ *code_off = val - likely->vma;
+ }
+ }
+ return val;
+ }
+
/* Go find the opd reloc at the sym address. */
lo = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE);
BFD_ASSERT (lo != NULL);
sym[len + 1] = i % 10 + '0';
h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
if (h != NULL
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ && !h->def_regular)
{
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = htab->sfpr;
h->root.u.def.value = htab->sfpr->size;
h->type = STT_FUNC;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->def_regular = 1;
_bfd_elf_link_hash_hide_symbol (info, h, TRUE);
writing = TRUE;
if (htab->sfpr->contents == NULL)
&fh->elf.root.u.def.value) != (bfd_vma) -1)
{
fh->elf.root.type = fh->oh->elf.root.type;
- fh->elf.elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+ fh->elf.forced_local = 1;
}
/* If this is a function code symbol, transfer dynamic linking
return FALSE;
}
fdh = (struct ppc_link_hash_entry *) bh;
- fdh->elf.elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
+ fdh->elf.non_elf = 0;
fdh->elf.size = 24;
fdh->elf.type = STT_OBJECT;
}
if (fdh != NULL
- && (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
+ && !fdh->elf.forced_local
&& (info->shared
- || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
+ || fdh->elf.def_dynamic
+ || fdh->elf.ref_dynamic
|| (fdh->elf.root.type == bfd_link_hash_undefweak
&& ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
{
if (fdh->elf.dynindx == -1)
if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
return FALSE;
- fdh->elf.elf_link_hash_flags
- |= (fh->elf.elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_REF_DYNAMIC
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK
- | ELF_LINK_NON_GOT_REF));
+ fdh->elf.ref_regular |= fh->elf.ref_regular;
+ fdh->elf.ref_dynamic |= fh->elf.ref_dynamic;
+ fdh->elf.ref_regular_nonweak |= fh->elf.ref_regular_nonweak;
+ fdh->elf.non_got_ref |= fh->elf.non_got_ref;
if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
{
struct plt_entry **ep = &fdh->elf.plt.plist;
ep = &(*ep)->next;
*ep = fh->elf.plt.plist;
fh->elf.plt.plist = NULL;
- fdh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ fdh->elf.needs_plt = 1;
}
fdh->is_func_descriptor = 1;
fdh->oh = fh;
linker dragging in a definition from a static library. */
force_local
= (info->shared
- && ((fh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+ && (!fh->elf.def_regular
|| fdh == NULL
- || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
- || (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0));
+ || !fdh->elf.def_regular
+ || fdh->elf.forced_local));
_bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
return TRUE;
/* Deal with function syms. */
if (h->type == STT_FUNC
- || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+ || h->needs_plt)
{
/* Clear procedure linkage table information for any symbol that
won't need a .plt entry. */
&& h->root.type == bfd_link_hash_undefweak))
{
h->plt.plist = NULL;
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->needs_plt = 0;
}
}
else
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->weakdef != NULL)
+ if (h->u.weakdef != NULL)
{
- BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
- || h->weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->weakdef->root.u.def.section;
- h->root.u.def.value = h->weakdef->root.u.def.value;
+ BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+ || h->u.weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->u.weakdef->root.u.def.section;
+ h->root.u.def.value = h->u.weakdef->root.u.def.value;
if (ELIMINATE_COPY_RELOCS)
- h->elf_link_hash_flags
- = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF)
- | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF));
+ h->non_got_ref = h->u.weakdef->non_got_ref;
return TRUE;
}
/* If there are no references to this symbol that do not use the
GOT, we don't need to generate a copy reloc. */
- if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0)
+ if (!h->non_got_ref)
return TRUE;
if (ELIMINATE_COPY_RELOCS)
we'll be keeping the dynamic relocs and avoiding the copy reloc. */
if (p == NULL)
{
- h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
+ h->non_got_ref = 0;
return TRUE;
}
}
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
{
htab->relbss->size += sizeof (Elf64_External_Rela);
- h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+ h->needs_copy = 1;
}
/* We need to figure out the alignment required for this symbol. I
if ((h == NULL
|| ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
+ && !h->def_dynamic))
&& (next_r == -1 || next_r == -2))
return 1 - next_r;
return 1;
opd_adjust = get_opd_info (sec);
if (opd_adjust == NULL)
{
- /* Must be a ld -r link. ie. check_relocs hasn't been
- called. */
+ /* check_relocs hasn't been called. Must be a ld -r link
+ or --just-symbols object. */
opd_adjust = bfd_zalloc (obfd, amt);
ppc64_elf_section_data (sec)->opd.adjust = opd_adjust;
}
memset (opd_adjust, 0, amt);
+ if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+ continue;
+
if (sec->output_section == bfd_abs_section_ptr)
continue;
ok_tprel = FALSE;
is_local = FALSE;
if (h == NULL
- || !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))
+ || !h->def_dynamic)
{
is_local = TRUE;
value += sym_sec->output_offset;
return TRUE;
}
+/* Called via elf_link_hash_traverse from ppc64_elf_edit_toc to adjust
+ the values of any global symbols in a toc section that has been
+ edited. Globals in toc sections should be a rarity, so this function
+ sets a flag if any are found in toc sections other than the one just
+ edited, so that futher hash table traversals can be avoided. */
+
+struct adjust_toc_info
+{
+ asection *toc;
+ unsigned long *skip;
+ bfd_boolean global_toc_syms;
+};
+
+static bfd_boolean
+adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
+{
+ struct ppc_link_hash_entry *eh;
+ struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf;
+
+ if (h->root.type == bfd_link_hash_indirect)
+ return TRUE;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ return TRUE;
+
+ eh = (struct ppc_link_hash_entry *) h;
+ if (eh->adjust_done)
+ return TRUE;
+
+ if (eh->elf.root.u.def.section == toc_inf->toc)
+ {
+ unsigned long skip = toc_inf->skip[eh->elf.root.u.def.value >> 3];
+ if (skip != (unsigned long) -1)
+ eh->elf.root.u.def.value -= skip;
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%s defined in removed toc entry"), eh->elf.root.root.string);
+ eh->elf.root.u.def.section = &bfd_abs_section;
+ eh->elf.root.u.def.value = 0;
+ }
+ eh->adjust_done = 1;
+ }
+ else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0)
+ toc_inf->global_toc_syms = TRUE;
+
+ return TRUE;
+}
+
+/* Examine all relocs referencing .toc sections in order to remove
+ unused .toc entries. */
+
+bfd_boolean
+ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+{
+ bfd *ibfd;
+ struct adjust_toc_info toc_inf;
+
+ toc_inf.global_toc_syms = TRUE;
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ {
+ asection *toc, *sec;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym *local_syms;
+ struct elf_link_hash_entry **sym_hashes;
+ Elf_Internal_Rela *relstart, *rel, *wrel;
+ unsigned long *skip, *drop;
+ unsigned char *used;
+ unsigned char *keep, last, some_unused;
+
+ toc = bfd_get_section_by_name (ibfd, ".toc");
+ if (toc == NULL
+ || toc->sec_info_type == ELF_INFO_TYPE_JUST_SYMS
+ || elf_discarded_section (toc))
+ continue;
+
+ local_syms = NULL;
+ symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (ibfd);
+
+ /* Look at sections dropped from the final link. */
+ skip = NULL;
+ relstart = NULL;
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ {
+ if (sec->reloc_count == 0
+ || !elf_discarded_section (sec)
+ || get_opd_info (sec)
+ || (sec->flags & SEC_ALLOC) == 0
+ || (sec->flags & SEC_DEBUGGING) != 0)
+ continue;
+
+ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, FALSE);
+ if (relstart == NULL)
+ goto error_ret;
+
+ /* Run through the relocs to see which toc entries might be
+ unused. */
+ for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+ {
+ enum elf_ppc64_reloc_type r_type;
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ bfd_vma val;
+
+ r_type = ELF64_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ default:
+ continue;
+
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO_DS:
+ break;
+ }
+
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+ r_symndx, ibfd))
+ goto error_ret;
+
+ if (sym_sec != toc)
+ continue;
+
+ if (h != NULL)
+ val = h->root.u.def.value;
+ else
+ val = sym->st_value;
+ val += rel->r_addend;
+
+ if (val >= toc->size)
+ continue;
+
+ /* Anything in the toc ought to be aligned to 8 bytes.
+ If not, don't mark as unused. */
+ if (val & 7)
+ continue;
+
+ if (skip == NULL)
+ {
+ skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8);
+ if (skip == NULL)
+ goto error_ret;
+ }
+
+ skip[val >> 3] = 1;
+ }
+
+ if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
+ }
+
+ if (skip == NULL)
+ continue;
+
+ used = bfd_zmalloc (sizeof (*used) * (toc->size + 7) / 8);
+ if (used == NULL)
+ {
+ error_ret:
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ free (local_syms);
+ if (sec != NULL
+ && relstart != NULL
+ && elf_section_data (sec)->relocs != relstart)
+ free (relstart);
+ if (skip != NULL)
+ free (skip);
+ return FALSE;
+ }
+
+ /* Now check all kept sections that might reference the toc. */
+ for (sec = ibfd->sections;
+ sec != NULL;
+ /* Check the toc itself last. */
+ sec = (sec == toc ? NULL
+ : sec->next == toc && sec->next->next ? sec->next->next
+ : sec->next == NULL ? toc
+ : sec->next))
+ {
+ int repeat;
+
+ if (sec->reloc_count == 0
+ || elf_discarded_section (sec)
+ || get_opd_info (sec)
+ || (sec->flags & SEC_ALLOC) == 0
+ || (sec->flags & SEC_DEBUGGING) != 0)
+ continue;
+
+ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE);
+ if (relstart == NULL)
+ goto error_ret;
+
+ /* Mark toc entries referenced as used. */
+ repeat = 0;
+ do
+ for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+ {
+ enum elf_ppc64_reloc_type r_type;
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ bfd_vma val;
+
+ r_type = ELF64_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO_DS:
+ /* In case we're taking addresses of toc entries. */
+ case R_PPC64_ADDR64:
+ break;
+
+ default:
+ continue;
+ }
+
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+ r_symndx, ibfd))
+ {
+ free (used);
+ goto error_ret;
+ }
+
+ if (sym_sec != toc)
+ continue;
+
+ if (h != NULL)
+ val = h->root.u.def.value;
+ else
+ val = sym->st_value;
+ val += rel->r_addend;
+
+ if (val >= toc->size)
+ continue;
+
+ /* For the toc section, we only mark as used if
+ this entry itself isn't unused. */
+ if (sec == toc
+ && !used[val >> 3]
+ && (used[rel->r_offset >> 3]
+ || !skip[rel->r_offset >> 3]))
+ /* Do all the relocs again, to catch reference
+ chains. */
+ repeat = 1;
+
+ used[val >> 3] = 1;
+ }
+ while (repeat);
+ }
+
+ /* Merge the used and skip arrays. Assume that TOC
+ doublewords not appearing as either used or unused belong
+ to to an entry more than one doubleword in size. */
+ for (drop = skip, keep = used, last = 0, some_unused = 0;
+ drop < skip + (toc->size + 7) / 8;
+ ++drop, ++keep)
+ {
+ if (*keep)
+ {
+ *drop = 0;
+ last = 0;
+ }
+ else if (*drop)
+ {
+ some_unused = 1;
+ last = 1;
+ }
+ else
+ *drop = last;
+ }
+
+ free (used);
+
+ if (some_unused)
+ {
+ bfd_byte *contents, *src;
+ unsigned long off;
+
+ /* Shuffle the toc contents, and at the same time convert the
+ skip array from booleans into offsets. */
+ if (!bfd_malloc_and_get_section (ibfd, toc, &contents))
+ goto error_ret;
+
+ elf_section_data (toc)->this_hdr.contents = contents;
+
+ for (src = contents, off = 0, drop = skip;
+ src < contents + toc->size;
+ src += 8, ++drop)
+ {
+ if (*drop)
+ {
+ *drop = (unsigned long) -1;
+ off += 8;
+ }
+ else if (off != 0)
+ {
+ *drop = off;
+ memcpy (src - off, src, 8);
+ }
+ }
+ toc->rawsize = toc->size;
+ toc->size = src - contents - off;
+
+ /* Read toc relocs. */
+ relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL, TRUE);
+ if (relstart == NULL)
+ goto error_ret;
+
+ /* Remove unused toc relocs, and adjust those we keep. */
+ wrel = relstart;
+ for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
+ if (skip[rel->r_offset >> 3] != (unsigned long) -1)
+ {
+ wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
+ wrel->r_info = rel->r_info;
+ wrel->r_addend = rel->r_addend;
+ ++wrel;
+ }
+ toc->reloc_count = wrel - relstart;
+
+ /* Adjust addends for relocs against the toc section sym. */
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ {
+ if (sec->reloc_count == 0
+ || elf_discarded_section (sec))
+ continue;
+
+ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+ TRUE);
+ if (relstart == NULL)
+ goto error_ret;
+
+ for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+ {
+ enum elf_ppc64_reloc_type r_type;
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+
+ r_type = ELF64_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ default:
+ continue;
+
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_ADDR64:
+ break;
+ }
+
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+ r_symndx, ibfd))
+ goto error_ret;
+
+ if (sym_sec != toc || h != NULL || sym->st_value != 0)
+ continue;
+
+ rel->r_addend -= skip[rel->r_addend >> 3];
+ }
+ }
+
+ /* We shouldn't have local or global symbols defined in the TOC,
+ but handle them anyway. */
+ if (local_syms != NULL)
+ {
+ Elf_Internal_Sym *sym;
+
+ for (sym = local_syms;
+ sym < local_syms + symtab_hdr->sh_info;
+ ++sym)
+ if (sym->st_shndx != SHN_UNDEF
+ && (sym->st_shndx < SHN_LORESERVE
+ || sym->st_shndx > SHN_HIRESERVE)
+ && sym->st_value != 0
+ && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
+ {
+ if (skip[sym->st_value >> 3] != (unsigned long) -1)
+ sym->st_value -= skip[sym->st_value >> 3];
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%s defined in removed toc entry"),
+ bfd_elf_local_sym_name (ibfd, sym));
+ sym->st_value = 0;
+ sym->st_shndx = SHN_ABS;
+ }
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
+ }
+
+ /* Finally, adjust any global syms defined in the toc. */
+ if (toc_inf.global_toc_syms)
+ {
+ toc_inf.toc = toc;
+ toc_inf.skip = skip;
+ toc_inf.global_toc_syms = FALSE;
+ elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
+ &toc_inf);
+ }
+ }
+
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ {
+ if (!info->keep_memory)
+ free (local_syms);
+ else
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
+ free (skip);
+ }
+
+ return TRUE;
+}
+
/* Allocate space in .plt, .got and associated reloc sections for
dynamic relocs. */
if (!doneone)
{
h->plt.plist = NULL;
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->needs_plt = 0;
}
}
else
{
h->plt.plist = NULL;
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->needs_plt = 0;
}
eh = (struct ppc_link_hash_entry *) h;
Undefined weak syms won't yet be marked as dynamic,
nor will all TLS symbols. */
if (h->dynindx == -1
- && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ && !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
if ((gent->tls_type & TLS_LD) != 0
- && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))
+ && !h->def_dynamic)
{
gent->got.offset = ppc64_tlsld_got (gent->owner)->offset;
continue;
symbols which turn out to need copy relocs or are not
dynamic. */
- if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ if (!h->non_got_ref
+ && h->def_dynamic
+ && !h->def_regular)
{
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ && !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+ if (!is_ppc64_elf_target (ibfd->xvec))
continue;
if (ppc64_tlsld_got (ibfd)->refcount > 0)
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
+ if (!is_ppc64_elf_target (ibfd->xvec))
+ continue;
+
s = ppc64_elf_tdata (ibfd)->got;
if (s != NULL && s != htab->got)
{
bfd_byte *p;
unsigned int indx;
struct plt_entry *ent;
- bfd_vma off;
+ bfd_vma dest, off;
int size;
/* Massage our args to the form they really have. */
case ppc_stub_long_branch:
case ppc_stub_long_branch_r2off:
/* Branches are relative. This is where we are going to. */
- off = (stub_entry->target_value
- + stub_entry->target_section->output_offset
- + stub_entry->target_section->output_section->vma);
+ off = dest = (stub_entry->target_value
+ + stub_entry->target_section->output_offset
+ + stub_entry->target_section->output_section->vma);
/* And this is where we are coming from. */
off -= (stub_entry->stub_offset
bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
BFD_ASSERT (off + (1 << 25) < (bfd_vma) (1 << 26));
+
+ if (info->emitrelocations)
+ {
+ Elf_Internal_Rela *relocs, *r;
+ struct bfd_elf_section_data *elfsec_data;
+
+ elfsec_data = elf_section_data (stub_entry->stub_sec);
+ relocs = elfsec_data->relocs;
+ if (relocs == NULL)
+ {
+ bfd_size_type relsize;
+ relsize = stub_entry->stub_sec->reloc_count * sizeof (*relocs);
+ relocs = bfd_alloc (htab->stub_bfd, relsize);
+ if (relocs == NULL)
+ return FALSE;
+ elfsec_data->relocs = relocs;
+ elfsec_data->rel_hdr.sh_size = relsize;
+ elfsec_data->rel_hdr.sh_entsize = 24;
+ stub_entry->stub_sec->reloc_count = 0;
+ }
+ r = relocs + stub_entry->stub_sec->reloc_count;
+ stub_entry->stub_sec->reloc_count += 1;
+ r->r_offset = loc - stub_entry->stub_sec->contents;
+ r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
+ r->r_addend = dest;
+ if (stub_entry->h != NULL)
+ {
+ struct elf_link_hash_entry **hashes;
+ unsigned long symndx;
+ struct ppc_link_hash_entry *h;
+
+ hashes = elf_sym_hashes (htab->stub_bfd);
+ if (hashes == NULL)
+ {
+ bfd_size_type hsize;
+
+ hsize = (htab->stub_globals + 1) * sizeof (*hashes);
+ hashes = bfd_zalloc (htab->stub_bfd, hsize);
+ if (hashes == NULL)
+ return FALSE;
+ elf_sym_hashes (htab->stub_bfd) = hashes;
+ htab->stub_globals = 1;
+ }
+ symndx = htab->stub_globals++;
+ h = stub_entry->h;
+ 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;
+ 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;
+ else
+ {
+ off = (h->elf.root.u.def.value
+ + h->elf.root.u.def.section->output_offset
+ + h->elf.root.u.def.section->output_section->vma);
+ r->r_addend -= off;
+ }
+ }
+ }
break;
case ppc_stub_plt_branch:
bfd_put_64 (htab->brlt->owner, off,
htab->brlt->contents + br_entry->offset);
- if (info->shared)
+ if (htab->relbrlt != NULL)
{
/* Create a reloc for the branch lookup table entry. */
Elf_Internal_Rela rela;
stub_entry->stub_sec->size += size;
- if (htab->emit_stub_syms
- && !(stub_entry->stub_type == ppc_stub_plt_call
- && stub_entry->h->oh != NULL
- && 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))
+ if (htab->emit_stub_syms)
{
struct elf_link_hash_entry *h;
- h = elf_link_hash_lookup (&htab->elf, stub_entry->root.string,
- TRUE, FALSE, FALSE);
+ size_t len1, len2;
+ char *name;
+ const char *const stub_str[] = { "long_branch",
+ "long_branch_r2off",
+ "plt_branch",
+ "plt_branch_r2off",
+ "plt_call" };
+
+ len1 = strlen (stub_str[stub_entry->stub_type - 1]);
+ len2 = strlen (stub_entry->root.string);
+ name = bfd_malloc (len1 + len2 + 2);
+ if (name == NULL)
+ return FALSE;
+ memcpy (name, stub_entry->root.string, 9);
+ memcpy (name + 9, stub_str[stub_entry->stub_type - 1], len1);
+ memcpy (name + len1 + 9, stub_entry->root.string + 8, len2 - 8 + 1);
+ h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
if (h == NULL)
return FALSE;
if (h->root.type == bfd_link_hash_new)
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = stub_entry->stub_sec;
h->root.u.def.value = stub_entry->stub_offset;
- h->elf_link_hash_flags = (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK
- | ELF_LINK_FORCED_LOCAL);
+ h->ref_regular = 1;
+ h->def_regular = 1;
+ h->ref_regular_nonweak = 1;
+ h->forced_local = 1;
+ h->non_elf = 0;
}
}
br_entry->offset = htab->brlt->size;
htab->brlt->size += 8;
- if (info->shared)
+ if (htab->relbrlt != NULL)
htab->relbrlt->size += sizeof (Elf64_External_Rela);
}
if (stub_entry->stub_type != ppc_stub_plt_branch)
size = 28;
}
+
+ if (info->emitrelocations
+ && (stub_entry->stub_type == ppc_stub_long_branch
+ || stub_entry->stub_type == ppc_stub_long_branch_r2off))
+ stub_entry->stub_sec->reloc_count += 1;
}
stub_entry->stub_sec->size += size;
stub_entry->target_section = code_sec;
stub_entry->h = hash;
stub_entry->addend = irela->r_addend;
+
+ if (stub_entry->h != NULL)
+ htab->stub_globals += 1;
+
stub_changed = TRUE;
}
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
- stub_sec->size = 0;
+ {
+ stub_sec->size = 0;
+ stub_sec->reloc_count = 0;
+ }
htab->brlt->size = 0;
- if (info->shared)
+ if (htab->relbrlt != NULL)
htab->relbrlt->size = 0;
bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = htab->glink;
h->root.u.def.value = 0;
- h->elf_link_hash_flags = (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK
- | ELF_LINK_FORCED_LOCAL);
+ h->ref_regular = 1;
+ h->def_regular = 1;
+ h->ref_regular_nonweak = 1;
+ h->forced_local = 1;
+ h->non_elf = 0;
}
}
p = htab->glink->contents;
if (htab->brlt->contents == NULL)
return FALSE;
}
- if (info->shared && htab->relbrlt->size != 0)
+ if (htab->relbrlt != NULL && htab->relbrlt->size != 0)
{
htab->relbrlt->contents = bfd_zalloc (htab->relbrlt->owner,
htab->relbrlt->size);
if (*stats == NULL)
return FALSE;
- sprintf (*stats, _("linker stubs in %u groups\n"
+ sprintf (*stats, _("linker stubs in %u group%s\n"
" branch %lu\n"
" toc adjust %lu\n"
" long branch %lu\n"
" long toc adj %lu\n"
" plt call %lu"),
stub_sec_count,
+ stub_sec_count == 1 ? "" : "s",
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],
ppc_howto_init ();
htab = ppc_hash_table (info);
+
+ /* Don't relocate stub sections. */
+ if (input_section->owner == htab->stub_bfd)
+ return TRUE;
+
local_got_ents = elf_local_got_ents (input_bfd);
TOCstart = elf_gp (output_bfd);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
if (tls_type == (TLS_TLS | TLS_LD)
&& (h == NULL
- || (h->elf.elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) == 0))
+ || !h->elf.def_dynamic))
offp = &ppc64_tlsld_got (input_bfd)->offset;
else
{
&& !info->shared
&& h != NULL
&& h->elf.dynindx != -1
- && !(h->elf.elf_link_hash_flags & ELF_LINK_NON_GOT_REF)
- && (h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
- && !(h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+ && !h->elf.non_got_ref
+ && h->elf.def_dynamic
+ && !h->elf.def_regular))
{
Elf_Internal_Rela outrel;
bfd_boolean skip, relocate;
not process them. */
if (unresolved_reloc
&& !((input_section->flags & SEC_DEBUGGING) != 0
- && (h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
+ && h->elf.def_dynamic))
{
(*_bfd_error_handler)
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
}
if (!((*info->callbacks->reloc_overflow)
- (info, sym_name, ppc64_elf_howto_table[r_type]->name,
+ (info, (h ? &h->elf.root : NULL), sym_name,
+ ppc64_elf_howto_table[r_type]->name,
rel->r_addend, input_bfd, input_section, rel->r_offset)))
return FALSE;
}
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
}
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+ if (h->needs_copy)
{
Elf_Internal_Rela rela;
bfd_byte *loc;
}
/* We need to handle writing out multiple GOT sections ourselves,
- since we didn't add them to DYNOBJ. */
+ since we didn't add them to DYNOBJ. We know dynobj is the first
+ bfd. */
while ((dynobj = dynobj->link_next) != NULL)
{
asection *s;
+
+ if (!is_ppc64_elf_target (dynobj->xvec))
+ continue;
+
s = ppc64_elf_tdata (dynobj)->got;
if (s != NULL
&& s->size != 0