PR ld/11088
authorAlan Modra <amodra@gmail.com>
Thu, 17 Dec 2009 05:45:25 +0000 (05:45 +0000)
committerAlan Modra <amodra@gmail.com>
Thu, 17 Dec 2009 05:45:25 +0000 (05:45 +0000)
include/elf/
* ppc.h (R_PPC_RELAX32, R_PPC_RELAX32PC, R_PPC_RELAX32_PLT,
R_PPC_RELAX32PC_PLT): Delete.
(R_PPC_RELAX, R_PPC_RELAX_PLT, R_PPC_RELAX_PLTREL24): Define.
bfd/
* elf32-ppc.c (update_plt_info): Clear sec here when addend is
less than 32768..
(ppc_elf_check_relocs): ..rather than doing so here.  Ignore new
relax relocs.
(ppc_elf_gc_sweep_hook): Don't segfault when symbol hiding has
removed plt_entry records.
(ppc_elf_tls_setup): Handle PIE calls to __tls_get_addr correctly.
(ppc_elf_tls_optimize): Likewise.  Also dec __tls_get_addr refcount
when optimizing code using new tlsgd and tlsld marker relocs.
(ppc_elf_relax_section): Differentiate relaxed PLTREL24 relocs
from ADDR24 relocs using plt or glink.  Don't clear the addend
for R_PPC_RELAX_PLTREL24.
(ppc_elf_relocate_section): Correctly handle addends on relaxed
PLTREL24 relocs.

bfd/ChangeLog
bfd/elf32-ppc.c
include/elf/ChangeLog
include/elf/ppc.h

index 1d430e35dfce94c95ab35ad62aa780e5f51449fd..1c4412a1da643dd662e73a62269845f4030d1a5c 100644 (file)
@@ -1,3 +1,21 @@
+2009-12-17  Alan Modra  <amodra@bigpond.net.au>
+
+       PR ld/11088
+       * elf32-ppc.c (update_plt_info): Clear sec here when addend is
+       less than 32768..
+       (ppc_elf_check_relocs): ..rather than doing so here.  Ignore new
+       relax relocs.
+       (ppc_elf_gc_sweep_hook): Don't segfault when symbol hiding has
+       removed plt_entry records.
+       (ppc_elf_tls_setup): Handle PIE calls to __tls_get_addr correctly.
+       (ppc_elf_tls_optimize): Likewise.  Also dec __tls_get_addr refcount
+       when optimizing code using new tlsgd and tlsld marker relocs.
+       (ppc_elf_relax_section): Differentiate relaxed PLTREL24 relocs
+       from ADDR24 relocs using plt or glink.  Don't clear the addend
+       for R_PPC_RELAX_PLTREL24.
+       (ppc_elf_relocate_section): Correctly handle addends on relaxed
+       PLTREL24 relocs.
+
 2009-12-17  Alan Modra  <amodra@bigpond.net.au>
 
        PR ld/11088
index e863f7e34023e92b1ecef8514cbd3c356e66d7df..0c372f00a4155545578dc69a4566ca3cebe02aa0 100644 (file)
@@ -3323,6 +3323,8 @@ update_plt_info (bfd *abfd, struct plt_entry **plist,
 {
   struct plt_entry *ent;
 
+  if (addend < 32768)
+    sec = NULL;
   for (ent = *plist; ent != NULL; ent = ent->next)
     if (ent->sec == sec && ent->addend == addend)
       break;
@@ -3508,8 +3510,7 @@ ppc_elf_check_relocs (bfd *abfd,
                      if (info->shared)
                        addend = rel->r_addend;
                    }
-                 if (!update_plt_info (abfd, ifunc,
-                                       addend < 32768 ? NULL : got2, addend))
+                 if (!update_plt_info (abfd, ifunc, got2, addend))
                    return FALSE;
                }
            }
@@ -3748,8 +3749,7 @@ ppc_elf_check_relocs (bfd *abfd,
                    addend = rel->r_addend;
                }
              h->needs_plt = 1;
-             if (!update_plt_info (abfd, &h->plt.plist,
-                                   addend < 32768 ? NULL : got2, addend))
+             if (!update_plt_info (abfd, &h->plt.plist, got2, addend))
                return FALSE;
            }
          break;
@@ -3780,10 +3780,9 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_EMB_MRKREF:
        case R_PPC_NONE:
        case R_PPC_max:
-       case R_PPC_RELAX32:
-       case R_PPC_RELAX32PC:
-       case R_PPC_RELAX32_PLT:
-       case R_PPC_RELAX32PC_PLT:
+       case R_PPC_RELAX:
+       case R_PPC_RELAX_PLT:
+       case R_PPC_RELAX_PLTREL24:
          break;
 
          /* These should only appear in dynamic objects.  */
@@ -4486,7 +4485,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
                  struct plt_entry *ent;
 
                  ent = find_plt_ent (&h->plt.plist, NULL, 0);
-                 if (ent->plt.refcount > 0)
+                 if (ent != NULL && ent->plt.refcount > 0)
                    ent->plt.refcount -= 1;
                }
            }
@@ -4534,7 +4533,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
              if (r_type == R_PPC_PLTREL24 && info->shared)
                addend = rel->r_addend;
              ent = find_plt_ent (&h->plt.plist, got2, addend);
-             if (ent->plt.refcount > 0)
+             if (ent != NULL && ent->plt.refcount > 0)
                ent->plt.refcount -= 1;
            }
          break;
@@ -4582,9 +4581,10 @@ ppc_elf_tls_setup (bfd *obfd,
                       && tga->root.type == bfd_link_hash_undefweak)))
            {
              struct plt_entry *ent;
-             ent = find_plt_ent (&tga->plt.plist, NULL, 0);
-             if (ent != NULL
-                 && ent->plt.refcount > 0)
+             for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
+               if (ent->plt.refcount > 0)
+                 break;
+             if (ent != NULL)
                {
                  tga->root.type = bfd_link_hash_indirect;
                  tga->root.u.i.link = &opt->root;
@@ -4669,6 +4669,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
       {
        Elf_Internal_Sym *locsyms = NULL;
        Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+       asection *got2 = bfd_get_section_by_name (ibfd, ".got2");
 
        for (sec = ibfd->sections; sec != NULL; sec = sec->next)
          if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
@@ -4762,6 +4763,13 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      else
                        continue;
 
+                   case R_PPC_TLSGD:
+                   case R_PPC_TLSLD:
+                     expecting_tls_get_addr = 2;
+                     tls_set = 0;
+                     tls_clear = 0;
+                     break;
+
                    default:
                      continue;
                    }
@@ -4769,7 +4777,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                  if (pass == 0)
                    {
                      if (!expecting_tls_get_addr
-                         || !sec->has_tls_get_addr_call)
+                         || (expecting_tls_get_addr == 1
+                             && !sec->has_tls_get_addr_call))
                        continue;
 
                      if (rel + 1 < relend
@@ -4785,6 +4794,23 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      break;
                    }
 
+                 if (expecting_tls_get_addr)
+                   {
+                     struct plt_entry *ent;
+                     bfd_vma addend = 0;
+
+                     if (info->shared
+                         && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
+                       addend = rel[1].r_addend;
+                     ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
+                                         got2, addend);
+                     if (ent != NULL && ent->plt.refcount > 0)
+                       ent->plt.refcount -= 1;
+
+                     if (expecting_tls_get_addr == 2)
+                       continue;
+                   }
+
                  if (h != NULL)
                    {
                      tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
@@ -4829,16 +4855,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                        *got_count -= 1;
                    }
 
-                 if (expecting_tls_get_addr)
-                   {
-                     struct plt_entry *ent;
-
-                     ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
-                                         NULL, 0);
-                     if (ent != NULL && ent->plt.refcount > 0)
-                       ent->plt.refcount -= 1;
-                   }
-
                  *tls_mask |= tls_set;
                  *tls_mask &= ~tls_clear;
                }
@@ -6239,28 +6255,28 @@ ppc_elf_relax_section (bfd *abfd,
            {
              size = 4 * ARRAY_SIZE (shared_stub_entry);
              insn_offset = 12;
-             stub_rtype = R_PPC_RELAX32PC;
            }
          else
            {
              size = 4 * ARRAY_SIZE (stub_entry);
              insn_offset = 0;
-             stub_rtype = R_PPC_RELAX32;
            }
-
-         if (R_PPC_RELAX32_PLT - R_PPC_RELAX32
-             != R_PPC_RELAX32PC_PLT - R_PPC_RELAX32PC)
-           abort ();
+         stub_rtype = R_PPC_RELAX;
          if (tsec == htab->plt
              || tsec == htab->glink)
-           stub_rtype += R_PPC_RELAX32_PLT - R_PPC_RELAX32;
+           {
+             stub_rtype = R_PPC_RELAX_PLT;
+             if (r_type == R_PPC_PLTREL24)
+               stub_rtype = R_PPC_RELAX_PLTREL24;
+           }
 
          /* Hijack the old relocation.  Since we need two
             relocations for this use a "composite" reloc.  */
          irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                       stub_rtype);
          irel->r_offset = trampoff + insn_offset;
-         if (r_type == R_PPC_PLTREL24)
+         if (r_type == R_PPC_PLTREL24
+             && stub_rtype != R_PPC_RELAX_PLTREL24)
            irel->r_addend = 0;
 
          /* Record the fixup so we don't do it again this section.  */
@@ -6430,7 +6446,7 @@ ppc_elf_relax_section (bfd *abfd,
     {
       /* Convert the internal relax relocs to external form.  */
       for (irel = internal_relocs; irel < irelend; irel++)
-       if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX32)
+       if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX)
          {
            unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
 
@@ -7669,12 +7685,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
-       case R_PPC_RELAX32PC_PLT:
-       case R_PPC_RELAX32_PLT:
+       case R_PPC_RELAX_PLT:
+       case R_PPC_RELAX_PLTREL24:
          if (h != NULL)
            {
-             struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
-                                                   info->shared ? addend : 0);
+             struct plt_entry *ent;
+             bfd_vma got2_addend = 0;
+
+             if (r_type == R_PPC_RELAX_PLTREL24)
+               {
+                 if (info->shared)
+                   got2_addend = addend;
+                 addend = 0;
+               }
+             ent = find_plt_ent (&h->plt.plist, got2, got2_addend);
              if (htab->plt_type == PLT_NEW)
                relocation = (htab->glink->output_section->vma
                              + htab->glink->output_offset
@@ -7684,18 +7708,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
                              + htab->plt->output_offset
                              + ent->plt.offset);
            }
-         if (r_type == R_PPC_RELAX32_PLT)
-           goto relax32;
          /* Fall thru */
 
-       case R_PPC_RELAX32PC:
-         relocation -= (input_section->output_section->vma
-                        + input_section->output_offset
-                        + rel->r_offset - 4);
-         /* Fall thru */
+       case R_PPC_RELAX:
+         if (info->shared)
+           relocation -= (input_section->output_section->vma
+                          + input_section->output_offset
+                          + rel->r_offset - 4);
 
-       case R_PPC_RELAX32:
-       relax32:
          {
            unsigned long t0;
            unsigned long t1;
index fa3433439dee2b6a19d17138ad0677f35c032378..2befe57207bec96a2c4bae0e5077ba4f89b585de 100644 (file)
@@ -1,3 +1,9 @@
+2009-12-17  Alan Modra  <amodra@bigpond.net.au>
+
+       * ppc.h (R_PPC_RELAX32, R_PPC_RELAX32PC, R_PPC_RELAX32_PLT,
+       R_PPC_RELAX32PC_PLT): Delete.
+       (R_PPC_RELAX, R_PPC_RELAX_PLT, R_PPC_RELAX_PLTREL24): Define.
+
 2009-11-28  Joseph Myers  <joseph@codesourcery.com>
 
        * common.h (ELFOSABI_FENIXOS, EM_TI_C6000, EM_TI_C2000,
index e2de0ad76f8d7cf00a6d2c7a205962ab8a2f87d8..a77c833d2242b88a30d55295ae42a7156a6d78af 100644 (file)
@@ -73,10 +73,9 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
 
 #ifndef RELOC_MACROS_GEN_FUNC
 /* Fake relocations for branch stubs, only used internally by ld.  */
-  RELOC_NUMBER (R_PPC_RELAX32,          48)
-  RELOC_NUMBER (R_PPC_RELAX32PC,        49)
-  RELOC_NUMBER (R_PPC_RELAX32_PLT,      50)
-  RELOC_NUMBER (R_PPC_RELAX32PC_PLT,    51)
+  RELOC_NUMBER (R_PPC_RELAX,            48)
+  RELOC_NUMBER (R_PPC_RELAX_PLT,        49)
+  RELOC_NUMBER (R_PPC_RELAX_PLTREL24,   50)
 #endif
 
   /* Relocs added to support TLS.  */