From b86ac8e3a5a3117696b1760003b8e09ed13f1de9 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 29 Jan 2015 11:09:55 +1030 Subject: [PATCH] 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. --- bfd/ChangeLog | 7 +++++ bfd/elf32-ppc.c | 15 ++++++--- bfd/elf64-ppc.c | 13 +++++--- ld/testsuite/ChangeLog | 6 ++++ ld/testsuite/ld-powerpc/powerpc.exp | 7 +++-- ld/testsuite/ld-powerpc/tlsld.d | 43 ++++++++++++++++++++++++++ ld/testsuite/ld-powerpc/tlsld.s | 48 +++++++++++++++++++++++++++++ ld/testsuite/ld-powerpc/tlsld32.d | 44 ++++++++++++++++++++++++++ ld/testsuite/ld-powerpc/tlsld32.s | 43 ++++++++++++++++++++++++++ 9 files changed, 215 insertions(+), 11 deletions(-) create mode 100644 ld/testsuite/ld-powerpc/tlsld.d create mode 100644 ld/testsuite/ld-powerpc/tlsld.s create mode 100644 ld/testsuite/ld-powerpc/tlsld32.d create mode 100644 ld/testsuite/ld-powerpc/tlsld32.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f5a50fa2385..464400f9273 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2015-01-29 Alan Modra + + * 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 * elf64-ppc.h (struct ppc64_elf_params): Add "object_in_toc". diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 7adb0f692c3..c467f14b687 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -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. */ diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index da37465feeb..d597fec59a3 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -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) { diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index c5effcd4ba5..d05b76256a4 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2015-01-29 Alan Modra + + * 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 PR ld/17878 diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index 81cc310ad8f..48aec4ae4fc 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -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 index 00000000000..d66d1dbf802 --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsld.d @@ -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 index 00000000000..925d8bf66e4 --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsld.s @@ -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 index 00000000000..b0fd657057c --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsld32.d @@ -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 index 00000000000..f5561d4a509 --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsld32.s @@ -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 -- 2.30.2