PR30697, ppc32 mix of local-dynamic and global-dynamic TLS
authorAlan Modra <amodra@gmail.com>
Fri, 4 Aug 2023 05:39:53 +0000 (15:09 +0930)
committerAlan Modra <amodra@gmail.com>
Fri, 4 Aug 2023 08:29:01 +0000 (17:59 +0930)
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.

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

index 2c544b11de576626fe6131fa0b73d991d6372c0c..37bfbcfc3ba9d50ffc05931218685c7823fc0bf8 100644 (file)
@@ -5126,13 +5126,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))
@@ -5141,9 +5140,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
@@ -5161,13 +5162,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;
            }
        }
     }
index 16e25b09a143a7230d932d811993810f8041bc9c..6cb7bd2577eaefcd9df706d65ea505b7ded043f4 100644 (file)
@@ -522,5 +522,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 (file)
index 0000000..88e26b9
--- /dev/null
@@ -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 (file)
index 0000000..889eb44
--- /dev/null
@@ -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