Rearrange PLT reloc output on powerpc
authorAlan Modra <amodra@gmail.com>
Sun, 8 Apr 2018 23:51:59 +0000 (09:21 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 9 Apr 2018 07:32:19 +0000 (17:02 +0930)
The current scheme where we output PLT relocs for global symbols in
finish_dynamic_symbol, and PLT relocs for local symbols when
outputting stubs does not work if PLT entries are to be used for
inline PLT sequences against non-dynamic globals or local symbols.

bfd/
* elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs
for local symbols to..
(write_plt_relocs_for_local_syms): ..here.  New function.
(ppc64_elf_finish_dynamic_symbol): Move output of PLT relocs for
global symbols to..
(build_global_entry_stubs_and_plt): ..here.  Rename from
build_global_entry_stubs.
(ppc64_elf_build_stubs): Always call build_global_entry_stubs_and_plt.
Call write_plt_relocs_for_local_syms.
* elf32-ppc.c (get_sym_h): New function.
(ppc_elf_relax_section): Use get_sym_h.
(ppc_elf_relocate_section): Move output of PLT relocs and glink
stubs for local symbols to..
(ppc_finish_symbols): ..here.  New function.
(ppc_elf_finish_dynamic_symbol): Move output of PLT relocs for
global syms to..
(write_global_sym_plt): ..here.  New function.
* elf32-ppc.h (ppc_elf_modify_segment_map): Delete attribute.
(ppc_finish_symbols): Declare.
ld/
* ppc32elf.em (ppc_finish): Call ppc_finish_symbols.

bfd/ChangeLog
bfd/elf32-ppc.c
bfd/elf32-ppc.h
bfd/elf64-ppc.c
ld/ChangeLog
ld/emultempl/ppc32elf.em

index cb65c7d1490980425793897181bef95d547cef33..f6388c19dc5e2345ce384c464e5c34920a1f1b18 100644 (file)
@@ -1,3 +1,25 @@
+2018-04-09  Alan Modra  <amodra@gmail.com>
+
+       * elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs
+       for local symbols to..
+       (write_plt_relocs_for_local_syms): ..here.  New function.
+       (ppc64_elf_finish_dynamic_symbol): Move output of PLT relocs for
+       global symbols to..
+       (build_global_entry_stubs_and_plt): ..here.  Rename from
+       build_global_entry_stubs.
+       (ppc64_elf_build_stubs): Always call build_global_entry_stubs_and_plt.
+       Call write_plt_relocs_for_local_syms.
+       * elf32-ppc.c (get_sym_h): New function.
+       (ppc_elf_relax_section): Use get_sym_h.
+       (ppc_elf_relocate_section): Move output of PLT relocs and glink
+       stubs for local symbols to..
+       (ppc_finish_symbols): ..here.  New function.
+       (ppc_elf_finish_dynamic_symbol): Move output of PLT relocs for
+       global syms to..
+       (write_global_sym_plt): ..here.  New function.
+       * elf32-ppc.h (ppc_elf_modify_segment_map): Delete attribute.
+       (ppc_finish_symbols): Declare.
+
 2018-04-09  Alan Modra  <amodra@gmail.com>
 
        * elf32-ppc.c (ppc_elf_check_relocs): Handle PLT16 relocs.
index 973630112d2701f0be10c83d79dd8e3acfd29323..d24b095a543b6935c13d54847b8f28e025b505c7 100644 (file)
@@ -5085,6 +5085,93 @@ ppc_elf_gc_mark_hook (asection *sec,
 
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
+
+static bfd_boolean
+get_sym_h (struct elf_link_hash_entry **hp,
+          Elf_Internal_Sym **symp,
+          asection **symsecp,
+          unsigned char **tls_maskp,
+          Elf_Internal_Sym **locsymsp,
+          unsigned long r_symndx,
+          bfd *ibfd)
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+
+  if (r_symndx >= symtab_hdr->sh_info)
+    {
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
+
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+            || h->root.type == bfd_link_hash_warning)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+      if (hp != NULL)
+       *hp = h;
+
+      if (symp != NULL)
+       *symp = NULL;
+
+      if (symsecp != NULL)
+       {
+         asection *symsec = NULL;
+         if (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+           symsec = h->root.u.def.section;
+         *symsecp = symsec;
+       }
+
+      if (tls_maskp != NULL)
+       *tls_maskp = &ppc_elf_hash_entry (h)->tls_mask;
+    }
+  else
+    {
+      Elf_Internal_Sym *sym;
+      Elf_Internal_Sym *locsyms = *locsymsp;
+
+      if (locsyms == NULL)
+       {
+         locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+         if (locsyms == NULL)
+           locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+                                           symtab_hdr->sh_info,
+                                           0, NULL, NULL, NULL);
+         if (locsyms == NULL)
+           return FALSE;
+         *locsymsp = locsyms;
+       }
+      sym = locsyms + r_symndx;
+
+      if (hp != NULL)
+       *hp = NULL;
+
+      if (symp != NULL)
+       *symp = sym;
+
+      if (symsecp != NULL)
+       *symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx);
+
+      if (tls_maskp != NULL)
+       {
+         bfd_signed_vma *local_got;
+         unsigned char *tls_mask;
+
+         tls_mask = NULL;
+         local_got = elf_local_got_refcounts (ibfd);
+         if (local_got != NULL)
+           {
+             struct plt_entry **local_plt = (struct plt_entry **)
+               (local_got + symtab_hdr->sh_info);
+             unsigned char *lgot_masks = (unsigned char *)
+               (local_plt + symtab_hdr->sh_info);
+             tls_mask = &lgot_masks[r_symndx];
+           }
+         *tls_maskp = tls_mask;
+       }
+    }
+  return TRUE;
+}
 \f
 /* Set plt output section type, htab->tls_get_addr, and call the
    generic ELF tls_setup function.  */
@@ -6892,6 +6979,7 @@ ppc_elf_relax_section (bfd *abfd,
          bfd_byte *hit_addr;
          unsigned long t0;
          struct elf_link_hash_entry *h;
+         Elf_Internal_Sym *isym;
          struct plt_entry **plist;
          unsigned char sym_type;
 
@@ -6919,57 +7007,34 @@ ppc_elf_relax_section (bfd *abfd,
            }
 
          /* Get the value of the symbol referred to by the reloc.  */
-         h = NULL;
-         if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
-           {
-             /* A local symbol.  */
-             Elf_Internal_Sym *isym;
+         if (!get_sym_h (&h, &isym, &tsec, NULL, &isymbuf,
+                         ELF32_R_SYM (irel->r_info), abfd))
+           goto error_return;
 
-             /* Read this BFD's local symbols.  */
-             if (isymbuf == NULL)
-               {
-                 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
-                 if (isymbuf == NULL)
-                   isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
-                                                   symtab_hdr->sh_info, 0,
-                                                   NULL, NULL, NULL);
-                 if (isymbuf == 0)
-                   goto error_return;
-               }
-             isym = isymbuf + ELF32_R_SYM (irel->r_info);
-             if (isym->st_shndx == SHN_UNDEF)
+         if (isym != NULL)
+           {
+             if (tsec != NULL)
+               ;
+             else if (isym->st_shndx == SHN_UNDEF)
                tsec = bfd_und_section_ptr;
              else if (isym->st_shndx == SHN_ABS)
                tsec = bfd_abs_section_ptr;
              else if (isym->st_shndx == SHN_COMMON)
                tsec = bfd_com_section_ptr;
-             else
-               tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
              toff = isym->st_value;
              sym_type = ELF_ST_TYPE (isym->st_info);
            }
          else
            {
-             /* Global symbol handling.  */
-             unsigned long indx;
-
-             indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
-             h = elf_sym_hashes (abfd)[indx];
-
-             while (h->root.type == bfd_link_hash_indirect
-                    || h->root.type == bfd_link_hash_warning)
-               h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-             if (h->root.type == bfd_link_hash_defined
-                 || h->root.type == bfd_link_hash_defweak)
-               {
-                 tsec = h->root.u.def.section;
-                 toff = h->root.u.def.value;
-               }
+             if (tsec != NULL)
+               toff = h->root.u.def.value;
              else if (h->root.type == bfd_link_hash_undefined
                       || h->root.type == bfd_link_hash_undefweak)
                {
+                 unsigned long indx;
+
+                 indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
                  tsec = bfd_und_section_ptr;
                  toff = bfd_link_relocatable (link_info) ? indx : 0;
                }
@@ -8308,32 +8373,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
                      (_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"),
                       input_bfd, input_section, rel->r_offset, sym_name);
                }
-             if (h == NULL && (ent->plt.offset & 1) == 0)
-               {
-                 Elf_Internal_Rela rela;
-                 bfd_byte *loc;
-
-                 rela.r_offset = (htab->elf.iplt->output_section->vma
-                                  + htab->elf.iplt->output_offset
-                                  + ent->plt.offset);
-                 rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
-                 rela.r_addend = relocation;
-                 loc = htab->elf.irelplt->contents;
-                 loc += (htab->elf.irelplt->reloc_count++
-                         * sizeof (Elf32_External_Rela));
-                 bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-                 htab->local_ifunc_resolver = 1;
-
-                 ent->plt.offset |= 1;
-               }
-             if (h == NULL && (ent->glink_offset & 1) == 0)
-               {
-                 unsigned char *p = ((unsigned char *) htab->glink->contents
-                                     + ent->glink_offset);
-
-                 write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
-                 ent->glink_offset |= 1;
-               }
 
              unresolved_reloc = FALSE;
              if (htab->plt_type == PLT_NEW
@@ -10027,27 +10066,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
   return ret;
 }
 \f
-/* Finish up dynamic symbol handling.  We set the contents of various
-   dynamic sections here.  */
+/* Write out the PLT relocs and entries for H.  */
 
 static bfd_boolean
-ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
-                              struct bfd_link_info *info,
-                              struct elf_link_hash_entry *h,
-                              Elf_Internal_Sym *sym)
+write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
 {
-  struct ppc_elf_link_hash_table *htab;
+  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
   struct plt_entry *ent;
   bfd_boolean doneone;
 
-#ifdef DEBUG
-  fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
-          h->root.root.string);
-#endif
-
-  htab = ppc_elf_hash_table (info);
-  BFD_ASSERT (htab->elf.dynobj != NULL);
-
   doneone = FALSE;
   for (ent = h->plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.offset != (bfd_vma) -1)
@@ -10090,10 +10118,10 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                /* Fill in the .plt on VxWorks.  */
                if (bfd_link_pic (info))
                  {
-                   bfd_put_32 (output_bfd,
+                   bfd_put_32 (info->output_bfd,
                                plt_entry[0] | PPC_HA (got_offset),
                                htab->elf.splt->contents + ent->plt.offset + 0);
-                   bfd_put_32 (output_bfd,
+                   bfd_put_32 (info->output_bfd,
                                plt_entry[1] | PPC_LO (got_offset),
                                htab->elf.splt->contents + ent->plt.offset + 4);
                  }
@@ -10101,17 +10129,17 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                  {
                    bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
 
-                   bfd_put_32 (output_bfd,
+                   bfd_put_32 (info->output_bfd,
                                plt_entry[0] | PPC_HA (got_loc),
                                htab->elf.splt->contents + ent->plt.offset + 0);
-                   bfd_put_32 (output_bfd,
+                   bfd_put_32 (info->output_bfd,
                                plt_entry[1] | PPC_LO (got_loc),
                                htab->elf.splt->contents + ent->plt.offset + 4);
                  }
 
-               bfd_put_32 (output_bfd, plt_entry[2],
+               bfd_put_32 (info->output_bfd, plt_entry[2],
                            htab->elf.splt->contents + ent->plt.offset + 8);
-               bfd_put_32 (output_bfd, plt_entry[3],
+               bfd_put_32 (info->output_bfd, plt_entry[3],
                            htab->elf.splt->contents + ent->plt.offset + 12);
 
                /* This instruction is an immediate load.  The value loaded is
@@ -10120,7 +10148,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                   low-order 16 bits of the load instruction.  */
                /* NOTE: It appears that this is now an index rather than a
                   prescaled offset.  */
-               bfd_put_32 (output_bfd,
+               bfd_put_32 (info->output_bfd,
                            plt_entry[4] | reloc_index,
                            htab->elf.splt->contents + ent->plt.offset + 16);
                /* This instruction is a PC-relative branch whose target is
@@ -10129,21 +10157,22 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                   The address is encoded in bits 6-29, inclusive.  The value
                   stored is right-shifted by two bits, permitting a 26-bit
                   offset.  */
-               bfd_put_32 (output_bfd,
+               bfd_put_32 (info->output_bfd,
                            (plt_entry[5]
                             | (-(ent->plt.offset + 20) & 0x03fffffc)),
                            htab->elf.splt->contents + ent->plt.offset + 20);
-               bfd_put_32 (output_bfd, plt_entry[6],
+               bfd_put_32 (info->output_bfd, plt_entry[6],
                            htab->elf.splt->contents + ent->plt.offset + 24);
-               bfd_put_32 (output_bfd, plt_entry[7],
+               bfd_put_32 (info->output_bfd, plt_entry[7],
                            htab->elf.splt->contents + ent->plt.offset + 28);
 
                /* Fill in the GOT entry corresponding to this PLT slot with
                   the address immediately after the "bctr" instruction
                   in this PLT entry.  */
-               bfd_put_32 (output_bfd, (htab->elf.splt->output_section->vma
-                                        + htab->elf.splt->output_offset
-                                        + ent->plt.offset + 16),
+               bfd_put_32 (info->output_bfd,
+                           (htab->elf.splt->output_section->vma
+                            + htab->elf.splt->output_offset
+                            + ent->plt.offset + 16),
                            htab->elf.sgotplt->contents + got_offset);
 
                if (!bfd_link_pic (info))
@@ -10161,7 +10190,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                R_PPC_ADDR16_HA);
                    rela.r_addend = got_offset;
-                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                   bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
                    loc += sizeof (Elf32_External_Rela);
 
                    /* Provide the @l relocation for the second instruction.  */
@@ -10171,7 +10200,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                R_PPC_ADDR16_LO);
                    rela.r_addend = got_offset;
-                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                   bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
                    loc += sizeof (Elf32_External_Rela);
 
                    /* Provide a relocation for the GOT entry corresponding to this
@@ -10182,7 +10211,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                    rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
                                                R_PPC_ADDR32);
                    rela.r_addend = ent->plt.offset + 16;
-                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                   bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
                  }
 
                /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT.
@@ -10217,7 +10246,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                    bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
                                   + htab->glink->output_section->vma
                                   + htab->glink->output_offset);
-                   bfd_put_32 (output_bfd, val,
+                   bfd_put_32 (info->output_bfd, val,
                                splt->contents + ent->plt.offset);
                  }
              }
@@ -10252,44 +10281,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                if (h->type == STT_GNU_IFUNC && is_static_defined (h))
                  htab->maybe_local_ifunc_resolver = 1;
              }
-           bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-
-           if (!h->def_regular)
-             {
-               /* Mark the symbol as undefined, rather than as
-                  defined in the .plt section.  Leave the value if
-                  there were any relocations where pointer equality
-                  matters (this is a clue for the dynamic linker, to
-                  make function pointer comparisons work between an
-                  application and shared library), otherwise set it
-                  to zero.  */
-               sym->st_shndx = SHN_UNDEF;
-               if (!h->pointer_equality_needed)
-                 sym->st_value = 0;
-               else if (!h->ref_regular_nonweak)
-                 {
-                   /* This breaks function pointer comparisons, but
-                      that is better than breaking tests for a NULL
-                      function pointer.  */
-                   sym->st_value = 0;
-                 }
-             }
-           else if (h->type == STT_GNU_IFUNC
-                    && !bfd_link_pic (info))
-             {
-               /* Set the value of ifunc symbols in a non-pie
-                  executable to the glink entry.  This is to avoid
-                  text relocations.  We can't do this for ifunc in
-                  allocate_dynrelocs, as we do for normal dynamic
-                  function symbols with plt entries, because we need
-                  to keep the original value around for the ifunc
-                  relocation.  */
-               sym->st_shndx = (_bfd_elf_section_from_bfd_section
-                                (output_bfd, htab->glink->output_section));
-               sym->st_value = (ent->glink_offset
-                                + htab->glink->output_offset
-                                + htab->glink->output_section->vma);
-             }
+           bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
            doneone = TRUE;
          }
 
@@ -10298,14 +10290,14 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
            || h->dynindx == -1)
          {
            unsigned char *p;
-           asection *splt = htab->elf.splt;
+           asection *plt = htab->elf.splt;
 
            if (!htab->elf.dynamic_sections_created
                || h->dynindx == -1)
-             splt = htab->elf.iplt;
+             plt = htab->elf.iplt;
 
            p = (unsigned char *) htab->glink->contents + ent->glink_offset;
-           write_glink_stub (h, ent, splt, p, info);
+           write_glink_stub (h, ent, plt, p, info);
 
            if (!bfd_link_pic (info))
              /* We only need one non-PIC glink stub.  */
@@ -10314,6 +10306,165 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
        else
          break;
       }
+  return TRUE;
+}
+
+/* Finish up PLT handling.  */
+
+bfd_boolean
+ppc_finish_symbols (struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  bfd *ibfd;
+
+  if (!htab)
+    return TRUE;
+
+  elf_link_hash_traverse (&htab->elf, write_global_sym_plt, info);
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      bfd_vma *local_got, *end_local_got;
+      struct plt_entry **local_plt, **lplt, **end_local_plt;
+      Elf_Internal_Shdr *symtab_hdr;
+      bfd_size_type locsymcount;
+      Elf_Internal_Sym *local_syms = NULL;
+      struct plt_entry *ent;
+
+      if (!is_ppc_elf (ibfd))
+       continue;
+
+      local_got = elf_local_got_offsets (ibfd);
+      if (!local_got)
+       continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_local_got = local_got + locsymcount;
+      local_plt = (struct plt_entry **) end_local_got;
+      end_local_plt = local_plt + locsymcount;
+      for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+       for (ent = *lplt; ent != NULL; ent = ent->next)
+         {
+           if (ent->plt.offset != (bfd_vma) -1)
+             {
+               Elf_Internal_Sym *sym;
+               asection *sym_sec;
+               asection *plt, *relplt;
+               bfd_byte *loc;
+               bfd_vma val;
+               Elf_Internal_Rela rela;
+
+               if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+                               lplt - local_plt, ibfd))
+                 {
+                   if (local_syms != NULL
+                       && symtab_hdr->contents != (unsigned char *) local_syms)
+                     free (local_syms);
+                   return FALSE;
+                 }
+
+               val = sym->st_value;
+               if (sym_sec != NULL && sym_sec->output_section != NULL)
+                 val += sym_sec->output_offset + sym_sec->output_section->vma;
+
+               BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
+
+               htab->local_ifunc_resolver = 1;
+               plt = htab->elf.iplt;
+               relplt = htab->elf.irelplt;
+
+               rela.r_offset = (ent->plt.offset
+                                + plt->output_offset
+                                + plt->output_section->vma);
+               rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+               rela.r_addend = val;
+               loc = relplt->contents + (relplt->reloc_count++
+                                         * sizeof (Elf32_External_Rela));
+               bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
+             }
+           if ((ent->glink_offset & 1) == 0)
+             {
+               unsigned char *p = ((unsigned char *) htab->glink->contents
+                                   + ent->glink_offset);
+
+               write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
+               ent->glink_offset |= 1;
+             }
+         }
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
+       {
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
+       }
+    }
+  return TRUE;
+}
+
+/* Finish up dynamic symbol handling.  We set the contents of various
+   dynamic sections here.  */
+
+static bfd_boolean
+ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
+                              struct bfd_link_info *info,
+                              struct elf_link_hash_entry *h,
+                              Elf_Internal_Sym *sym)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  struct plt_entry *ent;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
+          h->root.root.string);
+#endif
+
+  if (!h->def_regular
+      || (h->type == STT_GNU_IFUNC && !bfd_link_pic (info)))
+    for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+      if (ent->plt.offset != (bfd_vma) -1)
+       {
+         if (!h->def_regular)
+           {
+             /* Mark the symbol as undefined, rather than as
+                defined in the .plt section.  Leave the value if
+                there were any relocations where pointer equality
+                matters (this is a clue for the dynamic linker, to
+                make function pointer comparisons work between an
+                application and shared library), otherwise set it
+                to zero.  */
+             sym->st_shndx = SHN_UNDEF;
+             if (!h->pointer_equality_needed)
+               sym->st_value = 0;
+             else if (!h->ref_regular_nonweak)
+               {
+                 /* This breaks function pointer comparisons, but
+                    that is better than breaking tests for a NULL
+                    function pointer.  */
+                 sym->st_value = 0;
+               }
+           }
+         else
+           {
+             /* Set the value of ifunc symbols in a non-pie
+                executable to the glink entry.  This is to avoid
+                text relocations.  We can't do this for ifunc in
+                allocate_dynrelocs, as we do for normal dynamic
+                function symbols with plt entries, because we need
+                to keep the original value around for the ifunc
+                relocation.  */
+             sym->st_shndx
+               = (_bfd_elf_section_from_bfd_section
+                  (info->output_bfd, htab->glink->output_section));
+             sym->st_value = (ent->glink_offset
+                              + htab->glink->output_offset
+                              + htab->glink->output_section->vma);
+           }
+         break;
+       }
 
   if (h->needs_copy)
     {
index f56d027bf6945f4d7b25fdffc5b1cc940e78ec28..265859bcc134eed9a86879f0fc6fdefdb16fe317 100644 (file)
@@ -63,6 +63,6 @@ int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *);
 asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *);
 bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *);
 void ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *);
-extern bfd_boolean ppc_elf_modify_segment_map (bfd *,
-                          struct bfd_link_info * ATTRIBUTE_UNUSED);
+extern bfd_boolean ppc_elf_modify_segment_map (bfd *, struct bfd_link_info *);
 extern bfd_boolean ppc_elf_section_processing (bfd *, Elf_Internal_Shdr *);
+extern bfd_boolean ppc_finish_symbols (struct bfd_link_info *);
index 835baecdb0640742371117296da9c95b7e2059a2..8291db8d2598f39e40ee92644809f9b4b535afec 100644 (file)
@@ -11158,29 +11158,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       dest += plt->output_offset + plt->output_section->vma;
 
-      if (stub_entry->h == NULL
-         && (stub_entry->plt_ent->plt.offset & 1) == 0)
-       {
-         Elf_Internal_Rela rela;
-         bfd_byte *rl;
-
-         rela.r_offset = dest;
-         if (htab->opd_abi)
-           rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
-         else
-           rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
-         rela.r_addend = (stub_entry->target_value
-                          + stub_entry->target_section->output_offset
-                          + stub_entry->target_section->output_section->vma);
-
-         rl = (htab->elf.irelplt->contents
-               + (htab->elf.irelplt->reloc_count++
-                  * sizeof (Elf64_External_Rela)));
-         bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
-         stub_entry->plt_ent->plt.offset |= 1;
-         htab->local_ifunc_resolver = 1;
-       }
-
       off = (dest
             - elf_gp (info->output_bfd)
             - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
@@ -13016,34 +12993,84 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
 }
 
 /* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to
-   write out any global entry stubs.  */
+   write out any global entry stubs, and PLT relocations.  */
 
 static bfd_boolean
-build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
+build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
-  struct plt_entry *pent;
+  struct plt_entry *ent;
   asection *s;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
+  info = inf;
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
+  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+    if (ent->plt.offset != (bfd_vma) -1)
+      {
+       /* This symbol has an entry in the procedure linkage
+          table.  Set it up.  */
+       Elf_Internal_Rela rela;
+       bfd_byte *loc;
+
+       if (!htab->elf.dynamic_sections_created
+           || h->dynindx == -1)
+         {
+           if (!(h->def_regular
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak)))
+             continue;
+           rela.r_offset = (htab->elf.iplt->output_section->vma
+                            + htab->elf.iplt->output_offset
+                            + ent->plt.offset);
+           if (htab->opd_abi)
+             rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+           else
+             rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+           rela.r_addend = (h->root.u.def.value
+                            + h->root.u.def.section->output_offset
+                            + h->root.u.def.section->output_section->vma
+                            + ent->addend);
+           loc = (htab->elf.irelplt->contents
+                  + (htab->elf.irelplt->reloc_count++
+                     * sizeof (Elf64_External_Rela)));
+           htab->local_ifunc_resolver = 1;
+         }
+       else
+         {
+           rela.r_offset = (htab->elf.splt->output_section->vma
+                            + htab->elf.splt->output_offset
+                            + ent->plt.offset);
+           rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
+           rela.r_addend = ent->addend;
+           loc = (htab->elf.srelplt->contents
+                  + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
+                     / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
+           if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+             htab->maybe_local_ifunc_resolver = 1;
+         }
+       bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+      }
+
   if (!h->pointer_equality_needed)
     return TRUE;
 
   if (h->def_regular)
     return TRUE;
 
-  info = inf;
-  htab = ppc_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-
   s = htab->global_entry;
-  for (pent = h->plt.plist; pent != NULL; pent = pent->next)
-    if (pent->plt.offset != (bfd_vma) -1
-       && pent->addend == 0)
+  if (s == NULL || s->size == 0)
+    return TRUE;
+
+  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+    if (ent->plt.offset != (bfd_vma) -1
+       && ent->addend == 0)
       {
        bfd_byte *p;
        asection *plt;
@@ -13054,7 +13081,7 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
        if (!htab->elf.dynamic_sections_created
            || h->dynindx == -1)
          plt = htab->elf.iplt;
-       off = pent->plt.offset + plt->output_offset + plt->output_section->vma;
+       off = ent->plt.offset + plt->output_offset + plt->output_section->vma;
        off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
 
        if (off + 0x80008000 > 0xffffffff || (off & 3) != 0)
@@ -13108,6 +13135,91 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
+/* Write PLT relocs for locals.  */
+
+static bfd_boolean
+write_plt_relocs_for_local_syms (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      struct got_entry **lgot_ents, **end_lgot_ents;
+      struct plt_entry **local_plt, **lplt, **end_local_plt;
+      Elf_Internal_Shdr *symtab_hdr;
+      bfd_size_type locsymcount;
+      Elf_Internal_Sym *local_syms = NULL;
+      struct plt_entry *ent;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      lgot_ents = elf_local_got_ents (ibfd);
+      if (!lgot_ents)
+       continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_lgot_ents = lgot_ents + locsymcount;
+      local_plt = (struct plt_entry **) end_lgot_ents;
+      end_local_plt = local_plt + locsymcount;
+      for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+       for (ent = *lplt; ent != NULL; ent = ent->next)
+         if (ent->plt.offset != (bfd_vma) -1)
+           {
+             Elf_Internal_Sym *sym;
+             asection *sym_sec;
+             asection *plt, *relplt;
+             bfd_byte *loc;
+             bfd_vma val;
+             Elf_Internal_Rela rela;
+
+             if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+                             lplt - local_plt, ibfd))
+               {
+                 if (local_syms != NULL
+                     && symtab_hdr->contents != (unsigned char *) local_syms)
+                   free (local_syms);
+                 return FALSE;
+               }
+
+             val = sym->st_value + ent->addend;
+             val += PPC64_LOCAL_ENTRY_OFFSET (sym->st_other);
+             if (sym_sec != NULL && sym_sec->output_section != NULL)
+               val += sym_sec->output_offset + sym_sec->output_section->vma;
+
+             BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
+
+             htab->local_ifunc_resolver = 1;
+             plt = htab->elf.iplt;
+             relplt = htab->elf.irelplt;
+
+             rela.r_offset = (ent->plt.offset
+                              + plt->output_offset
+                              + plt->output_section->vma);
+             if (htab->opd_abi)
+               rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+             else
+               rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+             rela.r_addend = val;
+             loc = relplt->contents + (relplt->reloc_count++
+                                       * sizeof (Elf64_External_Rela));
+             bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+           }
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
+       {
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
+       }
+    }
+  return TRUE;
+}
+
 /* Build all the stubs associated with the current output file.
    The stubs are kept in a hash table attached to the main linker
    hash table.  This function is called via gldelf64ppc_finish.  */
@@ -13262,9 +13374,11 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
        }
     }
 
-  /* Build .glink global entry stubs.  */
-  if (htab->global_entry != NULL && htab->global_entry->size != 0)
-    elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
+  /* Build .glink global entry stubs, and PLT relocs for globals.  */
+  elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info);
+
+  if (!write_plt_relocs_for_local_syms (info))
+    return FALSE;
 
   if (htab->brlt != NULL && htab->brlt->size != 0)
     {
@@ -15488,85 +15602,41 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
 {
   struct ppc_link_hash_table *htab;
   struct plt_entry *ent;
-  Elf_Internal_Rela rela;
-  bfd_byte *loc;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
-  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
-    if (ent->plt.offset != (bfd_vma) -1)
-      {
-       /* This symbol has an entry in the procedure linkage
-          table.  Set it up.  */
-       if (!htab->elf.dynamic_sections_created
-           || h->dynindx == -1)
-         {
-           BFD_ASSERT (h->type == STT_GNU_IFUNC
-                       && h->def_regular
-                       && (h->root.type == bfd_link_hash_defined
-                           || h->root.type == bfd_link_hash_defweak));
-           rela.r_offset = (htab->elf.iplt->output_section->vma
-                            + htab->elf.iplt->output_offset
-                            + ent->plt.offset);
-           if (htab->opd_abi)
-             rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
-           else
-             rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
-           rela.r_addend = (h->root.u.def.value
-                            + h->root.u.def.section->output_offset
-                            + h->root.u.def.section->output_section->vma
-                            + ent->addend);
-           loc = (htab->elf.irelplt->contents
-                  + (htab->elf.irelplt->reloc_count++
-                     * sizeof (Elf64_External_Rela)));
-           htab->local_ifunc_resolver = 1;
-         }
-       else
-         {
-           rela.r_offset = (htab->elf.splt->output_section->vma
-                            + htab->elf.splt->output_offset
-                            + ent->plt.offset);
-           rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
-           rela.r_addend = ent->addend;
-           loc = (htab->elf.srelplt->contents
-                  + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
-                     / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
-           if (h->type == STT_GNU_IFUNC && is_static_defined (h))
-             htab->maybe_local_ifunc_resolver = 1;
-         }
-       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
-
-       if (!htab->opd_abi)
-         {
-           if (!h->def_regular)
-             {
-               /* Mark the symbol as undefined, rather than as
-                  defined in glink.  Leave the value if there were
-                  any relocations where pointer equality matters
-                  (this is a clue for the dynamic linker, to make
-                  function pointer comparisons work between an
-                  application and shared library), otherwise set it
-                  to zero.  */
-               sym->st_shndx = SHN_UNDEF;
-               if (!h->pointer_equality_needed)
-                 sym->st_value = 0;
-               else if (!h->ref_regular_nonweak)
-                 {
-                   /* This breaks function pointer comparisons, but
-                      that is better than breaking tests for a NULL
-                      function pointer.  */
-                   sym->st_value = 0;
-                 }
-             }
-         }
-      }
+  if (!htab->opd_abi && !h->def_regular)
+    for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+      if (ent->plt.offset != (bfd_vma) -1)
+       {
+         /* Mark the symbol as undefined, rather than as
+            defined in glink.  Leave the value if there were
+            any relocations where pointer equality matters
+            (this is a clue for the dynamic linker, to make
+            function pointer comparisons work between an
+            application and shared library), otherwise set it
+            to zero.  */
+         sym->st_shndx = SHN_UNDEF;
+         if (!h->pointer_equality_needed)
+           sym->st_value = 0;
+         else if (!h->ref_regular_nonweak)
+           {
+             /* This breaks function pointer comparisons, but
+                that is better than breaking tests for a NULL
+                function pointer.  */
+             sym->st_value = 0;
+           }
+         break;
+       }
 
   if (h->needs_copy)
     {
       /* This symbol needs a copy reloc.  Set it up.  */
+      Elf_Internal_Rela rela;
       asection *srel;
+      bfd_byte *loc;
 
       if (h->dynindx == -1
          || (h->root.type != bfd_link_hash_defined
index b2fd135a52afb4e1dbb5ed04c79b2ebdd2395b15..4e697a3b6385b60b54c2b8170e1dd9024482081c 100644 (file)
@@ -1,3 +1,7 @@
+2018-04-09  Alan Modra  <amodra@gmail.com>
+
+       * ppc32elf.em (ppc_finish): Call ppc_finish_symbols.
+
 2018-04-05  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/22318
index 3c335b7412ff096fd0f76f0766014c2652f703bf..05a2894e2b93cac16376389f005bcc7579b90215 100644 (file)
@@ -212,6 +212,8 @@ ppc_finish (void)
 {
   if (params.ppc476_workaround)
     lang_for_each_statement (no_zero_padding);
+  if (!ppc_finish_symbols (&link_info))
+    einfo (_("%X%P: ppc_finish_symbols problem %E\n"));
   finish_default ();
 }