PowerPC64le PLT reference counting
authorAlan Modra <amodra@gmail.com>
Wed, 5 Apr 2017 03:17:41 +0000 (12:47 +0930)
committerAlan Modra <amodra@gmail.com>
Wed, 5 Apr 2017 12:29:44 +0000 (21:59 +0930)
A fix for ELFv2 ABI garbage-collection.

* elf64-ppc.c (ppc64_elf_gc_sweep_hook): Support ELFv2 PLT
reference counting.

bfd/ChangeLog
bfd/elf64-ppc.c

index 4703b21f8ee57ace640b7170a9e18ca941df1b78..0e4ad30158ef710538170e88d6df560e621843ac 100644 (file)
@@ -1,3 +1,8 @@
+2017-04-05  Alan Modra  <amodra@gmail.com>
+
+       * elf64-ppc.c (ppc64_elf_gc_sweep_hook): Support ELFv2 PLT
+       reference counting.
+
 2017-04-02  Jon Turney  <jon.turney@dronecode.org.uk>
 
        (_bfd_XXi_swap_aouthdr_out): For clarity, use defines rather than
index ae3903289a90b6e00e9b642b85101bc90c35f3d1..386db9a0dfea73f4bc5922bc54272648fa22e665 100644 (file)
@@ -6595,7 +6595,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       enum elf_ppc64_reloc_type r_type;
       struct elf_link_hash_entry *h = NULL;
-      struct plt_entry **plt_list;
+      struct plt_entry **plt_list = NULL;
       unsigned char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -6674,6 +6674,8 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
            if (ent->got.refcount > 0)
              ent->got.refcount -= 1;
          }
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
+           plt_list = &h->plt.plist;
          break;
 
        case R_PPC64_PLT16_HA:
@@ -6685,7 +6687,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL24:
-         plt_list = NULL;
          if (h != NULL)
            plt_list = &h->plt.plist;
          else if (local_got_ents != NULL)
@@ -6697,21 +6698,39 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
              if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
                plt_list = local_plt + r_symndx;
            }
-         if (plt_list)
-           {
-             struct plt_entry *ent;
+         break;
 
-             for (ent = *plt_list; ent != NULL; ent = ent->next)
-               if (ent->addend == rel->r_addend)
-                 break;
-             if (ent != NULL && ent->plt.refcount > 0)
-               ent->plt.refcount -= 1;
-           }
+       case R_PPC64_ADDR64:
+       case R_PPC64_ADDR16:
+       case R_PPC64_ADDR16_DS:
+       case R_PPC64_ADDR16_HA:
+       case R_PPC64_ADDR16_HI:
+       case R_PPC64_ADDR16_HIGH:
+       case R_PPC64_ADDR16_HIGHA:
+       case R_PPC64_ADDR16_HIGHER:
+       case R_PPC64_ADDR16_HIGHERA:
+       case R_PPC64_ADDR16_HIGHEST:
+       case R_PPC64_ADDR16_HIGHESTA:
+       case R_PPC64_ADDR16_LO:
+       case R_PPC64_ADDR16_LO_DS:
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1
+             && rel->r_addend == 0)
+           plt_list = &h->plt.plist;
          break;
 
        default:
          break;
        }
+      if (plt_list != NULL)
+       {
+         struct plt_entry *ent;
+
+         for (ent = *plt_list; ent != NULL; ent = ent->next)
+           if (ent->addend == rel->r_addend)
+             break;
+         if (ent != NULL && ent->plt.refcount > 0)
+           ent->plt.refcount -= 1;
+       }
     }
   return TRUE;
 }