diff options
author | Alan Modra <amodra@gmail.com> | 2015-01-29 11:09:55 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2015-01-29 13:13:02 +1030 |
commit | b86ac8e3a5a3117696b1760003b8e09ed13f1de9 (patch) | |
tree | 62ef24abc3d0ef13113729ea6f1ae626e556e4af /bfd/elf32-ppc.c | |
parent | 912ae7dd0fa4658133d4fb77954a57c8548c37d6 (diff) | |
download | gdb-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/elf32-ppc.c')
-rw-r--r-- | bfd/elf32-ppc.c | 15 |
1 files changed, 10 insertions, 5 deletions
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. */ |