Correct PowerPC64 local-dynamic TLS linker optimization

The linker hardcoded r3 into a local-dynamic to local-exec TLS
optimization sequence.  This is normally the case since r3 is required
as a parameter to (the optimized out) __tls_get_addr call.  However,
it is possible for a compiler, LLVM in this case, to set up the
parameter value in another register then copy it to r3 before the
call.

When fixing this problem, I noticed that ppc32 had another bug when
optimizing away one of the TLS insns to a nop.

The patch also tidies a mask used by global-dynamic to initial-exec
TLS optimization, to just select the fields needed.  Leaving the
offset in the instruction wasn't a bug since it will be overwritten
anyway.

bfd/
	* elf64-ppc.c (ppc64_elf_relocate_section): Correct GOT_TLSLD
	optimization.  Tidy mask for GOT_TLSGD optimization.
	* elf32-ppc.c (ppc_elf_relocate_section): Likewise.  Correct
	location of nop zapping high insn too.
ld/testsuite/
	* ld-powerpc/tlsld.d, * ld-powerpc/tlsld.s: New test.
	* ld-powerpc/tlsld32.d, * ld-powerpc/tlsld32.s: New test.
	* ld-powerpc/powerpc.exp: Run them.  Move tocvar and tocnovar.
This commit is contained in:
Alan Modra 2015-01-29 11:09:55 +10:30
parent 912ae7dd0f
commit b86ac8e3a5
9 changed files with 215 additions and 11 deletions

View file

@ -1,3 +1,10 @@
2015-01-29 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ppc64_elf_relocate_section): Correct GOT_TLSLD
optimization. Tidy mask for GOT_TLSGD optimization.
* elf32-ppc.c (ppc_elf_relocate_section): Likewise. Correct
location of nop zapping high insn too.
2015-01-28 Alan Modra <amodra@gmail.com>
* elf64-ppc.h (struct ppc64_elf_params): Add "object_in_toc".

View file

@ -7760,8 +7760,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
+ R_PPC_GOT_TPREL16);
else
{
bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
rel->r_offset -= d_offset;
bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
r_type = R_PPC_NONE;
}
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@ -7794,12 +7794,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
&& branch_reloc_hash_match (input_bfd, rel + 1,
htab->tls_get_addr))
offset = rel[1].r_offset;
/* We read the low GOT_TLS insn because we need to keep
the destination reg. It may be something other than
the usual r3, and moved to r3 before the call by
intervening code. */
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - d_offset);
insn1 &= (1 << 26) - 1;
insn1 &= (0x1f << 21) | (0x1f << 16);
insn1 |= 32 << 26; /* lwz */
if (offset != (bfd_vma) -1)
{
@ -7814,7 +7818,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
else
{
/* LE */
insn1 = 0x3c620000; /* addis 3,2,0 */
insn1 &= 0x1f << 21;
insn1 |= 0x3c020000; /* addis r,2,0 */
if (tls_gd == 0)
{
/* Was an LD reloc. */

View file

@ -13417,12 +13417,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
htab->tls_get_addr,
htab->tls_get_addr_fd))
offset = rel[1].r_offset;
/* We read the low GOT_TLS (or TOC16) insn because we
need to keep the destination reg. It may be
something other than the usual r3, and moved to r3
before the call by intervening code. */
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - d_offset);
insn1 &= (1 << 26) - (1 << 2);
insn1 &= (0x1f << 21) | (0x1f << 16);
insn1 |= 58 << 26; /* ld */
insn2 = 0x7c636a14; /* add 3,3,13 */
if (offset != (bfd_vma) -1)
@ -13437,7 +13441,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
else
{
/* LE */
insn1 = 0x3c6d0000; /* addis 3,13,0 */
insn1 &= 0x1f << 21;
insn1 |= 0x3c0d0000; /* addis r,13,0 */
insn2 = 0x38630000; /* addi 3,3,0 */
if (tls_gd == 0)
{

View file

@ -1,3 +1,9 @@
2015-01-29 Alan Modra <amodra@gmail.com>
* ld-powerpc/tlsld.d, * ld-powerpc/tlsld.s: New test.
* ld-powerpc/tlsld32.d, * ld-powerpc/tlsld32.s: New test.
* ld-powerpc/powerpc.exp: Run them. Move tocvar and tocnovar.
2015-01-28 H.J. Lu <hongjiu.lu@intel.com>
PR ld/17878

View file

@ -282,8 +282,13 @@ if [ supports_ppc64 ] then {
run_dump_test "ambiguousv2"
run_dump_test "ambiguousv2b"
run_dump_test "defsym"
run_dump_test "tocvar"
run_dump_test "tocnovar"
run_dump_test "tlsld"
}
run_dump_test "tlsld32"
if { [istarget "powerpc*-eabi*"] } {
run_ld_link_tests $ppceabitests
}
@ -320,5 +325,3 @@ run_dump_test "attr-gnu-12-11"
run_dump_test "attr-gnu-12-21"
run_dump_test "vle-multiseg-6"
run_dump_test "tocvar"
run_dump_test "tocnovar"

View file

@ -0,0 +1,43 @@
#source: tlsld.s
#as: -a64
#ld: -melf64ppc
#objdump: -dr
#target: powerpc64*-*-*
.*: file format .*
Disassembly of section \.text:
.*:
.* nop
.* addis r29,r13,0
.* mr r3,r29
.* nop
.* addi r3,r3,4096
.* addis r3,r3,0
.* ld r3,-32768\(r3\)
.* nop
.* addis r29,r13,0
.* mr r3,r29
.* nop
.* addi r3,r3,4096
.* ld r3,-32768\(r3\)
.* nop
.* nop
.* nop
.* nop
.* addis r29,r13,0
.* mr r3,r29
.* nop
.* addi r3,r3,-28672
.* ld r3,0\(r3\)
.* nop
.* nop
.* addis r29,r13,0
.* mr r3,r29
.* nop
.* addi r3,r3,-28672
.* ld r3,0\(r3\)
.* nop
.* nop
.* nop

View file

@ -0,0 +1,48 @@
.section ".opd","aw",@progbits
.p2align 3
.globl _start
_start:
.quad .L_start,.TOC.@tocbase,0
.text
.L_start:
addis 3,2,PrettyStackTraceHead@got@tlsld@ha
addi 29,3,PrettyStackTraceHead@got@tlsld@l
mr 3,29
bl __tls_get_addr(PrettyStackTraceHead@tlsld)
nop
addis 3,3,PrettyStackTraceHead@dtprel@ha
ld 3,PrettyStackTraceHead@dtprel@l(3)
nop
addi 29,2,PrettyStackTraceHead@got@tlsld
mr 3,29
bl __tls_get_addr(PrettyStackTraceHead@tlsld)
nop
ld 3,PrettyStackTraceHead@dtprel(3)
nop
nop
nop
addis 3,2,PrettyStackTraceHead@got@tlsgd@ha
addi 29,3,PrettyStackTraceHead@got@tlsgd@l
mr 3,29
bl __tls_get_addr(PrettyStackTraceHead@tlsgd)
nop
ld 3,0(3)
nop
nop
addi 29,2,PrettyStackTraceHead@got@tlsgd
mr 3,29
bl __tls_get_addr(PrettyStackTraceHead@tlsgd)
nop
ld 3,0(3)
nop
nop
nop
.section ".tbss","awT",@nobits
.align 3
PrettyStackTraceHead:
.space 8

View file

@ -0,0 +1,44 @@
#source: tlsld32.s
#as: -a32
#ld: -melf32ppc
#objdump: -dr
#target: powerpc*-*-*
.*: file format .*
Disassembly of section \.text:
.*:
.* nop
.* addis r29,r2,0
.* mr r3,r29
.* addi r3,r3,4096
.* addis r3,r3,0
.* lwz r3,-32768\(r3\)
.* nop
.* nop
.* addis r29,r2,0
.* mr r3,r29
.* addi r3,r3,4096
.* lwz r3,-32768\(r3\)
.* nop
.* nop
.* nop
.* nop
.* nop
.* addis r29,r2,0
.* mr r3,r29
.* addi r3,r3,-28672
.* lwz r3,0\(r3\)
.* nop
.* nop
.* nop
.* addis r29,r2,0
.* mr r3,r29
.* addi r3,r3,-28672
.* lwz r3,0\(r3\)
.* nop
.* nop
.* nop
.* nop
#pass

View file

@ -0,0 +1,43 @@
.text
.globl _start
_start:
addis 3,31,PrettyStackTraceHead@got@tlsld@ha
addi 29,3,PrettyStackTraceHead@got@tlsld@l
mr 3,29
bl __tls_get_addr(PrettyStackTraceHead@tlsld)
addis 3,3,PrettyStackTraceHead@dtprel@ha
lwz 3,PrettyStackTraceHead@dtprel@l(3)
nop
nop
addi 29,31,PrettyStackTraceHead@got@tlsld
mr 3,29
bl __tls_get_addr(PrettyStackTraceHead@tlsld)
lwz 3,PrettyStackTraceHead@dtprel(3)
nop
nop
nop
nop
addis 3,31,PrettyStackTraceHead@got@tlsgd@ha
addi 29,3,PrettyStackTraceHead@got@tlsgd@l
mr 3,29
bl __tls_get_addr(PrettyStackTraceHead@tlsgd)
lwz 3,0(3)
nop
nop
nop
addi 29,31,PrettyStackTraceHead@got@tlsgd
mr 3,29
bl __tls_get_addr(PrettyStackTraceHead@tlsgd)
lwz 3,0(3)
nop
nop
nop
nop
.section ".tbss","awT",@nobits
.align 2
PrettyStackTraceHead:
.space 4