Allocate ppc64 got and dynrelocs before plt

The idea being to make undefined weak syms dynamic, before deciding
whether a sym needs a plt entry.  Fixes pr19719 ld testcase.

	* elf64-ppc.c (allocate_dynrelocs): Allocate got and other dynamic
	relocs before plt relocs.
This commit is contained in:
Alan Modra 2016-05-18 23:59:04 +09:30
parent 9f284bf9da
commit 57e7d11848
2 changed files with 148 additions and 142 deletions

View File

@ -1,3 +1,8 @@
2016-05-19 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (allocate_dynrelocs): Allocate got and other dynamic
relocs before plt relocs.
2016-05-19 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ppc64_elf_branch_reloc): Check for NULL owner

View File

@ -5150,7 +5150,7 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
}
/* 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);
@ -9553,71 +9553,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
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. */
@ -9687,99 +9622,165 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
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 (bfd_link_pic (info))
if (eh->dyn_relocs != NULL
&& (htab->elf.dynamic_sections_created
|| h->type == STT_GNU_IFUNC))
{
/* 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 **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. */
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
if (bfd_link_pic (info))
{
/* 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))
{
p->count -= p->pc_count;
p->pc_count = 0;
if (p->count == 0)
*pp = p->next;
else
pp = &p->next;
struct elf_dyn_relocs **pp;
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;
}
}
/* Also discard relocs on undefined weak syms with
non-default visibility. */
if (eh->dyn_relocs != NULL
&& h->root.type == bfd_link_hash_undefweak)
{
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)
if (!h->non_got_ref)
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;
}
}
}
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)
else if (ELIMINATE_COPY_RELOCS)
{
/* 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)
/* 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)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
/* 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 that succeeded, we know we'll be keeping all the
relocs. */
if (h->dynindx != -1)
goto keep;
}
/* If that succeeded, we know we'll be keeping all the
relocs. */
if (h->dynindx != -1)
goto keep;
eh->dyn_relocs = NULL;
keep: ;
}
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;