2009-06-17 H.J. Lu <hongjiu.lu@intel.com>
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 18 Jun 2009 00:45:14 +0000 (00:45 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 18 Jun 2009 00:45:14 +0000 (00:45 +0000)
* elf-bfd.h (_bfd_elf_allocate_ifunc_dyn_relocs): New.
* elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Likewise.
* elf32-i386.c (elf_i386_allocate_dynrelocs): Use it.
* elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Likewise.

2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>

* elf-bfd.h (_bfd_elf_create_ifunc_dyn_reloc): New.
* elf-ifunc.c (_bfd_elf_create_ifunc_dyn_reloc): Likewise.
* elf32-i386.c (elf_i386_check_relocs): Use it.
* elf64-x86-64.c (elf64_x86_64_check_relocs): Likewise.

2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>

* elf-bfd.h (elf_dyn_relocs): New.

* elf32-i386.c (elf_i386_dyn_relocs): Removed.
(elf_i386_link_hash_entry): Replace elf_i386_dyn_relocs with
elf_dyn_relocs.
(elf_i386_copy_indirect_symbol): Likewise.
(elf_i386_check_relocs): Likewise.
(elf_i386_gc_sweep_hook): Likewise.
(elf_i386_allocate_dynrelocs): Likewise.
(elf_i386_readonly_dynrelocs): Likewise.
(elf_i386_size_dynamic_sections): Likewise.

* elf64-x86-64.c (elf64_x86_64_dyn_relocs): Removed.
(elf64_x86_64_link_hash_entry): Replace elf64_x86_64_dyn_relocs
with elf_dyn_relocs.
(elf64_x86_64_copy_indirect_symbol): Updated.
(elf64_x86_64_check_relocs): Likewise.
(elf64_x86_64_gc_sweep_hook): Likewise.
(elf64_x86_64_adjust_dynamic_symbol): Likewise.
(elf64_x86_64_allocate_dynrelocs): Likewise.
(elf64_x86_64_readonly_dynrelocs): Likewise.
(elf64_x86_64_size_dynamic_sections): Likewise.

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

index 15e73e9fb2e34713b5f47151e8e04a89a44fabd5..6458ccfba45126082602a53ecf66859d98cc82bd 100644 (file)
@@ -1,3 +1,42 @@
+2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * elf-bfd.h (_bfd_elf_allocate_ifunc_dyn_relocs): New.
+       * elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Likewise.
+       * elf32-i386.c (elf_i386_allocate_dynrelocs): Use it.
+       * elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Likewise.
+
+2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * elf-bfd.h (_bfd_elf_create_ifunc_dyn_reloc): New.
+       * elf-ifunc.c (_bfd_elf_create_ifunc_dyn_reloc): Likewise.
+       * elf32-i386.c (elf_i386_check_relocs): Use it.
+       * elf64-x86-64.c (elf64_x86_64_check_relocs): Likewise.
+
+2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * elf-bfd.h (elf_dyn_relocs): New.
+
+       * elf32-i386.c (elf_i386_dyn_relocs): Removed.
+       (elf_i386_link_hash_entry): Replace elf_i386_dyn_relocs with
+       elf_dyn_relocs.
+       (elf_i386_copy_indirect_symbol): Likewise.
+       (elf_i386_check_relocs): Likewise.
+       (elf_i386_gc_sweep_hook): Likewise.
+       (elf_i386_allocate_dynrelocs): Likewise.
+       (elf_i386_readonly_dynrelocs): Likewise.
+       (elf_i386_size_dynamic_sections): Likewise.
+
+       * elf64-x86-64.c (elf64_x86_64_dyn_relocs): Removed.
+       (elf64_x86_64_link_hash_entry): Replace elf64_x86_64_dyn_relocs
+       with elf_dyn_relocs.
+       (elf64_x86_64_copy_indirect_symbol): Updated.
+       (elf64_x86_64_check_relocs): Likewise.
+       (elf64_x86_64_gc_sweep_hook): Likewise.
+       (elf64_x86_64_adjust_dynamic_symbol): Likewise.
+       (elf64_x86_64_allocate_dynrelocs): Likewise.
+       (elf64_x86_64_readonly_dynrelocs): Likewise.
+       (elf64_x86_64_size_dynamic_sections): Likewise.
+
 2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>
 
        * elf32-arm.c (create_got_section): Get existing .rela.got
index b81f0097432a530b168c844a2abd37db7a3edc55..d1a23ad99935a8b922ac773daed95e0f658b3710 100644 (file)
@@ -2157,8 +2157,34 @@ extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, int);
 extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
 extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
 
+/* The linker may needs to keep track of the number of relocs that it
+   decides to copy as dynamic relocs in check_relocs for each symbol.
+   This is so that it can later discard them if they are found to be
+   unnecessary.  We can store the information in a field extending the
+   regular ELF linker hash table.  */
+
+struct elf_dyn_relocs
+{
+  struct elf_dyn_relocs *next;
+
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* Total number of relocs copied for the input section.  */
+  bfd_size_type count;
+
+  /* Number of pc-relative relocs copied for the input section.  */
+  bfd_size_type pc_count;
+};
+
 extern bfd_boolean _bfd_elf_create_ifunc_sections
   (bfd *, struct bfd_link_info *);
+extern asection * _bfd_elf_create_ifunc_dyn_reloc
+  (bfd *, struct bfd_link_info *, asection *sec, asection *sreloc,
+   struct elf_dyn_relocs **);
+extern bfd_boolean _bfd_elf_allocate_ifunc_dyn_relocs
+  (struct bfd_link_info *, struct elf_link_hash_entry *,
+   struct elf_dyn_relocs **, unsigned int, unsigned int);
 
 /* Large common section.  */
 extern asection _bfd_elf_large_com_section;
index 4bfc31b55cc108e53b4f5d399e875e9e66d329f9..b9b50c3628efa0e0ba77c86e998e1f4fd96a2c94 100644 (file)
@@ -103,3 +103,185 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
 
   return TRUE;
 }
+
+/* For a STT_GNU_IFUNC symbol, create a dynamic reloc section, SRELOC,
+   for the input section, SEC, and append this reloc to HEAD.  */
+
+asection *
+_bfd_elf_create_ifunc_dyn_reloc (bfd *abfd, struct bfd_link_info *info,
+                                asection *sec, asection *sreloc,
+                                struct elf_dyn_relocs **head)
+{
+  struct elf_dyn_relocs *p;
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  if (sreloc == NULL)
+    {
+      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+      if (htab->dynobj == NULL)
+       htab->dynobj = abfd;
+
+      sreloc = _bfd_elf_make_dynamic_reloc_section (sec, htab->dynobj,
+                                                   bed->s->log_file_align,
+                                                   abfd,
+                                                   bed->rela_plts_and_copies_p); 
+      if (sreloc == NULL)
+       return NULL;
+    }
+                     
+  p = *head;
+  if (p == NULL || p->sec != sec)
+    {
+      bfd_size_type amt = sizeof *p;
+
+      p = ((struct elf_dyn_relocs *) bfd_alloc (htab->dynobj, amt));
+      if (p == NULL)
+       return NULL;
+      p->next = *head;
+      *head = p;
+      p->sec = sec;
+      p->count = 0;
+      p->pc_count = 0;
+    }
+  p->count += 1;
+
+  return sreloc;
+}
+
+/* Allocate space in .plt, .got and associated reloc sections for
+   dynamic relocs against a STT_GNU_IFUNC symbol definition.  */
+
+bfd_boolean
+_bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
+                                   struct elf_link_hash_entry *h,
+                                   struct elf_dyn_relocs **head,
+                                   unsigned int plt_entry_size,
+                                   unsigned int got_entry_size)
+{
+  asection *plt, *gotplt, *relplt;
+  struct elf_dyn_relocs *p;
+  unsigned int sizeof_reloc;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_table *htab;
+
+  /* When a shared library references a STT_GNU_IFUNC symbol defined
+     in executable, the address of the resolved function may be used.
+     But in non-shared executable, the address of its .plt slot may
+     be used.  Pointer equality may not work correctly.  PIE should
+     be used if pointer equality is required here.  */
+  if (!info->shared
+      && (h->dynindx != -1
+         || info->export_dynamic)
+      && h->pointer_equality_needed)
+    {
+      info->callbacks->einfo 
+       (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
+          "equality in `%B' can not be used when making an "
+          "executable; recompile with -fPIE and relink with -pie\n"),
+        h->root.root.string,
+        h->root.u.def.section->owner);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  /* Return and discard space for dynamic relocations against it if
+     it is never referenced in a non-shared object.  */
+  if (!h->ref_regular)
+    {
+      if (h->plt.refcount > 0
+         || h->got.refcount > 0)
+       abort ();
+      h->got.offset = (bfd_vma) -1;
+      *head = NULL;
+      return TRUE;
+    }
+
+  bed = get_elf_backend_data (info->output_bfd);
+  if (bed->rela_plts_and_copies_p)
+    sizeof_reloc = bed->s->sizeof_rela;
+  else
+    sizeof_reloc = bed->s->sizeof_rel;
+
+  htab = elf_hash_table (info);
+
+  /* When building a static executable, use .iplt, .igot.plt and
+     .rel[a].iplt sections for STT_GNU_IFUNC symbols.  */
+  if (htab->splt != NULL)
+    {
+      plt = htab->splt;
+      gotplt = htab->sgotplt;
+      relplt = htab->srelplt;
+
+      /* If this is the first .plt entry, make room for the special
+        first entry.  */
+      if (plt->size == 0)
+       plt->size += plt_entry_size;
+    }
+  else
+    {
+      plt = htab->iplt;
+      gotplt = htab->igotplt;
+      relplt = htab->irelplt;
+    }
+
+  /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
+     the original value for R_*_IRELATIVE.  */  
+  h->plt.offset = plt->size;
+
+  /* Make room for this entry in the .plt/.iplt section.  */
+  plt->size += plt_entry_size;
+
+  /* We also need to make an entry in the .got.plt/.got.iplt section,
+     which will be placed in the .got section by the linker script.  */
+  gotplt->size += got_entry_size;
+
+  /* We also need to make an entry in the .rel[a].plt/.rel[a].iplt
+     section.  */
+  relplt->size += sizeof_reloc;
+  relplt->reloc_count++;
+
+  /* We need dynamic relocation for STT_GNU_IFUNC symbol only when
+     there is a non-GOT reference in a shared object.  */
+  if (!info->shared
+      || !h->non_got_ref)
+    *head = NULL;
+
+  /* Finally, allocate space.  */
+  for (p = *head; p != NULL; p = p->next)
+    htab->irelifunc->size += p->count * sizeof_reloc;
+
+  /* For STT_GNU_IFUNC symbol, .got.plt has the real function addres
+     and .got has the PLT entry adddress.  We will load the GOT entry
+     with the PLT entry in finish_dynamic_symbol if it is used.  For
+     branch, it uses .got.plt.  For symbol value,
+     1. Use .got.plt in a shared object if it is forced local or not
+     dynamic.
+     2. Use .got.plt in a non-shared object if pointer equality isn't
+     needed.
+     3. Use .got.plt in PIE.
+     4. Use .got.plt if .got isn't used.
+     5. Otherwise use .got so that it can be shared among different
+     objects at run-time.
+     We only need to relocate .got entry in shared object.  */
+  if ((info->shared
+       && (h->dynindx == -1
+          || h->forced_local))
+      || (!info->shared
+         && !h->pointer_equality_needed)
+      || (info->executable && info->shared)
+      || htab->sgot == NULL)
+    {
+      /* Use .got.plt.  */
+      h->got.offset = (bfd_vma) -1;
+    }
+  else
+    {
+      h->got.offset = htab->sgot->size;
+      htab->sgot->size += got_entry_size;
+      if (info->shared)
+       htab->srelgot->size += sizeof_reloc;
+    }
+
+  return TRUE;
+}
index 60a414237a71d82455a43d3ff21cd2db29b1461d..32ea2873053e057532fdacbabc83ee0b7d834cbb 100644 (file)
@@ -577,26 +577,6 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] =
 #define PLTRESOLVE_RELOCS 2
 #define PLT_NON_JUMP_SLOT_RELOCS 2
 
-/* The i386 linker needs to keep track of the number of relocs that it
-   decides to copy as dynamic relocs in check_relocs for each symbol.
-   This is so that it can later discard them if they are found to be
-   unnecessary.  We store the information in a field extending the
-   regular ELF linker hash table.  */
-
-struct elf_i386_dyn_relocs
-{
-  struct elf_i386_dyn_relocs *next;
-
-  /* The input section of the reloc.  */
-  asection *sec;
-
-  /* Total number of relocs copied for the input section.  */
-  bfd_size_type count;
-
-  /* Number of pc-relative relocs copied for the input section.  */
-  bfd_size_type pc_count;
-};
-
 /* i386 ELF linker hash entry.  */
 
 struct elf_i386_link_hash_entry
@@ -604,7 +584,7 @@ struct elf_i386_link_hash_entry
   struct elf_link_hash_entry elf;
 
   /* Track dynamic relocs copied for this symbol.  */
-  struct elf_i386_dyn_relocs *dyn_relocs;
+  struct elf_dyn_relocs *dyn_relocs;
 
 #define GOT_UNKNOWN    0
 #define GOT_NORMAL     1
@@ -919,14 +899,14 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info,
     {
       if (edir->dyn_relocs != NULL)
        {
-         struct elf_i386_dyn_relocs **pp;
-         struct elf_i386_dyn_relocs *p;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
          /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
            {
-             struct elf_i386_dyn_relocs *q;
+             struct elf_dyn_relocs *q;
 
              for (q = edir->dyn_relocs; q != NULL; q = q->next)
                if (q->sec == p->sec)
@@ -1407,39 +1387,14 @@ elf_i386_check_relocs (bfd *abfd,
                  h->pointer_equality_needed = 1;
                  if (info->shared)
                    {
-                     struct elf_i386_dyn_relocs *p;
-                     struct elf_i386_dyn_relocs **head;
-
                      /* We must copy these reloc types into the
                         output file.  Create a reloc section in
                         dynobj and make room for this reloc.  */
+                     sreloc = _bfd_elf_create_ifunc_dyn_reloc
+                       (abfd, info, sec, sreloc,
+                        &((struct elf_i386_link_hash_entry *) h)->dyn_relocs);
                      if (sreloc == NULL)
-                       {
-                         if (htab->elf.dynobj == NULL)
-                           htab->elf.dynobj = abfd;
-
-                         sreloc = _bfd_elf_make_dynamic_reloc_section
-                           (sec, htab->elf.dynobj, 2, abfd, FALSE);
-
-                         if (sreloc == NULL)
-                           return FALSE;
-                       }
-
-                     head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
-                     p = *head;
-                     if (p == NULL || p->sec != sec)
-                       {
-                         bfd_size_type amt = sizeof *p;
-                         p = bfd_alloc (htab->elf.dynobj, amt);
-                         if (p == NULL)
-                           return FALSE;
-                         p->next = *head;
-                         *head = p;
-                         p->sec = sec;
-                         p->count = 0;
-                         p->pc_count = 0;
-                       }
-                     p->count += 1;
+                       return FALSE;
                    }
                  break;
 
@@ -1669,8 +1624,8 @@ elf_i386_check_relocs (bfd *abfd,
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
            {
-             struct elf_i386_dyn_relocs *p;
-             struct elf_i386_dyn_relocs **head;
+             struct elf_dyn_relocs *p;
+             struct elf_dyn_relocs **head;
 
              /* We must copy these reloc types into the output file.
                 Create a reloc section in dynobj and make room for
@@ -1707,7 +1662,7 @@ elf_i386_check_relocs (bfd *abfd,
                    return FALSE;
 
                  vpp = &elf_section_data (s)->local_dynrel;
-                 head = (struct elf_i386_dyn_relocs **)vpp;
+                 head = (struct elf_dyn_relocs **)vpp;
                }
 
              p = *head;
@@ -1808,8 +1763,8 @@ elf_i386_gc_sweep_hook (bfd *abfd,
       if (r_symndx >= symtab_hdr->sh_info)
        {
          struct elf_i386_link_hash_entry *eh;
-         struct elf_i386_dyn_relocs **pp;
-         struct elf_i386_dyn_relocs *p;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
@@ -1980,7 +1935,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (ELIMINATE_COPY_RELOCS && !htab->is_vxworks)
     {
       struct elf_i386_link_hash_entry * eh;
-      struct elf_i386_dyn_relocs *p;
+      struct elf_dyn_relocs *p;
 
       eh = (struct elf_i386_link_hash_entry *) h;
       for (p = eh->dyn_relocs; p != NULL; p = p->next)
@@ -2037,7 +1992,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   struct bfd_link_info *info;
   struct elf_i386_link_hash_table *htab;
   struct elf_i386_link_hash_entry *eh;
-  struct elf_i386_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -2056,123 +2011,9 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
      here if it is defined and referenced in a non-shared object.  */
   if (h->type == STT_GNU_IFUNC
       && h->def_regular)
-    {
-      asection *plt, *gotplt, *relplt;
-
-      /* When a shared library references a STT_GNU_IFUNC symbol
-        defined in executable, the address of the resolved function
-        may be used.  But in non-shared executable, the address of
-        its .plt slot may be used.  Pointer equality may not work
-        correctly.  PIE should be used if pointer equality is
-        required here.  */
-      if (!info->shared
-         && (h->dynindx != -1
-             || info->export_dynamic)
-         && h->pointer_equality_needed)
-       {
-         info->callbacks->einfo 
-           (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
-              "equality in `%B' can not be used when making an "
-              "executable; recompile with -fPIE and relink with -pie\n"),
-            h->root.root.string,
-            h->root.u.def.section->owner);
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
-       }
-
-      /* Return and discard space for dynamic relocations against it if
-        it is never referenced in a non-shared object.  */
-      if (!h->ref_regular)
-       {
-         if (h->plt.refcount > 0
-             || h->got.refcount > 0)
-           abort ();
-         h->got.offset = (bfd_vma) -1;
-         eh->dyn_relocs = NULL;
-         return TRUE;
-       }
-
-      /* When building a static executable, use .iplt, .igot.plt and
-        .rel.iplt sections for STT_GNU_IFUNC symbols.  */
-      if (htab->elf.splt != NULL)
-       {
-         plt = htab->elf.splt;
-         gotplt = htab->elf.sgotplt;
-         relplt = htab->elf.srelplt;
-         
-         /* If this is the first .plt entry, make room for the special
-            first entry.  */
-         if (plt->size == 0)
-           plt->size += PLT_ENTRY_SIZE;
-       }
-      else
-       {
-         plt = htab->elf.iplt;
-         gotplt = htab->elf.igotplt;
-         relplt = htab->elf.irelplt;
-       }
-
-      /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
-        the original value for R_386_IRELATIVE.  */  
-      h->plt.offset = plt->size;
-
-      /* Make room for this entry in the .plt/.iplt section.  */
-      plt->size += PLT_ENTRY_SIZE;
-
-      /* We also need to make an entry in the .got.plt/.got.iplt
-        section, which will be placed in the .got section by the
-        linker script.  */
-      gotplt->size += 4;
-
-      /* We also need to make an entry in the .rela.plt/.rela.iplt
-        section.  */
-      relplt->size += sizeof (Elf32_External_Rel);
-      relplt->reloc_count++;
-
-      /* We need dynamic relocation for STT_GNU_IFUNC symbol only
-        when there is a non-GOT reference in a shared object.  */
-      if (!info->shared
-         || !h->non_got_ref)
-       eh->dyn_relocs = NULL;
-
-      /* Finally, allocate space.  */
-      for (p = eh->dyn_relocs; p != NULL; p = p->next)
-       htab->elf.irelifunc->size += p->count * sizeof (Elf32_External_Rel);
-
-      /* For STT_GNU_IFUNC symbol, .got.plt has the real function
-        addres and .got has the PLT entry adddress.  We will load
-        the GOT entry with the PLT entry in finish_dynamic_symbol if
-        it is used.  For branch, it uses .got.plt.  For symbol value,
-        1. Use .got.plt in a shared object if it is forced local or
-        not dynamic.
-        2. Use .got.plt in a non-shared object if pointer equality 
-        isn't needed.
-        3. Use .got.plt in PIE.
-        4. Use .got.plt if .got isn't used.
-        5. Otherwise use .got so that it can be shared among different
-        objects at run-time.
-        We only need to relocate .got entry in shared object.  */
-      if ((info->shared
-          && (h->dynindx == -1
-              || h->forced_local))
-         || (!info->shared
-             && !h->pointer_equality_needed)
-         || (info->executable && info->shared)
-         || htab->elf.sgot == NULL)
-       {
-         /* Use .got.plt.  */
-         h->got.offset = (bfd_vma) -1;
-       }
-      else
-       {
-         h->got.offset = htab->elf.sgot->size;
-         htab->elf.sgot->size += 4;
-         if (info->shared)
-           htab->elf.srelgot->size += sizeof (Elf32_External_Rel);
-       }
-
-      return TRUE;
-    }
+    return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
+                                              &eh->dyn_relocs,
+                                              PLT_ENTRY_SIZE, 4);
   else if (htab->elf.dynamic_sections_created
           && h->plt.refcount > 0)
     {
@@ -2337,7 +2178,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         should avoid writing assembly like ".long foo - .".  */
       if (SYMBOL_CALLS_LOCAL (info, h))
        {
-         struct elf_i386_dyn_relocs **pp;
+         struct elf_dyn_relocs **pp;
 
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
            {
@@ -2352,7 +2193,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
       if (htab->is_vxworks)
        {
-         struct elf_i386_dyn_relocs **pp;
+         struct elf_dyn_relocs **pp;
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
            {
              if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
@@ -2452,7 +2293,7 @@ static bfd_boolean
 elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 {
   struct elf_i386_link_hash_entry *eh;
-  struct elf_i386_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
@@ -2522,9 +2363,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       for (s = ibfd->sections; s != NULL; s = s->next)
        {
-         struct elf_i386_dyn_relocs *p;
+         struct elf_dyn_relocs *p;
 
-         for (p = ((struct elf_i386_dyn_relocs *)
+         for (p = ((struct elf_dyn_relocs *)
                     elf_section_data (s)->local_dynrel);
               p != NULL;
               p = p->next)
index 5947a3e82f820d60a8881308b562581b858d8f4d..617832ab416252b8c11d5a7453cf52d5c886b7b6 100644 (file)
@@ -396,27 +396,6 @@ static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] =
   0, 0, 0, 0   /* replaced with offset to start of .plt0.  */
 };
 
-/* The x86-64 linker needs to keep track of the number of relocs that
-   it decides to copy as dynamic relocs in check_relocs for each symbol.
-   This is so that it can later discard them if they are found to be
-   unnecessary.  We store the information in a field extending the
-   regular ELF linker hash table.  */
-
-struct elf64_x86_64_dyn_relocs
-{
-  /* Next section.  */
-  struct elf64_x86_64_dyn_relocs *next;
-
-  /* The input section of the reloc.  */
-  asection *sec;
-
-  /* Total number of relocs copied for the input section.  */
-  bfd_size_type count;
-
-  /* Number of pc-relative relocs copied for the input section.  */
-  bfd_size_type pc_count;
-};
-
 /* x86-64 ELF linker hash entry.  */
 
 struct elf64_x86_64_link_hash_entry
@@ -424,7 +403,7 @@ struct elf64_x86_64_link_hash_entry
   struct elf_link_hash_entry elf;
 
   /* Track dynamic relocs copied for this symbol.  */
-  struct elf64_x86_64_dyn_relocs *dyn_relocs;
+  struct elf_dyn_relocs *dyn_relocs;
 
 #define GOT_UNKNOWN    0
 #define GOT_NORMAL     1
@@ -726,14 +705,14 @@ elf64_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
     {
       if (edir->dyn_relocs != NULL)
        {
-         struct elf64_x86_64_dyn_relocs **pp;
-         struct elf64_x86_64_dyn_relocs *p;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
          /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
            {
-             struct elf64_x86_64_dyn_relocs *q;
+             struct elf_dyn_relocs *q;
 
              for (q = edir->dyn_relocs; q != NULL; q = q->next)
                if (q->sec == p->sec)
@@ -1192,41 +1171,14 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  h->pointer_equality_needed = 1;
                  if (info->shared)
                    {
-                     struct elf64_x86_64_dyn_relocs *p;
-                     struct elf64_x86_64_dyn_relocs **head;
-
                      /* We must copy these reloc types into the output
                         file.  Create a reloc section in dynobj and
                         make room for this reloc.  */
+                     sreloc = _bfd_elf_create_ifunc_dyn_reloc
+                       (abfd, info, sec, sreloc,
+                        &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs);
                      if (sreloc == NULL)
-                       {
-                         if (htab->elf.dynobj == NULL)
-                           htab->elf.dynobj = abfd;
-
-                         sreloc = _bfd_elf_make_dynamic_reloc_section
-                           (sec, htab->elf.dynobj, 3, abfd, TRUE);
-
-                         if (sreloc == NULL)
-                           return FALSE;
-                       }
-                     
-                     head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs;
-                     p = *head;
-                     if (p == NULL || p->sec != sec)
-                       {
-                         bfd_size_type amt = sizeof *p;
-
-                         p = ((struct elf64_x86_64_dyn_relocs *)
-                              bfd_alloc (htab->elf.dynobj, amt));
-                         if (p == NULL)
-                           return FALSE;
-                         p->next = *head;
-                         *head = p;
-                         p->sec = sec;
-                         p->count = 0;
-                         p->pc_count = 0;
-                       }
-                     p->count += 1;
+                       return FALSE;
                    }
                  break;
 
@@ -1500,8 +1452,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
            {
-             struct elf64_x86_64_dyn_relocs *p;
-             struct elf64_x86_64_dyn_relocs **head;
+             struct elf_dyn_relocs *p;
+             struct elf_dyn_relocs **head;
 
              /* We must copy these reloc types into the output file.
                 Create a reloc section in dynobj and make room for
@@ -1540,7 +1492,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  /* Beware of type punned pointers vs strict aliasing
                     rules.  */
                  vpp = &(elf_section_data (s)->local_dynrel);
-                 head = (struct elf64_x86_64_dyn_relocs **)vpp;
+                 head = (struct elf_dyn_relocs **)vpp;
                }
 
              p = *head;
@@ -1548,7 +1500,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                {
                  bfd_size_type amt = sizeof *p;
 
-                 p = ((struct elf64_x86_64_dyn_relocs *)
+                 p = ((struct elf_dyn_relocs *)
                       bfd_alloc (htab->elf.dynobj, amt));
                  if (p == NULL)
                    return FALSE;
@@ -1642,8 +1594,8 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
       if (r_symndx >= symtab_hdr->sh_info)
        {
          struct elf64_x86_64_link_hash_entry *eh;
-         struct elf64_x86_64_dyn_relocs **pp;
-         struct elf64_x86_64_dyn_relocs *p;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
@@ -1820,7 +1772,7 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (ELIMINATE_COPY_RELOCS)
     {
       struct elf64_x86_64_link_hash_entry * eh;
-      struct elf64_x86_64_dyn_relocs *p;
+      struct elf_dyn_relocs *p;
 
       eh = (struct elf64_x86_64_link_hash_entry *) h;
       for (p = eh->dyn_relocs; p != NULL; p = p->next)
@@ -1881,7 +1833,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   struct bfd_link_info *info;
   struct elf64_x86_64_link_hash_table *htab;
   struct elf64_x86_64_link_hash_entry *eh;
-  struct elf64_x86_64_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -1897,124 +1849,10 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
      here if it is defined and referenced in a non-shared object.  */
   if (h->type == STT_GNU_IFUNC
       && h->def_regular)
-    {
-      asection *plt, *gotplt, *relplt;
-
-      /* When a shared library references a STT_GNU_IFUNC symbol
-        defined in executable, the address of the resolved function
-        may be used.  But in non-shared executable, the address of
-        its .plt slot may be used.  Pointer equality may not work
-        correctly.  PIE should be used if pointer equality is
-        required here.  */
-      if (!info->shared
-         && (h->dynindx != -1
-             || info->export_dynamic)
-         && h->pointer_equality_needed)
-       {
-         info->callbacks->einfo 
-           (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
-              "equality in `%B' can not be used when making an "
-              "executable; recompile with -fPIE and relink with -pie\n"),
-            h->root.root.string,
-            h->root.u.def.section->owner);
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
-       }
-
-      /* Return and discard space for dynamic relocations against it if
-        it is never referenced in a non-shared object.  */
-      if (!h->ref_regular)
-       {
-         if (h->plt.refcount > 0
-             || h->got.refcount > 0)
-           abort ();
-         h->got.offset = (bfd_vma) -1;
-         eh->dyn_relocs = NULL;
-         return TRUE;
-       }
-
-      /* When building a static executable, use .iplt, .igot.plt and
-        .rela.iplt sections for STT_GNU_IFUNC symbols.  */
-      if (htab->elf.splt != NULL)
-       {
-         plt = htab->elf.splt;
-         gotplt = htab->elf.sgotplt;
-         relplt = htab->elf.srelplt;
-         
-         /* If this is the first .plt entry, make room for the special
-            first entry.  */
-         if (plt->size == 0)
-           plt->size += PLT_ENTRY_SIZE;
-       }
-      else
-       {
-         plt = htab->elf.iplt;
-         gotplt = htab->elf.igotplt;
-         relplt = htab->elf.irelplt;
-       }
-
-      /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
-        the original value for R_X86_64_IRELATIVE.  */  
-      h->plt.offset = plt->size;
-
-      /* Make room for this entry in the .plt/.iplt section.  */
-      plt->size += PLT_ENTRY_SIZE;
-
-      /* We also need to make an entry in the .got.plt/.got.iplt
-        section, which will be placed in the .got section by the
-        linker script.  */
-      gotplt->size += GOT_ENTRY_SIZE;
-
-      /* We also need to make an entry in the .rela.plt/.rela.iplt
-        section.  */
-      relplt->size += sizeof (Elf64_External_Rela);
-      relplt->reloc_count++;
-
-      /* We need dynamic relocation for STT_GNU_IFUNC symbol only
-        when there is a non-GOT reference in a shared object.  */
-      if (!info->shared
-         || !h->non_got_ref)
-       eh->dyn_relocs = NULL;
-
-      /* Finally, allocate space.  */
-      for (p = eh->dyn_relocs; p != NULL; p = p->next)
-       htab->elf.irelifunc->size
-         += p->count * sizeof (Elf64_External_Rela);
-
-      /* For STT_GNU_IFUNC symbol, .got.plt has the real function
-        addres and .got has the PLT entry adddress.  We will load
-        the GOT entry with the PLT entry in finish_dynamic_symbol if
-        it is used.  For branch, it uses .got.plt.  For symbol value,
-        1. Use .got.plt in a shared object if it is forced local or
-        not dynamic.
-        2. Use .got.plt in a non-shared object if pointer equality 
-        isn't needed.
-        3. Use .got.plt in PIE.
-        4. Use .got.plt if .got isn't used.
-        5. Otherwise use .got so that it can be shared among different
-        objects at run-time.
-        We only need to relocate .got entry in shared object.  */
-      if ((info->shared
-          && (h->dynindx == -1
-              || h->forced_local))
-         || (!info->shared
-             && !h->pointer_equality_needed)
-         || (info->executable && info->shared)
-         || htab->elf.sgot == NULL)
-       {
-         /* Use .got.plt.  */
-         h->got.offset = (bfd_vma) -1;
-       }
-      else
-       {
-         h->got.offset = htab->elf.sgot->size;
-         htab->elf.sgot->size += GOT_ENTRY_SIZE;
-         if (info->shared)
-           htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
-       }
-
-      return TRUE;
-    }
+    return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
+                                              &eh->dyn_relocs,
+                                              PLT_ENTRY_SIZE,
+                                              GOT_ENTRY_SIZE);
   else if (htab->elf.dynamic_sections_created
           && h->plt.refcount > 0)
     {
@@ -2159,7 +1997,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
         should avoid writing weird assembly.  */
       if (SYMBOL_CALLS_LOCAL (info, h))
        {
-         struct elf64_x86_64_dyn_relocs **pp;
+         struct elf_dyn_relocs **pp;
 
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
            {
@@ -2260,7 +2098,7 @@ static bfd_boolean
 elf64_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 {
   struct elf64_x86_64_link_hash_entry *eh;
-  struct elf64_x86_64_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
@@ -2330,9 +2168,9 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       for (s = ibfd->sections; s != NULL; s = s->next)
        {
-         struct elf64_x86_64_dyn_relocs *p;
+         struct elf_dyn_relocs *p;
 
-         for (p = (struct elf64_x86_64_dyn_relocs *)
+         for (p = (struct elf_dyn_relocs *)
                    (elf_section_data (s)->local_dynrel);
               p != NULL;
               p = p->next)