OSDN Git Service

* elf32-ppc.c (ppc_elf_check_relocs): Always set up sections
authorAlan Modra <amodra@bigpond.net.au>
Wed, 29 Jul 2009 14:56:36 +0000 (14:56 +0000)
committerAlan Modra <amodra@bigpond.net.au>
Wed, 29 Jul 2009 14:56:36 +0000 (14:56 +0000)
used by indirect function support.  Count dynamic relocs for
ifunc syms.
(ppc_elf_adjust_dynamic_symbol): Tweak for ifunc.
(allocate_dynrelocs): Allocate all non-dynamic ifunc plt entries
in iplt and their relocs in reliplt.  Don't make ifunc syms
dynamic.  Allocate got entry relocs for non-dynamic ifunc in
reliplt.  Handle other dynamic relocs for ifunc.
(ppc_elf_size_dynamic_sections): Alloc dyn relocs for static
ifunc in reliplt, likewise relocs for got against local ifunc.
Typo fix on reliplt size adjust.
(ppc_elf_relocate_section): Don't use plt scheme of allocating
relocs 1-1 with entries for iplt, instead just add using
reloc_count.  Write got relocs and dyn relocs for ifunc to reliplt.
Error on invalid ifunc dyn relocs.
(ppc_elf_finish_dynamic_symbol): Adjust for non-dynamic ifunc plt
in iplt/reliplt.
* elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_JMP_IREL,
R_PPC64_REL16, R_PPC64_REL16_LO, R_PPC64_REL16_HI, R_PPC64_REL16_HA.
(ppc64_elf_reloc_type_lookup): Handle new relocs.
(ppc64_elf_check_relocs): Likewise.  Count dyn relocs for ifunc.
(allocate_dynrelocs): As for elf32-ppc.c above.
(ppc64_elf_size_dynamic_sections): Likewise.
(ppc_build_one_stub): Put non-dynamic ifunc plt call stubs in iplt,
and their relocs in reliplt.  Use R_PPC64_JMP_IREL.
(ppc_size_one_stub): Similarly.
(ppc64_elf_relocate_section): As for elf32-ppc.c above.  Handle new
relocs too.
(ppc64_elf_finish_dynamic_symbol): As for elf32-ppc.c above.

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

index 5d3be83..5a10493 100644 (file)
@@ -1,3 +1,35 @@
+2009-07-30  Alan Modra  <amodra@bigpond.net.au>
+
+       * elf32-ppc.c (ppc_elf_check_relocs): Always set up sections
+       used by indirect function support.  Count dynamic relocs for
+       ifunc syms.
+       (ppc_elf_adjust_dynamic_symbol): Tweak for ifunc.
+       (allocate_dynrelocs): Allocate all non-dynamic ifunc plt entries
+       in iplt and their relocs in reliplt.  Don't make ifunc syms
+       dynamic.  Allocate got entry relocs for non-dynamic ifunc in
+       reliplt.  Handle other dynamic relocs for ifunc.
+       (ppc_elf_size_dynamic_sections): Alloc dyn relocs for static
+       ifunc in reliplt, likewise relocs for got against local ifunc.
+       Typo fix on reliplt size adjust.
+       (ppc_elf_relocate_section): Don't use plt scheme of allocating
+       relocs 1-1 with entries for iplt, instead just add using
+       reloc_count.  Write got relocs and dyn relocs for ifunc to reliplt.
+       Error on invalid ifunc dyn relocs.
+       (ppc_elf_finish_dynamic_symbol): Adjust for non-dynamic ifunc plt
+       in iplt/reliplt.
+       * elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_JMP_IREL,
+       R_PPC64_REL16, R_PPC64_REL16_LO, R_PPC64_REL16_HI, R_PPC64_REL16_HA.
+       (ppc64_elf_reloc_type_lookup): Handle new relocs.
+       (ppc64_elf_check_relocs): Likewise.  Count dyn relocs for ifunc.
+       (allocate_dynrelocs): As for elf32-ppc.c above.
+       (ppc64_elf_size_dynamic_sections): Likewise.
+       (ppc_build_one_stub): Put non-dynamic ifunc plt call stubs in iplt,
+       and their relocs in reliplt.  Use R_PPC64_JMP_IREL.
+       (ppc_size_one_stub): Similarly.
+       (ppc64_elf_relocate_section): As for elf32-ppc.c above.  Handle new
+       relocs too.
+       (ppc64_elf_finish_dynamic_symbol): As for elf32-ppc.c above.
+
 2009-07-29  Hans-Peter Nilsson  <hp@bitrange.com>
 
        * elf64-mmix.c (mmix_elf_relax_section): Revert 2009-05-27
index 814c8a0..d1e2cfc 100644 (file)
@@ -3408,6 +3408,13 @@ ppc_elf_check_relocs (bfd *abfd,
     ppc_elf_howto_init ();
 
   htab = ppc_elf_hash_table (info);
+  if (htab->glink == NULL)
+    {
+      if (htab->elf.dynobj == NULL)
+       htab->elf.dynobj = abfd;
+      if (!ppc_elf_create_glink (htab->elf.dynobj, info))
+       return FALSE;
+    }
   tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
                              FALSE, FALSE, TRUE);
   symtab_hdr = &elf_symtab_hdr (abfd);
@@ -3451,23 +3458,8 @@ ppc_elf_check_relocs (bfd *abfd,
 
       tls_type = 0;
       ifunc = NULL;
-      r_type = ELF32_R_TYPE (rel->r_info);
-      if (!htab->is_vxworks && is_branch_reloc (r_type))
+      if (!htab->is_vxworks)
        {
-         if (h != NULL && h == tga)
-           {
-             if (rel != relocs
-                 && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
-                     || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
-               /* We have a new-style __tls_get_addr call with a marker
-                  reloc.  */
-               ;
-             else
-               /* Mark this section as having an old-style call.  */
-               sec->has_tls_get_addr_call = 1;
-           }
-
-         /* STT_GNU_IFUNC symbols must have a PLT entry.  */
          if (h != NULL)
            {
              if (h->type == STT_GNU_IFUNC)
@@ -3491,6 +3483,25 @@ ppc_elf_check_relocs (bfd *abfd,
                    return FALSE;
                }
            }
+       }
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+      if (!htab->is_vxworks && is_branch_reloc (r_type))
+       {
+         if (h != NULL && h == tga)
+           {
+             if (rel != relocs
+                 && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
+                     || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
+               /* We have a new-style __tls_get_addr call with a marker
+                  reloc.  */
+               ;
+             else
+               /* Mark this section as having an old-style call.  */
+               sec->has_tls_get_addr_call = 1;
+           }
+
+         /* STT_GNU_IFUNC symbols must have a PLT entry.  */
          if (ifunc != NULL)
            {
              bfd_vma addend = 0;
@@ -3503,14 +3514,6 @@ ppc_elf_check_relocs (bfd *abfd,
              if (!update_plt_info (abfd, ifunc,
                                    addend < 32768 ? NULL : got2, addend))
                return FALSE;
-
-             if (htab->glink == NULL)
-               {
-                 if (htab->elf.dynobj == NULL)
-                   htab->elf.dynobj = abfd;
-                 if (!ppc_elf_create_glink (htab->elf.dynobj, info))
-                   return FALSE;
-               }
            }
        }
 
@@ -3938,7 +3941,9 @@ ppc_elf_check_relocs (bfd *abfd,
                  && !info->shared
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
-                     || !h->def_regular)))
+                     || !h->def_regular))
+             || (!info->shared
+                 && ifunc != NULL))
            {
              struct ppc_elf_dyn_relocs *p;
              struct ppc_elf_dyn_relocs **head;
@@ -4859,8 +4864,10 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        }
       else
        {
-         /* After adjust_dynamic_symbol, non_got_ref set means that
-            dyn_relocs for this symbol should be discarded.
+         /* After adjust_dynamic_symbol, non_got_ref set in the
+            non-shared case means that we have allocated space in
+            .dynbss for the symbol and thus dyn_relocs for this
+            symbol should be discarded.
             If we get here we know we are making a PLT entry for this
             symbol, and in an executable we'd normally resolve
             relocations against this symbol to the PLT entry.  Allow
@@ -4868,6 +4875,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             relocs will not cause text relocation.  */
          if (!h->ref_regular_nonweak
              && h->non_got_ref
+             && h->type != STT_GNU_IFUNC
              && !htab->is_vxworks
              && !ppc_elf_hash_entry (h)->has_sda_refs
              && !readonly_dynrelocs (h))
@@ -5105,10 +5113,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
              {
                asection *s = htab->plt;
-               if (!dyn)
+               if (!dyn || h->dynindx == -1)
                  s = htab->iplt;
 
-               if (htab->plt_type == PLT_NEW || !dyn)
+               if (htab->plt_type == PLT_NEW || !dyn || h->dynindx == -1)
                  {
                    if (!doneone)
                      {
@@ -5186,7 +5194,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                /* We also need to make an entry in the .rela.plt section.  */
                if (!doneone)
                  {
-                   if (!htab->elf.dynamic_sections_created)
+                   if (!htab->elf.dynamic_sections_created
+                       || h->dynindx == -1)
                      htab->reliplt->size += sizeof (Elf32_External_Rela);
                    else
                      {
@@ -5246,7 +5255,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       /* Make sure this symbol is output as a dynamic symbol.  */
       if (eh->elf.dynindx == -1
          && !eh->elf.forced_local
-         && !eh->elf.def_regular
+         && eh->elf.type != STT_GNU_IFUNC
          && htab->elf.dynamic_sections_created)
        {
          if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
@@ -5279,19 +5288,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        eh->elf.got.offset = (bfd_vma) -1;
       else
        {
+         asection *rsec = NULL;
          eh->elf.got.offset = allocate_got (htab, need);
          dyn = htab->elf.dynamic_sections_created;
          if ((info->shared
               || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
              && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
                  || eh->elf.root.type != bfd_link_hash_undefweak))
+           rsec = htab->relgot;
+         else if (h->type == STT_GNU_IFUNC)
+           rsec = htab->reliplt;
+         if (rsec != NULL)
            {
              /* All the entries we allocated need relocs.
                 Except LD only needs one.  */
              if ((eh->tls_mask & TLS_LD) != 0
                  && eh->elf.def_dynamic)
                need -= 4;
-             htab->relgot->size += need * (sizeof (Elf32_External_Rela) / 4);
+             rsec->size += need * (sizeof (Elf32_External_Rela) / 4);
            }
        }
     }
@@ -5299,7 +5313,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     eh->elf.got.offset = (bfd_vma) -1;
 
   if (eh->dyn_relocs == NULL
-      || !htab->elf.dynamic_sections_created)
+      || (!htab->elf.dynamic_sections_created
+         && h->type != STT_GNU_IFUNC))
     return TRUE;
 
   /* In the shared -Bsymbolic case, discard space allocated for
@@ -5370,6 +5385,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            }
        }
     }
+  else if (h->type == STT_GNU_IFUNC)
+    {
+      if (!h->non_got_ref)
+       eh->dyn_relocs = NULL;
+    }
   else if (ELIMINATE_COPY_RELOCS)
     {
       /* For the non-shared case, discard space for relocs against
@@ -5382,8 +5402,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
          /* Make sure this symbol is output as a dynamic symbol.
             Undefined weak syms won't yet be marked as dynamic.  */
          if (h->dynindx == -1
-             && !h->forced_local
-             && !h->def_regular)
+             && !h->forced_local)
            {
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
                return FALSE;
@@ -5404,6 +5423,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
       asection *sreloc = elf_section_data (p->sec)->sreloc;
+      if (!htab->elf.dynamic_sections_created)
+       sreloc = htab->reliplt;
       sreloc->size += p->count * sizeof (Elf32_External_Rela);
     }
 
@@ -5508,8 +5529,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                }
              else if (p->count != 0)
                {
-                 elf_section_data (p->sec)->sreloc->size
-                   += p->count * sizeof (Elf32_External_Rela);
+                 asection *sreloc = elf_section_data (p->sec)->sreloc;
+                 if (!htab->elf.dynamic_sections_created)
+                   sreloc = htab->reliplt;
+                 sreloc->size += p->count * sizeof (Elf32_External_Rela);
                  if ((p->sec->output_section->flags
                       & (SEC_READONLY | SEC_ALLOC))
                      == (SEC_READONLY | SEC_ALLOC))
@@ -5553,6 +5576,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                if (info->shared)
                  htab->relgot->size += (need
                                         * (sizeof (Elf32_External_Rela) / 4));
+               else if ((*lgot_masks & PLT_IFUNC) != 0)
+                 htab->reliplt->size += (need
+                                         * (sizeof (Elf32_External_Rela) / 4));
              }
          }
        else
@@ -5590,7 +5616,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
                if (!doneone)
                  {
-                   htab->reliplt += sizeof (Elf32_External_Rela);
+                   htab->reliplt->size += sizeof (Elf32_External_Rela);
                    doneone = TRUE;
                  }
              }
@@ -6912,7 +6938,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        }
 
       ifunc = NULL;
-      if (!htab->is_vxworks && is_branch_reloc (r_type))
+      if (!htab->is_vxworks)
        {
          if (h != NULL)
            {
@@ -6929,7 +6955,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  ifunc = local_plt + r_symndx;
                }
            }
-         if (ifunc != NULL)
+         if (ifunc != NULL && is_branch_reloc (r_type))
            {
              struct plt_entry *ent = find_plt_ent (ifunc, got2, rel->r_addend);
 
@@ -6943,8 +6969,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                   + ent->plt.offset);
                  rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
                  rela.r_addend = relocation;
-                 loc = (htab->reliplt->contents
-                        + ent->plt.offset * sizeof (Elf32_External_Rela) / 4);
+                 loc = htab->reliplt->contents;
+                 loc += (htab->reliplt->reloc_count++
+                         * sizeof (Elf32_External_Rela));
                  bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
                  ent->plt.offset |= 1;
@@ -7081,6 +7108,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              off &= ~1;
            else
              {
+               asection *rsec;
                unsigned int tls_m = (tls_mask
                                      & (TLS_LD | TLS_GD | TLS_DTPREL
                                         | TLS_TPREL | TLS_TPRELGD));
@@ -7119,11 +7147,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
                      }
 
                    /* Generate relocs for the dynamic linker.  */
+                   rsec = NULL;
                    if ((info->shared || indx != 0)
                        && (offp == &htab->tlsld_got.offset
                            || h == NULL
                            || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                            || h->root.type != bfd_link_hash_undefweak))
+                     rsec = htab->relgot;
+                   else if (ifunc != NULL)
+                     rsec = htab->reliplt;
+                   if (rsec != NULL)
                      {
                        outrel.r_offset = (htab->got->output_section->vma
                                           + htab->got->output_offset
@@ -7134,8 +7167,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                            outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32);
                            if (tls_ty == (TLS_TLS | TLS_GD))
                              {
-                               loc = htab->relgot->contents;
-                               loc += (htab->relgot->reloc_count++
+                               loc = rsec->contents;
+                               loc += (rsec->reloc_count++
                                        * sizeof (Elf32_External_Rela));
                                bfd_elf32_swap_reloca_out (output_bfd,
                                                           &outrel, loc);
@@ -7148,18 +7181,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32);
                        else if (tls_ty == (TLS_TLS | TLS_TPREL))
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32);
-                       else if (indx == 0)
-                         outrel.r_info = ELF32_R_INFO (indx, R_PPC_RELATIVE);
-                       else
+                       else if (indx != 0)
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
+                       else if (ifunc != NULL)
+                         outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+                       else
+                         outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
                        if (indx == 0 && tls_ty != (TLS_TLS | TLS_LD))
                          {
                            outrel.r_addend += relocation;
                            if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
                              outrel.r_addend -= htab->elf.tls_sec->vma;
                          }
-                       loc = htab->relgot->contents;
-                       loc += (htab->relgot->reloc_count++
+                       loc = rsec->contents;
+                       loc += (rsec->reloc_count++
                                * sizeof (Elf32_External_Rela));
                        bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
                      }
@@ -7350,7 +7385,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  && h != NULL
                  && h->dynindx != -1
                  && !h->non_got_ref
-                 && !h->def_regular))
+                 && !h->def_regular)
+             || (!info->shared
+                 && ifunc != NULL))
            {
              int skip;
 
@@ -7366,8 +7403,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                 time.  */
              if (sreloc == NULL)
                {
-                 sreloc = _bfd_elf_get_dynamic_reloc_section
-                   (input_bfd, input_section, /*rela?*/ TRUE);
+                 sreloc = elf_section_data (input_section)->sreloc;
+                 if (!htab->elf.dynamic_sections_created)
+                   sreloc = htab->reliplt;
                  if (sreloc == NULL)
                    return FALSE;
                }
@@ -7397,13 +7435,35 @@ ppc_elf_relocate_section (bfd *output_bfd,
                {
                  outrel.r_addend = relocation + rel->r_addend;
 
-                 if (r_type == R_PPC_ADDR32)
-                   outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
-                 else
+                 if (r_type != R_PPC_ADDR32)
                    {
                      long indx = 0;
 
-                     if (r_symndx == 0 || bfd_is_abs_section (sec))
+                     if (ifunc != NULL)
+                       {
+                         /* If we get here when building a static
+                            executable, then the libc startup function
+                            responsible for applying indirect function
+                            relocations is going to complain about
+                            the reloc type.
+                            If we get here when building a dynamic
+                            executable, it will be because we have
+                            a text relocation.  The dynamic loader
+                            will set the text segment writable and
+                            non-executable to apply text relocations.
+                            So we'll segfault when trying to run the
+                            indirection function to resolve the reloc.  */
+                         (*_bfd_error_handler)
+                           (_("%B(%A+0x%lx): relocation %s for indirect "
+                              "function %s unsupported"),
+                            input_bfd,
+                            input_section,
+                            (long) rel->r_offset,
+                            howto->name,
+                            sym_name);
+                         ret = FALSE;
+                       }
+                     else if (r_symndx == 0 || bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                        {
@@ -7418,7 +7478,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                             against a section symbol.  It would be
                             proper to subtract the symbol's value,
                             osec->vma, from the emitted reloc addend,
-                            but ld.so expects buggy relocs.  */
+                            but ld.so expects buggy relocs.
+                            FIXME: Why not always use a zero index?  */
                          osec = sec->output_section;
                          indx = elf_section_data (osec)->dynindx;
                          if (indx == 0)
@@ -7437,6 +7498,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
                      outrel.r_info = ELF32_R_INFO (indx, r_type);
                    }
+                 else if (ifunc != NULL)
+                   outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+                 else
+                   outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
                }
 
              loc = sreloc->contents;
@@ -7891,7 +7956,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
            bfd_vma reloc_index;
 
            if (htab->plt_type == PLT_NEW
-               || !htab->elf.dynamic_sections_created)
+               || !htab->elf.dynamic_sections_created
+               || h->dynindx == -1)
              reloc_index = ent->plt.offset / 4;
            else
              {
@@ -7905,7 +7971,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
            /* This symbol has an entry in the procedure linkage table.
               Set it up.  */
            if (htab->plt_type == PLT_VXWORKS
-               && htab->elf.dynamic_sections_created)
+               && htab->elf.dynamic_sections_created
+               && h->dynindx != -1)
              {
                bfd_vma got_offset;
                const bfd_vma *plt_entry;
@@ -8028,14 +8095,16 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
            else
              {
                asection *splt = htab->plt;
-               if (!htab->elf.dynamic_sections_created)
+               if (!htab->elf.dynamic_sections_created
+                   || h->dynindx == -1)
                  splt = htab->iplt;
 
                rela.r_offset = (splt->output_section->vma
                                 + splt->output_offset
                                 + ent->plt.offset);
                if (htab->plt_type == PLT_OLD
-                   || !htab->elf.dynamic_sections_created)
+                   || !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.  */
@@ -8065,11 +8134,14 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
            else
              rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
 
-           if (!htab->elf.dynamic_sections_created)
-             loc = htab->reliplt->contents;
+           if (!htab->elf.dynamic_sections_created
+               || h->dynindx == -1)
+             loc = (htab->reliplt->contents
+                    + (htab->reliplt->reloc_count++
+                       * sizeof (Elf32_External_Rela)));
            else
-             loc = htab->relplt->contents;
-           loc += reloc_index * sizeof (Elf32_External_Rela);
+             loc = (htab->relplt->contents
+                    + reloc_index * sizeof (Elf32_External_Rela));
            bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
            if (!h->def_regular)
@@ -8096,10 +8168,12 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
          }
 
        if (htab->plt_type == PLT_NEW
-           || !htab->elf.dynamic_sections_created)
+           || !htab->elf.dynamic_sections_created
+           || h->dynindx == -1)
          {
            asection *splt = htab->plt;
-           if (!htab->elf.dynamic_sections_created)
+           if (!htab->elf.dynamic_sections_created
+               || h->dynindx == -1)
              splt = htab->iplt;
 
            write_glink_stub (ent, splt, info);
index d744990..f154658 100644 (file)
@@ -1874,6 +1874,20 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_PPC64_JMP_IREL,     /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_JMP_IREL",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   HOWTO (R_PPC64_IRELATIVE,    /* type */
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
@@ -1888,6 +1902,67 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         ONES (64),             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  /* A 16 bit relative relocation.  */
+  HOWTO (R_PPC64_REL16,                /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_REL16",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* A 16 bit relative relocation without overflow.  */
+  HOWTO (R_PPC64_REL16_LO,     /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_REL16_LO",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* The high order 16 bits of a relative address.  */
+  HOWTO (R_PPC64_REL16_HI,     /* type */
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_REL16_HI",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* The high order 16 bits of a relative address, plus 1 if the contents of
+     the low 16 bits, treated as a signed number, is negative.  */
+  HOWTO (R_PPC64_REL16_HA,     /* type */
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_ha_reloc,    /* special_function */
+        "R_PPC64_REL16_HA",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC64_GNU_VTINHERIT,        /* type */
         0,                     /* rightshift */
@@ -2156,6 +2231,14 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:    r = R_PPC64_DTPREL16_HIGHESTA;
       break;
+    case BFD_RELOC_16_PCREL:                   r = R_PPC64_REL16;
+      break;
+    case BFD_RELOC_LO16_PCREL:                 r = R_PPC64_REL16_LO;
+      break;
+    case BFD_RELOC_HI16_PCREL:                 r = R_PPC64_REL16_HI;
+      break;
+    case BFD_RELOC_HI16_S_PCREL:               r = R_PPC64_REL16_HA;
+      break;
     case BFD_RELOC_VTABLE_INHERIT:             r = R_PPC64_GNU_VTINHERIT;
       break;
     case BFD_RELOC_VTABLE_ENTRY:               r = R_PPC64_GNU_VTENTRY;
@@ -4763,6 +4846,29 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       tls_type = 0;
       ifunc = NULL;
+      if (h != NULL)
+       {
+         if (h->type == STT_GNU_IFUNC)
+           {
+             h->needs_plt = 1;
+             ifunc = &h->plt.plist;
+           }
+       }
+      else
+       {
+         Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                                         abfd, r_symndx);
+         if (isym == NULL)
+           return FALSE;
+
+         if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+           {
+             ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                            rel->r_addend, PLT_IFUNC);
+             if (ifunc == NULL)
+               return FALSE;
+           }
+       }
       r_type = ELF64_R_TYPE (rel->r_info);
       if (is_branch_reloc (r_type))
        {
@@ -4780,29 +4886,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            }
 
          /* STT_GNU_IFUNC symbols must have a PLT entry.  */
-         if (h != NULL)
-           {
-             if (h->type == STT_GNU_IFUNC)
-               {
-                 h->needs_plt = 1;
-                 ifunc = &h->plt.plist;
-               }
-           }
-         else
-           {
-             Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
-                                                             abfd, r_symndx);
-             if (isym == NULL)
-               return FALSE;
-
-             if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
-               {
-                 ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
-                                                rel->r_addend, PLT_IFUNC);
-                 if (ifunc == NULL)
-                   return FALSE;
-               }
-           }
          if (ifunc != NULL
              && !update_plt_info (abfd, ifunc, rel->r_addend))
            return FALSE;
@@ -4944,6 +5027,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
 
          /* Nor do these.  */
+       case R_PPC64_REL16:
+       case R_PPC64_REL16_LO:
+       case R_PPC64_REL16_HI:
+       case R_PPC64_REL16_HA:
+         break;
+
        case R_PPC64_TOC16:
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_HI:
@@ -5194,7 +5283,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  && !info->shared
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
-                     || !h->def_regular)))
+                     || !h->def_regular))
+             || (!info->shared
+                 && ifunc != NULL))
            {
              struct ppc_dyn_relocs *p;
              struct ppc_dyn_relocs **head;
@@ -7990,7 +8081,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       for (pent = h->plt.plist; pent != NULL; pent = pent->next)
        if (pent->plt.refcount > 0)
          {
-           if (!htab->elf.dynamic_sections_created)
+           if (!htab->elf.dynamic_sections_created
+               || h->dynindx == -1)
              {
                s = htab->iplt;
                pent->plt.offset = s->size;
@@ -8069,12 +8161,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     if (gent->got.refcount > 0)
       {
        bfd_boolean dyn;
+       asection *rsec;
 
        /* Make sure this symbol is output as a dynamic symbol.
           Undefined weak syms won't yet be marked as dynamic,
           nor will all TLS symbols.  */
        if (h->dynindx == -1
            && !h->forced_local
+           && h->type != STT_GNU_IFUNC
            && htab->elf.dynamic_sections_created)
          {
            if (! bfd_elf_link_record_dynamic_symbol (info, h))
@@ -8097,20 +8191,25 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        s->size
          += (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8;
        dyn = htab->elf.dynamic_sections_created;
+       rsec = NULL;
        if ((info->shared
             || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
            && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                || h->root.type != bfd_link_hash_undefweak))
-         ppc64_elf_tdata (gent->owner)->relgot->size
-           += (gent->tls_type & eh->tls_mask & TLS_GD
-               ? 2 * sizeof (Elf64_External_Rela)
-               : sizeof (Elf64_External_Rela));
+         rsec = ppc64_elf_tdata (gent->owner)->relgot;
+       else if (h->type == STT_GNU_IFUNC)
+         rsec = htab->reliplt;
+       if (rsec != NULL)
+         rsec->size += (gent->tls_type & eh->tls_mask & TLS_GD
+                        ? 2 * sizeof (Elf64_External_Rela)
+                        : sizeof (Elf64_External_Rela));
       }
     else
       gent->got.offset = (bfd_vma) -1;
 
   if (eh->dyn_relocs == NULL
-      || !htab->elf.dynamic_sections_created)
+      || (!htab->elf.dynamic_sections_created
+         && h->type != STT_GNU_IFUNC))
     return TRUE;
 
   /* In the shared -Bsymbolic case, discard space allocated for
@@ -8160,6 +8259,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            }
        }
     }
+  else if (h->type == STT_GNU_IFUNC)
+    {
+      if (!h->non_got_ref)
+       eh->dyn_relocs = NULL;
+    }
   else if (ELIMINATE_COPY_RELOCS)
     {
       /* For the non-shared case, discard space for relocs against
@@ -8193,6 +8297,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
       asection *sreloc = elf_section_data (p->sec)->sreloc;
+      if (!htab->elf.dynamic_sections_created)
+       sreloc = htab->reliplt;
       sreloc->size += p->count * sizeof (Elf64_External_Rela);
     }
 
@@ -8291,6 +8397,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              else if (p->count != 0)
                {
                  srel = elf_section_data (p->sec)->sreloc;
+                 if (!htab->elf.dynamic_sections_created)
+                   srel = htab->reliplt;
                  srel->size += p->count * sizeof (Elf64_External_Rela);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
@@ -8324,19 +8432,15 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                  }
                else
                  {
+                   unsigned int num = 1;
                    ent->got.offset = s->size;
                    if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
-                     {
-                       s->size += 16;
-                       if (info->shared)
-                         srel->size += 2 * sizeof (Elf64_External_Rela);
-                     }
-                   else
-                     {
-                       s->size += 8;
-                       if (info->shared)
-                         srel->size += sizeof (Elf64_External_Rela);
-                     }
+                     num = 2;
+                   s->size += num * 8;
+                   if (info->shared)
+                     srel->size += num * sizeof (Elf64_External_Rela);
+                   else if ((*lgot_masks & PLT_IFUNC) != 0)
+                     htab->reliplt->size += num * sizeof (Elf64_External_Rela);
                  }
              }
            else
@@ -8356,7 +8460,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                ent->plt.offset = s->size;
                s->size += PLT_ENTRY_SIZE;
 
-               htab->reliplt += sizeof (Elf64_External_Rela);
+               htab->reliplt->size += sizeof (Elf64_External_Rela);
              }
            else
              ent->plt.offset = (bfd_vma) -1;
@@ -9029,7 +9133,9 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        abort ();
 
       plt = htab->plt;
-      if (!htab->elf.dynamic_sections_created)
+      if (!htab->elf.dynamic_sections_created
+         || stub_entry->h == NULL
+         || stub_entry->h->elf.dynindx == -1)
        plt = htab->iplt;
 
       dest += plt->output_offset + plt->output_section->vma;
@@ -9041,20 +9147,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          bfd_byte *rl;
 
          rela.r_offset = dest;
-         rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+         rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
          rela.r_addend = (stub_entry->target_value
                           + stub_entry->target_section->output_offset
                           + stub_entry->target_section->output_section->vma);
 
-         if (!htab->elf.dynamic_sections_created)
-           rl = (htab->reliplt->contents
-                 + (stub_entry->plt_ent->plt.offset
-                    / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
-         else
-           rl = (htab->relplt->contents
-                 + ((stub_entry->plt_ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
-                    / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
-         bfd_elf32_swap_reloca_out (info->output_bfd, &rela, rl);
+         rl = (htab->reliplt->contents
+               + (htab->reliplt->reloc_count++
+                  * sizeof (Elf64_External_Rela)));
+         bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
          stub_entry->plt_ent->plt.offset |= 1;
        }
 
@@ -9162,7 +9263,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (off >= (bfd_vma) -2)
        abort ();
       plt = htab->plt;
-      if (!htab->elf.dynamic_sections_created)
+      if (!htab->elf.dynamic_sections_created
+         || stub_entry->h == NULL
+         || stub_entry->h->elf.dynindx == -1)
        plt = htab->iplt;
       off += (plt->output_offset
              + plt->output_section->vma
@@ -11093,7 +11196,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                   && sec->output_section != NULL
                   && sec->id <= htab->top_id
                   && (htab->stub_group[sec->id].toc_off
-                      != htab->stub_group[input_section->id].toc_off)))
+                      != htab->stub_group[input_section->id].toc_off))
+              || (h == NULL
+                  && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
              && (stub_entry = ppc_get_stub_entry (input_section, sec, fdh,
                                                   rel, htab)) != NULL
              && (stub_entry->stub_type == ppc_stub_plt_call
@@ -11377,14 +11482,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                /* Generate relocs for the dynamic linker, except in
                   the case of TLSLD where we'll use one entry per
                   module.  */
-               asection *relgot = ppc64_elf_tdata (input_bfd)->relgot;
+               asection *relgot;
+               bfd_boolean ifunc;
 
                *offp = off | 1;
+               relgot = NULL;
+               ifunc = (h != NULL
+                        ? h->elf.type == STT_GNU_IFUNC
+                        : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
                if ((info->shared || indx != 0)
                    && (offp == &ppc64_tlsld_got (input_bfd)->offset
                        || h == NULL
                        || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                        || h->elf.root.type != bfd_link_hash_undefweak))
+                 relgot = ppc64_elf_tdata (input_bfd)->relgot;
+               else if (ifunc)
+                 relgot = htab->reliplt;
+               if (relgot != NULL)
                  {
                    outrel.r_offset = (got->output_section->vma
                                       + got->output_offset
@@ -11411,9 +11525,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
                    else if (tls_type == (TLS_TLS | TLS_TPREL))
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64);
-                   else if (indx == 0)
+                   else if (indx != 0)
+                     outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT);
+                   else
                      {
-                       outrel.r_info = ELF64_R_INFO (indx, R_PPC64_RELATIVE);
+                       if (ifunc)
+                         outrel.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+                       else
+                         outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
 
                        /* Write the .got section contents for the sake
                           of prelink.  */
@@ -11421,8 +11540,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                        bfd_put_64 (output_bfd, outrel.r_addend + relocation,
                                    loc);
                      }
-                   else
-                     outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT);
 
                    if (indx == 0 && tls_type != (TLS_TLS | TLS_LD))
                      {
@@ -11541,6 +11658,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            addend -= sec->output_section->vma;
          break;
 
+       case R_PPC64_REL16:
+       case R_PPC64_REL16_LO:
+       case R_PPC64_REL16_HI:
+       case R_PPC64_REL16_HA:
+         break;
+
        case R_PPC64_REL14:
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRTAKEN:
@@ -11633,7 +11756,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  && h != NULL
                  && h->elf.dynindx != -1
                  && !h->elf.non_got_ref
-                 && !h->elf.def_regular))
+                 && !h->elf.def_regular)
+             || (!info->shared
+                 && (h != NULL
+                     ? h->elf.type == STT_GNU_IFUNC
+                     : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
            {
              Elf_Internal_Rela outrel;
              bfd_boolean skip, relocate;
@@ -11698,19 +11825,42 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                             entry in this lib.  */
                          unresolved_reloc = FALSE;
                        }
-                     outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+                     if (!is_opd
+                         && r_type == R_PPC64_ADDR64
+                         && (h != NULL
+                             ? h->elf.type == STT_GNU_IFUNC
+                             : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
+                       outrel.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+                     else
+                       {
+                         outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
 
-                     /* We need to relocate .opd contents for ld.so.
-                        Prelink also wants simple and consistent rules
-                        for relocs.  This make all RELATIVE relocs have
-                        *r_offset equal to r_addend.  */
-                     relocate = TRUE;
+                         /* We need to relocate .opd contents for ld.so.
+                            Prelink also wants simple and consistent rules
+                            for relocs.  This make all RELATIVE relocs have
+                            *r_offset equal to r_addend.  */
+                         relocate = TRUE;
+                       }
                    }
                  else
                    {
                      long indx = 0;
 
-                     if (r_symndx == 0 || bfd_is_abs_section (sec))
+                     if (h != NULL
+                         ? h->elf.type == STT_GNU_IFUNC
+                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                       {
+                         (*_bfd_error_handler)
+                           (_("%B(%A+0x%lx): relocation %s for indirect "
+                              "function %s unsupported"),
+                            input_bfd,
+                            input_section,
+                            (long) rel->r_offset,
+                            ppc64_elf_howto_table[r_type]->name,
+                            sym_name);
+                         ret = FALSE;
+                       }
+                     else if (r_symndx == 0 || bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                        {
@@ -11748,6 +11898,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
 
              sreloc = elf_section_data (input_section)->sreloc;
+             if (!htab->elf.dynamic_sections_created)
+               sreloc = htab->reliplt;
              if (sreloc == NULL)
                abort ();
 
@@ -11789,6 +11941,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_COPY:
        case R_PPC64_GLOB_DAT:
        case R_PPC64_JMP_SLOT:
+       case R_PPC64_JMP_IREL:
        case R_PPC64_RELATIVE:
          /* We shouldn't ever see these dynamic relocs in relocatable
             files.  */
@@ -11821,6 +11974,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_ADDR16_HA:
+       case R_PPC64_REL16_HA:
        case R_PPC64_ADDR16_HIGHERA:
        case R_PPC64_ADDR16_HIGHESTA:
        case R_PPC64_TOC16_HA:
@@ -12037,14 +12191,6 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
       {
        /* This symbol has an entry in the procedure linkage
           table.  Set it up.  */
-       asection *plt = htab->plt;
-       if (!htab->elf.dynamic_sections_created)
-         plt = htab->iplt;
-
-       rela.r_offset = (plt->output_section->vma
-                        + plt->output_offset
-                        + ent->plt.offset);
-
        if (!htab->elf.dynamic_sections_created
            || h->dynindx == -1)
          {
@@ -12052,26 +12198,29 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
                        && h->def_regular
                        && (h->root.type == bfd_link_hash_defined
                            || h->root.type == bfd_link_hash_defweak));
-           rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+           rela.r_offset = (htab->iplt->output_section->vma
+                            + htab->iplt->output_offset
+                            + ent->plt.offset);
+           rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
            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->reliplt->contents
+                  + (htab->reliplt->reloc_count++
+                     * sizeof (Elf64_External_Rela)));
          }
        else
          {
+           rela.r_offset = (htab->plt->output_section->vma
+                            + htab->plt->output_offset
+                            + ent->plt.offset);
            rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
            rela.r_addend = ent->addend;
+           loc = (htab->relplt->contents
+                  + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
+                     / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
          }
-
-       if (!htab->elf.dynamic_sections_created)
-         loc = (htab->reliplt->contents
-                + (ent->plt.offset
-                   / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
-       else
-         loc = (htab->relplt->contents
-                + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
-                   / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
        bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
       }