From ea5fe5d01e5a182ee7a0eddb54a702109a9f5931 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 4 Aug 2023 15:09:53 +0930 Subject: PR30697, ppc32 mix of local-dynamic and global-dynamic TLS This fixes miscounting of dynamic relocations on GOT entries when a) there are both local-dynamic and global-dynamic tls accesss for a given symbol, and b) the symbol is global with non-default visibility, and c) the __tls_get_addr calls aren't optimised away. PR 30697 bfd/ * elf32-ppc.c (allocate_dynrelocs): Correct local-dynamic reloc count. ld/ * testsuite/ld-powerpc/tls32ldgd.d, * testsuite/ld-powerpc/tls32ldgd.s: New test. * testsuite/ld-powerpc/powerpc.exp: Run it. (cherry picked from commit ae33771224660dac25e64c3f70943a17bfab7681) --- bfd/elf32-ppc.c | 16 +++++++--------- ld/testsuite/ld-powerpc/powerpc.exp | 1 + ld/testsuite/ld-powerpc/tls32ldgd.d | 13 +++++++++++++ ld/testsuite/ld-powerpc/tls32ldgd.s | 16 ++++++++++++++++ 4 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 ld/testsuite/ld-powerpc/tls32ldgd.d create mode 100644 ld/testsuite/ld-powerpc/tls32ldgd.s diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 5305130..fa5ba43 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -5144,13 +5144,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && eh->has_addr16_lo && htab->params->pic_fixup > 0)) { - unsigned int need; - /* Make sure this symbol is output as a dynamic symbol. */ if (!ensure_undef_dynamic (info, &eh->elf)) return false; - need = 0; + unsigned int need = got_entries_needed (eh->tls_mask); + unsigned int rel_need = need * sizeof (Elf32_External_Rela) / 4; if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD)) { if (SYMBOL_REFERENCES_LOCAL (info, &eh->elf)) @@ -5159,9 +5158,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) a local dynamic reloc against a non-local symbol. */ htab->tlsld_got.refcount += 1; else - need += 8; + { + need += 8; + rel_need += sizeof (Elf32_External_Rela); + } } - need += got_entries_needed (eh->tls_mask); if (need == 0) eh->elf.got.offset = (bfd_vma) -1; else @@ -5178,13 +5179,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { asection *rsec; - need *= sizeof (Elf32_External_Rela) / 4; - if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD)) - need -= sizeof (Elf32_External_Rela); rsec = htab->elf.srelgot; if (eh->elf.type == STT_GNU_IFUNC) rsec = htab->elf.irelplt; - rsec->size += need; + rsec->size += rel_need; } } } diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index 9eff14f..d7eca69 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -510,5 +510,6 @@ run_dump_test "non-contiguous-powerpc" run_dump_test "tprel32" run_dump_test "tprelbad" +run_dump_test tls32ldgd run_dump_test "undefweak" diff --git a/ld/testsuite/ld-powerpc/tls32ldgd.d b/ld/testsuite/ld-powerpc/tls32ldgd.d new file mode 100644 index 0000000..88e26b9 --- /dev/null +++ b/ld/testsuite/ld-powerpc/tls32ldgd.d @@ -0,0 +1,13 @@ +#as: -a32 +#ld: -shared -melf32ppc +#readelf: -rW + +Relocation section '\.rela\.dyn' at offset .* contains 3 entries: + Offset +Info +Type +Sym\. Value +Symbol's Name \+ Addend +.* +00000044 R_PPC_DTPMOD32 +0 +.* +0000004e R_PPC_DTPREL32 +0 +.* +00000044 R_PPC_DTPMOD32 +0 + +Relocation section '\.rela\.plt' at offset .* contains 1 entry: + Offset +Info +Type +Sym\. Value +Symbol's Name \+ Addend +.* +00000215 R_PPC_JMP_SLOT +00000000 +__tls_get_addr \+ 0 diff --git a/ld/testsuite/ld-powerpc/tls32ldgd.s b/ld/testsuite/ld-powerpc/tls32ldgd.s new file mode 100644 index 0000000..889eb44 --- /dev/null +++ b/ld/testsuite/ld-powerpc/tls32ldgd.s @@ -0,0 +1,16 @@ +#PR 30697 + .section ".tbss","awT",@nobits + .global _start,x + .hidden x + .align 2 +x: .space 4 + + .text +_start: + addi 3,30,x@got@tlsgd + bl __tls_get_addr(x@tlsgd)@plt + + addi 3,30,x@got@tlsld + bl __tls_get_addr(x@tlsld)@plt + addis 3,3,x@dtprel@ha + addi 3,3,x@dtprel@l -- cgit v1.1