PowerPC dynamic relocations

This patch fixes a number of issues with powerpc dynamic relocations.

1) Both ppc and ppc64 were emitting more dynamic symbols and
relocations than necessary, due to not supporting static linker
resolution of tls_index entries for __tls_get_addr_opt.  This meant
that any @got@tlsgd or @got@tlsld reloc needed to make their symbols
dynamic and generate dptmod and dtprel relocs for the dynamic linker.
That would have been passable, but what happened was that practically
all @got relocations resulted in their symbols being made dynamic and
dynamic relocations emitted against the GOT entries.  (Mostly visible
on ppc32 executables since ppc64 gcc really only uses @got style
relocs for TLS.)

2) The PowerOpen syntax was not supported with __tls_get_addr_opt.
DTPMOD/DTPREL relocs on tls_index TOC entries did not use the trick of
forcing dynamic symbols and relocations so those entries always
resulted in the full __tls_get_addr processing.  gcc doesn't use the
PowerOpen syntax for TLS, and normally such code would be optimized to
TLS IE or LE so the impact of missing this support was minimal.

3) In an executable, relocations against GNU indirect functions always
used the value of their PLT stub.   While this is correct, it is
better in some cases to use a dynamic relocation.  An extra dynamic
relocation can mean that calls via function pointers need not bounce
through the PLT stub at runtime.

The patch also tidies the PLT handling code in ppc32
allocate_dynrelocs.  Allocating PLT entries after other dynamic relocs
allows the PLT loop to omit special handling for undefined weak
symbols, and that in turn allows the loop to be simplified.

bfd/
	* elf32-ppc.c (ppc_elf_adjust_dynamic_symbol): Merge two cases
	where dynamic relocs are preferable.  Allow ifunc too.
	(ensure_undefweak_dynamic): New function.
	(allocate_dynrelocs): Use it here.  Move plt handling last and
	don't make symbols dynamic, simplifying loop.  Only make undef
	weak symbols with GOT entries dynamic.  Correct condition
	for GOT relocs.  Handle dynamic relocs on ifuncs.  Correct
	comments.  Remove goto.
	(ppc_elf_relocate_section): Correct test for using dynamic
	symbol on GOT relocs.  Rearrange test for emitting GOT relocs
	to suit.  Set up explicit tls_index entries and implicit GOT
	tls_index entries resolvable at link time for
	__tls_get_addr_opt.  Simplify test to clear mem for prelink.
	* elf64-ppc.c (allocate_got): Correct condition for GOT relocs.
	(ensure_undefweak_dynamic): New function.
	(allocate_dynrelocs): Use it here.  Only make undef weak symbols
	with GOT entries dynamic.  Remove unnecessary test of
	WILL_CALL_FINISH_DYNAMIC_SYMBOL in PLT handling.
	(ppc64_elf_relocate_section): Correct test for using dynamic
	symbol on GOT relocs.  Rearrange test for emitting GOT relocs
	to suit.  Set up explicit tls_index entries and implicit GOT
	tls_index entries resolvable at link time for __tls_get_addr_opt.
	Simplify expression to clear mem for prelink.
ld/
	* testsuite/ld-powerpc/tlsexe.r: Update for fewer dynamic relocs
	and symbols.
	* testsuite/ld-powerpc/tlsexe.d: Likewise.
	* testsuite/ld-powerpc/tlsexe.g: Likewise.
This commit is contained in:
Alan Modra 2017-01-24 08:43:01 +10:30
parent 741bcbe94d
commit f0158f4416
7 changed files with 383 additions and 313 deletions

View File

@ -1,3 +1,29 @@
2017-01-24 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (ppc_elf_adjust_dynamic_symbol): Merge two cases
where dynamic relocs are preferable. Allow ifunc too.
(ensure_undefweak_dynamic): New function.
(allocate_dynrelocs): Use it here. Move plt handling last and
don't make symbols dynamic, simplifying loop. Only make undef
weak symbols with GOT entries dynamic. Correct condition
for GOT relocs. Handle dynamic relocs on ifuncs. Correct
comments. Remove goto.
(ppc_elf_relocate_section): Correct test for using dynamic
symbol on GOT relocs. Rearrange test for emitting GOT relocs
to suit. Set up explicit tls_index entries and implicit GOT
tls_index entries resolvable at link time for
__tls_get_addr_opt. Simplify test to clear mem for prelink.
* elf64-ppc.c (allocate_got): Correct condition for GOT relocs.
(ensure_undefweak_dynamic): New function.
(allocate_dynrelocs): Use it here. Only make undef weak symbols
with GOT entries dynamic. Remove unnecessary test of
WILL_CALL_FINISH_DYNAMIC_SYMBOL in PLT handling.
(ppc64_elf_relocate_section): Correct test for using dynamic
symbol on GOT relocs. Rearrange test for emitting GOT relocs
to suit. Set up explicit tls_index entries and implicit GOT
tls_index entries resolvable at link time for __tls_get_addr_opt.
Simplify expression to clear mem for prelink.
2017-01-23 Yury Norov <ynorov@caviumnetworks.com>
* elfnn-aarch64.c: Fix relaxations for ILP32 mode.

View File

@ -5684,33 +5684,24 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
/* Taking a function's address in a read/write section
doesn't require us to define the function symbol in the
executable on a plt call stub. A dynamic reloc can
be used instead. */
if (h->pointer_equality_needed
&& h->type != STT_GNU_IFUNC
be used instead, giving better runtime performance.
(Calls via that function pointer don't need to bounce
through the plt call stub.) Similarly, use a dynamic
reloc for a weak reference when possible, allowing the
resolution of the symbol to be set at load time rather
than link time. */
if ((h->pointer_equality_needed
|| (!h->ref_regular_nonweak && h->non_got_ref))
&& !htab->is_vxworks
&& !ppc_elf_hash_entry (h)->has_sda_refs
&& !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
&& !htab->is_vxworks
&& !ppc_elf_hash_entry (h)->has_sda_refs
&& !readonly_dynrelocs (h))
h->non_got_ref = 0;
}
h->protected_def = 0;
return TRUE;
@ -5925,6 +5916,23 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
return where;
}
/* If H is undefined weak, make it dynamic if that makes sense. */
static bfd_boolean
ensure_undefweak_dynamic (struct bfd_link_info *info,
struct elf_link_hash_entry *h)
{
struct elf_link_hash_table *htab = elf_hash_table (info);
if (htab->dynamic_sections_created
&& h->root.type == bfd_link_hash_undefweak
&& h->dynindx == -1
&& !h->forced_local
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
return bfd_elf_link_record_dynamic_symbol (info, h);
return TRUE;
}
/* Allocate space in associated reloc sections for dynamic relocs. */
static bfd_boolean
@ -5934,175 +5942,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
struct ppc_elf_link_hash_entry *eh;
struct ppc_elf_link_hash_table *htab;
struct elf_dyn_relocs *p;
bfd_boolean dyn;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
htab = ppc_elf_hash_table (info);
if (htab->elf.dynamic_sections_created
|| h->type == STT_GNU_IFUNC)
{
struct plt_entry *ent;
bfd_boolean doneone = FALSE;
bfd_vma plt_offset = 0, glink_offset = 0;
bfd_boolean dyn;
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
{
/* Make sure this symbol is output as a dynamic symbol. */
if (h->dynindx == -1
&& !h->forced_local
&& !h->def_regular
&& htab->elf.dynamic_sections_created)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
dyn = htab->elf.dynamic_sections_created;
if (bfd_link_pic (info)
|| h->type == STT_GNU_IFUNC
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
{
asection *s = htab->elf.splt;
if (!dyn || h->dynindx == -1)
s = htab->elf.iplt;
if (htab->plt_type == PLT_NEW || !dyn || h->dynindx == -1)
{
if (!doneone)
{
plt_offset = s->size;
s->size += 4;
}
ent->plt.offset = plt_offset;
s = htab->glink;
if (!doneone || bfd_link_pic (info))
{
glink_offset = s->size;
s->size += GLINK_ENTRY_SIZE;
if (h == htab->tls_get_addr
&& !htab->params->no_tls_get_addr_opt)
s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
}
if (!doneone
&& !bfd_link_pic (info)
&& h->def_dynamic
&& !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = glink_offset;
}
ent->glink_offset = glink_offset;
if (htab->params->emit_stub_syms
&& !add_stub_sym (ent, h, info))
return FALSE;
}
else
{
if (!doneone)
{
/* If this is the first .plt entry, make room
for the special first entry. */
if (s->size == 0)
s->size += htab->plt_initial_entry_size;
/* The PowerPC PLT is actually composed of two
parts, the first part is 2 words (for a load
and a jump), and then there is a remaining
word available at the end. */
plt_offset = (htab->plt_initial_entry_size
+ (htab->plt_slot_size
* ((s->size
- htab->plt_initial_entry_size)
/ htab->plt_entry_size)));
/* If this symbol is not defined in a regular
file, and we are not generating a shared
library, then set the symbol to this location
in the .plt. This is to avoid text
relocations, and is required to make
function pointers compare as equal between
the normal executable and the shared library. */
if (! bfd_link_pic (info)
&& h->def_dynamic
&& !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = plt_offset;
}
/* Make room for this entry. */
s->size += htab->plt_entry_size;
/* After the 8192nd entry, room for two entries
is allocated. */
if (htab->plt_type == PLT_OLD
&& (s->size - htab->plt_initial_entry_size)
/ htab->plt_entry_size
> PLT_NUM_SINGLE_ENTRIES)
s->size += htab->plt_entry_size;
}
ent->plt.offset = plt_offset;
}
/* We also need to make an entry in the .rela.plt section. */
if (!doneone)
{
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
else
{
htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
if (htab->plt_type == PLT_VXWORKS)
{
/* Allocate space for the unloaded relocations. */
if (!bfd_link_pic (info)
&& htab->elf.dynamic_sections_created)
{
if (ent->plt.offset
== (bfd_vma) htab->plt_initial_entry_size)
{
htab->srelplt2->size
+= (sizeof (Elf32_External_Rela)
* VXWORKS_PLTRESOLVE_RELOCS);
}
htab->srelplt2->size
+= (sizeof (Elf32_External_Rela)
* VXWORKS_PLT_NON_JMP_SLOT_RELOCS);
}
/* Every PLT entry has an associated GOT entry in
.got.plt. */
htab->elf.sgotplt->size += 4;
}
}
doneone = TRUE;
}
}
else
ent->plt.offset = (bfd_vma) -1;
}
else
ent->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_elf_link_hash_entry *) h;
if (eh->elf.got.refcount > 0
|| (ELIMINATE_COPY_RELOCS
@ -6112,18 +5957,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
&& eh->has_addr16_lo
&& htab->params->pic_fixup > 0))
{
bfd_boolean dyn;
unsigned int need;
/* Make sure this symbol is output as a dynamic symbol. */
if (eh->elf.dynindx == -1
&& !eh->elf.forced_local
&& eh->elf.type != STT_GNU_IFUNC
&& htab->elf.dynamic_sections_created)
{
if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
return FALSE;
}
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (!ensure_undefweak_dynamic (info, &eh->elf))
return FALSE;
need = 0;
if ((eh->tls_mask & TLS_TLS) != 0)
@ -6152,9 +5991,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
else
{
eh->elf.got.offset = allocate_got (htab, need);
dyn = htab->elf.dynamic_sections_created;
if ((bfd_link_pic (info)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
|| (htab->elf.dynamic_sections_created
&& eh->elf.dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
&& (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
|| eh->elf.root.type != bfd_link_hash_undefweak))
{
@ -6174,17 +6014,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
else
eh->elf.got.offset = (bfd_vma) -1;
if (eh->dyn_relocs == NULL
|| !htab->elf.dynamic_sections_created)
return TRUE;
if (!htab->elf.dynamic_sections_created
&& h->type != STT_GNU_IFUNC)
eh->dyn_relocs = NULL;
if (eh->dyn_relocs == NULL)
;
/* 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))
else 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
@ -6237,21 +6079,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
/* Make sure undefined weak symbols are output as a dynamic
symbol in PIEs. */
else if (h->dynindx == -1
&& !h->forced_local
&& !h->def_regular)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
else if (!ensure_undefweak_dynamic (info, h))
return FALSE;
}
}
else if (ELIMINATE_COPY_RELOCS)
{
/* For the non-shared case, discard space for relocs against
/* For the non-pic 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
&& !(h->protected_def
@ -6261,25 +6097,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
{
/* 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 (!ensure_undefweak_dynamic (info, h))
return FALSE;
/* If that succeeded, we know we'll be keeping all the
relocs. */
if (h->dynindx != -1)
goto keep;
if (h->dynindx == -1)
eh->dyn_relocs = NULL;
}
eh->dyn_relocs = NULL;
keep: ;
else
eh->dyn_relocs = NULL;
}
/* Finally, allocate space. */
/* Allocate space. */
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
asection *sreloc = elf_section_data (p->sec)->sreloc;
@ -6288,6 +6116,152 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
sreloc->size += p->count * sizeof (Elf32_External_Rela);
}
/* Handle PLT relocs. Done last, after dynindx has settled. */
dyn = htab->elf.dynamic_sections_created && h->dynindx != -1;
if (dyn || h->type == STT_GNU_IFUNC)
{
struct plt_entry *ent;
bfd_boolean doneone = FALSE;
bfd_vma plt_offset = 0, glink_offset = 0;
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
{
asection *s = htab->elf.splt;
if (!dyn)
s = htab->elf.iplt;
if (htab->plt_type == PLT_NEW || !dyn)
{
if (!doneone)
{
plt_offset = s->size;
s->size += 4;
}
ent->plt.offset = plt_offset;
s = htab->glink;
if (!doneone || bfd_link_pic (info))
{
glink_offset = s->size;
s->size += GLINK_ENTRY_SIZE;
if (h == htab->tls_get_addr
&& !htab->params->no_tls_get_addr_opt)
s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
}
if (!doneone
&& !bfd_link_pic (info)
&& h->def_dynamic
&& !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = glink_offset;
}
ent->glink_offset = glink_offset;
if (htab->params->emit_stub_syms
&& !add_stub_sym (ent, h, info))
return FALSE;
}
else
{
if (!doneone)
{
/* If this is the first .plt entry, make room
for the special first entry. */
if (s->size == 0)
s->size += htab->plt_initial_entry_size;
/* The PowerPC PLT is actually composed of two
parts, the first part is 2 words (for a load
and a jump), and then there is a remaining
word available at the end. */
plt_offset = (htab->plt_initial_entry_size
+ (htab->plt_slot_size
* ((s->size
- htab->plt_initial_entry_size)
/ htab->plt_entry_size)));
/* If this symbol is not defined in a regular
file, and we are not generating a shared
library, then set the symbol to this location
in the .plt. This is to avoid text
relocations, and is required to make
function pointers compare as equal between
the normal executable and the shared library. */
if (! bfd_link_pic (info)
&& h->def_dynamic
&& !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = plt_offset;
}
/* Make room for this entry. */
s->size += htab->plt_entry_size;
/* After the 8192nd entry, room for two entries
is allocated. */
if (htab->plt_type == PLT_OLD
&& (s->size - htab->plt_initial_entry_size)
/ htab->plt_entry_size
> PLT_NUM_SINGLE_ENTRIES)
s->size += htab->plt_entry_size;
}
ent->plt.offset = plt_offset;
}
/* We also need to make an entry in the .rela.plt section. */
if (!doneone)
{
if (!dyn)
htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
else
{
htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
if (htab->plt_type == PLT_VXWORKS)
{
/* Allocate space for the unloaded relocations. */
if (!bfd_link_pic (info)
&& htab->elf.dynamic_sections_created)
{
if (ent->plt.offset
== (bfd_vma) htab->plt_initial_entry_size)
{
htab->srelplt2->size
+= (sizeof (Elf32_External_Rela)
* VXWORKS_PLTRESOLVE_RELOCS);
}
htab->srelplt2->size
+= (sizeof (Elf32_External_Rela)
* VXWORKS_PLT_NON_JMP_SLOT_RELOCS);
}
/* Every PLT entry has an associated GOT entry in
.got.plt. */
htab->elf.sgotplt->size += 4;
}
}
doneone = TRUE;
}
}
else
ent->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;
}
@ -8502,11 +8476,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
offp = &htab->tlsld_got.offset;
else if (h != NULL)
{
bfd_boolean dyn;
dyn = htab->elf.dynamic_sections_created;
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
|| (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h)))
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1
|| SYMBOL_REFERENCES_LOCAL (info, h)
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak))
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
locally, or the symbol was forced to be local
@ -8514,7 +8488,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
;
else
{
BFD_ASSERT (h->dynindx != -1);
indx = h->dynindx;
unresolved_reloc = FALSE;
}
@ -8573,11 +8546,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
}
/* Generate relocs for the dynamic linker. */
if ((bfd_link_pic (info) || indx != 0)
&& (offp == &htab->tlsld_got.offset
|| h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
if (indx != 0
|| (bfd_link_pic (info)
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak
|| offp == &htab->tlsld_got.offset)))
{
asection *rsec = htab->elf.srelgot;
bfd_byte * loc;
@ -8635,25 +8609,31 @@ ppc_elf_relocate_section (bfd *output_bfd,
else
{
bfd_vma value = relocation;
int tlsopt = (htab->plt_type == PLT_NEW
&& !htab->params->no_tls_get_addr_opt
&& htab->tls_get_addr != NULL
&& htab->tls_get_addr->plt.plist != NULL);
if (tls_ty == (TLS_TLS | TLS_LD))
value = 1;
else if (tls_ty != 0)
if (tls_ty != 0)
{
if (htab->elf.tls_sec == NULL)
value = 0;
else
{
value -= htab->elf.tls_sec->vma + DTP_OFFSET;
if (tls_ty == (TLS_TLS | TLS_TPREL))
if (tls_ty & TLS_LD)
value = 0;
else
value -= htab->elf.tls_sec->vma + DTP_OFFSET;
if ((tls_ty & TLS_TPREL)
|| (tlsopt && !(tls_ty & TLS_DTPREL)))
value += DTP_OFFSET - TP_OFFSET;
}
if (tls_ty == (TLS_TLS | TLS_GD))
if (tls_ty & (TLS_LD | TLS_GD))
{
bfd_put_32 (input_bfd, value,
htab->elf.sgot->contents + off + 4);
value = 1;
value = !tlsopt;
}
}
bfd_put_32 (input_bfd, value,
@ -8987,17 +8967,43 @@ ppc_elf_relocate_section (bfd *output_bfd,
if (skip == -1)
goto copy_reloc;
/* This reloc will be computed at runtime. We clear the memory
so that it contains predictable value. */
if (! skip
&& ((input_section->flags & SEC_ALLOC) != 0
|| ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE))
/* This reloc will be computed at runtime. Clear the memory
so that it contains a predictable value for prelink. */
if (!skip)
{
relocation = howto->pc_relative ? outrel.r_offset : 0;
addend = 0;
break;
}
}
else if (r_type == R_PPC_DTPMOD32
&& htab->plt_type == PLT_NEW
&& !htab->params->no_tls_get_addr_opt
&& htab->tls_get_addr != NULL
&& htab->tls_get_addr->plt.plist != NULL)
{
/* Set up for __tls_get_addr_opt stub when this entry
does not have dynamic relocs. */
relocation = 0;
/* Set up the next word for local dynamic. If it turns
out to be global dynamic, the reloc will overwrite
this value. */
if (rel->r_offset + 8 <= input_section->size)
bfd_put_32 (input_bfd, DTP_OFFSET - TP_OFFSET,
contents + rel->r_offset + 4);
}
else if (r_type == R_PPC_DTPREL32
&& htab->plt_type == PLT_NEW
&& !htab->params->no_tls_get_addr_opt
&& htab->tls_get_addr != NULL
&& htab->tls_get_addr->plt.plist != NULL
&& rel > relocs
&& rel[-1].r_info == ELF32_R_INFO (r_symndx, R_PPC_DTPMOD32)
&& rel[-1].r_offset + 4 == rel->r_offset)
{
/* __tls_get_addr_opt stub value. */
addend += DTP_OFFSET - TP_OFFSET;
}
break;
case R_PPC_RELAX_PLT:

View File

@ -9597,7 +9597,6 @@ allocate_got (struct elf_link_hash_entry *h,
struct got_entry *gent)
{
struct ppc_link_hash_table *htab = ppc_hash_table (info);
bfd_boolean dyn;
struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)
? 16 : 8);
@ -9608,14 +9607,15 @@ allocate_got (struct elf_link_hash_entry *h,
gent->got.offset = got->size;
got->size += entsize;
dyn = htab->elf.dynamic_sections_created;
if (h->type == STT_GNU_IFUNC)
{
htab->elf.irelplt->size += rentsize;
htab->got_reli_size += rentsize;
}
else if ((bfd_link_pic (info)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
|| (htab->elf.dynamic_sections_created
&& h->dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, h)))
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
{
@ -9644,6 +9644,23 @@ merge_got_entries (struct got_entry **pent)
}
}
/* If H is undefined weak, make it dynamic if that makes sense. */
static bfd_boolean
ensure_undefweak_dynamic (struct bfd_link_info *info,
struct elf_link_hash_entry *h)
{
struct elf_link_hash_table *htab = elf_hash_table (info);
if (htab->dynamic_sections_created
&& h->root.type == bfd_link_hash_undefweak
&& h->dynindx == -1
&& !h->forced_local
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
return bfd_elf_link_record_dynamic_symbol (info, h);
return TRUE;
}
/* Allocate space in .plt, .got and associated reloc sections for
dynamic relocs. */
@ -9716,16 +9733,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if (!gent->is_indirect)
{
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic,
nor will all TLS symbols. */
if (h->dynindx == -1
&& !h->forced_local
&& h->type != STT_GNU_IFUNC
&& htab->elf.dynamic_sections_created)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
Undefined weak syms won't yet be marked as dynamic. */
if (!ensure_undefweak_dynamic (info, h))
return FALSE;
if (!is_ppc64_elf (gent->owner))
abort ();
@ -9779,12 +9789,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
/* 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 (!ensure_undefweak_dynamic (info, h))
return FALSE;
}
}
else if (h->type == STT_GNU_IFUNC)
@ -9815,20 +9821,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
/* For the non-pic 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)
{
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (!ensure_undefweak_dynamic (info, h))
return FALSE;
/* First make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
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 (h->non_got_ref
|| h->def_regular
|| h->dynindx == -1)
if (h->dynindx == -1)
eh->dyn_relocs = NULL;
}
else
eh->dyn_relocs = NULL;
}
@ -9843,8 +9847,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
}
if ((htab->elf.dynamic_sections_created
&& h->dynindx != -1
&& WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
&& h->dynindx != -1)
|| h->type == STT_GNU_IFUNC)
{
struct plt_entry *pent;
@ -14405,14 +14408,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
ent = ppc64_tlsld_got (input_bfd);
else
{
if (h != NULL)
{
bfd_boolean dyn = htab->elf.dynamic_sections_created;
if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
&h->elf)
|| (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
if (!htab->elf.dynamic_sections_created
|| h->elf.dynindx == -1
|| SYMBOL_REFERENCES_LOCAL (info, &h->elf)
|| (ELF_ST_VISIBILITY (h->elf.other) != STV_DEFAULT
&& h->elf.root.type == bfd_link_hash_undefweak))
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
locally, or the symbol was forced to be local
@ -14420,7 +14422,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
;
else
{
BFD_ASSERT (h->elf.dynindx != -1);
indx = h->elf.dynindx;
unresolved_reloc = FALSE;
}
@ -14470,12 +14471,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
if (ifunc)
relgot = htab->elf.irelplt;
else if ((bfd_link_pic (info) || indx != 0)
&& (h == NULL
|| (tls_type == (TLS_TLS | TLS_LD)
&& !h->elf.def_dynamic)
|| ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
|| h->elf.root.type != bfd_link_hash_undefweak))
else if (indx != 0
|| (bfd_link_pic (info)
&& (h == NULL
|| (ELF_ST_VISIBILITY (h->elf.other)
== STV_DEFAULT)
|| h->elf.root.type != bfd_link_hash_undefweak
|| (tls_type == (TLS_TLS | TLS_LD)
&& !h->elf.def_dynamic))))
relgot = ppc64_elf_tdata (ent->owner)->relgot;
if (relgot != NULL)
{
@ -14541,28 +14544,34 @@ ppc64_elf_relocate_section (bfd *output_bfd,
emitting a reloc. */
else
{
int tlsopt
= (htab->params->tls_get_addr_opt
&& htab->tls_get_addr_fd != NULL
&& htab->tls_get_addr_fd->elf.plt.plist != NULL);
relocation += addend;
if (tls_type == (TLS_TLS | TLS_LD))
relocation = 1;
else if (tls_type != 0)
if (tls_type != 0)
{
if (htab->elf.tls_sec == NULL)
relocation = 0;
else
{
relocation -= htab->elf.tls_sec->vma + DTP_OFFSET;
if (tls_type == (TLS_TLS | TLS_TPREL))
if (tls_type & TLS_LD)
relocation = 0;
else
relocation -= htab->elf.tls_sec->vma + DTP_OFFSET;
if ((tls_type & TLS_TPREL)
|| (tlsopt && !(tls_type & TLS_DTPREL)))
relocation += DTP_OFFSET - TP_OFFSET;
}
if (tls_type == (TLS_TLS | TLS_GD))
if (tls_type & (TLS_GD | TLS_LD))
{
bfd_put_64 (output_bfd, relocation,
got->contents + off + 8);
relocation = 1;
relocation = !tlsopt;
}
}
bfd_put_64 (output_bfd, relocation,
got->contents + off);
}
@ -14957,11 +14966,35 @@ ppc64_elf_relocate_section (bfd *output_bfd,
addend = outrel.r_addend;
/* Adjust pc_relative relocs to have zero in *r_offset. */
else if (ppc64_elf_howto_table[r_type]->pc_relative)
addend = (input_section->output_section->vma
+ input_section->output_offset
+ rel->r_offset);
addend = outrel.r_offset;
}
}
else if (r_type == R_PPC64_DTPMOD64
&& htab->params->tls_get_addr_opt
&& htab->tls_get_addr_fd != NULL
&& htab->tls_get_addr_fd->elf.plt.plist != NULL)
{
/* Set up for __tls_get_addr_opt stub, when this entry
does not have dynamic relocs. */
relocation = 0;
/* Set up the next word for local dynamic. If it turns
out to be global dynamic, the reloc will overwrite
this value. */
if (rel->r_offset + 16 <= input_section->size)
bfd_put_64 (input_bfd, DTP_OFFSET - TP_OFFSET,
contents + rel->r_offset + 8);
}
else if (r_type == R_PPC64_DTPREL64
&& htab->params->tls_get_addr_opt
&& htab->tls_get_addr_fd != NULL
&& htab->tls_get_addr_fd->elf.plt.plist != NULL
&& rel > relocs
&& rel[-1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPMOD64)
&& rel[-1].r_offset + 8 == rel->r_offset)
{
/* __tls_get_addr_opt stub value. */
addend += DTP_OFFSET - TP_OFFSET;
}
break;
case R_PPC64_COPY:

View File

@ -1,3 +1,10 @@
2017-01-24 Alan Modra <amodra@gmail.com>
* testsuite/ld-powerpc/tlsexe.r: Update for fewer dynamic relocs
and symbols.
* testsuite/ld-powerpc/tlsexe.d: Likewise.
* testsuite/ld-powerpc/tlsexe.g: Likewise.
2017-01-23 Yury Norov <ynorov@caviumnetworks.com>
* testsuite/ld-aarch64/aarch64-elf.exp: Run new tests.

View File

@ -67,8 +67,8 @@ Disassembly of section \.text:
.* (e9 4d 90 2a|2a 90 4d e9) lwa r10,-28632\(r13\)
.* (3d 2d 00 00|00 00 2d 3d) addis r9,r13,0
.* (a9 49 90 30|30 90 49 a9) lha r10,-28624\(r9\)
.* (00 00 00 00|e0 02 01 00) .*
.* (00 01 02 e0|00 00 00 00) .*
.* (00 00 00 00|20 02 01 00) .*
.* (00 01 02 20|00 00 00 00) .*
.* <__glink_PLTresolve>:
.* (7d 88 02 a6|a6 02 88 7d) mflr r12
.* (42 9f 00 05|05 00 9f 42) bcl 20,4\*cr7\+so,.*

View File

@ -7,6 +7,6 @@
.*
Contents of section \.got:
10010700 (00000000|00870110) (10018700|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff) .*
.* 00000000 00000000 00000000 00000000 .*
10010600 (00000000|00860110) (10018600|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff) .*
.* 00000000 00000000 00000000 00000000 .*
.* 00000000 00000000 (ffffffff|5080ffff) (ffff8050|ffffffff) .*

View File

@ -51,11 +51,10 @@ Program Headers:
+04 +\.dynamic *
+05 +\.tdata \.tbss *
Relocation section '\.rela\.dyn' at offset .* contains 3 entries:
Relocation section '\.rela\.dyn' at offset .* contains 2 entries:
+Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
[0-9a-f ]+R_PPC64_TPREL64 +0+ gd \+ 0
[0-9a-f ]+R_PPC64_DTPMOD64 +0+ ld \+ 0
[0-9a-f ]+R_PPC64_DTPREL64 +0+50 ld2 \+ 0
Relocation section '\.rela\.plt' at offset .* contains 1 entries:
+Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
@ -66,7 +65,6 @@ Symbol table '\.dynsym' contains [0-9]+ entries:
.* NOTYPE +LOCAL +DEFAULT +UND *
.* TLS +GLOBAL +DEFAULT +UND gd
.* TLS +GLOBAL +DEFAULT +UND ld
.* TLS +GLOBAL +DEFAULT +9 ld2
.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start
.* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt
.* NOTYPE +GLOBAL +DEFAULT +13 _edata