Correct PowerPC64 local-dynamic TLS linker optimization
authorAlan Modra <amodra@gmail.com>
Thu, 29 Jan 2015 00:39:55 +0000 (11:09 +1030)
committerAlan Modra <amodra@gmail.com>
Thu, 29 Jan 2015 02:43:02 +0000 (13:13 +1030)
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.

bfd/ChangeLog
bfd/elf32-ppc.c
bfd/elf64-ppc.c
ld/testsuite/ChangeLog
ld/testsuite/ld-powerpc/powerpc.exp
ld/testsuite/ld-powerpc/tlsld.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/tlsld.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/tlsld32.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/tlsld32.s [new file with mode: 0644]

index f5a50fa2385d6cba7a726722d0df42d78abc9265..464400f9273161b7d04bc034a3f4852d7a4833b3 100644 (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".
index 7adb0f692c33ab94a18e849e4b6cfaf99ee7c6ef..c467f14b6872d4519f87c59f5d6146fd1afba742 100644 (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.  */
index da37465feeb50b2f0d721156a847335c3d8f418d..d597fec59a387e89c5cc3bd131677baccad04fe8 100644 (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)
                    {
index c5effcd4ba5b6180297f768098909c97839e5b98..d05b76256a4b45cc4ee8f868ba977bbfaac502a3 100644 (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
index 81cc310ad8fbed71bc08920fd9b6b7fdb1a38a20..48aec4ae4fc1f6b6043cfc4112f90dbd8d60f0d9 100644 (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"
diff --git a/ld/testsuite/ld-powerpc/tlsld.d b/ld/testsuite/ld-powerpc/tlsld.d
new file mode 100644 (file)
index 0000000..d66d1db
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-powerpc/tlsld.s b/ld/testsuite/ld-powerpc/tlsld.s
new file mode 100644 (file)
index 0000000..925d8bf
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-powerpc/tlsld32.d b/ld/testsuite/ld-powerpc/tlsld32.d
new file mode 100644 (file)
index 0000000..b0fd657
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-powerpc/tlsld32.s b/ld/testsuite/ld-powerpc/tlsld32.s
new file mode 100644 (file)
index 0000000..f5561d4
--- /dev/null
@@ -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