TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTREL32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
type = ELF64_R_TYPE (dst->r_info);
if (type >= ARRAY_SIZE (ppc64_elf_howto_table))
{
- (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
- abfd, (int) type);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B: invalid relocation type %d"),
+ abfd, (int) type);
type = R_PPC64_NONE;
}
cache_ptr->howto = ppc64_elf_howto_table[type];
}
/* Fix bad default arch selected for a 64 bit input bfd when the
- default is 32 bit. */
+ default is 32 bit. Also select arch based on apuinfo. */
static bfd_boolean
ppc64_elf_object_p (bfd *abfd)
{
- if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 32)
+ if (!abfd->arch_info->the_default)
+ return TRUE;
+
+ if (abfd->arch_info->bits_per_word == 32)
{
Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
BFD_ASSERT (abfd->arch_info->bits_per_word == 64);
}
}
- return TRUE;
+ return _bfd_elf_ppc_set_arch (abfd);
}
/* Support for core dump NOTE sections. */
\f
/* Parameters for the qsort hook. */
static bfd_boolean synthetic_relocatable;
+static asection *synthetic_opd;
/* qsort comparison function for ppc64_elf_get_synthetic_symtab. */
return 1;
/* then .opd symbols. */
- if (strcmp (a->section->name, ".opd") == 0
- && strcmp (b->section->name, ".opd") != 0)
- return -1;
- if (strcmp (a->section->name, ".opd") != 0
- && strcmp (b->section->name, ".opd") == 0)
- return 1;
+ if (synthetic_opd != NULL)
+ {
+ if (strcmp (a->section->name, ".opd") == 0
+ && strcmp (b->section->name, ".opd") != 0)
+ return -1;
+ if (strcmp (a->section->name, ".opd") != 0
+ && strcmp (b->section->name, ".opd") == 0)
+ return 1;
+ }
/* then other code symbols. */
if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
synthetic_relocatable = relocatable;
+ synthetic_opd = opd;
qsort (syms, symcount, sizeof (*syms), compare_symbols);
if (!relocatable && symcount > 1)
}
i = 0;
- if (strcmp (syms[i]->section->name, ".opd") == 0)
+ /* Note that here and in compare_symbols we can't compare opd and
+ sym->section directly. With separate debug info files, the
+ symbols will be extracted from the debug file while abfd passed
+ to this function is the real binary. */
+ if (opd != NULL && strcmp (syms[i]->section->name, ".opd") == 0)
++i;
codesecsym = i;
break;
secsymend = i;
- for (; i < symcount; ++i)
- if (strcmp (syms[i]->section->name, ".opd") != 0)
- break;
+ if (opd != NULL)
+ for (; i < symcount; ++i)
+ if (strcmp (syms[i]->section->name, ".opd") != 0)
+ break;
opdsymend = i;
for (; i < symcount; ++i)
/* Track dynamic relocs copied for this symbol. */
struct elf_dyn_relocs *dyn_relocs;
+ /* Chain of aliases referring to a weakdef. */
+ struct ppc_link_hash_entry *weakref;
+
/* Link between function code and descriptor symbols. */
struct ppc_link_hash_entry *oh;
more than one stub used to reach say, printf, and we need to
distinguish between them. */
group = htab->sec_info[input_section->id].u.group;
+ if (group == NULL)
+ return NULL;
if (h != NULL && h->u.stub_cache != NULL
&& h->u.stub_cache->h == h
TRUE, FALSE);
if (stub_entry == NULL)
{
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: %B: cannot create stub entry %s\n"),
section->owner, stub_name);
return NULL;
edir->elf.needs_plt |= eind->elf.needs_plt;
edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
+ /* If we were called to copy over info for a weak sym, don't copy
+ dyn_relocs, plt/got info, or dynindx. We used to copy dyn_relocs
+ in order to simplify readonly_dynrelocs and save a field in the
+ symbol hash entry, but that means dyn_relocs can't be used in any
+ tests about a specific symbol, or affect other symbol flags which
+ are then tested.
+ Chain weakdefs so we can get from the weakdef back to an alias.
+ The list is circular so that we don't need to use u.weakdef as
+ well as this list to look at all aliases. */
+ if (eind->elf.root.type != bfd_link_hash_indirect)
+ {
+ struct ppc_link_hash_entry *cur, *add, *next;
+
+ add = eind;
+ do
+ {
+ cur = edir->weakref;
+ if (cur != NULL)
+ {
+ do
+ {
+ /* We can be called twice for the same symbols.
+ Don't make multiple loops. */
+ if (cur == add)
+ return;
+ cur = cur->weakref;
+ } while (cur != edir);
+ }
+ next = add->weakref;
+ if (cur != add)
+ {
+ add->weakref = edir->weakref != NULL ? edir->weakref : edir;
+ edir->weakref = add;
+ }
+ add = next;
+ } while (add != NULL && add != eind);
+ return;
+ }
+
/* Copy over any dynamic relocs we may have on the indirect sym. */
if (eind->dyn_relocs != NULL)
{
eind->dyn_relocs = NULL;
}
- /* If we were called to copy over info for a weak sym, that's all.
- You might think dyn_relocs need not be copied over; After all,
- both syms will be dynamic or both non-dynamic so we're just
- moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
- code in ppc64_elf_adjust_dynamic_symbol needs to check for
- dyn_relocs in read-only sections, and it does so on what is the
- DIR sym here. */
- if (eind->elf.root.type != bfd_link_hash_indirect)
- return;
-
/* Copy over got entries that we may have already seen to the
symbol which just became indirect. */
if (eind->elf.got.glist != NULL)
{
if (abiversion (ibfd) == 0)
set_abiversion (ibfd, 1);
- else if (abiversion (ibfd) == 2)
+ else if (abiversion (ibfd) >= 2)
{
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
" version %d\n"),
ibfd, abiversion (ibfd));
}
/* We need to fix the undefs list for any syms we have twiddled to
- undef_weak. */
+ undefweak. */
if (htab->twiddled_syms)
{
bfd_link_repair_undef_list (&htab->elf.root);
tls_type = TLS_TLS | TLS_DTPREL;
dogottls:
sec->has_tls_reloc = 1;
- /* Fall thru */
+ /* Fall through */
case R_PPC64_GOT16:
case R_PPC64_GOT16_DS:
/* It does not make sense to have a procedure linkage
table entry for a non-ifunc local symbol. */
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: %s reloc against local symbol\n"),
abfd, sec, rel->r_offset,
ppc64_elf_howto_table[r_type]->name);
{
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: %H: %s reloc unsupported "
"in shared libraries and PIEs.\n"),
abfd, sec, rel->r_offset,
case R_PPC64_TOC16_DS:
htab->do_multi_toc = 1;
ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
+ /* Fall through. */
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_HI:
case R_PPC64_TOC16_HA:
object file when linking. */
static bfd_boolean
-ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
unsigned long iflags, oflags;
if ((ibfd->flags & BFD_LINKER_CREATED) != 0)
if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd))
return TRUE;
- if (!_bfd_generic_verify_endian_match (ibfd, obfd))
+ if (!_bfd_generic_verify_endian_match (ibfd, info))
return FALSE;
iflags = elf_elfheader (ibfd)->e_flags;
if (iflags & ~EF_PPC64_ABI)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B uses unknown e_flags 0x%lx"), ibfd, iflags);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
else if (iflags != oflags && iflags != 0)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: ABI version %ld is not compatible with ABI version %ld output"),
ibfd, iflags, oflags);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
+ _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+
/* Merge Tag_compatibility attributes and any common GNU ones. */
- _bfd_elf_merge_object_attributes (ibfd, obfd);
+ _bfd_elf_merge_object_attributes (ibfd, info);
return TRUE;
}
{
FILE *file = ptr;
- /* xgettext:c-format */
fprintf (file, _("private flags = 0x%lx:"),
elf_elfheader (abfd)->e_flags);
return TRUE;
}
-/* Return true if we have dynamic relocs that apply to read-only sections. */
+/* Return true if we have dynamic relocs against H that apply to
+ read-only sections. */
static bfd_boolean
readonly_dynrelocs (struct elf_link_hash_entry *h)
return FALSE;
}
+/* Return true if we have dynamic relocs against H or any of its weak
+ aliases, that apply to read-only sections. */
+
+static bfd_boolean
+alias_readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+ struct ppc_link_hash_entry *eh;
+
+ eh = (struct ppc_link_hash_entry *) h;
+ do
+ {
+ if (readonly_dynrelocs (&eh->elf))
+ return TRUE;
+ eh = eh->weakref;
+ } while (eh != NULL && &eh->elf != h);
+
+ return FALSE;
+}
+
+/* Return whether EH has pc-relative dynamic relocs. */
+
+static bfd_boolean
+pc_dynrelocs (struct ppc_link_hash_entry *eh)
+{
+ struct elf_dyn_relocs *p;
+
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ if (p->pc_count != 0)
+ return TRUE;
+ return FALSE;
+}
+
+/* Return true if a global entry stub will be created for H. Valid
+ for ELFv2 before plt entries have been allocated. */
+
+static bfd_boolean
+global_entry_stub (struct elf_link_hash_entry *h)
+{
+ struct plt_entry *pent;
+
+ if (!h->pointer_equality_needed
+ || h->def_regular)
+ return FALSE;
+
+ for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+ if (pent->plt.refcount > 0
+ && pent->addend == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
h->needs_plt = 0;
h->pointer_equality_needed = 0;
}
- else if (abiversion (info->output_bfd) == 2)
+ else if (abiversion (info->output_bfd) >= 2)
{
/* Taking a function's address in a read/write section
doesn't require us to define the function symbol in the
executable on a global entry stub. A dynamic reloc can
- be used instead. */
- if (h->pointer_equality_needed
- && h->type != STT_GNU_IFUNC
- && !readonly_dynrelocs (h))
+ be used instead. The reason we prefer a few more dynamic
+ relocs is that calling via a global entry stub costs a
+ few more instructions, and pointer_equality_needed causes
+ extra work in ld.so when resolving these symbols. */
+ if (global_entry_stub (h)
+ && !alias_readonly_dynrelocs (h))
{
h->pointer_equality_needed = 0;
+ /* After adjust_dynamic_symbol, non_got_ref set in
+ the non-pic case means that dyn_relocs for this
+ symbol should be discarded. */
h->non_got_ref = 0;
}
- /* After adjust_dynamic_symbol, non_got_ref set in the
- non-shared case means that we have allocated space in
- .dynbss for the symbol and thus dyn_relocs for this
- symbol should be discarded.
- If we get here we know we are making a PLT entry for this
- symbol, and in an executable we'd normally resolve
- relocations against this symbol to the PLT entry. Allow
- dynamic relocs if the reference is weak, and the dynamic
- relocs will not cause text relocation. */
- else if (!h->ref_regular_nonweak
- && h->non_got_ref
- && h->type != STT_GNU_IFUNC
- && !readonly_dynrelocs (h))
- h->non_got_ref = 0;
-
/* If making a plt entry, then we don't need copy relocs. */
return TRUE;
}
return TRUE;
/* Don't generate a copy reloc for symbols defined in the executable. */
- if (!h->def_dynamic || !h->ref_regular || h->def_regular)
- return TRUE;
+ if (!h->def_dynamic || !h->ref_regular || h->def_regular
- /* If -z nocopyreloc was given, don't generate them either. */
- if (info->nocopyreloc)
- {
- h->non_got_ref = 0;
- return TRUE;
- }
+ /* If -z nocopyreloc was given, don't generate them either. */
+ || info->nocopyreloc
- /* If we didn't find any dynamic relocs in read-only sections, then
- we'll be keeping the dynamic relocs and avoiding the copy reloc. */
- if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h))
- {
- h->non_got_ref = 0;
- return TRUE;
- }
+ /* If we didn't find any dynamic relocs in read-only sections, then
+ we'll be keeping the dynamic relocs and avoiding the copy reloc. */
+ || (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h))
- /* Protected variables do not work with .dynbss. The copy in
- .dynbss won't be used by the shared library with the protected
- definition for the variable. Text relocations are preferable
- to an incorrect program. */
- if (h->protected_def)
+ /* Protected variables do not work with .dynbss. The copy in
+ .dynbss won't be used by the shared library with the protected
+ definition for the variable. Text relocations are preferable
+ to an incorrect program. */
+ || h->protected_def)
{
h->non_got_ref = 0;
return TRUE;
return NULL;
if (ent.sec == NULL || ent.sec->output_section == NULL)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
return NULL;
}
}
}
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
sec->owner, sec);
bfd_set_error (bfd_error_bad_value);
something silly in .opd with the assembler. No .opd
optimization for them! */
broken_opd:
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: .opd is not a regular array of opd entries"), ibfd);
broken = TRUE;
break;
if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64
|| (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: unexpected reloc type %u in .opd section"),
ibfd, r_type);
broken = TRUE;
sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym,
sym_sec);
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: undefined sym `%s' in .opd section"),
ibfd, sym_name);
broken = TRUE;
case R_PPC64_GOT_TLSLD16_LO:
expecting_tls_get_addr = 1;
found_tls_get_addr_arg = 1;
- /* Fall thru */
+ /* Fall through. */
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
case R_PPC64_GOT_TLSGD16_LO:
expecting_tls_get_addr = 1;
found_tls_get_addr_arg = 1;
- /* Fall thru */
+ /* Fall through. */
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_HA:
case R_PPC64_TLSGD:
case R_PPC64_TLSLD:
found_tls_get_addr_arg = 1;
- /* Fall thru */
+ /* Fall through. */
case R_PPC64_TLS:
case R_PPC64_TOC16:
could just mark this symbol to exclude it
from tls optimization but it's safer to skip
the entire optimization. */
+ /* xgettext:c-format */
info->callbacks->minfo (_("%H arg lost __tls_get_addr, "
"TLS optimization disabled\n"),
ibfd, sec, rel->r_offset);
if ((toc_inf->skip[i] & (ref_from_discarded | can_optimize)) != 0)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%s defined on removed toc entry"), eh->elf.root.root.string);
do
++i;
ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
sprintf (str, "%#08x", insn);
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: toc optimization is not supported for"
" %s instruction.\n"),
ibfd, sec, rel->r_offset & ~3, str);
}
if ((opc & (0x3f << 2)) == (58u << 2))
break;
- /* Fall thru */
+ /* Fall through. */
default:
/* Wrong sort of reloc, or not a ld. We may
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: %s references "
"optimized away TOC entry\n"),
ibfd, sec, rel->r_offset,
if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
{
if (local_toc_syms)
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%s defined on removed toc entry"),
bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
do
struct ppc_link_hash_table *htab;
asection *s;
struct ppc_link_hash_entry *eh;
- struct elf_dyn_relocs *p;
struct got_entry **pgent, *gent;
if (h->root.type == bfd_link_hash_indirect)
if (htab == NULL)
return FALSE;
- if ((htab->elf.dynamic_sections_created
- && h->dynindx != -1
- && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
- || h->type == STT_GNU_IFUNC)
- {
- struct plt_entry *pent;
- bfd_boolean doneone = FALSE;
- for (pent = h->plt.plist; pent != NULL; pent = pent->next)
- if (pent->plt.refcount > 0)
- {
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
- {
- s = htab->elf.iplt;
- pent->plt.offset = s->size;
- s->size += PLT_ENTRY_SIZE (htab);
- s = htab->elf.irelplt;
- }
- else
- {
- /* If this is the first .plt entry, make room for the special
- first entry. */
- s = htab->elf.splt;
- if (s->size == 0)
- s->size += PLT_INITIAL_ENTRY_SIZE (htab);
-
- pent->plt.offset = s->size;
-
- /* Make room for this entry. */
- s->size += PLT_ENTRY_SIZE (htab);
-
- /* Make room for the .glink code. */
- s = htab->glink;
- if (s->size == 0)
- s->size += GLINK_CALL_STUB_SIZE;
- if (htab->opd_abi)
- {
- /* We need bigger stubs past index 32767. */
- if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
- s->size += 4;
- s->size += 2*4;
- }
- else
- s->size += 4;
-
- /* We also need to make an entry in the .rela.plt section. */
- s = htab->elf.srelplt;
- }
- s->size += sizeof (Elf64_External_Rela);
- doneone = TRUE;
- }
- else
- pent->plt.offset = (bfd_vma) -1;
- if (!doneone)
- {
- h->plt.plist = NULL;
- h->needs_plt = 0;
- }
- }
- else
- {
- h->plt.plist = NULL;
- h->needs_plt = 0;
- }
-
eh = (struct ppc_link_hash_entry *) h;
/* Run through the TLS GD got entries first if we're changing them
to TPREL. */
allocate_got (h, info, gent);
}
- if (eh->dyn_relocs == NULL
- || (!htab->elf.dynamic_sections_created
- && h->type != STT_GNU_IFUNC))
- return TRUE;
-
- /* In the shared -Bsymbolic case, discard space allocated for
- dynamic pc-relative relocs against symbols which turn out to be
- defined in regular objects. For the normal shared case, discard
- space for relocs that have become local due to symbol visibility
- changes. */
+ if (!htab->elf.dynamic_sections_created
+ && h->type != STT_GNU_IFUNC)
+ eh->dyn_relocs = NULL;
- if (bfd_link_pic (info))
+ if (eh->dyn_relocs != NULL)
{
- /* Relocs that use pc_count are those that appear on a call insn,
- or certain REL relocs (see must_be_dyn_reloc) that can be
- generated via assembly. We want calls to protected symbols to
- resolve directly to the function rather than going via the plt.
- If people want function pointer comparisons to work as expected
- then they should avoid writing weird assembly. */
- if (SYMBOL_CALLS_LOCAL (info, h))
+ struct elf_dyn_relocs *p, **pp;
+
+ /* In the shared -Bsymbolic case, discard space allocated for
+ dynamic pc-relative relocs against symbols which turn out to
+ be defined in regular objects. For the normal shared case,
+ discard space for relocs that have become local due to symbol
+ visibility changes. */
+
+ if (bfd_link_pic (info))
{
- struct elf_dyn_relocs **pp;
+ /* Relocs that use pc_count are those that appear on a call
+ insn, or certain REL relocs (see must_be_dyn_reloc) that
+ can be generated via assembly. We want calls to
+ protected symbols to resolve directly to the function
+ rather than going via the plt. If people want function
+ pointer comparisons to work as expected then they should
+ avoid writing weird assembly. */
+ if (SYMBOL_CALLS_LOCAL (info, h))
+ {
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ {
+ p->count -= p->pc_count;
+ p->pc_count = 0;
+ if (p->count == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ /* Also discard relocs on undefined weak syms with
+ non-default visibility. */
+ if (eh->dyn_relocs != NULL
+ && h->root.type == bfd_link_hash_undefweak)
{
- p->count -= p->pc_count;
- p->pc_count = 0;
- if (p->count == 0)
- *pp = p->next;
- else
- pp = &p->next;
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ eh->dyn_relocs = NULL;
+
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ else if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
}
}
-
- /* Also discard relocs on undefined weak syms with non-default
- visibility. */
- if (eh->dyn_relocs != NULL
- && h->root.type == bfd_link_hash_undefweak)
+ else if (h->type == STT_GNU_IFUNC)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- eh->dyn_relocs = NULL;
+ /* A plt entry is always created when making direct calls to
+ an ifunc, even when building a static executable, but
+ that doesn't cover all cases. We may have only an ifunc
+ initialised function pointer for a given ifunc symbol.
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- else if (h->dynindx == -1
- && !h->forced_local)
+ For ELFv2, dynamic relocations are not required when
+ generating a global entry PLT stub. */
+ if (abiversion (info->output_bfd) >= 2)
{
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ if (global_entry_stub (h))
+ eh->dyn_relocs = NULL;
}
- }
- }
- else if (h->type == STT_GNU_IFUNC)
- {
- if (!h->non_got_ref)
- eh->dyn_relocs = NULL;
- }
- else if (ELIMINATE_COPY_RELOCS)
- {
- /* For the non-shared case, discard space for relocs against
- symbols which turn out to need copy relocs or are not
- dynamic. */
- if (!h->non_got_ref
- && !h->def_regular)
+ /* For ELFv1 we have function descriptors. Descriptors need
+ to be treated like PLT entries and thus have dynamic
+ relocations. One exception is when the function
+ descriptor is copied into .dynbss (which should only
+ happen with ancient versions of gcc). */
+ else if (h->needs_copy)
+ eh->dyn_relocs = NULL;
+ }
+ else if (ELIMINATE_COPY_RELOCS)
{
- /* Make sure this symbol is output as a dynamic symbol.
+ /* For the non-pic case, discard space for relocs against
+ symbols which turn out to need copy relocs or are not
+ dynamic. */
+
+ /* First 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->forced_local)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
- }
+ if (h->root.type == bfd_link_hash_undefweak
+ && !h->non_got_ref
+ && !h->def_regular
+ && h->dynindx == -1
+ && !h->forced_local
+ && !bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
- /* If that succeeded, we know we'll be keeping all the
- relocs. */
- if (h->dynindx != -1)
- goto keep;
+ if (h->non_got_ref
+ || h->def_regular
+ || h->dynindx == -1)
+ eh->dyn_relocs = NULL;
}
- eh->dyn_relocs = NULL;
-
- keep: ;
+ /* Finally, allocate space. */
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *sreloc = elf_section_data (p->sec)->sreloc;
+ if (eh->elf.type == STT_GNU_IFUNC)
+ sreloc = htab->elf.irelplt;
+ sreloc->size += p->count * sizeof (Elf64_External_Rela);
+ }
}
- /* Finally, allocate space. */
- for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ if ((htab->elf.dynamic_sections_created
+ && h->dynindx != -1
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
+ || h->type == STT_GNU_IFUNC)
{
- asection *sreloc = elf_section_data (p->sec)->sreloc;
- if (eh->elf.type == STT_GNU_IFUNC)
- sreloc = htab->elf.irelplt;
- sreloc->size += p->count * sizeof (Elf64_External_Rela);
+ struct plt_entry *pent;
+ bfd_boolean doneone = FALSE;
+ for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+ if (pent->plt.refcount > 0)
+ {
+ if (!htab->elf.dynamic_sections_created
+ || h->dynindx == -1)
+ {
+ s = htab->elf.iplt;
+ pent->plt.offset = s->size;
+ s->size += PLT_ENTRY_SIZE (htab);
+ s = htab->elf.irelplt;
+ }
+ else
+ {
+ /* If this is the first .plt entry, make room for the special
+ first entry. */
+ s = htab->elf.splt;
+ if (s->size == 0)
+ s->size += PLT_INITIAL_ENTRY_SIZE (htab);
+
+ pent->plt.offset = s->size;
+
+ /* Make room for this entry. */
+ s->size += PLT_ENTRY_SIZE (htab);
+
+ /* Make room for the .glink code. */
+ s = htab->glink;
+ if (s->size == 0)
+ s->size += GLINK_CALL_STUB_SIZE;
+ if (htab->opd_abi)
+ {
+ /* We need bigger stubs past index 32767. */
+ if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+ s->size += 4;
+ s->size += 2*4;
+ }
+ else
+ s->size += 4;
+
+ /* We also need to make an entry in the .rela.plt section. */
+ s = htab->elf.srelplt;
+ }
+ s->size += sizeof (Elf64_External_Rela);
+ doneone = TRUE;
+ }
+ else
+ pent->plt.offset = (bfd_vma) -1;
+ if (!doneone)
+ {
+ h->plt.plist = NULL;
+ h->needs_plt = 0;
+ }
+ }
+ else
+ {
+ h->plt.plist = NULL;
+ h->needs_plt = 0;
}
return TRUE;
need to define the symbol in the executable on a call stub.
This is to avoid text relocations. */
s->size = (s->size + 15) & -16;
+ h->root.type = bfd_link_hash_defined;
h->root.u.def.section = s;
h->root.u.def.value = s->size;
s->size += 16;
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: linkage table error against `%T'\n"),
stub_entry->h != NULL
? stub_entry->h->elf.root.root.string
{
struct ppc_link_hash_table *htab;
asection *osec;
- bfd_size_type stub14_group_size;
bfd_boolean suppress_size_errors;
htab = ppc_hash_table (info);
return FALSE;
suppress_size_errors = FALSE;
- stub14_group_size = stub_group_size >> 10;
if (stub_group_size == 1)
{
/* Default values. */
if (stubs_always_before_branch)
- {
- stub_group_size = 0x1e00000;
- stub14_group_size = 0x7800;
- }
+ stub_group_size = 0x1e00000;
else
- {
- stub_group_size = 0x1c00000;
- stub14_group_size = 0x7000;
- }
+ stub_group_size = 0x1c00000;
suppress_size_errors = TRUE;
}
bfd_boolean big_sec;
bfd_vma curr_toc;
struct map_stub *group;
+ bfd_size_type group_size;
curr = tail;
total = tail->size;
- big_sec = total > (ppc64_elf_section_data (tail) != NULL
- && ppc64_elf_section_data (tail)->has_14bit_branch
- ? stub14_group_size : stub_group_size);
+ group_size = (ppc64_elf_section_data (tail) != NULL
+ && ppc64_elf_section_data (tail)->has_14bit_branch
+ ? stub_group_size >> 10 : stub_group_size);
+
+ big_sec = total > group_size;
if (big_sec && !suppress_size_errors)
- (*_bfd_error_handler) (_("%B section %A exceeds stub group size"),
- tail->owner, tail);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B section %A exceeds stub group size"),
+ tail->owner, tail);
curr_toc = htab->sec_info[tail->id].toc_off;
while ((prev = htab->sec_info[curr->id].u.list) != NULL
&& ((total += curr->output_offset - prev->output_offset)
< (ppc64_elf_section_data (prev) != NULL
&& ppc64_elf_section_data (prev)->has_14bit_branch
- ? stub14_group_size : stub_group_size))
+ ? (group_size = stub_group_size >> 10) : group_size))
&& htab->sec_info[prev->id].toc_off == curr_toc)
curr = prev;
/* OK, the size from the start of CURR to the end is less
- than stub_group_size and thus can be handled by one stub
+ than group_size and thus can be handled by one stub
section. (or the tail section is itself larger than
- stub_group_size, in which case we may be toast.) We
- should really be keeping track of the total size of stubs
- added here, as stubs contribute to the final output
- section size. That's a little tricky, and this way will
- only break if stubs added make the total size more than
- 2^25, ie. for the default stub_group_size, if stubs total
- more than 2097152 bytes, or nearly 75000 plt call stubs. */
+ group_size, in which case we may be toast.) We should
+ really be keeping track of the total size of stubs added
+ here, as stubs contribute to the final output section
+ size. That's a little tricky, and this way will only
+ break if stubs added make the total size more than 2^25,
+ ie. for the default stub_group_size, if stubs total more
+ than 2097152 bytes, or nearly 75000 plt call stubs. */
group = bfd_alloc (curr->owner, sizeof (*group));
if (group == NULL)
return FALSE;
}
while (tail != curr && (tail = prev) != NULL);
- /* But wait, there's more! Input sections up to stub_group_size
+ /* But wait, there's more! Input sections up to group_size
bytes before the stub section can be handled by it too.
Don't do this if we have a really large section after the
stubs, as adding more stubs increases the chance that
&& ((total += tail->output_offset - prev->output_offset)
< (ppc64_elf_section_data (prev) != NULL
&& ppc64_elf_section_data (prev)->has_14bit_branch
- ? stub14_group_size : stub_group_size))
+ ? (group_size = stub_group_size >> 10) : group_size))
&& htab->sec_info[prev->id].toc_off == curr_toc)
{
tail = prev;
if (!group_sections (info, stub_group_size, stubs_always_before_branch))
return FALSE;
+#define STUB_SHRINK_ITER 20
+ /* Loop until no stubs added. After iteration 20 of this loop we may
+ exit on a stub section shrinking. This is to break out of a
+ pathological case where adding stubs on one iteration decreases
+ section gaps (perhaps due to alignment), which then requires
+ fewer or smaller stubs on the next iteration. */
+
while (1)
{
bfd *input_bfd;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
- && stub_sec->rawsize != stub_sec->size)
+ && stub_sec->rawsize != stub_sec->size
+ && (htab->stub_iteration <= STUB_SHRINK_ITER
+ || stub_sec->rawsize < stub_sec->size))
break;
- /* Exit from this loop when no stubs have been added, and no stubs
- have changed size. */
if (stub_sec == NULL
&& (htab->glink_eh_frame == NULL
|| htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size);
if (stub_sec->contents == NULL)
return FALSE;
- /* We want to check that built size is the same as calculated
- size. rawsize is a convenient location to use. */
- stub_sec->rawsize = stub_sec->size;
stub_sec->size = 0;
}
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
stub_sec_count += 1;
- if (stub_sec->rawsize != stub_sec->size)
+ if (stub_sec->rawsize != stub_sec->size
+ && (htab->stub_iteration <= STUB_SHRINK_ITER
+ || stub_sec->rawsize < stub_sec->size))
break;
}
else
info->callbacks->einfo
(!IS_PPC64_TLS_RELOC (r_type)
+ /* xgettext:c-format */
? _("%P: %H: %s used with TLS symbol `%T'\n")
+ /* xgettext:c-format */
: _("%P: %H: %s used with non-TLS symbol `%T'\n"),
input_bfd, input_section, rel->r_offset,
ppc64_elf_howto_table[r_type]->name,
case R_PPC64_ADDR14_BRTAKEN:
case R_PPC64_REL14_BRTAKEN:
insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */
- /* Fall thru. */
+ /* Fall through. */
/* Branch not taken prediction relocations. */
case R_PPC64_ADDR14_BRNTAKEN:
case R_PPC64_REL14_BRNTAKEN:
insn |= bfd_get_32 (output_bfd,
contents + rel->r_offset) & ~(0x01 << 21);
- /* Fall thru. */
+ /* Fall through. */
case R_PPC64_REL14:
max_br_offset = 1 << 15;
- /* Fall thru. */
+ /* Fall through. */
case R_PPC64_REL24:
/* Calls to functions with a different TOC, such as calls to
if (stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: call to `%T' lacks nop, can't restore toc; "
"recompile with -fPIC\n"),
input_bfd, input_section, rel->r_offset, sym_name);
else
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: call to `%T' lacks nop, can't restore toc; "
"(-mcmodel=small toc adjust stub)\n"),
input_bfd, input_section, rel->r_offset, sym_name);
{
default:
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: unknown relocation type %d for `%T'\n"),
input_bfd, (int) r_type, sym_name);
case R_PPC64_DTPREL64:
if (htab->elf.tls_sec != NULL)
addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
- /* Fall thru */
+ /* Fall through. */
/* Relocations that may need to be propagated if this is a
dynamic object. */
if (NO_OPD_RELOCS && is_opd)
break;
- if ((bfd_link_pic (info)
- && (h == NULL
- || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
- || h->elf.root.type != bfd_link_hash_undefweak)
- && (must_be_dyn_reloc (info, r_type)
- || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && h->elf.dynindx != -1
- && !h->elf.non_got_ref
- && !h->elf.def_regular)
- || (!bfd_link_pic (info)
- && (h != NULL
- ? h->elf.type == STT_GNU_IFUNC
- : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
+ if (bfd_link_pic (info)
+ ? ((h != NULL && pc_dynrelocs (h))
+ || must_be_dyn_reloc (info, r_type))
+ : (h != NULL
+ ? h->dyn_relocs != NULL
+ : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
{
bfd_boolean skip, relocate;
asection *sreloc;
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: %s for indirect "
"function `%T' unsupported\n"),
input_bfd, input_section, rel->r_offset,
/* These ones haven't been implemented yet. */
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: %s is not supported for `%T'\n"),
input_bfd,
ppc64_elf_howto_table[r_type]->name, sym_name);
alone (it will be set to zero elsewhere in the link). */
if (sec == NULL)
break;
- /* Fall thru */
+ /* Fall through. */
case R_PPC64_GOT16_HA:
case R_PPC64_PLTGOT16_HA:
{
relocation ^= relocation & mask;
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: error: %s not a multiple of %u\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
rel->r_offset) != (bfd_vma) -1)
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: unresolvable %s against `%T'\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
&& (h->elf.root.type == bfd_link_hash_undefweak
|| h->elf.root.type == bfd_link_hash_undefined)
&& is_branch_reloc (r_type))))
- {
- if (!((*info->callbacks->reloc_overflow)
- (info, &h->elf.root, sym_name,
- reloc_name, orig_rel.r_addend,
- input_bfd, input_section, rel->r_offset)))
- return FALSE;
- }
+ info->callbacks->reloc_overflow (info, &h->elf.root,
+ sym_name, reloc_name,
+ orig_rel.r_addend,
+ input_bfd, input_section,
+ rel->r_offset);
}
else
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: %s against `%T': error %d\n"),
input_bfd, input_section, rel->r_offset,
reloc_name, sym_name, (int) r);