x86: Add sizeof_reloc to elf_x86_link_hash_table
[binutils-gdb.git] / bfd / elfxx-x86.c
index d43fe31ede64e907b1224849cd83e81c6986e8dd..fe5d211af2d2fe68216adeb490d21b8c6a4577d3 100644 (file)
 #define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
 #define ELFX32_DYNAMIC_INTERPRETER "/lib/ldx32.so.1"
 
+bfd_boolean
+_bfd_x86_elf_mkobject (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd,
+                                 sizeof (struct elf_x86_obj_tdata),
+                                 get_elf_backend_data (abfd)->target_id);
+}
+
 /* _TLS_MODULE_BASE_ needs to be treated especially when linking
    executables.  Rather than setting it to the beginning of the TLS
    section, we have to set it to the end.    This function may be called
@@ -269,6 +277,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
     {
       ret->r_info = elf64_r_info;
       ret->r_sym = elf64_r_sym;
+      ret->sizeof_reloc = sizeof (Elf64_External_Rela);
       ret->pointer_r_type = R_X86_64_64;
       ret->dynamic_interpreter = ELF64_DYNAMIC_INTERPRETER;
       ret->dynamic_interpreter_size = sizeof ELF64_DYNAMIC_INTERPRETER;
@@ -281,6 +290,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
       ret->r_sym = elf32_r_sym;
       if (bed->target_id == X86_64_ELF_DATA)
        {
+         ret->sizeof_reloc = sizeof (Elf32_External_Rela);
          ret->pointer_r_type = R_X86_64_32;
          ret->dynamic_interpreter = ELFX32_DYNAMIC_INTERPRETER;
          ret->dynamic_interpreter_size
@@ -289,6 +299,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
        }
       else
        {
+         ret->sizeof_reloc = sizeof (Elf32_External_Rel);
          ret->pointer_r_type = R_386_32;
          ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
          ret->dynamic_interpreter_size
@@ -531,6 +542,237 @@ _bfd_x86_elf_hash_symbol (struct elf_link_hash_entry *h)
   return _bfd_elf_hash_symbol (h);
 }
 
+/* Adjust a symbol defined by a dynamic object and referenced by a
+   regular object.  The current definition is in some section of the
+   dynamic object, but we're not including those sections.  We have to
+   change the definition to something the rest of the link can
+   understand.  */
+
+bfd_boolean
+_bfd_x86_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
+                                   struct elf_link_hash_entry *h)
+{
+  struct elf_x86_link_hash_table *htab;
+  asection *s, *srel;
+  struct elf_x86_link_hash_entry *eh;
+  struct elf_dyn_relocs *p;
+  const struct elf_backend_data *bed
+    = get_elf_backend_data (info->output_bfd);
+
+  /* STT_GNU_IFUNC symbol must go through PLT. */
+  if (h->type == STT_GNU_IFUNC)
+    {
+      /* All local STT_GNU_IFUNC references must be treate as local
+        calls via local PLT.  */
+      if (h->ref_regular
+         && SYMBOL_CALLS_LOCAL (info, h))
+       {
+         bfd_size_type pc_count = 0, count = 0;
+         struct elf_dyn_relocs **pp;
+
+         eh = (struct elf_x86_link_hash_entry *) h;
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+           {
+             pc_count += p->pc_count;
+             p->count -= p->pc_count;
+             p->pc_count = 0;
+             count += p->count;
+             if (p->count == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+
+         if (pc_count || count)
+           {
+             h->non_got_ref = 1;
+             if (pc_count)
+               {
+                 /* Increment PLT reference count only for PC-relative
+                    references.  */
+                 h->needs_plt = 1;
+                 if (h->plt.refcount <= 0)
+                   h->plt.refcount = 1;
+                 else
+                   h->plt.refcount += 1;
+               }
+           }
+       }
+
+      if (h->plt.refcount <= 0)
+       {
+         h->plt.offset = (bfd_vma) -1;
+         h->needs_plt = 0;
+       }
+      return TRUE;
+    }
+
+  /* If this is a function, put it in the procedure linkage table.  We
+     will fill in the contents of the procedure linkage table later,
+     when we know the address of the .got section.  */
+  if (h->type == STT_FUNC
+      || h->needs_plt)
+    {
+      if (h->plt.refcount <= 0
+         || SYMBOL_CALLS_LOCAL (info, h)
+         || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+             && h->root.type == bfd_link_hash_undefweak))
+       {
+         /* This case can occur if we saw a PLT32 reloc in an input
+            file, but the symbol was never referred to by a dynamic
+            object, or if all references were garbage collected.  In
+            such a case, we don't actually need to build a procedure
+            linkage table, and we can just do a PC32 reloc instead.  */
+         h->plt.offset = (bfd_vma) -1;
+         h->needs_plt = 0;
+       }
+
+      return TRUE;
+    }
+  else
+    /* It's possible that we incorrectly decided a .plt reloc was needed
+     * for an R_386_PC32/R_X86_64_PC32 reloc to a non-function sym in
+       check_relocs.  We can't decide accurately between function and
+       non-function syms in check-relocs;  Objects loaded later in
+       the link may change h->type.  So fix it now.  */
+    h->plt.offset = (bfd_vma) -1;
+
+  eh = (struct elf_x86_link_hash_entry *) h;
+
+  /* If this is a weak symbol, and there is a real definition, the
+     processor independent code will have arranged for us to see the
+     real definition first, and we can just use the same value.  */
+  if (h->u.weakdef != NULL)
+    {
+      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->u.weakdef->root.u.def.section;
+      h->root.u.def.value = h->u.weakdef->root.u.def.value;
+      if (ELIMINATE_COPY_RELOCS
+         || info->nocopyreloc
+         || SYMBOL_NO_COPYRELOC (info, eh))
+       {
+         /* NB: needs_copy is always 0 for i386.  */
+         h->non_got_ref = h->u.weakdef->non_got_ref;
+         eh->needs_copy = h->u.weakdef->needs_copy;
+       }
+      return TRUE;
+    }
+
+  /* This is a reference to a symbol defined by a dynamic object which
+     is not a function.  */
+
+  /* If we are creating a shared library, we must presume that the
+     only references to the symbol are via the global offset table.
+     For such cases we need not do anything here; the relocations will
+     be handled correctly by relocate_section.  */
+  if (!bfd_link_executable (info))
+    return TRUE;
+
+  /* If there are no references to this symbol that do not use the
+     GOT nor R_386_GOTOFF relocation, we don't need to generate a copy
+     reloc.  NB: gotoff_ref is always 0 for x86-64.  */
+  if (!h->non_got_ref && !eh->gotoff_ref)
+    return TRUE;
+
+  /* If -z nocopyreloc was given, we won't generate them either.  */
+  if (info->nocopyreloc || SYMBOL_NO_COPYRELOC (info, eh))
+    {
+      h->non_got_ref = 0;
+      return TRUE;
+    }
+
+  htab = elf_x86_hash_table (info, bed->target_id);
+  if (htab == NULL)
+    return FALSE;
+
+  /* If there aren't any dynamic relocs in read-only sections nor
+     R_386_GOTOFF relocation, then we can keep the dynamic relocs and
+     avoid the copy reloc.  This doesn't work on VxWorks, where we can
+     not have dynamic relocations (other than copy and jump slot
+     relocations) in an executable.  */
+  if (ELIMINATE_COPY_RELOCS
+      && (bed->target_id == X86_64_ELF_DATA
+         || (!eh->gotoff_ref
+             && !htab->is_vxworks)))
+    {
+      for (p = eh->dyn_relocs; p != NULL; p = p->next)
+       {
+         s = p->sec->output_section;
+         if (s != NULL && (s->flags & SEC_READONLY) != 0)
+           break;
+       }
+
+      /* If we didn't find any dynamic relocs in read-only sections,
+        then we'll be keeping the dynamic relocs and avoiding the copy
+        reloc.  */
+      if (p == NULL)
+       {
+         h->non_got_ref = 0;
+         return TRUE;
+       }
+    }
+
+  /* We must allocate the symbol in our .dynbss section, which will
+     become part of the .bss section of the executable.  There will be
+     an entry for this symbol in the .dynsym section.  The dynamic
+     object will contain position independent code, so all references
+     from the dynamic object to this symbol will go through the global
+     offset table.  The dynamic linker will use the .dynsym entry to
+     determine the address it must put in the global offset table, so
+     both the dynamic object and the regular object will refer to the
+     same memory location for the variable.  */
+
+  /* We must generate a R_386_COPY/R_X86_64_COPY reloc to tell the
+     dynamic linker to copy the initial value out of the dynamic object
+     and into the runtime process image.  */
+  if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+    {
+      s = htab->elf.sdynrelro;
+      srel = htab->elf.sreldynrelro;
+    }
+  else
+    {
+      s = htab->elf.sdynbss;
+      srel = htab->elf.srelbss;
+    }
+  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
+    {
+      srel->size += htab->sizeof_reloc;
+      h->needs_copy = 1;
+    }
+
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
+}
+
+/* Return the section that should be marked against GC for a given
+   relocation. */
+
+asection *
+_bfd_x86_elf_gc_mark_hook (asection *sec,
+                          struct bfd_link_info *info,
+                          Elf_Internal_Rela *rel,
+                          struct elf_link_hash_entry *h,
+                          Elf_Internal_Sym *sym)
+{
+  /* Compiler should optimize this out.  */
+  if (((unsigned int) R_X86_64_GNU_VTINHERIT
+       != (unsigned int) R_386_GNU_VTINHERIT)
+      || ((unsigned int) R_X86_64_GNU_VTENTRY
+         != (unsigned int) R_386_GNU_VTENTRY))
+    abort ();
+
+  if (h != NULL)
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_X86_64_GNU_VTINHERIT:
+      case R_X86_64_GNU_VTENTRY:
+       return NULL;
+      }
+
+  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
+}
+
 static bfd_vma
 elf_i386_get_plt_got_vma (struct elf_x86_plt *plt_p ATTRIBUTE_UNUSED,
                          bfd_vma off,
@@ -989,6 +1231,8 @@ error_alignment:
   if (htab == NULL)
     return pbfd;
 
+  htab->is_vxworks = plt_layout->is_vxworks;
+
   use_ibt_plt = info->ibtplt || info->ibt;
   if (!use_ibt_plt && pbfd != NULL)
     {
@@ -1111,7 +1355,7 @@ error_alignment:
   if (dynobj == NULL)
     return pbfd;
 
-  if (plt_layout->is_vxworks
+  if (htab->is_vxworks
       && !elf_vxworks_create_dynamic_sections (dynobj, info,
                                               &htab->srelplt2))
     {