x86: Add _bfd_x86_elf_allocate_dynrelocs
authorH.J. Lu <hjl.tools@gmail.com>
Sat, 2 Sep 2017 14:26:54 +0000 (07:26 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Sat, 2 Sep 2017 14:27:40 +0000 (07:27 -0700)
Share _bfd_x86_elf_allocate_dynrelocs in elf32-i386.c and elf64-x86-64.c.

* elf32-i386.c (elf_i386_allocate_dynrelocs): Removed.
(elf_i386_allocate_local_dynrelocs): Likewise.
(elf_i386_size_dynamic_sections): Replace
elf_i386_allocate_dynrelocs/elf_i386_allocate_local_dynrelocs
with _bfd_x86_elf_allocate_dynrelocs and
_bfd_x86_elf_allocate_local_dynrelocs.
* elf64-x86-64.c (elf_x86_64_allocate_dynrelocs): Removed.
(elf_x86_64_allocate_local_dynrelocs): Likewise.
(elf_x86_64_size_dynamic_sections): Replace
elf_x86_64_allocate_dynrelocs/elf_x86_64_allocate_local_dynrelocs
with _bfd_x86_elf_allocate_dynrelocs and
_bfd_x86_elf_allocate_local_dynrelocs.
* elfxx-x86.c (_bfd_x86_elf_allocate_dynrelocs): New function.
(_bfd_x86_elf_allocate_local_dynrelocs): Likewise.
* elfxx-x86.h (_bfd_x86_elf_allocate_dynrelocs): New prototype.
(_bfd_x86_elf_allocate_local_dynrelocs): Likewise.

bfd/ChangeLog
bfd/elf32-i386.c
bfd/elf64-x86-64.c
bfd/elfxx-x86.c
bfd/elfxx-x86.h

index 5830e42..4d6fb59 100644 (file)
@@ -1,5 +1,24 @@
 2017-09-02  H.J. Lu  <hongjiu.lu@intel.com>
 
+       * elf32-i386.c (elf_i386_allocate_dynrelocs): Removed.
+       (elf_i386_allocate_local_dynrelocs): Likewise.
+       (elf_i386_size_dynamic_sections): Replace
+       elf_i386_allocate_dynrelocs/elf_i386_allocate_local_dynrelocs
+       with _bfd_x86_elf_allocate_dynrelocs and
+       _bfd_x86_elf_allocate_local_dynrelocs.
+       * elf64-x86-64.c (elf_x86_64_allocate_dynrelocs): Removed.
+       (elf_x86_64_allocate_local_dynrelocs): Likewise.
+       (elf_x86_64_size_dynamic_sections): Replace
+       elf_x86_64_allocate_dynrelocs/elf_x86_64_allocate_local_dynrelocs
+       with _bfd_x86_elf_allocate_dynrelocs and
+       _bfd_x86_elf_allocate_local_dynrelocs.
+       * elfxx-x86.c (_bfd_x86_elf_allocate_dynrelocs): New function.
+       (_bfd_x86_elf_allocate_local_dynrelocs): Likewise.
+       * elfxx-x86.h (_bfd_x86_elf_allocate_dynrelocs): New prototype.
+       (_bfd_x86_elf_allocate_local_dynrelocs): Likewise.
+
+2017-09-02  H.J. Lu  <hongjiu.lu@intel.com>
+
        * elf32-i386.c (is_i386_elf): Removed.
        (elf_i386_check_relocs): Replace is_i386_elf with is_x86_elf.
        (elf_i386_size_dynamic_sections): Likewise.
index bc2b219..2caff7f 100644 (file)
@@ -1951,456 +1951,6 @@ error_return:
   return FALSE;
 }
 
-/* Allocate space in .plt, .got and associated reloc sections for
-   dynamic relocs.  */
-
-static bfd_boolean
-elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
-{
-  struct bfd_link_info *info;
-  struct elf_x86_link_hash_table *htab;
-  struct elf_x86_link_hash_entry *eh;
-  struct elf_dyn_relocs *p;
-  unsigned plt_entry_size;
-  bfd_boolean resolved_to_zero;
-
-  if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
-
-  eh = (struct elf_x86_link_hash_entry *) h;
-
-  info = (struct bfd_link_info *) inf;
-  htab = elf_x86_hash_table (info, I386_ELF_DATA);
-  if (htab == NULL)
-    return FALSE;
-
-  plt_entry_size = htab->plt.plt_entry_size;
-
-  resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
-                                                     I386_ELF_DATA,
-                                                     eh->has_got_reloc,
-                                                     eh);
-
-  /* Clear the reference count of function pointer relocations if
-     symbol isn't a normal function.  */
-  if (h->type != STT_FUNC)
-    eh->func_pointer_refcount = 0;
-
-  /* We can't use the GOT PLT if pointer equality is needed since
-     finish_dynamic_symbol won't clear symbol value and the dynamic
-     linker won't update the GOT slot.  We will get into an infinite
-     loop at run-time.  */
-  if (htab->plt_got != NULL
-      && h->type != STT_GNU_IFUNC
-      && !h->pointer_equality_needed
-      && h->plt.refcount > 0
-      && h->got.refcount > 0)
-    {
-      /* Don't use the regular PLT if there are both GOT and GOTPLT
-         reloctions.  */
-      h->plt.offset = (bfd_vma) -1;
-
-      /* Use the GOT PLT.  */
-      eh->plt_got.refcount = 1;
-    }
-
-  /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
-     here if it is defined and referenced in a non-shared object.  */
-  if (h->type == STT_GNU_IFUNC
-      && h->def_regular)
-    {
-      if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs,
-                                             &htab->readonly_dynrelocs_against_ifunc,
-                                             plt_entry_size,
-                                             (htab->plt.has_plt0
-                                              * plt_entry_size),
-                                              4, TRUE))
-       {
-         asection *s = htab->plt_second;
-         if (h->plt.offset != (bfd_vma) -1 && s != NULL)
-           {
-             /* Use the second PLT section if it is created.  */
-             eh->plt_second.offset = s->size;
-
-             /* Make room for this entry in the second PLT section.  */
-             s->size += htab->non_lazy_plt->plt_entry_size;
-           }
-
-         return TRUE;
-       }
-      else
-       return FALSE;
-    }
-  /* Don't create the PLT entry if there are only function pointer
-     relocations which can be resolved at run-time.  */
-  else if (htab->elf.dynamic_sections_created
-          && (h->plt.refcount > eh->func_pointer_refcount
-              || eh->plt_got.refcount > 0))
-    {
-      bfd_boolean use_plt_got = eh->plt_got.refcount > 0;
-
-      /* Clear the reference count of function pointer relocations
-        if PLT is used.  */
-      eh->func_pointer_refcount = 0;
-
-      /* 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
-         && !resolved_to_zero
-         && h->root.type == bfd_link_hash_undefweak)
-       {
-         if (! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
-       }
-
-      if (bfd_link_pic (info)
-         || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
-       {
-         asection *s = htab->elf.splt;
-         asection *second_s = htab->plt_second;
-         asection *got_s = htab->plt_got;
-
-         /* If this is the first .plt entry, make room for the special
-            first entry.  The .plt section is used by prelink to undo
-            prelinking for dynamic relocations.  */
-         if (s->size == 0)
-           s->size = htab->plt.has_plt0 * plt_entry_size;
-
-         if (use_plt_got)
-           eh->plt_got.offset = got_s->size;
-         else
-           {
-             h->plt.offset = s->size;
-             if (second_s)
-               eh->plt_second.offset = second_s->size;
-           }
-
-         /* If this symbol is not defined in a regular file, and we are
-            not generating a shared library, then set the symbol to this
-            location in the .plt.  This is required to make function
-            pointers compare as equal between the normal executable and
-            the shared library.  */
-         if (! bfd_link_pic (info)
-             && !h->def_regular)
-           {
-             if (use_plt_got)
-               {
-                 /* We need to make a call to the entry of the GOT PLT
-                    instead of regular PLT entry.  */
-                 h->root.u.def.section = got_s;
-                 h->root.u.def.value = eh->plt_got.offset;
-               }
-             else
-               {
-                 if (second_s)
-                   {
-                     /* We need to make a call to the entry of the
-                        second PLT instead of regular PLT entry.  */
-                     h->root.u.def.section = second_s;
-                     h->root.u.def.value = eh->plt_second.offset;
-                   }
-                 else
-                   {
-                     h->root.u.def.section = s;
-                     h->root.u.def.value = h->plt.offset;
-                   }
-               }
-           }
-
-         /* Make room for this entry.  */
-         if (use_plt_got)
-           got_s->size += htab->non_lazy_plt->plt_entry_size;
-         else
-           {
-             s->size += plt_entry_size;
-             if (second_s)
-               second_s->size += htab->non_lazy_plt->plt_entry_size;
-
-             /* We also need to make an entry in the .got.plt section,
-                which will be placed in the .got section by the linker
-                script.  */
-             htab->elf.sgotplt->size += 4;
-
-             /* There should be no PLT relocation against resolved
-                undefined weak symbol in executable.  */
-             if (!resolved_to_zero)
-               {
-                 /* We also need to make an entry in the .rel.plt
-                    section.  */
-                 htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
-                 htab->elf.srelplt->reloc_count++;
-               }
-           }
-
-         if (htab->is_vxworks && !bfd_link_pic (info))
-           {
-             /* VxWorks has a second set of relocations for each PLT entry
-                in executables.  They go in a separate relocation section,
-                which is processed by the kernel loader.  */
-
-             /* There are two relocations for the initial PLT entry: an
-                R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an
-                R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8.  */
-
-             asection *srelplt2 = htab->srelplt2;
-             if (h->plt.offset == plt_entry_size)
-               srelplt2->size += (sizeof (Elf32_External_Rel) * 2);
-
-             /* There are two extra relocations for each subsequent PLT entry:
-                an R_386_32 relocation for the GOT entry, and an R_386_32
-                relocation for the PLT entry.  */
-
-             srelplt2->size += (sizeof (Elf32_External_Rel) * 2);
-           }
-       }
-      else
-       {
-         eh->plt_got.offset = (bfd_vma) -1;
-         h->plt.offset = (bfd_vma) -1;
-         h->needs_plt = 0;
-       }
-    }
-  else
-    {
-      eh->plt_got.offset = (bfd_vma) -1;
-      h->plt.offset = (bfd_vma) -1;
-      h->needs_plt = 0;
-    }
-
-  eh->tlsdesc_got = (bfd_vma) -1;
-
-  /* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary,
-     make it a R_386_TLS_LE_32 requiring no TLS entry.  */
-  if (h->got.refcount > 0
-      && bfd_link_executable (info)
-      && h->dynindx == -1
-      && (elf_x86_hash_entry (h)->tls_type & GOT_TLS_IE))
-    h->got.offset = (bfd_vma) -1;
-  else if (h->got.refcount > 0)
-    {
-      asection *s;
-      bfd_boolean dyn;
-      int tls_type = elf_x86_hash_entry (h)->tls_type;
-
-      /* 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
-         && !resolved_to_zero
-         && h->root.type == bfd_link_hash_undefweak)
-       {
-         if (! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
-       }
-
-      s = htab->elf.sgot;
-      if (GOT_TLS_GDESC_P (tls_type))
-       {
-         eh->tlsdesc_got = htab->elf.sgotplt->size
-           - elf_x86_compute_jump_table_size (htab);
-         htab->elf.sgotplt->size += 8;
-         h->got.offset = (bfd_vma) -2;
-       }
-      if (! GOT_TLS_GDESC_P (tls_type)
-         || GOT_TLS_GD_P (tls_type))
-       {
-         h->got.offset = s->size;
-         s->size += 4;
-         /* R_386_TLS_GD needs 2 consecutive GOT slots.  */
-         if (GOT_TLS_GD_P (tls_type) || tls_type == GOT_TLS_IE_BOTH)
-           s->size += 4;
-       }
-      dyn = htab->elf.dynamic_sections_created;
-      /* R_386_TLS_IE_32 needs one dynamic relocation,
-        R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation,
-        (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we
-        need two), R_386_TLS_GD needs one if local symbol and two if
-        global.  No dynamic relocation against resolved undefined weak
-        symbol in executable.  */
-      if (tls_type == GOT_TLS_IE_BOTH)
-       htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rel);
-      else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
-              || (tls_type & GOT_TLS_IE))
-       htab->elf.srelgot->size += sizeof (Elf32_External_Rel);
-      else if (GOT_TLS_GD_P (tls_type))
-       htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rel);
-      else if (! GOT_TLS_GDESC_P (tls_type)
-              && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-                   && !resolved_to_zero)
-                  || h->root.type != bfd_link_hash_undefweak)
-              && (bfd_link_pic (info)
-                  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
-       htab->elf.srelgot->size += sizeof (Elf32_External_Rel);
-      if (GOT_TLS_GDESC_P (tls_type))
-       htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
-    }
-  else
-    h->got.offset = (bfd_vma) -1;
-
-  if (eh->dyn_relocs == NULL)
-    return TRUE;
-
-  /* In the shared -Bsymbolic case, discard space allocated for
-     dynamic pc-relative relocs against symbols which turn out to be
-     defined in regular objects.  For the normal shared case, discard
-     space for pc-relative relocs that have become local due to symbol
-     visibility changes.  */
-
-  if (bfd_link_pic (info))
-    {
-      /* The only reloc that uses pc_count is R_386_PC32, which will
-        appear on a call or on something like ".long foo - .".  We
-        want calls to protected symbols to resolve directly to the
-        function rather than going via the plt.  If people want
-        function pointer comparisons to work as expected then they
-        should avoid writing assembly like ".long foo - .".  */
-      if (SYMBOL_CALLS_LOCAL (info, h))
-       {
-         struct elf_dyn_relocs **pp;
-
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-           {
-             p->count -= p->pc_count;
-             p->pc_count = 0;
-             if (p->count == 0)
-               *pp = p->next;
-             else
-               pp = &p->next;
-           }
-       }
-
-      if (htab->is_vxworks)
-       {
-         struct elf_dyn_relocs **pp;
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-           {
-             if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
-               *pp = p->next;
-             else
-               pp = &p->next;
-           }
-       }
-
-      /* Also discard relocs on undefined weak syms with non-default
-        visibility or in PIE.  */
-      if (eh->dyn_relocs != NULL
-         && h->root.type == bfd_link_hash_undefweak)
-       {
-         /* Undefined weak symbol is never bound locally in shared
-            library.  */
-         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-             || resolved_to_zero)
-           {
-             if (h->non_got_ref)
-               {
-                 /* Keep dynamic non-GOT/non-PLT relocation so that we
-                    can branch to 0 without PLT.  */
-                 struct elf_dyn_relocs **pp;
-
-                 for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-                   if (p->pc_count == 0)
-                     *pp = p->next;
-                   else
-                     {
-                       /* Remove non-R_386_PC32 relocation.  */
-                       p->count = p->pc_count;
-                       pp = &p->next;
-                     }
-
-                 if (eh->dyn_relocs != NULL)
-                   {
-                     /* Make sure undefined weak symbols are output
-                        as dynamic symbols in PIEs for dynamic non-GOT
-                        non-PLT reloations.  */
-                     if (! bfd_elf_link_record_dynamic_symbol (info, h))
-                       return FALSE;
-                   }
-               }
-             else
-               eh->dyn_relocs = NULL;
-           }
-         else if (h->dynindx == -1
-                  && !h->forced_local)
-           {
-             if (! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
-           }
-       }
-    }
-  else if (ELIMINATE_COPY_RELOCS)
-    {
-      /* For the non-shared case, discard space for relocs against
-        symbols which turn out to need copy relocs or are not
-        dynamic.  Keep dynamic relocations for run-time function
-        pointer initialization.  */
-
-      if ((!h->non_got_ref
-          || eh->func_pointer_refcount > 0
-          || (h->root.type == bfd_link_hash_undefweak
-              && !resolved_to_zero))
-         && ((h->def_dynamic
-              && !h->def_regular)
-             || (htab->elf.dynamic_sections_created
-                 && (h->root.type == bfd_link_hash_undefweak
-                     || h->root.type == bfd_link_hash_undefined))))
-       {
-         /* 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
-             && !resolved_to_zero
-             && h->root.type == bfd_link_hash_undefweak)
-           {
-             if (! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
-           }
-
-         /* If that succeeded, we know we'll be keeping all the
-            relocs.  */
-         if (h->dynindx != -1)
-           goto keep;
-       }
-
-      eh->dyn_relocs = NULL;
-      eh->func_pointer_refcount = 0;
-
-    keep: ;
-    }
-
-  /* Finally, allocate space.  */
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-    {
-      asection *sreloc;
-
-      sreloc = elf_section_data (p->sec)->sreloc;
-
-      BFD_ASSERT (sreloc != NULL);
-      sreloc->size += p->count * sizeof (Elf32_External_Rel);
-    }
-
-  return TRUE;
-}
-
-/* Allocate space in .plt, .got and associated reloc sections for
-   local dynamic relocs.  */
-
-static bfd_boolean
-elf_i386_allocate_local_dynrelocs (void **slot, void *inf)
-{
-  struct elf_link_hash_entry *h
-    = (struct elf_link_hash_entry *) *slot;
-
-  if (h->type != STT_GNU_IFUNC
-      || !h->def_regular
-      || !h->ref_regular
-      || !h->forced_local
-      || h->root.type != bfd_link_hash_defined)
-    abort ();
-
-  return elf_i386_allocate_dynrelocs (h, inf);
-}
-
 /* Convert load via the GOT slot to load immediate.  */
 
 static bfd_boolean
@@ -2673,11 +2223,12 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
 
   /* Allocate global sym .plt and .got entries, and space for global
      sym dynamic relocs.  */
-  elf_link_hash_traverse (&htab->elf, elf_i386_allocate_dynrelocs, info);
+  elf_link_hash_traverse (&htab->elf, _bfd_x86_elf_allocate_dynrelocs,
+                         info);
 
   /* Allocate .plt and .got entries, and space for local symbols.  */
   htab_traverse (htab->loc_hash_table,
-                elf_i386_allocate_local_dynrelocs,
+                _bfd_x86_elf_allocate_local_dynrelocs,
                 info);
 
   /* For every jump slot reserved in the sgotplt, reloc_count is
index 7a6e1f1..ed67d89 100644 (file)
@@ -2394,414 +2394,6 @@ error_return:
   return FALSE;
 }
 
-/* Allocate space in .plt, .got and associated reloc sections for
-   dynamic relocs.  */
-
-static bfd_boolean
-elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
-{
-  struct bfd_link_info *info;
-  struct elf_x86_link_hash_table *htab;
-  struct elf_x86_link_hash_entry *eh;
-  struct elf_dyn_relocs *p;
-  const struct elf_backend_data *bed;
-  unsigned int plt_entry_size;
-  bfd_boolean resolved_to_zero;
-
-  if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
-
-  eh = (struct elf_x86_link_hash_entry *) h;
-
-  info = (struct bfd_link_info *) inf;
-  htab = elf_x86_hash_table (info, X86_64_ELF_DATA);
-  if (htab == NULL)
-    return FALSE;
-  bed = get_elf_backend_data (info->output_bfd);
-
-  plt_entry_size = htab->plt.plt_entry_size;
-
-  resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
-                                                     X86_64_ELF_DATA,
-                                                     eh->has_got_reloc,
-                                                     eh);
-
-  /* We can't use the GOT PLT if pointer equality is needed since
-     finish_dynamic_symbol won't clear symbol value and the dynamic
-     linker won't update the GOT slot.  We will get into an infinite
-     loop at run-time.  */
-  if (htab->plt_got != NULL
-      && h->type != STT_GNU_IFUNC
-      && !h->pointer_equality_needed
-      && h->plt.refcount > 0
-      && h->got.refcount > 0)
-    {
-      /* Don't use the regular PLT if there are both GOT and GOTPLT
-         reloctions.  */
-      h->plt.offset = (bfd_vma) -1;
-
-      /* Use the GOT PLT.  */
-      eh->plt_got.refcount = 1;
-    }
-
-  /* Clear the reference count of function pointer relocations if
-     symbol isn't a normal function.  */
-  if (h->type != STT_FUNC)
-    eh->func_pointer_refcount = 0;
-
-  /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
-     here if it is defined and referenced in a non-shared object.  */
-  if (h->type == STT_GNU_IFUNC
-      && h->def_regular)
-    {
-      if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h,
-                                             &eh->dyn_relocs,
-                                             &htab->readonly_dynrelocs_against_ifunc,
-                                             plt_entry_size,
-                                             (htab->plt.has_plt0
-                                              * plt_entry_size),
-                                             GOT_ENTRY_SIZE, TRUE))
-       {
-         asection *s = htab->plt_second;
-         if (h->plt.offset != (bfd_vma) -1 && s != NULL)
-           {
-             /* Use the second PLT section if it is created.  */
-             eh->plt_second.offset = s->size;
-
-             /* Make room for this entry in the second PLT section.  */
-             s->size += htab->non_lazy_plt->plt_entry_size;
-           }
-
-         return TRUE;
-       }
-      else
-       return FALSE;
-    }
-  /* Don't create the PLT entry if there are only function pointer
-     relocations which can be resolved at run-time.  */
-  else if (htab->elf.dynamic_sections_created
-          && (h->plt.refcount > eh->func_pointer_refcount
-              || eh->plt_got.refcount > 0))
-    {
-      bfd_boolean use_plt_got = eh->plt_got.refcount > 0;
-
-      /* Clear the reference count of function pointer relocations
-        if PLT is used.  */
-      eh->func_pointer_refcount = 0;
-
-      /* 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
-         && !resolved_to_zero
-         && h->root.type == bfd_link_hash_undefweak)
-       {
-         if (! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
-       }
-
-      if (bfd_link_pic (info)
-         || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
-       {
-         asection *s = htab->elf.splt;
-         asection *second_s = htab->plt_second;
-         asection *got_s = htab->plt_got;
-
-         /* If this is the first .plt entry, make room for the special
-            first entry.  The .plt section is used by prelink to undo
-            prelinking for dynamic relocations.  */
-         if (s->size == 0)
-           s->size = htab->plt.has_plt0 * plt_entry_size;
-
-         if (use_plt_got)
-           eh->plt_got.offset = got_s->size;
-         else
-           {
-             h->plt.offset = s->size;
-             if (second_s)
-               eh->plt_second.offset = second_s->size;
-           }
-
-         /* If this symbol is not defined in a regular file, and we are
-            not generating a shared library, then set the symbol to this
-            location in the .plt.  This is required to make function
-            pointers compare as equal between the normal executable and
-            the shared library.  */
-         if (! bfd_link_pic (info)
-             && !h->def_regular)
-           {
-             if (use_plt_got)
-               {
-                 /* We need to make a call to the entry of the GOT PLT
-                    instead of regular PLT entry.  */
-                 h->root.u.def.section = got_s;
-                 h->root.u.def.value = eh->plt_got.offset;
-               }
-             else
-               {
-                 if (second_s)
-                   {
-                     /* We need to make a call to the entry of the
-                        second PLT instead of regular PLT entry.  */
-                     h->root.u.def.section = second_s;
-                     h->root.u.def.value = eh->plt_second.offset;
-                   }
-                 else
-                   {
-                     h->root.u.def.section = s;
-                     h->root.u.def.value = h->plt.offset;
-                   }
-               }
-           }
-
-         /* Make room for this entry.  */
-         if (use_plt_got)
-           got_s->size += htab->non_lazy_plt->plt_entry_size;
-         else
-           {
-             s->size += plt_entry_size;
-             if (second_s)
-               second_s->size += htab->non_lazy_plt->plt_entry_size;
-
-             /* We also need to make an entry in the .got.plt section,
-                which will be placed in the .got section by the linker
-                script.  */
-             htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
-
-             /* There should be no PLT relocation against resolved
-                undefined weak symbol in executable.  */
-             if (!resolved_to_zero)
-               {
-                 /* We also need to make an entry in the .rela.plt
-                    section.  */
-                 htab->elf.srelplt->size += bed->s->sizeof_rela;
-                 htab->elf.srelplt->reloc_count++;
-               }
-           }
-       }
-      else
-       {
-         eh->plt_got.offset = (bfd_vma) -1;
-         h->plt.offset = (bfd_vma) -1;
-         h->needs_plt = 0;
-       }
-    }
-  else
-    {
-      eh->plt_got.offset = (bfd_vma) -1;
-      h->plt.offset = (bfd_vma) -1;
-      h->needs_plt = 0;
-    }
-
-  eh->tlsdesc_got = (bfd_vma) -1;
-
-  /* If R_X86_64_GOTTPOFF symbol is now local to the binary,
-     make it a R_X86_64_TPOFF32 requiring no GOT entry.  */
-  if (h->got.refcount > 0
-      && bfd_link_executable (info)
-      && h->dynindx == -1
-      && elf_x86_hash_entry (h)->tls_type == GOT_TLS_IE)
-    {
-      h->got.offset = (bfd_vma) -1;
-    }
-  else if (h->got.refcount > 0)
-    {
-      asection *s;
-      bfd_boolean dyn;
-      int tls_type = elf_x86_hash_entry (h)->tls_type;
-
-      /* 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
-         && !resolved_to_zero
-         && h->root.type == bfd_link_hash_undefweak)
-       {
-         if (! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
-       }
-
-      if (GOT_TLS_GDESC_P (tls_type))
-       {
-         eh->tlsdesc_got = htab->elf.sgotplt->size
-           - elf_x86_compute_jump_table_size (htab);
-         htab->elf.sgotplt->size += 2 * GOT_ENTRY_SIZE;
-         h->got.offset = (bfd_vma) -2;
-       }
-      if (! GOT_TLS_GDESC_P (tls_type)
-         || GOT_TLS_GD_P (tls_type))
-       {
-         s = htab->elf.sgot;
-         h->got.offset = s->size;
-         s->size += GOT_ENTRY_SIZE;
-         if (GOT_TLS_GD_P (tls_type))
-           s->size += GOT_ENTRY_SIZE;
-       }
-      dyn = htab->elf.dynamic_sections_created;
-      /* R_X86_64_TLSGD needs one dynamic relocation if local symbol
-        and two if global.  R_X86_64_GOTTPOFF needs one dynamic
-        relocation.  No dynamic relocation against resolved undefined
-        weak symbol in executable.  */
-      if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
-         || tls_type == GOT_TLS_IE)
-       htab->elf.srelgot->size += bed->s->sizeof_rela;
-      else if (GOT_TLS_GD_P (tls_type))
-       htab->elf.srelgot->size += 2 * bed->s->sizeof_rela;
-      else if (! GOT_TLS_GDESC_P (tls_type)
-              && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-                   && !resolved_to_zero)
-                  || h->root.type != bfd_link_hash_undefweak)
-              && (bfd_link_pic (info)
-                  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
-       htab->elf.srelgot->size += bed->s->sizeof_rela;
-      if (GOT_TLS_GDESC_P (tls_type))
-       {
-         htab->elf.srelplt->size += bed->s->sizeof_rela;
-         htab->tlsdesc_plt = (bfd_vma) -1;
-       }
-    }
-  else
-    h->got.offset = (bfd_vma) -1;
-
-  if (eh->dyn_relocs == NULL)
-    return TRUE;
-
-  /* In the shared -Bsymbolic case, discard space allocated for
-     dynamic pc-relative relocs against symbols which turn out to be
-     defined in regular objects.  For the normal shared case, discard
-     space for pc-relative relocs that have become local due to symbol
-     visibility changes.  */
-
-  if (bfd_link_pic (info))
-    {
-      /* Relocs that use pc_count are those that appear on a call
-        insn, or certain REL relocs that can generated via assembly.
-        We want calls to protected symbols to resolve directly to the
-        function rather than going via the plt.  If people want
-        function pointer comparisons to work as expected then they
-        should avoid writing weird assembly.  */
-      if (SYMBOL_CALLS_LOCAL (info, h))
-       {
-         struct elf_dyn_relocs **pp;
-
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-           {
-             p->count -= p->pc_count;
-             p->pc_count = 0;
-             if (p->count == 0)
-               *pp = p->next;
-             else
-               pp = &p->next;
-           }
-       }
-
-      /* Also discard relocs on undefined weak syms with non-default
-        visibility or in PIE.  */
-      if (eh->dyn_relocs != NULL)
-       {
-         if (h->root.type == bfd_link_hash_undefweak)
-           {
-             /* Undefined weak symbol is never bound locally in shared
-                library.  */
-             if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-                 || resolved_to_zero)
-               eh->dyn_relocs = NULL;
-             else if (h->dynindx == -1
-                      && ! h->forced_local
-                      && ! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
-           }
-         /* For PIE, discard space for pc-relative relocs against
-            symbols which turn out to need copy relocs.  */
-         else if (bfd_link_executable (info)
-                  && (h->needs_copy || eh->needs_copy)
-                  && h->def_dynamic
-                  && !h->def_regular)
-           {
-             struct elf_dyn_relocs **pp;
-
-             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-               {
-                 if (p->pc_count != 0)
-                   *pp = p->next;
-                 else
-                   pp = &p->next;
-               }
-           }
-       }
-    }
-  else if (ELIMINATE_COPY_RELOCS)
-    {
-      /* For the non-shared case, discard space for relocs against
-        symbols which turn out to need copy relocs or are not
-        dynamic.  Keep dynamic relocations for run-time function
-        pointer initialization.  */
-
-      if ((!h->non_got_ref
-          || eh->func_pointer_refcount > 0
-          || (h->root.type == bfd_link_hash_undefweak
-              && !resolved_to_zero))
-         && ((h->def_dynamic
-              && !h->def_regular)
-             || (htab->elf.dynamic_sections_created
-                 && (h->root.type == bfd_link_hash_undefweak
-                     || h->root.type == bfd_link_hash_undefined))))
-       {
-         /* 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
-             && ! resolved_to_zero
-             && h->root.type == bfd_link_hash_undefweak
-             && ! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
-
-         /* If that succeeded, we know we'll be keeping all the
-            relocs.  */
-         if (h->dynindx != -1)
-           goto keep;
-       }
-
-      eh->dyn_relocs = NULL;
-      eh->func_pointer_refcount = 0;
-
-    keep: ;
-    }
-
-  /* Finally, allocate space.  */
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-    {
-      asection * sreloc;
-
-      sreloc = elf_section_data (p->sec)->sreloc;
-
-      BFD_ASSERT (sreloc != NULL);
-
-      sreloc->size += p->count * bed->s->sizeof_rela;
-    }
-
-  return TRUE;
-}
-
-/* Allocate space in .plt, .got and associated reloc sections for
-   local dynamic relocs.  */
-
-static bfd_boolean
-elf_x86_64_allocate_local_dynrelocs (void **slot, void *inf)
-{
-  struct elf_link_hash_entry *h
-    = (struct elf_link_hash_entry *) *slot;
-
-  if (h->type != STT_GNU_IFUNC
-      || !h->def_regular
-      || !h->ref_regular
-      || !h->forced_local
-      || h->root.type != bfd_link_hash_defined)
-    abort ();
-
-  return elf_x86_64_allocate_dynrelocs (h, inf);
-}
-
 /* Convert load via the GOT slot to load immediate.  */
 
 static bfd_boolean
@@ -3072,12 +2664,12 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
 
   /* Allocate global sym .plt and .got entries, and space for global
      sym dynamic relocs.  */
-  elf_link_hash_traverse (&htab->elf, elf_x86_64_allocate_dynrelocs,
+  elf_link_hash_traverse (&htab->elf, _bfd_x86_elf_allocate_dynrelocs,
                          info);
 
   /* Allocate .plt and .got entries, and space for local symbols.  */
   htab_traverse (htab->loc_hash_table,
-                elf_x86_64_allocate_local_dynrelocs,
+                _bfd_x86_elf_allocate_local_dynrelocs,
                 info);
 
   /* For every jump slot reserved in the sgotplt, reloc_count is
index b3d241c..646b251 100644 (file)
@@ -79,6 +79,459 @@ _bfd_x86_elf_dtpoff_base (struct bfd_link_info *info)
   return elf_hash_table (info)->tls_sec->vma;
 }
 
+/* Allocate space in .plt, .got and associated reloc sections for
+   dynamic relocs.  */
+
+bfd_boolean
+_bfd_x86_elf_allocate_dynrelocs (struct elf_link_hash_entry *h,
+                                void *inf)
+{
+  struct bfd_link_info *info;
+  struct elf_x86_link_hash_table *htab;
+  struct elf_x86_link_hash_entry *eh;
+  struct elf_dyn_relocs *p;
+  unsigned int plt_entry_size;
+  bfd_boolean resolved_to_zero;
+  const struct elf_backend_data *bed;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  eh = (struct elf_x86_link_hash_entry *) h;
+
+  info = (struct bfd_link_info *) inf;
+  bed = get_elf_backend_data (info->output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  if (htab == NULL)
+    return FALSE;
+
+  plt_entry_size = htab->plt.plt_entry_size;
+
+  resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
+                                                     bed->target_id,
+                                                     eh->has_got_reloc,
+                                                     eh);
+
+  /* Clear the reference count of function pointer relocations if
+     symbol isn't a normal function.  */
+  if (h->type != STT_FUNC)
+    eh->func_pointer_refcount = 0;
+
+  /* We can't use the GOT PLT if pointer equality is needed since
+     finish_dynamic_symbol won't clear symbol value and the dynamic
+     linker won't update the GOT slot.  We will get into an infinite
+     loop at run-time.  */
+  if (htab->plt_got != NULL
+      && h->type != STT_GNU_IFUNC
+      && !h->pointer_equality_needed
+      && h->plt.refcount > 0
+      && h->got.refcount > 0)
+    {
+      /* Don't use the regular PLT if there are both GOT and GOTPLT
+         reloctions.  */
+      h->plt.offset = (bfd_vma) -1;
+
+      /* Use the GOT PLT.  */
+      eh->plt_got.refcount = 1;
+    }
+
+  /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
+     here if it is defined and referenced in a non-shared object.  */
+  if (h->type == STT_GNU_IFUNC
+      && h->def_regular)
+    {
+      if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs,
+                                             &htab->readonly_dynrelocs_against_ifunc,
+                                             plt_entry_size,
+                                             (htab->plt.has_plt0
+                                              * plt_entry_size),
+                                              htab->got_entry_size,
+                                              TRUE))
+       {
+         asection *s = htab->plt_second;
+         if (h->plt.offset != (bfd_vma) -1 && s != NULL)
+           {
+             /* Use the second PLT section if it is created.  */
+             eh->plt_second.offset = s->size;
+
+             /* Make room for this entry in the second PLT section.  */
+             s->size += htab->non_lazy_plt->plt_entry_size;
+           }
+
+         return TRUE;
+       }
+      else
+       return FALSE;
+    }
+  /* Don't create the PLT entry if there are only function pointer
+     relocations which can be resolved at run-time.  */
+  else if (htab->elf.dynamic_sections_created
+          && (h->plt.refcount > eh->func_pointer_refcount
+              || eh->plt_got.refcount > 0))
+    {
+      bfd_boolean use_plt_got = eh->plt_got.refcount > 0;
+
+      /* Clear the reference count of function pointer relocations
+        if PLT is used.  */
+      eh->func_pointer_refcount = 0;
+
+      /* 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
+         && !resolved_to_zero
+         && h->root.type == bfd_link_hash_undefweak)
+       {
+         if (! bfd_elf_link_record_dynamic_symbol (info, h))
+           return FALSE;
+       }
+
+      if (bfd_link_pic (info)
+         || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
+       {
+         asection *s = htab->elf.splt;
+         asection *second_s = htab->plt_second;
+         asection *got_s = htab->plt_got;
+
+         /* If this is the first .plt entry, make room for the special
+            first entry.  The .plt section is used by prelink to undo
+            prelinking for dynamic relocations.  */
+         if (s->size == 0)
+           s->size = htab->plt.has_plt0 * plt_entry_size;
+
+         if (use_plt_got)
+           eh->plt_got.offset = got_s->size;
+         else
+           {
+             h->plt.offset = s->size;
+             if (second_s)
+               eh->plt_second.offset = second_s->size;
+           }
+
+         /* If this symbol is not defined in a regular file, and we are
+            not generating a shared library, then set the symbol to this
+            location in the .plt.  This is required to make function
+            pointers compare as equal between the normal executable and
+            the shared library.  */
+         if (! bfd_link_pic (info)
+             && !h->def_regular)
+           {
+             if (use_plt_got)
+               {
+                 /* We need to make a call to the entry of the GOT PLT
+                    instead of regular PLT entry.  */
+                 h->root.u.def.section = got_s;
+                 h->root.u.def.value = eh->plt_got.offset;
+               }
+             else
+               {
+                 if (second_s)
+                   {
+                     /* We need to make a call to the entry of the
+                        second PLT instead of regular PLT entry.  */
+                     h->root.u.def.section = second_s;
+                     h->root.u.def.value = eh->plt_second.offset;
+                   }
+                 else
+                   {
+                     h->root.u.def.section = s;
+                     h->root.u.def.value = h->plt.offset;
+                   }
+               }
+           }
+
+         /* Make room for this entry.  */
+         if (use_plt_got)
+           got_s->size += htab->non_lazy_plt->plt_entry_size;
+         else
+           {
+             s->size += plt_entry_size;
+             if (second_s)
+               second_s->size += htab->non_lazy_plt->plt_entry_size;
+
+             /* We also need to make an entry in the .got.plt section,
+                which will be placed in the .got section by the linker
+                script.  */
+             htab->elf.sgotplt->size += htab->got_entry_size;
+
+             /* There should be no PLT relocation against resolved
+                undefined weak symbol in executable.  */
+             if (!resolved_to_zero)
+               {
+                 /* We also need to make an entry in the .rel.plt
+                    section.  */
+                 htab->elf.srelplt->size += htab->sizeof_reloc;
+                 htab->elf.srelplt->reloc_count++;
+               }
+           }
+
+         if (htab->is_vxworks && !bfd_link_pic (info))
+           {
+             /* VxWorks has a second set of relocations for each PLT entry
+                in executables.  They go in a separate relocation section,
+                which is processed by the kernel loader.  */
+
+             /* There are two relocations for the initial PLT entry: an
+                R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an
+                R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8.  */
+
+             asection *srelplt2 = htab->srelplt2;
+             if (h->plt.offset == plt_entry_size)
+               srelplt2->size += (htab->sizeof_reloc * 2);
+
+             /* There are two extra relocations for each subsequent PLT entry:
+                an R_386_32 relocation for the GOT entry, and an R_386_32
+                relocation for the PLT entry.  */
+
+             srelplt2->size += (htab->sizeof_reloc * 2);
+           }
+       }
+      else
+       {
+         eh->plt_got.offset = (bfd_vma) -1;
+         h->plt.offset = (bfd_vma) -1;
+         h->needs_plt = 0;
+       }
+    }
+  else
+    {
+      eh->plt_got.offset = (bfd_vma) -1;
+      h->plt.offset = (bfd_vma) -1;
+      h->needs_plt = 0;
+    }
+
+  eh->tlsdesc_got = (bfd_vma) -1;
+
+  /* For i386, if R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the
+     binary, make it a R_386_TLS_LE_32 requiring no TLS entry.  For
+     x86-64, if R_X86_64_GOTTPOFF symbol is now local to the binary,
+     make it a R_X86_64_TPOFF32 requiring no GOT entry.  */
+  if (h->got.refcount > 0
+      && bfd_link_executable (info)
+      && h->dynindx == -1
+      && (elf_x86_hash_entry (h)->tls_type & GOT_TLS_IE))
+    h->got.offset = (bfd_vma) -1;
+  else if (h->got.refcount > 0)
+    {
+      asection *s;
+      bfd_boolean dyn;
+      int tls_type = elf_x86_hash_entry (h)->tls_type;
+
+      /* 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
+         && !resolved_to_zero
+         && h->root.type == bfd_link_hash_undefweak)
+       {
+         if (! bfd_elf_link_record_dynamic_symbol (info, h))
+           return FALSE;
+       }
+
+      s = htab->elf.sgot;
+      if (GOT_TLS_GDESC_P (tls_type))
+       {
+         eh->tlsdesc_got = htab->elf.sgotplt->size
+           - elf_x86_compute_jump_table_size (htab);
+         htab->elf.sgotplt->size += 2 * htab->got_entry_size;
+         h->got.offset = (bfd_vma) -2;
+       }
+      if (! GOT_TLS_GDESC_P (tls_type)
+         || GOT_TLS_GD_P (tls_type))
+       {
+         h->got.offset = s->size;
+         s->size += htab->got_entry_size;
+         /* R_386_TLS_GD and R_X86_64_TLSGD need 2 consecutive GOT
+            slots.  */
+         if (GOT_TLS_GD_P (tls_type) || tls_type == GOT_TLS_IE_BOTH)
+           s->size += htab->got_entry_size;
+       }
+      dyn = htab->elf.dynamic_sections_created;
+      /* R_386_TLS_IE_32 needs one dynamic relocation,
+        R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation,
+        (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we
+        need two), R_386_TLS_GD and R_X86_64_TLSGD need one if local
+        symbol and two if global.  No dynamic relocation against
+        resolved undefined weak symbol in executable.  */
+      if (tls_type == GOT_TLS_IE_BOTH)
+       htab->elf.srelgot->size += 2 * htab->sizeof_reloc;
+      else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
+              || (tls_type & GOT_TLS_IE))
+       htab->elf.srelgot->size += htab->sizeof_reloc;
+      else if (GOT_TLS_GD_P (tls_type))
+       htab->elf.srelgot->size += 2 * htab->sizeof_reloc;
+      else if (! GOT_TLS_GDESC_P (tls_type)
+              && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                   && !resolved_to_zero)
+                  || h->root.type != bfd_link_hash_undefweak)
+              && (bfd_link_pic (info)
+                  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+       htab->elf.srelgot->size += htab->sizeof_reloc;
+      if (GOT_TLS_GDESC_P (tls_type))
+       htab->elf.srelplt->size += htab->sizeof_reloc;
+    }
+  else
+    h->got.offset = (bfd_vma) -1;
+
+  if (eh->dyn_relocs == NULL)
+    return TRUE;
+
+  /* In the shared -Bsymbolic case, discard space allocated for
+     dynamic pc-relative relocs against symbols which turn out to be
+     defined in regular objects.  For the normal shared case, discard
+     space for pc-relative relocs that have become local due to symbol
+     visibility changes.  */
+
+  if (bfd_link_pic (info))
+    {
+      /* Relocs that use pc_count are those that appear on a call
+        insn, or certain REL relocs that can generated via assembly.
+        We want calls to protected symbols to resolve directly to the
+        function rather than going via the plt.  If people want
+        function pointer comparisons to work as expected then they
+        should avoid writing weird assembly.  */
+      if (SYMBOL_CALLS_LOCAL (info, h))
+       {
+         struct elf_dyn_relocs **pp;
+
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+           {
+             p->count -= p->pc_count;
+             p->pc_count = 0;
+             if (p->count == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+       }
+
+      if (htab->is_vxworks)
+       {
+         struct elf_dyn_relocs **pp;
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+           {
+             if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+       }
+
+      /* Also discard relocs on undefined weak syms with non-default
+        visibility or in PIE.  */
+      if (eh->dyn_relocs != NULL)
+       {
+         if (h->root.type == bfd_link_hash_undefweak)
+           {
+             /* Undefined weak symbol is never bound locally in shared
+                library.  */
+             if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+                 || resolved_to_zero)
+               {
+                 if (bed->target_id == I386_ELF_DATA
+                     && h->non_got_ref)
+                   {
+                     /* Keep dynamic non-GOT/non-PLT relocation so
+                        that we can branch to 0 without PLT.  */
+                     struct elf_dyn_relocs **pp;
+
+                     for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+                       if (p->pc_count == 0)
+                         *pp = p->next;
+                       else
+                         {
+                           /* Remove non-R_386_PC32 relocation.  */
+                           p->count = p->pc_count;
+                           pp = &p->next;
+                         }
+
+                     /* Make sure undefined weak symbols are output
+                        as dynamic symbols in PIEs for dynamic non-GOT
+                        non-PLT reloations.  */
+                     if (eh->dyn_relocs != NULL
+                         && !bfd_elf_link_record_dynamic_symbol (info, h))
+                       return FALSE;
+                   }
+                 else
+                   eh->dyn_relocs = NULL;
+               }
+             else if (h->dynindx == -1
+                      && !h->forced_local
+                      && !bfd_elf_link_record_dynamic_symbol (info, h))
+               return FALSE;
+           }
+         else if (bfd_link_executable (info)
+                  && (h->needs_copy || eh->needs_copy)
+                  && h->def_dynamic
+                  && !h->def_regular)
+           {
+             /* NB: needs_copy is set only for x86-64.  For PIE,
+                discard space for pc-relative relocs against symbols
+                which turn out to need copy relocs.  */
+             struct elf_dyn_relocs **pp;
+
+             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+               {
+                 if (p->pc_count != 0)
+                   *pp = p->next;
+                 else
+                   pp = &p->next;
+               }
+           }
+       }
+    }
+  else if (ELIMINATE_COPY_RELOCS)
+    {
+      /* For the non-shared case, discard space for relocs against
+        symbols which turn out to need copy relocs or are not
+        dynamic.  Keep dynamic relocations for run-time function
+        pointer initialization.  */
+
+      if ((!h->non_got_ref
+          || eh->func_pointer_refcount > 0
+          || (h->root.type == bfd_link_hash_undefweak
+              && !resolved_to_zero))
+         && ((h->def_dynamic
+              && !h->def_regular)
+             || (htab->elf.dynamic_sections_created
+                 && (h->root.type == bfd_link_hash_undefweak
+                     || h->root.type == bfd_link_hash_undefined))))
+       {
+         /* 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
+             && !resolved_to_zero
+             && h->root.type == bfd_link_hash_undefweak
+             && ! bfd_elf_link_record_dynamic_symbol (info, h))
+           return FALSE;
+
+         /* If that succeeded, we know we'll be keeping all the
+            relocs.  */
+         if (h->dynindx != -1)
+           goto keep;
+       }
+
+      eh->dyn_relocs = NULL;
+      eh->func_pointer_refcount = 0;
+
+    keep: ;
+    }
+
+  /* Finally, allocate space.  */
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+    {
+      asection *sreloc;
+
+      sreloc = elf_section_data (p->sec)->sreloc;
+
+      BFD_ASSERT (sreloc != NULL);
+      sreloc->size += p->count * htab->sizeof_reloc;
+    }
+
+  return TRUE;
+}
+
 /* Find any dynamic relocs that apply to read-only sections.  */
 
 bfd_boolean
@@ -117,6 +570,25 @@ _bfd_x86_elf_readonly_dynrelocs (struct elf_link_hash_entry *h,
   return TRUE;
 }
 
+/* Allocate space in .plt, .got and associated reloc sections for
+   local dynamic relocs.  */
+
+bfd_boolean
+_bfd_x86_elf_allocate_local_dynrelocs (void **slot, void *inf)
+{
+  struct elf_link_hash_entry *h
+    = (struct elf_link_hash_entry *) *slot;
+
+  if (h->type != STT_GNU_IFUNC
+      || !h->def_regular
+      || !h->ref_regular
+      || !h->forced_local
+      || h->root.type != bfd_link_hash_defined)
+    abort ();
+
+  return _bfd_x86_elf_allocate_dynrelocs (h, inf);
+}
+
 /* Find and/or create a hash entry for local symbol.  */
 
 struct elf_link_hash_entry *
index e383135..c694daf 100644 (file)
@@ -401,6 +401,12 @@ extern void _bfd_x86_elf_set_tls_module_base
 extern bfd_vma _bfd_x86_elf_dtpoff_base
   (struct bfd_link_info *);
 
+extern bfd_boolean _bfd_x86_elf_allocate_dynrelocs
+  (struct elf_link_hash_entry *, void *);
+
+extern bfd_boolean _bfd_x86_elf_allocate_local_dynrelocs
+  (void **, void *);
+
 extern bfd_boolean _bfd_x86_elf_readonly_dynrelocs
   (struct elf_link_hash_entry *, void *);