Support PLT16 relocs against local symbols
authorAlan Modra <amodra@gmail.com>
Sun, 8 Apr 2018 23:52:53 +0000 (09:22 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 9 Apr 2018 07:35:09 +0000 (17:05 +0930)
Necessary if gcc is to use PLT16 relocs to implement -mlongcall, and
there isn't a good technical reason why local symbols should be
excluded from PLT16 support.  Non-ifunc local symbol PLT entries go in
a separate section to other PLT entries.  In a fixed position
executable they won't need to be relocated, and in a PIE or shared
library I chose to not implement lazy relocation.

bfd/
* elf64-ppc.c (LOCAL_PLT_ENTRY_SIZE): Define.
(struct ppc_stub_hash_entry): Add symtype field.
(PLT_KEEP): Define.
(struct ppc_link_hash_table): Add pltlocal and relpltlocal.
(create_linkage_sections): Create pltlocal and relpltlocal.
(ppc64_elf_check_relocs): Allow PLT relocs on local symbols.
Set PLT_KEEP.
(ppc64_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls.
(allocate_dynrelocs): Allocate pltlocal and relpltlocal.
(ppc64_elf_size_dynamic_sections): Size pltlocal and relpltlocal.
Keep PLT entries for inline calls against locals.
(ppc_build_one_stub): Use pltlocal as appropriate.
(ppc_size_one_stub): Likewise.
(ppc64_elf_size_stubs): Set symtype.
(build_global_entry_stubs_and_plt): Init pltlocal and write
relpltlocal for globals.
(write_plt_relocs_for_local_syms): Likewise for local syms.
(ppc64_elf_relocate_section): Support PLT for local syms.
* elf32-ppc.c (PLT_KEEP): Define.
(struct ppc_elf_link_hash_table): Add pltlocal and relpltlocal.
(ppc_elf_create_glink): Create pltlocal and relpltlocal.
(ppc_elf_check_relocs): Allow PLT relocs on local symbols.
Set PLT_KEEP.  Adjust update_local_sym_info call.
(ppc_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls.
(allocate_dynrelocs): Allocate pltlocal and relpltlocal.
(ppc_elf_size_dynamic_sections): Size pltlocal and relpltlocal.
(ppc_elf_relocate_section): Support PLT16 relocs for local syms.
(write_global_sym_plt): Init pltlocal and write relpltlocal.
(ppc_finish_symbols): Likewise for locals.
ld/
* emulparams/elf32ppc.sh (OTHER_RELRO_SECTIONS_2): Add .branch_lt.
(OTHER_GOT_RELOC_SECTIONS): Add .rela.branch_lt.
* testsuite/ld-powerpc/elfv2so.d: Update for symbol/stub reordering.
* testsuite/ld-powerpc/relbrlt.d: Likewise.
* testsuite/ld-powerpc/relbrlt.s: Likewise.
* testsuite/ld-powerpc/tlsso.r: Likewise.
* testsuite/ld-powerpc/tlstocso.r: Likewise.
gold/
* powerpc.cc (Target_powerpc::lplt_): New variable.
(Target_powerpc::lplt_section): Associated accessor.
(Target_powerpc::plt_off): Handle local non-ifunc symbols.
(Target_powerpc::make_lplt_section): New function.
(Target_powerpc::make_local_plt_entry): New function.
(Powerpc_relobj::do_relocate_sections): Write out lplt.
(Output_data_plt_powerpc::first_plt_entry_offset): Zero for lplt.
(Output_data_plt_powerpc::add_local_entry): New function.
(Output_data_plt_powerpc::do_write): Ignore lplt.
(Target_powerpc::make_iplt_section): Make lplt first.
(Target_powerpc::make_brlt_section): Make .branch_lt relro.
(Target_powerpc::Scan::local): Handle PLT16 relocs.

12 files changed:
bfd/ChangeLog
bfd/elf32-ppc.c
bfd/elf64-ppc.c
gold/ChangeLog
gold/powerpc.cc
ld/ChangeLog
ld/emulparams/elf32ppc.sh
ld/testsuite/ld-powerpc/elfv2so.d
ld/testsuite/ld-powerpc/relbrlt.d
ld/testsuite/ld-powerpc/relbrlt.s
ld/testsuite/ld-powerpc/tlsso.r
ld/testsuite/ld-powerpc/tlstocso.r

index f6388c1..099d106 100644 (file)
@@ -1,5 +1,37 @@
 2018-04-09  Alan Modra  <amodra@gmail.com>
 
+       * elf64-ppc.c (LOCAL_PLT_ENTRY_SIZE): Define.
+       (struct ppc_stub_hash_entry): Add symtype field.
+       (PLT_KEEP): Define.
+       (struct ppc_link_hash_table): Add pltlocal and relpltlocal.
+       (create_linkage_sections): Create pltlocal and relpltlocal.
+       (ppc64_elf_check_relocs): Allow PLT relocs on local symbols.
+       Set PLT_KEEP.
+       (ppc64_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls.
+       (allocate_dynrelocs): Allocate pltlocal and relpltlocal.
+       (ppc64_elf_size_dynamic_sections): Size pltlocal and relpltlocal.
+       Keep PLT entries for inline calls against locals.
+       (ppc_build_one_stub): Use pltlocal as appropriate.
+       (ppc_size_one_stub): Likewise.
+       (ppc64_elf_size_stubs): Set symtype.
+       (build_global_entry_stubs_and_plt): Init pltlocal and write
+       relpltlocal for globals.
+       (write_plt_relocs_for_local_syms): Likewise for local syms.
+       (ppc64_elf_relocate_section): Support PLT for local syms.
+       * elf32-ppc.c (PLT_KEEP): Define.
+       (struct ppc_elf_link_hash_table): Add pltlocal and relpltlocal.
+       (ppc_elf_create_glink): Create pltlocal and relpltlocal.
+       (ppc_elf_check_relocs): Allow PLT relocs on local symbols.
+       Set PLT_KEEP.  Adjust update_local_sym_info call.
+       (ppc_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls.
+       (allocate_dynrelocs): Allocate pltlocal and relpltlocal.
+       (ppc_elf_size_dynamic_sections): Size pltlocal and relpltlocal.
+       (ppc_elf_relocate_section): Support PLT16 relocs for local syms.
+       (write_global_sym_plt): Init pltlocal and write relpltlocal.
+       (ppc_finish_symbols): Likewise for locals.
+
+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.
index d24b095..5da7230 100644 (file)
@@ -3248,6 +3248,7 @@ struct ppc_elf_link_hash_entry
   /* The above field is also used to mark function symbols.  In which
      case TLS_TLS will be 0.  */
 #define PLT_IFUNC       2      /* STT_GNU_IFUNC.  */
+#define PLT_KEEP        4      /* inline plt call requires plt entry.  */
 #define NON_GOT        256     /* local symbol plt, not stored.  */
 
   /* Nonzero if we have seen a small data relocation referring to this
@@ -3277,6 +3278,8 @@ struct ppc_elf_link_hash_table
   elf_linker_section_t sdata[2];
   asection *sbss;
   asection *glink_eh_frame;
+  asection *pltlocal;
+  asection *relpltlocal;
 
   /* The (unloaded but important) .rela.plt.unloaded on VxWorks.  */
   asection *srelplt2;
@@ -3526,6 +3529,26 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
       || ! bfd_set_section_alignment (abfd, s, 2))
     return FALSE;
 
+  /* Local plt entries.  */
+  flags = (SEC_ALLOC | SEC_LOAD
+          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->pltlocal = bfd_make_section_anyway_with_flags (abfd, ".branch_lt",
+                                                      flags);
+  if (htab->pltlocal == NULL
+      || ! bfd_set_section_alignment (abfd, htab->pltlocal, 2))
+    return FALSE;
+
+  if (bfd_link_pic (info))
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+              | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      htab->relpltlocal
+       = bfd_make_section_anyway_with_flags (abfd, ".rela.branch_lt", flags);
+      if (htab->relpltlocal == NULL
+         || ! bfd_set_section_alignment (abfd, htab->relpltlocal, 2))
+       return FALSE;
+    }
+
   if (!ppc_elf_create_linker_section (abfd, info, 0,
                                      &htab->sdata[0]))
     return FALSE;
@@ -4008,6 +4031,8 @@ ppc_elf_check_relocs (bfd *abfd,
       struct elf_link_hash_entry *h;
       int tls_type;
       struct plt_entry **ifunc;
+      struct plt_entry **pltent;
+      bfd_vma addend;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -4061,7 +4086,7 @@ ppc_elf_check_relocs (bfd *abfd,
                  || r_type == R_PPC_PLT16_HI
                  || r_type == R_PPC_PLT16_HA)
                {
-                 bfd_vma addend = 0;
+                 addend = 0;
                  if (r_type == R_PPC_PLTREL24)
                    ppc_elf_tdata (abfd)->makes_plt_call = 1;
                  if (bfd_link_pic (info)
@@ -4296,33 +4321,27 @@ ppc_elf_check_relocs (bfd *abfd,
          /* This symbol requires a procedure linkage table entry.  */
          if (h == NULL)
            {
-             if (ifunc == NULL)
-               {
-                 /* It does not make sense to have a procedure linkage
-                    table entry for a non-ifunc local symbol.  */
-                 info->callbacks->einfo
-                   /* xgettext:c-format */
-                   (_("%H: %s reloc against local symbol\n"),
-                    abfd, sec, rel->r_offset,
-                    ppc_elf_howto_table[r_type]->name);
-                 bfd_set_error (bfd_error_bad_value);
-                 return FALSE;
-               }
+             pltent = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                             NON_GOT | PLT_KEEP);
+             if (pltent == NULL)
+               return FALSE;
            }
          else
            {
-             bfd_vma addend = 0;
-
-             if (bfd_link_pic (info)
-                 && (r_type == R_PPC_PLTREL24
-                     || r_type == R_PPC_PLT16_LO
-                     || r_type == R_PPC_PLT16_HI
-                     || r_type == R_PPC_PLT16_HA))
-               addend = rel->r_addend;
+             if (r_type != R_PPC_PLTREL24)
+               ppc_elf_hash_entry (h)->tls_mask |= PLT_KEEP;
              h->needs_plt = 1;
-             if (!update_plt_info (abfd, &h->plt.plist, got2, addend))
-               return FALSE;
+             pltent = &h->plt.plist;
            }
+         addend = 0;
+         if (bfd_link_pic (info)
+             && (r_type == R_PPC_PLTREL24
+                 || r_type == R_PPC_PLT16_LO
+                 || r_type == R_PPC_PLT16_HI
+                 || r_type == R_PPC_PLT16_HA))
+           addend = rel->r_addend;
+         if (!update_plt_info (abfd, pltent, got2, addend))
+           return FALSE;
          break;
 
          /* The following relocations don't need to propagate the
@@ -5617,7 +5636,10 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        if (ent->plt.refcount > 0)
          break;
       if (ent == NULL
-         || (h->type != STT_GNU_IFUNC && local))
+         || (h->type != STT_GNU_IFUNC
+             && local
+             && ((ppc_elf_hash_entry (h)->tls_mask & (TLS_TLS | PLT_KEEP))
+                 != PLT_KEEP)))
        {
          /* A PLT entry is not required/allowed when:
 
@@ -6103,13 +6125,25 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       sreloc->size += p->count * sizeof (Elf32_External_Rela);
     }
 
-  /* Handle PLT relocs.  Done last, after dynindx has settled.  */
+  /* Handle PLT relocs.  Done last, after dynindx has settled.
+     We might need a PLT entry when the symbol
+     a) is dynamic, or
+     b) is an ifunc, or
+     c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or
+     d) has plt16 relocs and we are linking statically.  */
   dyn = htab->elf.dynamic_sections_created && h->dynindx != -1;
-  if (dyn || h->type == STT_GNU_IFUNC)
+  if (dyn
+      || h->type == STT_GNU_IFUNC
+      || (h->needs_plt && h->dynamic_adjusted)
+      || (h->needs_plt
+         && h->def_regular
+         && !htab->elf.dynamic_sections_created
+         && (ppc_elf_hash_entry (h)->tls_mask
+             & (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
     {
       struct plt_entry *ent;
       bfd_boolean doneone = FALSE;
-      bfd_vma plt_offset = 0, glink_offset = 0;
+      bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1;
 
       for (ent = h->plt.plist; ent != NULL; ent = ent->next)
        if (ent->plt.refcount > 0)
@@ -6117,7 +6151,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            asection *s = htab->elf.splt;
 
            if (!dyn)
-             s = htab->elf.iplt;
+             {
+               if (h->type == STT_GNU_IFUNC)
+                 s = htab->elf.iplt;
+               else
+                 s = htab->pltlocal;
+             }
 
            if (htab->plt_type == PLT_NEW || !dyn)
              {
@@ -6128,25 +6167,30 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                  }
                ent->plt.offset = plt_offset;
 
-               s = htab->glink;
-               if (!doneone || bfd_link_pic (info))
-                 {
-                   glink_offset = s->size;
-                   s->size += GLINK_ENTRY_SIZE (htab, h);
-                 }
-               if (!doneone
-                   && !bfd_link_pic (info)
-                   && h->def_dynamic
-                   && !h->def_regular)
+               if (s == htab->pltlocal)
+                 ent->glink_offset = glink_offset;
+               else
                  {
-                   h->root.u.def.section = s;
-                   h->root.u.def.value = glink_offset;
-                 }
-               ent->glink_offset = glink_offset;
+                   s = htab->glink;
+                   if (!doneone || bfd_link_pic (info))
+                     {
+                       glink_offset = s->size;
+                       s->size += GLINK_ENTRY_SIZE (htab, h);
+                     }
+                   if (!doneone
+                       && !bfd_link_pic (info)
+                       && h->def_dynamic
+                       && !h->def_regular)
+                     {
+                       h->root.u.def.section = s;
+                       h->root.u.def.value = glink_offset;
+                     }
+                   ent->glink_offset = glink_offset;
 
-               if (htab->params->emit_stub_syms
-                   && !add_stub_sym (ent, h, info))
-                 return FALSE;
+                   if (htab->params->emit_stub_syms
+                       && !add_stub_sym (ent, h, info))
+                     return FALSE;
+                 }
              }
            else
              {
@@ -6199,7 +6243,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            if (!doneone)
              {
                if (!dyn)
-                 htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
+                 {
+                   if (h->type == STT_GNU_IFUNC)
+                     {
+                       s = htab->elf.irelplt;
+                       s->size += sizeof (Elf32_External_Rela);
+                     }
+                   else if (bfd_link_pic (info))
+                     {
+                       s = htab->relpltlocal;
+                       s->size += sizeof (Elf32_External_Rela);
+                     }
+                 }
                else
                  {
                    htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
@@ -6425,16 +6480,25 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
        continue;
 
       /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
-      for (; local_plt < end_local_plt; ++local_plt)
+      lgot_masks = (char *) end_local_plt;
+      for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks)
        {
          struct plt_entry *ent;
          bfd_boolean doneone = FALSE;
-         bfd_vma plt_offset = 0, glink_offset = 0;
+         bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1;
 
          for (ent = *local_plt; ent != NULL; ent = ent->next)
            if (ent->plt.refcount > 0)
              {
-               s = htab->elf.iplt;
+               if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+                 s = htab->elf.iplt;
+               else if ((*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)
+                 {
+                   ent->plt.offset = (bfd_vma) -1;
+                   continue;
+                 }
+               else
+                 s = htab->pltlocal;
 
                if (!doneone)
                  {
@@ -6443,9 +6507,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                  }
                ent->plt.offset = plt_offset;
 
-               s = htab->glink;
-               if (!doneone || bfd_link_pic (info))
+               if (s != htab->pltlocal && (!doneone || bfd_link_pic (info)))
                  {
+                   s = htab->glink;
                    glink_offset = s->size;
                    s->size += GLINK_ENTRY_SIZE (htab, NULL);
                  }
@@ -6453,7 +6517,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 
                if (!doneone)
                  {
-                   htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
+                   if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+                     {
+                       s = htab->elf.irelplt;
+                       s->size += sizeof (Elf32_External_Rela);
+                     }
+                   else if (bfd_link_pic (info))
+                     {
+                       s = htab->relpltlocal;
+                       s->size += sizeof (Elf32_External_Rela);
+                     }
                    doneone = TRUE;
                  }
              }
@@ -6599,6 +6672,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
             comment below.  */
        }
       else if (s == htab->elf.iplt
+              || s == htab->pltlocal
               || s == htab->glink
               || s == htab->glink_eh_frame
               || s == htab->elf.sgotplt
@@ -9173,9 +9247,18 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HA:
-         plt_list = ifunc;
+         plt_list = NULL;
          if (h != NULL)
            plt_list = &h->plt.plist;
+         else if (ifunc != NULL)
+           plt_list = ifunc;
+         else if (local_got_offsets != NULL)
+           {
+             struct plt_entry **local_plt;
+             local_plt = (struct plt_entry **) (local_got_offsets
+                                                + symtab_hdr->sh_info);
+             plt_list = local_plt + r_symndx;
+           }
          unresolved_reloc = TRUE;
          if (plt_list != NULL)
            {
@@ -9183,11 +9266,23 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
              ent = find_plt_ent (plt_list, got2,
                                  bfd_link_pic (info) ? addend : 0);
-             if (ent != NULL)
+             if (ent != NULL && ent->plt.offset != (bfd_vma) -1)
                {
+                 asection *plt;
+
                  unresolved_reloc = FALSE;
-                 relocation = (htab->elf.splt->output_section->vma
-                               + htab->elf.splt->output_offset
+                 plt = htab->elf.splt;
+                 if (!htab->elf.dynamic_sections_created
+                     || h == NULL
+                     || h->dynindx == -1)
+                   {
+                     if (ifunc != NULL)
+                       plt = htab->elf.iplt;
+                     else
+                       plt = htab->pltlocal;
+                   }
+                 relocation = (plt->output_section->vma
+                               + plt->output_offset
                                + ent->plt.offset);
                  if (bfd_link_pic (info))
                    {
@@ -10085,6 +10180,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
            Elf_Internal_Rela rela;
            bfd_byte *loc;
            bfd_vma reloc_index;
+           asection *plt = htab->elf.splt;
+           asection *relplt = htab->elf.srelplt;
 
            if (htab->plt_type == PLT_NEW
                || !htab->elf.dynamic_sections_created
@@ -10120,10 +10217,10 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
                  {
                    bfd_put_32 (info->output_bfd,
                                plt_entry[0] | PPC_HA (got_offset),
-                               htab->elf.splt->contents + ent->plt.offset + 0);
+                               plt->contents + ent->plt.offset + 0);
                    bfd_put_32 (info->output_bfd,
                                plt_entry[1] | PPC_LO (got_offset),
-                               htab->elf.splt->contents + ent->plt.offset + 4);
+                               plt->contents + ent->plt.offset + 4);
                  }
                else
                  {
@@ -10131,16 +10228,16 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
 
                    bfd_put_32 (info->output_bfd,
                                plt_entry[0] | PPC_HA (got_loc),
-                               htab->elf.splt->contents + ent->plt.offset + 0);
+                               plt->contents + ent->plt.offset + 0);
                    bfd_put_32 (info->output_bfd,
                                plt_entry[1] | PPC_LO (got_loc),
-                               htab->elf.splt->contents + ent->plt.offset + 4);
+                               plt->contents + ent->plt.offset + 4);
                  }
 
                bfd_put_32 (info->output_bfd, plt_entry[2],
-                           htab->elf.splt->contents + ent->plt.offset + 8);
+                           plt->contents + ent->plt.offset + 8);
                bfd_put_32 (info->output_bfd, plt_entry[3],
-                           htab->elf.splt->contents + ent->plt.offset + 12);
+                           plt->contents + ent->plt.offset + 12);
 
                /* This instruction is an immediate load.  The value loaded is
                   the byte offset of the R_PPC_JMP_SLOT relocation from the
@@ -10150,7 +10247,7 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
                   prescaled offset.  */
                bfd_put_32 (info->output_bfd,
                            plt_entry[4] | reloc_index,
-                           htab->elf.splt->contents + ent->plt.offset + 16);
+                           plt->contents + ent->plt.offset + 16);
                /* This instruction is a PC-relative branch whose target is
                   the start of the PLT section.  The address of this branch
                   instruction is 20 bytes beyond the start of this PLT entry.
@@ -10160,19 +10257,18 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
                bfd_put_32 (info->output_bfd,
                            (plt_entry[5]
                             | (-(ent->plt.offset + 20) & 0x03fffffc)),
-                           htab->elf.splt->contents + ent->plt.offset + 20);
+                           plt->contents + ent->plt.offset + 20);
                bfd_put_32 (info->output_bfd, plt_entry[6],
-                           htab->elf.splt->contents + ent->plt.offset + 24);
+                           plt->contents + ent->plt.offset + 24);
                bfd_put_32 (info->output_bfd, plt_entry[7],
-                           htab->elf.splt->contents + ent->plt.offset + 28);
+                           plt->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 (info->output_bfd,
-                           (htab->elf.splt->output_section->vma
-                            + htab->elf.splt->output_offset
-                            + ent->plt.offset + 16),
+               bfd_put_32 (info->output_bfd, (plt->output_section->vma
+                                              + plt->output_offset
+                                              + ent->plt.offset + 16),
                            htab->elf.sgotplt->contents + got_offset);
 
                if (!bfd_link_pic (info))
@@ -10184,8 +10280,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
                         * sizeof (Elf32_External_Rela));
 
                    /* Provide the @ha relocation for the first instruction.  */
-                   rela.r_offset = (htab->elf.splt->output_section->vma
-                                    + htab->elf.splt->output_offset
+                   rela.r_offset = (plt->output_section->vma
+                                    + plt->output_offset
                                     + ent->plt.offset + 2);
                    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                R_PPC_ADDR16_HA);
@@ -10194,8 +10290,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
                    loc += sizeof (Elf32_External_Rela);
 
                    /* Provide the @l relocation for the second instruction.  */
-                   rela.r_offset = (htab->elf.splt->output_section->vma
-                                    + htab->elf.splt->output_offset
+                   rela.r_offset = (plt->output_section->vma
+                                    + plt->output_offset
                                     + ent->plt.offset + 6);
                    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                R_PPC_ADDR16_LO);
@@ -10222,66 +10318,83 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
                rela.r_offset = (htab->elf.sgotplt->output_section->vma
                                 + htab->elf.sgotplt->output_offset
                                 + got_offset);
-
+               rela.r_addend = 0;
              }
            else
              {
-               asection *splt = htab->elf.splt;
+               rela.r_addend = 0;
                if (!htab->elf.dynamic_sections_created
                    || h->dynindx == -1)
-                 splt = htab->elf.iplt;
+                 {
+                   if (h->type == STT_GNU_IFUNC)
+                     {
+                       plt = htab->elf.iplt;
+                       relplt = htab->elf.irelplt;
+                     }
+                   else
+                     {
+                       plt = htab->pltlocal;
+                       relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+                     }
+                   if (h->def_regular
+                       && (h->root.type == bfd_link_hash_defined
+                           || h->root.type == bfd_link_hash_defweak))
+                     rela.r_addend = SYM_VAL (h);
+                 }
 
-               rela.r_offset = (splt->output_section->vma
-                                + splt->output_offset
-                                + ent->plt.offset);
-               if (htab->plt_type == PLT_OLD
-                   || !htab->elf.dynamic_sections_created
-                   || h->dynindx == -1)
+               if (relplt == NULL)
                  {
-                   /* We don't need to fill in the .plt.  The ppc dynamic
-                      linker will fill it in.  */
+                   loc = plt->contents + ent->plt.offset;
+                   bfd_put_32 (info->output_bfd, rela.r_addend, loc);
                  }
                else
                  {
-                   bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
-                                  + htab->glink->output_section->vma
-                                  + htab->glink->output_offset);
-                   bfd_put_32 (info->output_bfd, val,
-                               splt->contents + ent->plt.offset);
+                   rela.r_offset = (plt->output_section->vma
+                                    + plt->output_offset
+                                    + ent->plt.offset);
+
+                   if (htab->plt_type == PLT_OLD
+                       || !htab->elf.dynamic_sections_created
+                       || h->dynindx == -1)
+                     {
+                       /* We don't need to fill in the .plt.  The ppc dynamic
+                          linker will fill it in.  */
+                     }
+                   else
+                     {
+                       bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
+                                      + htab->glink->output_section->vma
+                                      + htab->glink->output_offset);
+                       bfd_put_32 (info->output_bfd, val,
+                                   plt->contents + ent->plt.offset);
+                     }
                  }
              }
 
-           /* Fill in the entry in the .rela.plt section.  */
-           rela.r_addend = 0;
-           if (!htab->elf.dynamic_sections_created
-               || h->dynindx == -1)
+           if (relplt != NULL)
              {
-               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_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
-               rela.r_addend = SYM_VAL (h);
-             }
-           else
-             rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
-
-           if (!htab->elf.dynamic_sections_created
-               || h->dynindx == -1)
-             {
-               loc = (htab->elf.irelplt->contents
-                      + (htab->elf.irelplt->reloc_count++
-                         * sizeof (Elf32_External_Rela)));
-               htab->local_ifunc_resolver = 1;
-             }
-           else
-             {
-               loc = (htab->elf.srelplt->contents
-                      + reloc_index * sizeof (Elf32_External_Rela));
-               if (h->type == STT_GNU_IFUNC && is_static_defined (h))
-                 htab->maybe_local_ifunc_resolver = 1;
+               /* Fill in the entry in the .rela.plt section.  */
+               if (!htab->elf.dynamic_sections_created
+                   || h->dynindx == -1)
+                 {
+                   if (h->type == STT_GNU_IFUNC)
+                     rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+                   else
+                     rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+                   loc = relplt->contents + (relplt->reloc_count++
+                                             * sizeof (Elf32_External_Rela));
+                   htab->local_ifunc_resolver = 1;
+                 }
+               else
+                 {
+                   rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
+                   loc = relplt->contents + (reloc_index
+                                             * sizeof (Elf32_External_Rela));
+                   if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+                     htab->maybe_local_ifunc_resolver = 1;
+                 }
+               bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
              }
-           bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
            doneone = TRUE;
          }
 
@@ -10294,7 +10407,12 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
 
            if (!htab->elf.dynamic_sections_created
                || h->dynindx == -1)
-             plt = htab->elf.iplt;
+             {
+               if (h->type == STT_GNU_IFUNC)
+                 plt = htab->elf.iplt;
+               else
+                 break;
+             }
 
            p = (unsigned char *) htab->glink->contents + ent->glink_offset;
            write_glink_stub (h, ent, plt, p, info);
@@ -10368,16 +10486,32 @@ ppc_finish_symbols (struct bfd_link_info *info)
                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;
+               if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                 {
+                   htab->local_ifunc_resolver = 1;
+                   plt = htab->elf.iplt;
+                   relplt = htab->elf.irelplt;
+                   rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+                 }
+               else
+                 {
+                   plt = htab->pltlocal;
+                   if (bfd_link_pic (info))
+                     {
+                       relplt = htab->relpltlocal;
+                       rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+                     }
+                   else
+                     {
+                       loc = plt->contents + ent->plt.offset;
+                       bfd_put_32 (info->output_bfd, val, loc);
+                       continue;
+                     }
+                 }
 
                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));
index 8291db8..4ea6a9e 100644 (file)
@@ -129,6 +129,7 @@ static bfd_vma opd_entry_value
 
 /* The size in bytes of an entry in the procedure linkage table.  */
 #define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8)
+#define LOCAL_PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 16 : 8)
 
 /* The initial size of the plt reserved for the dynamic linker.  */
 #define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16)
@@ -3977,6 +3978,9 @@ struct ppc_stub_hash_entry {
   struct ppc_link_hash_entry *h;
   struct plt_entry *plt_ent;
 
+  /* Symbol type.  */
+  unsigned char symtype;
+
   /* Symbol st_other.  */
   unsigned char other;
 };
@@ -4068,6 +4072,7 @@ struct ppc_link_hash_entry
   /* The above field is also used to mark function symbols.  In which
      case TLS_TLS will be 0.  */
 #define PLT_IFUNC       2      /* STT_GNU_IFUNC.  */
+#define PLT_KEEP        4      /* inline plt call requires plt entry.  */
 #define NON_GOT        256     /* local symbol plt, not stored.  */
 };
 
@@ -4124,6 +4129,8 @@ struct ppc_link_hash_table
   asection *glink;
   asection *global_entry;
   asection *sfpr;
+  asection *pltlocal;
+  asection *relpltlocal;
   asection *brlt;
   asection *relbrlt;
   asection *glink_eh_frame;
@@ -4505,18 +4512,31 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
       || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
     return FALSE;
 
+  /* Local plt entries, put in .branch_lt but a separate section for
+     convenience.  */
+  htab->pltlocal = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
+                                                      flags);
+  if (htab->pltlocal == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->pltlocal, 3))
+    return FALSE;
+
   if (!bfd_link_pic (info))
     return TRUE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
-                                                     ".rela.branch_lt",
-                                                     flags);
+  htab->relbrlt
+    = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
   if (htab->relbrlt == NULL
       || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
     return FALSE;
 
+  htab->relpltlocal
+    = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
+  if (htab->relpltlocal == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->relpltlocal, 3))
+    return FALSE;
+
   return TRUE;
 }
 
@@ -5634,20 +5654,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              if (h->root.root.string[0] == '.'
                  && h->root.root.string[1] != '\0')
                ((struct ppc_link_hash_entry *) h)->is_func = 1;
+             ((struct ppc_link_hash_entry *) h)->tls_mask |= PLT_KEEP;
              plt_list = &h->plt.plist;
            }
          if (plt_list == NULL)
-           {
-             /* It does not make sense to have a procedure linkage
-                table entry for a non-ifunc local symbol.  */
-             info->callbacks->einfo
-               /* xgettext:c-format */
-               (_("%H: %s reloc against local symbol\n"),
-                abfd, sec, rel->r_offset,
-                ppc64_elf_howto_table[r_type]->name);
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
-           }
+           plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                             rel->r_addend,
+                                             NON_GOT | PLT_KEEP);
          if (!update_plt_info (abfd, plt_list, rel->r_addend))
            return FALSE;
          break;
@@ -7201,7 +7214,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        if (ent->plt.refcount > 0)
          break;
       if (ent == NULL
-         || (h->type != STT_GNU_IFUNC && local))
+         || (h->type != STT_GNU_IFUNC
+             && local
+             && (((struct ppc_link_hash_entry *) h)->tls_mask
+                 & (TLS_TLS | PLT_KEEP)) != PLT_KEEP))
        {
          h->plt.plist = NULL;
          h->needs_plt = 0;
@@ -9822,9 +9838,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        }
     }
 
-  if ((htab->elf.dynamic_sections_created
-       && h->dynindx != -1)
-      || h->type == STT_GNU_IFUNC)
+  /* We might need a PLT entry when the symbol
+     a) is dynamic, or
+     b) is an ifunc, or
+     c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or
+     d) has plt16 relocs and we are linking statically.  */
+  if ((htab->elf.dynamic_sections_created && h->dynindx != -1)
+      || h->type == STT_GNU_IFUNC
+      || (h->needs_plt && h->dynamic_adjusted)
+      || (h->needs_plt
+         && h->def_regular
+         && !htab->elf.dynamic_sections_created
+         && (((struct ppc_link_hash_entry *) h)->tls_mask
+             & (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
     {
       struct plt_entry *pent;
       bfd_boolean doneone = FALSE;
@@ -9834,10 +9860,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            if (!htab->elf.dynamic_sections_created
                || h->dynindx == -1)
              {
-               s = htab->elf.iplt;
-               pent->plt.offset = s->size;
-               s->size += PLT_ENTRY_SIZE (htab);
-               s = htab->elf.irelplt;
+               if (h->type == STT_GNU_IFUNC)
+                 {
+                   s = htab->elf.iplt;
+                   pent->plt.offset = s->size;
+                   s->size += PLT_ENTRY_SIZE (htab);
+                   s = htab->elf.irelplt;
+                 }
+               else
+                 {
+                   s = htab->pltlocal;
+                   pent->plt.offset = s->size;
+                   s->size += LOCAL_PLT_ENTRY_SIZE (htab);
+                   s = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+                 }
              }
            else
              {
@@ -9869,7 +9905,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                /* We also need to make an entry in the .rela.plt section.  */
                s = htab->elf.srelplt;
              }
-           s->size += sizeof (Elf64_External_Rela);
+           if (s != NULL)
+             s->size += sizeof (Elf64_External_Rela);
            doneone = TRUE;
          }
        else
@@ -10124,19 +10161,32 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
              *pent = ent->next;
        }
 
-      /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
-      for (; local_plt < end_local_plt; ++local_plt)
+      /* Allocate space for plt calls to local syms.  */
+      lgot_masks = (unsigned char *) end_local_plt;
+      for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks)
        {
          struct plt_entry *ent;
 
          for (ent = *local_plt; ent != NULL; ent = ent->next)
            if (ent->plt.refcount > 0)
              {
-               s = htab->elf.iplt;
-               ent->plt.offset = s->size;
-               s->size += PLT_ENTRY_SIZE (htab);
-
-               htab->elf.irelplt->size += sizeof (Elf64_External_Rela);
+               if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+                 {
+                   s = htab->elf.iplt;
+                   ent->plt.offset = s->size;
+                   s->size += PLT_ENTRY_SIZE (htab);
+                   htab->elf.irelplt->size += sizeof (Elf64_External_Rela);
+                 }
+               else if ((*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)
+                 ent->plt.offset = (bfd_vma) -1;
+               else
+                 {
+                   s = htab->pltlocal;
+                   ent->plt.offset = s->size;
+                   s->size += LOCAL_PLT_ENTRY_SIZE (htab);
+                   if (bfd_link_pic (info))
+                     htab->relpltlocal->size += sizeof (Elf64_External_Rela);
+                 }
              }
            else
              ent->plt.offset = (bfd_vma) -1;
@@ -10199,6 +10249,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
       else if (s == htab->elf.sgot
               || s == htab->elf.splt
               || s == htab->elf.iplt
+              || s == htab->pltlocal
               || s == htab->glink
               || s == htab->global_entry
               || s == htab->elf.sdynbss
@@ -11154,7 +11205,12 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (!htab->elf.dynamic_sections_created
          || stub_entry->h == NULL
          || stub_entry->h->elf.dynindx == -1)
-       plt = htab->elf.iplt;
+       {
+         if (stub_entry->symtype == STT_GNU_IFUNC)
+           plt = htab->elf.iplt;
+         else
+           plt = htab->pltlocal;
+       }
 
       dest += plt->output_offset + plt->output_section->vma;
 
@@ -11303,7 +11359,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (!htab->elf.dynamic_sections_created
          || stub_entry->h == NULL
          || stub_entry->h->elf.dynindx == -1)
-       plt = htab->elf.iplt;
+       {
+         if (stub_entry->symtype == STT_GNU_IFUNC)
+           plt = htab->elf.iplt;
+         else
+           plt = htab->pltlocal;
+       }
       off += (plt->output_offset
              + plt->output_section->vma
              - elf_gp (info->output_bfd)
@@ -12655,6 +12716,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                    }
                  stub_entry->h = hash;
                  stub_entry->plt_ent = plt_ent;
+                 stub_entry->symtype
+                   = hash ? hash->elf.type : ELF_ST_TYPE (sym->st_info);
                  stub_entry->other = hash ? hash->elf.other : sym->st_other;
 
                  if (stub_entry->h != NULL)
@@ -13017,6 +13080,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
        /* This symbol has an entry in the procedure linkage
           table.  Set it up.  */
        Elf_Internal_Rela rela;
+       asection *plt, *relplt;
        bfd_byte *loc;
 
        if (!htab->elf.dynamic_sections_created
@@ -13026,21 +13090,55 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
                  && (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);
+           if (h->type == STT_GNU_IFUNC)
+             {
+               plt = htab->elf.iplt;
+               relplt = htab->elf.irelplt;
+               htab->local_ifunc_resolver = 1;
+               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);
+             }
            else
-             rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+             {
+               plt = htab->pltlocal;
+               if (bfd_link_pic (info))
+                 {
+                   relplt = htab->relpltlocal;
+                   if (htab->opd_abi)
+                     rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_SLOT);
+                   else
+                     rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+                 }
+               else
+                 relplt = NULL;
+             }
            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;
+
+           if (relplt == NULL)
+             {
+               loc = plt->contents + ent->plt.offset;
+               bfd_put_64 (info->output_bfd, rela.r_addend, loc);
+               if (htab->opd_abi)
+                 {
+                   bfd_vma toc = elf_gp (info->output_bfd);
+                   toc += htab->sec_info[h->root.u.def.section->id].toc_off;
+                   bfd_put_64 (info->output_bfd, toc, loc + 8);
+                 }
+             }
+           else
+             {
+               rela.r_offset = (plt->output_section->vma
+                                + plt->output_offset
+                                + ent->plt.offset);
+               loc = relplt->contents + (relplt->reloc_count++
+                                         * sizeof (Elf64_External_Rela));
+               bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+             }
          }
        else
          {
@@ -13054,8 +13152,8 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
                      / 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);
          }
-       bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
       }
 
   if (!h->pointer_equality_needed)
@@ -13080,7 +13178,12 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
        plt = htab->elf.splt;
        if (!htab->elf.dynamic_sections_created
            || h->dynindx == -1)
-         plt = htab->elf.iplt;
+         {
+           if (h->type == STT_GNU_IFUNC)
+             plt = htab->elf.iplt;
+           else
+             plt = htab->pltlocal;
+         }
        off = ent->plt.offset + plt->output_offset + plt->output_section->vma;
        off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
 
@@ -13173,7 +13276,6 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info)
              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))
@@ -13189,23 +13291,53 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info)
              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;
+             if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+               {
+                 htab->local_ifunc_resolver = 1;
+                 plt = htab->elf.iplt;
+                 relplt = htab->elf.irelplt;
+               }
+             else
+               {
+                 plt = htab->pltlocal;
+                 relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+               }
 
-             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);
+             if (relplt == NULL)
+               {
+                 loc = plt->contents + ent->plt.offset;
+                 bfd_put_64 (info->output_bfd, val, loc);
+                 if (htab->opd_abi)
+                   {
+                     bfd_vma toc = elf_gp (ibfd);
+                     bfd_put_64 (info->output_bfd, toc, loc + 8);
+                   }
+               }
              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);
+               {
+                 Elf_Internal_Rela rela;
+                 rela.r_offset = (ent->plt.offset
+                                  + plt->output_offset
+                                  + plt->output_section->vma);
+                 if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                   {
+                     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);
+                   }
+                 else
+                   {
+                     if (htab->opd_abi)
+                       rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_SLOT);
+                     else
+                       rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+                   }
+                 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
@@ -14792,10 +14924,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              {
                struct plt_entry **local_plt = (struct plt_entry **)
                  (local_got_ents + symtab_hdr->sh_info);
-               unsigned char *local_got_tls_masks = (unsigned char *)
-                 (local_plt + symtab_hdr->sh_info);
-               if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
-                 plt_list = local_plt + r_symndx;
+               plt_list = local_plt + r_symndx;
              }
            if (plt_list)
              {
@@ -14812,7 +14941,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      if (!htab->elf.dynamic_sections_created
                          || h == NULL
                          || h->elf.dynindx == -1)
-                       plt = htab->elf.iplt;
+                       {
+                         if (h != NULL
+                             ? h->elf.type == STT_GNU_IFUNC
+                             : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                           plt = htab->elf.iplt;
+                         else
+                           plt = htab->pltlocal;
+                       }
+                     relocation = (plt->output_section->vma
+                                   + plt->output_offset
+                                   + ent->plt.offset);
                      if (r_type == R_PPC64_PLT16_HA
                          || r_type ==R_PPC64_PLT16_HI
                          || r_type ==R_PPC64_PLT16_LO
@@ -14822,9 +14961,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                 + htab->sec_info[input_section->id].toc_off);
                          relocation -= got;
                        }
-                     relocation = (plt->output_section->vma
-                                   + plt->output_offset
-                                   + ent->plt.offset);
                      addend = 0;
                      unresolved_reloc = FALSE;
                      break;
index 48c87e4..bb30237 100644 (file)
@@ -1,5 +1,20 @@
 2018-04-09  Alan Modra  <amodra@gmail.com>
 
+       * powerpc.cc (Target_powerpc::lplt_): New variable.
+       (Target_powerpc::lplt_section): Associated accessor.
+       (Target_powerpc::plt_off): Handle local non-ifunc symbols.
+       (Target_powerpc::make_lplt_section): New function.
+       (Target_powerpc::make_local_plt_entry): New function.
+       (Powerpc_relobj::do_relocate_sections): Write out lplt.
+       (Output_data_plt_powerpc::first_plt_entry_offset): Zero for lplt.
+       (Output_data_plt_powerpc::add_local_entry): New function.
+       (Output_data_plt_powerpc::do_write): Ignore lplt.
+       (Target_powerpc::make_iplt_section): Make lplt first.
+       (Target_powerpc::make_brlt_section): Make .branch_lt relro.
+       (Target_powerpc::Scan::local): Handle PLT16 relocs.
+
+2018-04-09  Alan Modra  <amodra@gmail.com>
+
        * powerpc.cc (Target_powerpc::plt_off): New functions.
        (is_plt16_reloc): New function.
        (Stub_table::plt_off): Use Target_powerpc::plt_off.
index 0975fee..c3f1b23 100644 (file)
@@ -607,7 +607,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
 
   Target_powerpc()
     : Sized_target<size, big_endian>(&powerpc_info),
-      got_(NULL), plt_(NULL), iplt_(NULL), brlt_section_(NULL),
+      got_(NULL), plt_(NULL), iplt_(NULL), lplt_(NULL), brlt_section_(NULL),
       glink_(NULL), rela_dyn_(NULL), copy_relocs_(),
       tlsld_got_offset_(-1U),
       stub_tables_(), branch_lookup_table_(), branch_info_(), tocsave_loc_(),
@@ -860,6 +860,13 @@ class Target_powerpc : public Sized_target<size, big_endian>
     return this->iplt_;
   }
 
+  // Get the LPLT section.
+  const Output_data_plt_powerpc<size, big_endian>*
+  lplt_section() const
+  {
+    return this->lplt_;
+  }
+
   // Return the plt offset and section for the given global sym.
   Address
   plt_off(const Symbol* gsym,
@@ -879,7 +886,11 @@ class Target_powerpc : public Sized_target<size, big_endian>
          unsigned int local_sym_index,
          const Output_data_plt_powerpc<size, big_endian>** sec) const
   {
-    *sec = this->iplt_section();
+    const Symbol_value<size>* lsym = relobj->local_symbol(local_sym_index);
+    if (lsym->is_ifunc_symbol())
+      *sec = this->iplt_section();
+    else
+      *sec = this->lplt_section();
     return relobj->local_plt_offset(local_sym_index);
   }
 
@@ -1441,6 +1452,9 @@ class Target_powerpc : public Sized_target<size, big_endian>
   make_iplt_section(Symbol_table*, Layout*);
 
   void
+  make_lplt_section(Layout*);
+
+  void
   make_brlt_section(Layout*);
 
   // Create a PLT entry for a global symbol.
@@ -1453,6 +1467,12 @@ class Target_powerpc : public Sized_target<size, big_endian>
                             Sized_relobj_file<size, big_endian>*,
                             unsigned int);
 
+  // Create a PLT entry for a local non-IFUNC symbol.
+  void
+  make_local_plt_entry(Layout*,
+                      Sized_relobj_file<size, big_endian>*,
+                      unsigned int);
+
 
   // Create a GOT entry for local dynamic __tls_get_addr.
   unsigned int
@@ -1585,6 +1605,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
   // section is emitted and marked with __rela_iplt_start and
   // __rela_iplt_end symbols.
   Output_data_plt_powerpc<size, big_endian>* iplt_;
+  // A PLT style section for local, non-ifunc symbols
+  Output_data_plt_powerpc<size, big_endian>* lplt_;
   // Section holding long branch destinations.
   Output_data_brlt_powerpc<size, big_endian>* brlt_section_;
   // The .glink section.
@@ -2469,6 +2491,35 @@ Powerpc_relobj<size, big_endian>::do_relocate_sections(
     }
   this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
                               start, this->shnum() - 1);
+
+  if (!parameters->options().output_is_position_independent())
+    {
+      Target_powerpc<size, big_endian>* target
+       = static_cast<Target_powerpc<size, big_endian>*>(
+           parameters->sized_target<size, big_endian>());
+      if (target->lplt_section() && target->lplt_section()->data_size() != 0)
+       {
+         const section_size_type offset = target->lplt_section()->offset();
+         const section_size_type oview_size
+           = convert_to_section_size_type(target->lplt_section()->data_size());
+         unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+         bool modified = false;
+         unsigned int nsyms = this->local_symbol_count();
+         for (unsigned int i = 0; i < nsyms; i++)
+           if (this->local_has_plt_offset(i))
+             {
+               Address value = this->local_symbol_value(i, 0);
+               if (size == 64)
+                 value += ppc64_local_entry_offset(i);
+               size_t off = this->local_plt_offset(i);
+               elfcpp::Swap<size, big_endian>::writeval(oview + off, value);
+               modified = true;
+             }
+         if (modified)
+           of->write_output_view(offset, oview_size, oview);
+       }
+    }
 }
 
 // Set up some symbols.
@@ -3668,6 +3719,9 @@ class Output_data_plt_powerpc : public Output_section_data_build
   add_ifunc_entry(Symbol*);
 
   void
+  add_local_entry(Sized_relobj_file<size, big_endian>*, unsigned int);
+
+  void
   add_local_ifunc_entry(Sized_relobj_file<size, big_endian>*, unsigned int);
 
   // Return the .rela.plt section data.
@@ -3704,8 +3758,8 @@ class Output_data_plt_powerpc : public Output_section_data_build
   unsigned int
   first_plt_entry_offset() const
   {
-    // IPLT has no reserved entry.
-    if (this->name_[3] == 'I')
+    // IPLT and LPLT have no reserved entry.
+    if (this->name_[3] == 'I' || this->name_[3] == 'L')
       return 0;
     return this->targ_->first_plt_entry_offset();
   }
@@ -3768,6 +3822,31 @@ Output_data_plt_powerpc<size, big_endian>::add_ifunc_entry(Symbol* gsym)
     }
 }
 
+// Add an entry for a local symbol to the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::add_local_entry(
+    Sized_relobj_file<size, big_endian>* relobj,
+    unsigned int local_sym_index)
+{
+  if (!relobj->local_has_plt_offset(local_sym_index))
+    {
+      section_size_type off = this->current_data_size();
+      relobj->set_local_plt_offset(local_sym_index, off);
+      if (this->rel_)
+       {
+         unsigned int dynrel = elfcpp::R_POWERPC_RELATIVE;
+         if (size == 64 && this->targ_->abiversion() < 2)
+           dynrel = elfcpp::R_POWERPC_JMP_SLOT;
+         this->rel_->add_symbolless_local_addend(relobj, local_sym_index,
+                                                 dynrel, this, off, 0);
+       }
+      off += this->plt_entry_size();
+      this->set_current_data_size(off);
+    }
+}
+
 // Add an entry for a local ifunc symbol to the IPLT.
 
 template<int size, bool big_endian>
@@ -3888,7 +3967,7 @@ template<int size, bool big_endian>
 void
 Output_data_plt_powerpc<size, big_endian>::do_write(Output_file* of)
 {
-  if (size == 32 && this->name_[3] != 'I')
+  if (size == 32 && (this->name_[3] != 'I' && this->name_[3] != 'L'))
     {
       const section_size_type offset = this->offset();
       const section_size_type oview_size
@@ -3966,6 +4045,7 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
   if (this->iplt_ == NULL)
     {
       this->make_plt_section(symtab, layout);
+      this->make_lplt_section(layout);
 
       Reloc_section* iplt_rel = new Reloc_section(false);
       if (this->rela_dyn_->output_section())
@@ -3978,6 +4058,40 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
     }
 }
 
+// Create the LPLT section.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_lplt_section(Layout* layout)
+{
+  if (this->lplt_ == NULL)
+    {
+      Reloc_section* lplt_rel = NULL;
+      if (parameters->options().output_is_position_independent())
+       {
+         lplt_rel = new Reloc_section(false);
+         this->rela_dyn_section(layout);
+         if (this->rela_dyn_->output_section())
+           this->rela_dyn_->output_section()
+             ->add_output_section_data(lplt_rel);
+       }
+      this->lplt_
+       = new Output_data_plt_powerpc<size, big_endian>(this, lplt_rel,
+                                                       "** LPLT");
+      this->make_brlt_section(layout);
+      if (this->brlt_section_ && this->brlt_section_->output_section())
+       this->brlt_section_->output_section()
+         ->add_output_section_data(this->lplt_);
+      else
+       layout->add_output_section_data(".branch_lt",
+                                       elfcpp::SHT_PROGBITS,
+                                       elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+                                       this->lplt_,
+                                       ORDER_RELRO,
+                                       true);
+    }
+}
+
 // A section for huge long branch addresses, similar to plt section.
 
 template<int size, bool big_endian>
@@ -6132,6 +6246,20 @@ Target_powerpc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
     }
 }
 
+// Make a PLT entry for a local symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_local_plt_entry(
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* relobj,
+    unsigned int r_sym)
+{
+  if (this->lplt_ == NULL)
+    this->make_lplt_section(layout);
+  this->lplt_->add_local_entry(relobj, r_sym);
+}
+
 // Make a PLT entry for a local STT_GNU_IFUNC symbol.
 
 template<int size, bool big_endian>
@@ -6669,6 +6797,17 @@ Target_powerpc<size, big_endian>::Scan::local(
        }
       break;
 
+    case elfcpp::R_POWERPC_PLT16_LO:
+    case elfcpp::R_POWERPC_PLT16_HI:
+    case elfcpp::R_POWERPC_PLT16_HA:
+    case elfcpp::R_PPC64_PLT16_LO_DS:
+      if (!is_ifunc)
+       {
+         unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+         target->make_local_plt_entry(layout, object, r_sym);
+       }
+      break;
+
     case elfcpp::R_POWERPC_REL24:
     case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_PPC_LOCAL24PC:
index 4e697a3..df36735 100644 (file)
@@ -1,5 +1,15 @@
 2018-04-09  Alan Modra  <amodra@gmail.com>
 
+       * emulparams/elf32ppc.sh (OTHER_RELRO_SECTIONS_2): Add .branch_lt.
+       (OTHER_GOT_RELOC_SECTIONS): Add .rela.branch_lt.
+       * testsuite/ld-powerpc/elfv2so.d: Update for symbol/stub reordering.
+       * testsuite/ld-powerpc/relbrlt.d: Likewise.
+       * testsuite/ld-powerpc/relbrlt.s: Likewise.
+       * testsuite/ld-powerpc/tlsso.r: Likewise.
+       * testsuite/ld-powerpc/tlstocso.r: Likewise.
+
+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>
index c3da115..477279c 100644 (file)
@@ -15,6 +15,10 @@ GOTPLT=".plt          ${RELOCATING-0} : SPECIAL { *(.plt) }"
 PLT=".plt          ${RELOCATING-0} : SPECIAL { *(.plt) }
   .iplt         ${RELOCATING-0} : { *(.iplt) }"
 OTHER_TEXT_SECTIONS="*(.glink)"
+OTHER_GOT_RELOC_SECTIONS="
+  .rela.branch_lt      ${RELOCATING-0} : { *(.rela.branch_lt) }"
+OTHER_RELRO_SECTIONS_2="
+  .branch_lt   ${RELOCATING-0} :${RELOCATING+ ALIGN(4)} { *(.branch_lt) }"
 EXTRA_EM_FILE=ppc32elf
 if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then
 # crt1.o defines data_start and __data_start.  Keep them first.
index e7cd45c..5f198a9 100644 (file)
@@ -14,16 +14,16 @@ Disassembly of section \.text:
 .*:    (4e 80 04 20|20 04 80 4e)       bctr
        \.\.\.
 
-.* <.*\.plt_call\.f1>:
+.* <.*\.plt_call\.f3>:
 .*:    (f8 41 00 18|18 00 41 f8)       std     r2,24\(r1\)
-.*:    (e9 82 80 40|40 80 82 e9)       ld      r12,-32704\(r2\)
+.*:    (e9 82 80 28|28 80 82 e9)       ld      r12,-32728\(r2\)
 .*:    (7d 89 03 a6|a6 03 89 7d)       mtctr   r12
 .*:    (4e 80 04 20|20 04 80 4e)       bctr
        \.\.\.
 
-.* <.*\.plt_call\.f3>:
+.* <.*\.plt_call\.f1>:
 .*:    (f8 41 00 18|18 00 41 f8)       std     r2,24\(r1\)
-.*:    (e9 82 80 28|28 80 82 e9)       ld      r12,-32728\(r2\)
+.*:    (e9 82 80 40|40 80 82 e9)       ld      r12,-32704\(r2\)
 .*:    (7d 89 03 a6|a6 03 89 7d)       mtctr   r12
 .*:    (4e 80 04 20|20 04 80 4e)       bctr
        \.\.\.
@@ -41,12 +41,12 @@ Disassembly of section \.text:
 .*:    (7c 08 02 a6|a6 02 08 7c)       mflr    r0
 .*:    (f8 21 ff e1|e1 ff 21 f8)       stdu    r1,-32\(r1\)
 .*:    (f8 01 00 30|30 00 01 f8)       std     r0,48\(r1\)
-.*:    (4b ff ff 8d|8d ff ff 4b)       bl      .*\.plt_call\.f1>
+.*:    (4b ff ff ad|ad ff ff 4b)       bl      .*\.plt_call\.f1>
 .*:    (e8 62 80 08|08 80 62 e8)       ld      r3,-32760\(r2\)
 .*:    (4b ff ff c5|c5 ff ff 4b)       bl      .*\.plt_call\.f2>
 .*:    (e8 41 00 18|18 00 41 e8)       ld      r2,24\(r1\)
 .*:    (e8 62 80 10|10 80 62 e8)       ld      r3,-32752\(r2\)
-.*:    (4b ff ff 99|99 ff ff 4b)       bl      .*\.plt_call\.f3>
+.*:    (4b ff ff 79|79 ff ff 4b)       bl      .*\.plt_call\.f3>
 .*:    (e8 41 00 18|18 00 41 e8)       ld      r2,24\(r1\)
 .*:    (4b ff ff 51|51 ff ff 4b)       bl      .*\.plt_call\.f4>
 .*:    (e8 41 00 18|18 00 41 e8)       ld      r2,24\(r1\)
index 6f3db7d..a00b1ff 100644 (file)
@@ -8,32 +8,32 @@
 Disassembly of section \.text:
 
 0*100000c0 <_start>:
-[0-9a-f         ]*:    (49 bf 00 21|21 00 bf 49)       bl      .*
+[0-9a-f         ]*:    (49 bf 00 2d|2d 00 bf 49)       bl      .*
 [0-9a-f         ]*: R_PPC64_REL24      \.text\+0x37e003c
 [0-9a-f         ]*:    (60 00 00 00|00 00 00 60)       nop
-[0-9a-f         ]*:    (49 bf 00 1d|1d 00 bf 49)       bl      .*
-[0-9a-f         ]*: R_PPC64_REL24      \.text\+0x3bf002c
+[0-9a-f         ]*:    (49 bf 00 19|19 00 bf 49)       bl      .*
+[0-9a-f         ]*: R_PPC64_REL24      \.text\+0x3bf0020
 [0-9a-f         ]*:    (60 00 00 00|00 00 00 60)       nop
 [0-9a-f         ]*:    (49 bf 00 21|21 00 bf 49)       bl      .*
-[0-9a-f         ]*: R_PPC64_REL24      \.text\+0x57e0030
+[0-9a-f         ]*: R_PPC64_REL24      \.text\+0x57e0024
 [0-9a-f         ]*:    (60 00 00 00|00 00 00 60)       nop
 [0-9a-f         ]*:    00 00 00 00     \.long 0x0
 [0-9a-f         ]*:    (4b ff ff e4|e4 ff ff 4b)       b       .* <_start>
        \.\.\.
 
-[0-9a-f         ]*<.*long_branch.*>:
-[0-9a-f         ]*:    (49 bf 00 1c|1c 00 bf 49)       b       .* <far>
-[0-9a-f         ]*: R_PPC64_REL24      \*ABS\*\+0x137e00fc
-
 [0-9a-f         ]*<.*plt_branch.*>:
-[0-9a-f         ]*:    (e9 82 80 f8|f8 80 82 e9)       ld      r12,-32520\(r2\)
-[0-9a-f         ]*: R_PPC64_TOC16_DS   \*ABS\*\+0x157f00f8
+[0-9a-f         ]*:    (e9 82 80 e8|e8 80 82 e9)       ld      r12,-32536\(r2\)
+[0-9a-f         ]*: R_PPC64_TOC16_DS   \*ABS\*\+0x157f00e8
 [0-9a-f         ]*:    (7d 89 03 a6|a6 03 89 7d)       mtctr   r12
 [0-9a-f         ]*:    (4e 80 04 20|20 04 80 4e)       bctr
 
+[0-9a-f         ]*<.*long_branch.*>:
+[0-9a-f         ]*:    (49 bf 00 10|10 00 bf 49)       b       .* <far>
+[0-9a-f         ]*: R_PPC64_REL24      \*ABS\*\+0x137e00fc
+
 [0-9a-f         ]*<.*plt_branch.*>:
-[0-9a-f         ]*:    (e9 82 81 00|00 81 82 e9)       ld      r12,-32512\(r2\)
-[0-9a-f         ]*: R_PPC64_TOC16_DS   \*ABS\*\+0x157f0100
+[0-9a-f         ]*:    (e9 82 80 f0|f0 80 82 e9)       ld      r12,-32528\(r2\)
+[0-9a-f         ]*: R_PPC64_TOC16_DS   \*ABS\*\+0x157f00f0
 [0-9a-f         ]*:    (7d 89 03 a6|a6 03 89 7d)       mtctr   r12
 [0-9a-f         ]*:    (4e 80 04 20|20 04 80 4e)       bctr
        \.\.\.
@@ -42,19 +42,19 @@ Disassembly of section \.text:
 [0-9a-f         ]*:    (4e 80 00 20|20 00 80 4e)       blr
        \.\.\.
 
-0*13bf00ec <far2far>:
+0*13bf00e0 <far2far>:
 [0-9a-f         ]*:    (4e 80 00 20|20 00 80 4e)       blr
        \.\.\.
 
-0*157e00f0 <huge>:
+0*157e00e4 <huge>:
 [0-9a-f         ]*:    (4e 80 00 20|20 00 80 4e)       blr
 
 Disassembly of section \.branch_lt:
 
-0*157f00f8 .*:
-[0-9a-f         ]*:    (00 00 00 00|ec 00 bf 13) .*
-[0-9a-f         ]*: R_PPC64_RELATIVE   \*ABS\*\+0x13bf00ec
-[0-9a-f         ]*:    (13 bf 00 ec|00 00 00 00) .*
-[0-9a-f         ]*:    (00 00 00 00|f0 00 7e 15) .*
-[0-9a-f         ]*: R_PPC64_RELATIVE   \*ABS\*\+0x157e00f0
-[0-9a-f         ]*:    (15 7e 00 f0|00 00 00 00) .*
+0*157f00e8 .*:
+[0-9a-f         ]*:    (00 00 00 00|e0 00 bf 13) .*
+[0-9a-f         ]*: R_PPC64_RELATIVE   \*ABS\*\+0x13bf00e0
+[0-9a-f         ]*:    (13 bf 00 e0|00 00 00 00) .*
+[0-9a-f         ]*:    (00 00 00 00|e4 00 7e 15) .*
+[0-9a-f         ]*: R_PPC64_RELATIVE   \*ABS\*\+0x157e00e4
+[0-9a-f         ]*:    (15 7e 00 e4|00 00 00 00) .*
index fade6a2..cee0cdd 100644 (file)
@@ -20,7 +20,7 @@ far:
  blr
 
  .section .text.pad2,"ax"
- .space 0x40ffec
+ .space 0x40ffe0
 
  .section .text.far2far,"ax"
 far2far:
index 218a0ce..5d349e5 100644 (file)
@@ -114,8 +114,8 @@ Symbol table '\.symtab' contains [0-9]+ entries:
 .* TLS +LOCAL +DEFAULT +7 le5
 .* FILE +LOCAL +DEFAULT +ABS 
 .* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
-.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr
 .* NOTYPE +LOCAL +DEFAULT +6 __glink_PLTresolve
+.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr
 .* TLS +GLOBAL +DEFAULT +UND gd
 .* TLS +GLOBAL +DEFAULT +8 le0
 .* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr
index 0296549..f8922ee 100644 (file)
@@ -110,8 +110,8 @@ Symbol table '\.symtab' contains [0-9]+ entries:
 .* NOTYPE +LOCAL +DEFAULT +11 \.Lie0
 .* FILE +LOCAL +DEFAULT +ABS 
 .* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
-.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr
 .* NOTYPE +LOCAL +DEFAULT +6 __glink_PLTresolve
+.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr
 .* TLS +GLOBAL +DEFAULT +UND gd
 .* TLS +GLOBAL +DEFAULT +8 le0
 .* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr