powerpc TLS in PIEs
authorAlan Modra <amodra@gmail.com>
Sat, 4 Nov 2017 03:11:29 +0000 (13:41 +1030)
committerAlan Modra <amodra@gmail.com>
Sat, 4 Nov 2017 23:07:33 +0000 (09:37 +1030)
This patch removes unnecessary GOT IE TLS relocations in PIEs.  Useful
with --no-tls-optimize, or with an enormous TLS segment.  With the
default --tls-optimize in effect IE code sequences will be edited to
LE under the same circumstances we can remove the GOT reloc.

* elf32-ppc.c (got_entries_needed, got_relocs_needed): New functions.
(allocate_dynrelocs, ppc_elf_size_dynamic_sections): Use them here.
(ppc_elf_relocate_section): Don't output a dynamic relocation
for IE GOT entries in an executable.
* elf64-ppc.c (allocate_got): Trim unnecessary TPREL relocs.
(ppc64_elf_size_dynamic_sections): Likewise.
(ppc64_elf_relocate_section): Likewise.

bfd/ChangeLog
bfd/elf32-ppc.c
bfd/elf64-ppc.c

index 37267e26bbe3d5a7032060f9ad1f7156736a484f..9a98d2aacde0c1efcda66971218885e35900f200 100644 (file)
@@ -1,3 +1,13 @@
+2017-11-04  Alan Modra  <amodra@gmail.com>
+
+       * elf32-ppc.c (got_entries_needed, got_relocs_needed): New functions.
+       (allocate_dynrelocs, ppc_elf_size_dynamic_sections): Use them here.
+       (ppc_elf_relocate_section): Don't output a dynamic relocation
+       for IE GOT entries in an executable.
+       * elf64-ppc.c (allocate_got): Trim unnecessary TPREL relocs.
+       (ppc64_elf_size_dynamic_sections): Likewise.
+       (ppc64_elf_relocate_section): Likewise.
+
 2017-11-04  Alan Modra  <amodra@gmail.com>
 
        * elf32-ppc.c (readonly_dynrelocs): Delete info param.  Update all
index d98cbcf7a59cac6338d750d700f4c84b922b4b61..40fc1fc47a07eced59d449e08d5ceebcf967a32b 100644 (file)
@@ -5751,6 +5751,45 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
   return where;
 }
 
+/* Calculate size of GOT entries for symbol given its TLS_MASK.
+   TLS_LD is excluded because those go in a special GOT slot.  */
+
+static inline unsigned int
+got_entries_needed (int tls_mask)
+{
+  unsigned int need;
+  if ((tls_mask & TLS_TLS) == 0)
+    need = 4;
+  else
+    {
+      need = 0;
+      if ((tls_mask & TLS_GD) != 0)
+       need += 8;
+      if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
+       need += 4;
+      if ((tls_mask & TLS_DTPREL) != 0)
+       need += 4;
+    }
+  return need;
+}
+
+/* Calculate size of relocs needed for symbol given its TLS_MASK and
+   NEEDed GOT entries.  KNOWN says a TPREL offset can be calculated at
+   link time.  */
+
+static inline unsigned int
+got_relocs_needed (int tls_mask, unsigned int need, bfd_boolean known)
+{
+  /* All the entries we allocated need relocs.
+     Except IE in executable with a local symbol.  We could also omit
+     the DTPREL reloc on the second word of a GD entry under the same
+     condition as that for IE, but ld.so needs to differentiate
+     LD and GD entries.  */
+  if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0 && known)
+    need -= 4;
+  return need * sizeof (Elf32_External_Rela) / 4;
+}
+
 /* If H is undefined, make it dynamic if that makes sense.  */
 
 static bfd_boolean
@@ -5801,27 +5840,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        return FALSE;
 
       need = 0;
-      if ((eh->tls_mask & TLS_TLS) != 0)
+      if ((eh->tls_mask & TLS_LD) != 0)
        {
-         if ((eh->tls_mask & TLS_LD) != 0)
-           {
-             if (!eh->elf.def_dynamic)
-               /* We'll just use htab->tlsld_got.offset.  This should
-                  always be the case.  It's a little odd if we have
-                  a local dynamic reloc against a non-local symbol.  */
-               htab->tlsld_got.refcount += 1;
-             else
-               need += 8;
-           }
-         if ((eh->tls_mask & TLS_GD) != 0)
+         if (!eh->elf.def_dynamic)
+           /* We'll just use htab->tlsld_got.offset.  This should
+              always be the case.  It's a little odd if we have
+              a local dynamic reloc against a non-local symbol.  */
+           htab->tlsld_got.refcount += 1;
+         else
            need += 8;
-         if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
-           need += 4;
-         if ((eh->tls_mask & TLS_DTPREL) != 0)
-           need += 4;
        }
-      else
-       need += 4;
+      need += got_entries_needed (eh->tls_mask);
       if (need == 0)
        eh->elf.got.offset = (bfd_vma) -1;
       else
@@ -5833,16 +5862,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                   && !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
              && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &eh->elf))
            {
-             asection *rsec = htab->elf.srelgot;
-
+             asection *rsec;
+             bfd_boolean tprel_known = (bfd_link_executable (info)
+                                        && SYMBOL_REFERENCES_LOCAL (info,
+                                                                    &eh->elf));
+
+             need = got_relocs_needed (eh->tls_mask, need, tprel_known);
+             if ((eh->tls_mask & TLS_LD) != 0 && eh->elf.def_dynamic)
+               need -= sizeof (Elf32_External_Rela);
+             rsec = htab->elf.srelgot;
              if (eh->elf.type == STT_GNU_IFUNC)
                rsec = htab->elf.irelplt;
-             /* All the entries we allocated need relocs.
-                Except LD only needs one.  */
-             if ((eh->tls_mask & TLS_LD) != 0
-                 && eh->elf.def_dynamic)
-               need -= 4;
-             rsec->size += need * (sizeof (Elf32_External_Rela) / 4);
+             rsec->size += need;
            }
        }
     }
@@ -6244,20 +6275,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       for (; local_got < end_local_got; ++local_got, ++lgot_masks)
        if (*local_got > 0)
          {
-           unsigned int need = 0;
-           if ((*lgot_masks & TLS_TLS) != 0)
-             {
-               if ((*lgot_masks & TLS_GD) != 0)
-                 need += 8;
-               if ((*lgot_masks & TLS_LD) != 0)
-                 htab->tlsld_got.refcount += 1;
-               if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
-                 need += 4;
-               if ((*lgot_masks & TLS_DTPREL) != 0)
-                 need += 4;
-             }
-           else
-             need += 4;
+           unsigned int need;
+           if ((*lgot_masks & TLS_LD) != 0)
+             htab->tlsld_got.refcount += 1;
+           need = got_entries_needed (*lgot_masks);
            if (need == 0)
              *local_got = (bfd_vma) -1;
            else
@@ -6265,10 +6286,14 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                *local_got = allocate_got (htab, need);
                if (bfd_link_pic (info))
                  {
-                   asection *srel = htab->elf.srelgot;
+                   asection *srel;
+                   bfd_boolean tprel_known = bfd_link_executable (info);
+
+                   need = got_relocs_needed (*lgot_masks, need, tprel_known);
+                   srel = htab->elf.srelgot;
                    if ((*lgot_masks & PLT_IFUNC) != 0)
                      srel = htab->elf.irelplt;
-                   srel->size += need * (sizeof (Elf32_External_Rela) / 4);
+                   srel->size += need;
                  }
              }
          }
@@ -8428,7 +8453,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
                        || (bfd_link_pic (info)
                            && (h == NULL
                                || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
-                               || offp == &htab->tlsld_got.offset)))
+                               || offp == &htab->tlsld_got.offset)
+                           && !(tls_ty == (TLS_TLS | TLS_TPREL)
+                                && bfd_link_executable (info)
+                                && SYMBOL_REFERENCES_LOCAL (info, h))))
                      {
                        asection *rsec = htab->elf.srelgot;
                        bfd_byte * loc;
index bd42af072fa747010307622b7f6581625fb45374..31cb2f2a2a33d15e55701dc35abdb3caaf94652d 100644 (file)
@@ -9584,7 +9584,10 @@ allocate_got (struct elf_link_hash_entry *h,
       htab->elf.irelplt->size += rentsize;
       htab->got_reli_size += rentsize;
     }
-  else if ((bfd_link_pic (info)
+  else if (((bfd_link_pic (info)
+            && !((gent->tls_type & TLS_TPREL) != 0
+                 && bfd_link_executable (info)
+                 && SYMBOL_REFERENCES_LOCAL (info, h)))
            || (htab->elf.dynamic_sections_created
                && h->dynindx != -1
                && !SYMBOL_REFERENCES_LOCAL (info, h)))
@@ -10072,7 +10075,9 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                        htab->elf.irelplt->size += rel_size;
                        htab->got_reli_size += rel_size;
                      }
-                   else if (bfd_link_pic (info))
+                   else if (bfd_link_pic (info)
+                            && !((ent->tls_type & TLS_TPREL) != 0
+                                 && bfd_link_executable (info)))
                      {
                        asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                        srel->size += rel_size;
@@ -14514,7 +14519,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                             && (h == NULL
                                 || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)
                                 || (tls_type == (TLS_TLS | TLS_LD)
-                                    && !h->elf.def_dynamic))))
+                                    && !h->elf.def_dynamic))
+                            && !(tls_type == (TLS_TLS | TLS_TPREL)
+                                 && bfd_link_executable (info)
+                                 && SYMBOL_REFERENCES_LOCAL (info, &h->elf))))
                  relgot = ppc64_elf_tdata (ent->owner)->relgot;
                if (relgot != NULL)
                  {