aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2015-01-29 11:09:55 +1030
committerAlan Modra <amodra@gmail.com>2015-01-29 13:13:02 +1030
commitb86ac8e3a5a3117696b1760003b8e09ed13f1de9 (patch)
tree62ef24abc3d0ef13113729ea6f1ae626e556e4af /bfd
parent912ae7dd0fa4658133d4fb77954a57c8548c37d6 (diff)
downloadgdb-b86ac8e3a5a3117696b1760003b8e09ed13f1de9.zip
gdb-b86ac8e3a5a3117696b1760003b8e09ed13f1de9.tar.gz
gdb-b86ac8e3a5a3117696b1760003b8e09ed13f1de9.tar.bz2
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.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog7
-rw-r--r--bfd/elf32-ppc.c15
-rw-r--r--bfd/elf64-ppc.c13
3 files changed, 26 insertions, 9 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index f5a50fa..464400f 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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".
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 7adb0f6..c467f14 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 da37465..d597fec 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)
{