nds32: Rename __BIT() to N32_BIT().
[deliverable/binutils-gdb.git] / bfd / elfxx-x86.c
index 6b7c119393ee96eeb84f151a5bc14f2cb218cfd6..c41dbeff762419d775566c7e14e2b80d3c416784 100644 (file)
@@ -79,6 +79,460 @@ _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.  */
+
+static bfd_boolean
+elf_x86_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, 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;
+         if (bed->target_id == X86_64_ELF_DATA)
+           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;
+           }
+       }
+
+      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 +571,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.  */
+
+static bfd_boolean
+elf_x86_allocate_local_dynreloc (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_allocate_dynrelocs (h, inf);
+}
+
 /* Find and/or create a hash entry for local symbol.  */
 
 struct elf_link_hash_entry *
@@ -249,6 +722,18 @@ elf_x86_link_hash_table_free (bfd *obfd)
   _bfd_elf_link_hash_table_free (obfd);
 }
 
+static bfd_boolean
+elf_i386_is_reloc_section (const char *secname)
+{
+  return CONST_STRNEQ (secname, ".rel");
+}
+
+static bfd_boolean
+elf_x86_64_is_reloc_section (const char *secname)
+{
+  return CONST_STRNEQ (secname, ".rela");
+}
+
 /* Create an x86 ELF linker hash table.  */
 
 struct bfd_link_hash_table *
@@ -272,35 +757,38 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
-#ifdef BFD64
+  if (bed->target_id == X86_64_ELF_DATA)
+    {
+      ret->is_reloc_section = elf_x86_64_is_reloc_section;
+      ret->dt_reloc = DT_RELA;
+      ret->dt_reloc_sz = DT_RELASZ;
+      ret->dt_reloc_ent = DT_RELAENT;
+      ret->got_entry_size = 8;
+      ret->tls_get_addr = "__tls_get_addr";
+    }
   if (ABI_64_P (abfd))
     {
-      ret->r_info = elf64_r_info;
-      ret->r_sym = elf64_r_sym;
       ret->sizeof_reloc = sizeof (Elf64_External_Rela);
-      ret->got_entry_size = 8;
       ret->pointer_r_type = R_X86_64_64;
       ret->dynamic_interpreter = ELF64_DYNAMIC_INTERPRETER;
       ret->dynamic_interpreter_size = sizeof ELF64_DYNAMIC_INTERPRETER;
-      ret->tls_get_addr = "__tls_get_addr";
     }
   else
-#endif
     {
-      ret->r_info = elf32_r_info;
-      ret->r_sym = elf32_r_sym;
       if (bed->target_id == X86_64_ELF_DATA)
        {
          ret->sizeof_reloc = sizeof (Elf32_External_Rela);
-         ret->got_entry_size = 8;
          ret->pointer_r_type = R_X86_64_32;
          ret->dynamic_interpreter = ELFX32_DYNAMIC_INTERPRETER;
          ret->dynamic_interpreter_size
            = sizeof ELFX32_DYNAMIC_INTERPRETER;
-         ret->tls_get_addr = "__tls_get_addr";
        }
       else
        {
+         ret->is_reloc_section = elf_i386_is_reloc_section;
+         ret->dt_reloc = DT_REL;
+         ret->dt_reloc_sz = DT_RELSZ;
+         ret->dt_reloc_ent = DT_RELENT;
          ret->sizeof_reloc = sizeof (Elf32_External_Rel);
          ret->got_entry_size = 4;
          ret->pointer_r_type = R_386_32;
@@ -310,6 +798,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
          ret->tls_get_addr = "___tls_get_addr";
        }
     }
+  ret->target_id = bed->target_id;
 
   ret->loc_hash_table = htab_try_create (1024,
                                         _bfd_x86_elf_local_htab_hash,
@@ -353,12 +842,28 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
       htab = elf_x86_hash_table (info, bed->target_id);
       if (htab)
        {
-         struct elf_link_hash_entry *h
-           = elf_link_hash_lookup (elf_hash_table (info),
+         struct elf_link_hash_entry *h;
+
+         h = elf_link_hash_lookup (elf_hash_table (info),
                                    htab->tls_get_addr,
                                    FALSE, FALSE, FALSE);
          if (h != NULL)
-           ((struct elf_x86_link_hash_entry *) h)->tls_get_addr = 1;
+           elf_x86_hash_entry (h)->tls_get_addr = 1;
+
+         /* "__ehdr_start" will be defined by linker as a hidden symbol
+            later if it is referenced and not defined.  */
+         h = elf_link_hash_lookup (elf_hash_table (info),
+                                   "__ehdr_start",
+                                   FALSE, FALSE, FALSE);
+         if (h != NULL
+             && (h->root.type == bfd_link_hash_new
+                 || h->root.type == bfd_link_hash_undefined
+                 || h->root.type == bfd_link_hash_undefweak
+                 || h->root.type == bfd_link_hash_common))
+           {
+             elf_x86_hash_entry (h)->local_ref = 2;
+             elf_x86_hash_entry (h)->linker_def = 1;
+           }
        }
     }
 
@@ -366,6 +871,429 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
   return _bfd_elf_link_check_relocs (abfd, info);
 }
 
+/* Set the sizes of the dynamic sections.  */
+
+bfd_boolean
+_bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
+                                   struct bfd_link_info *info)
+{
+  struct elf_x86_link_hash_table *htab;
+  bfd *dynobj;
+  asection *s;
+  bfd_boolean relocs;
+  bfd *ibfd;
+  const struct elf_backend_data *bed
+    = get_elf_backend_data (output_bfd);
+
+  htab = elf_x86_hash_table (info, bed->target_id);
+  if (htab == NULL)
+    return FALSE;
+  dynobj = htab->elf.dynobj;
+  if (dynobj == NULL)
+    abort ();
+
+  /* Set up .got offsets for local syms, and space for local dynamic
+     relocs.  */
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      bfd_signed_vma *local_got;
+      bfd_signed_vma *end_local_got;
+      char *local_tls_type;
+      bfd_vma *local_tlsdesc_gotent;
+      bfd_size_type locsymcount;
+      Elf_Internal_Shdr *symtab_hdr;
+      asection *srel;
+
+      if (! is_x86_elf (ibfd, htab))
+       continue;
+
+      for (s = ibfd->sections; s != NULL; s = s->next)
+       {
+         struct elf_dyn_relocs *p;
+
+         for (p = ((struct elf_dyn_relocs *)
+                    elf_section_data (s)->local_dynrel);
+              p != NULL;
+              p = p->next)
+           {
+             if (!bfd_is_abs_section (p->sec)
+                 && bfd_is_abs_section (p->sec->output_section))
+               {
+                 /* Input section has been discarded, either because
+                    it is a copy of a linkonce section or due to
+                    linker script /DISCARD/, so we'll be discarding
+                    the relocs too.  */
+               }
+             else if (htab->is_vxworks
+                      && strcmp (p->sec->output_section->name,
+                                 ".tls_vars") == 0)
+               {
+                 /* Relocations in vxworks .tls_vars sections are
+                    handled specially by the loader.  */
+               }
+             else if (p->count != 0)
+               {
+                 srel = elf_section_data (p->sec)->sreloc;
+                 srel->size += p->count * htab->sizeof_reloc;
+                 if ((p->sec->output_section->flags & SEC_READONLY) != 0
+                     && (info->flags & DF_TEXTREL) == 0)
+                   {
+                     info->flags |= DF_TEXTREL;
+                     if ((info->warn_shared_textrel && bfd_link_pic (info))
+                         || info->error_textrel)
+                       /* xgettext:c-format */
+                       info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'\n"),
+                                               p->sec->owner, p->sec);
+                   }
+               }
+           }
+       }
+
+      local_got = elf_local_got_refcounts (ibfd);
+      if (!local_got)
+       continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_local_got = local_got + locsymcount;
+      local_tls_type = elf_x86_local_got_tls_type (ibfd);
+      local_tlsdesc_gotent = elf_x86_local_tlsdesc_gotent (ibfd);
+      s = htab->elf.sgot;
+      srel = htab->elf.srelgot;
+      for (; local_got < end_local_got;
+          ++local_got, ++local_tls_type, ++local_tlsdesc_gotent)
+       {
+         *local_tlsdesc_gotent = (bfd_vma) -1;
+         if (*local_got > 0)
+           {
+             if (GOT_TLS_GDESC_P (*local_tls_type))
+               {
+                 *local_tlsdesc_gotent = htab->elf.sgotplt->size
+                   - elf_x86_compute_jump_table_size (htab);
+                 htab->elf.sgotplt->size += 2 * htab->got_entry_size;
+                 *local_got = (bfd_vma) -2;
+               }
+             if (! GOT_TLS_GDESC_P (*local_tls_type)
+                 || GOT_TLS_GD_P (*local_tls_type))
+               {
+                 *local_got = s->size;
+                 s->size += htab->got_entry_size;
+                 if (GOT_TLS_GD_P (*local_tls_type)
+                     || *local_tls_type == GOT_TLS_IE_BOTH)
+                   s->size += htab->got_entry_size;
+               }
+             if (bfd_link_pic (info)
+                 || GOT_TLS_GD_ANY_P (*local_tls_type)
+                 || (*local_tls_type & GOT_TLS_IE))
+               {
+                 if (*local_tls_type == GOT_TLS_IE_BOTH)
+                   srel->size += 2 * htab->sizeof_reloc;
+                 else if (GOT_TLS_GD_P (*local_tls_type)
+                          || ! GOT_TLS_GDESC_P (*local_tls_type))
+                   srel->size += htab->sizeof_reloc;
+                 if (GOT_TLS_GDESC_P (*local_tls_type))
+                   {
+                     htab->elf.srelplt->size += htab->sizeof_reloc;
+                     if (bed->target_id == X86_64_ELF_DATA)
+                       htab->tlsdesc_plt = (bfd_vma) -1;
+                   }
+               }
+           }
+         else
+           *local_got = (bfd_vma) -1;
+       }
+    }
+
+  if (htab->tls_ld_or_ldm_got.refcount > 0)
+    {
+      /* Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM
+         or R_X86_64_TLSLD relocs.  */
+      htab->tls_ld_or_ldm_got.offset = htab->elf.sgot->size;
+      htab->elf.sgot->size += 2 * htab->got_entry_size;
+      htab->elf.srelgot->size += htab->sizeof_reloc;
+    }
+  else
+    htab->tls_ld_or_ldm_got.offset = -1;
+
+  /* Allocate global sym .plt and .got entries, and space for global
+     sym dynamic relocs.  */
+  elf_link_hash_traverse (&htab->elf, elf_x86_allocate_dynrelocs,
+                         info);
+
+  /* Allocate .plt and .got entries, and space for local symbols.  */
+  htab_traverse (htab->loc_hash_table, elf_x86_allocate_local_dynreloc,
+                info);
+
+  /* For every jump slot reserved in the sgotplt, reloc_count is
+     incremented.  However, when we reserve space for TLS descriptors,
+     it's not incremented, so in order to compute the space reserved
+     for them, it suffices to multiply the reloc count by the jump
+     slot size.
+
+     PR ld/13302: We start next_irelative_index at the end of .rela.plt
+     so that R_{386,X86_64}_IRELATIVE entries come last.  */
+  if (htab->elf.srelplt)
+    {
+      htab->next_tls_desc_index = htab->elf.srelplt->reloc_count;
+      htab->sgotplt_jump_table_size
+       = elf_x86_compute_jump_table_size (htab);
+      htab->next_irelative_index = htab->elf.srelplt->reloc_count - 1;
+    }
+  else if (htab->elf.irelplt)
+    htab->next_irelative_index = htab->elf.irelplt->reloc_count - 1;
+
+  if (htab->tlsdesc_plt)
+    {
+      /* NB: tlsdesc_plt is set only for x86-64.  If we're not using
+        lazy TLS relocations, don't generate the PLT and GOT entries
+        they require.  */
+      if ((info->flags & DF_BIND_NOW))
+       htab->tlsdesc_plt = 0;
+      else
+       {
+         htab->tlsdesc_got = htab->elf.sgot->size;
+         htab->elf.sgot->size += htab->got_entry_size;
+         /* Reserve room for the initial entry.
+            FIXME: we could probably do away with it in this case.  */
+         if (htab->elf.splt->size == 0)
+           htab->elf.splt->size = htab->plt.plt_entry_size;
+         htab->tlsdesc_plt = htab->elf.splt->size;
+         htab->elf.splt->size += htab->plt.plt_entry_size;
+       }
+    }
+
+  if (htab->elf.sgotplt)
+    {
+      /* Don't allocate .got.plt section if there are no GOT nor PLT
+        entries and there is no reference to _GLOBAL_OFFSET_TABLE_.  */
+      if ((htab->elf.hgot == NULL
+          || !htab->elf.hgot->ref_regular_nonweak)
+         && (htab->elf.sgotplt->size == bed->got_header_size)
+         && (htab->elf.splt == NULL
+             || htab->elf.splt->size == 0)
+         && (htab->elf.sgot == NULL
+             || htab->elf.sgot->size == 0)
+         && (htab->elf.iplt == NULL
+             || htab->elf.iplt->size == 0)
+         && (htab->elf.igotplt == NULL
+             || htab->elf.igotplt->size == 0))
+       htab->elf.sgotplt->size = 0;
+    }
+
+  if (_bfd_elf_eh_frame_present (info))
+    {
+      if (htab->plt_eh_frame != NULL
+         && htab->elf.splt != NULL
+         && htab->elf.splt->size != 0
+         && !bfd_is_abs_section (htab->elf.splt->output_section))
+       htab->plt_eh_frame->size = htab->plt.eh_frame_plt_size;
+
+      if (htab->plt_got_eh_frame != NULL
+         && htab->plt_got != NULL
+         && htab->plt_got->size != 0
+         && !bfd_is_abs_section (htab->plt_got->output_section))
+       htab->plt_got_eh_frame->size
+         = htab->non_lazy_plt->eh_frame_plt_size;
+
+      /* Unwind info for the second PLT and .plt.got sections are
+        identical.  */
+      if (htab->plt_second_eh_frame != NULL
+         && htab->plt_second != NULL
+         && htab->plt_second->size != 0
+         && !bfd_is_abs_section (htab->plt_second->output_section))
+       htab->plt_second_eh_frame->size
+         = htab->non_lazy_plt->eh_frame_plt_size;
+    }
+
+  /* We now have determined the sizes of the various dynamic sections.
+     Allocate memory for them.  */
+  relocs = FALSE;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      bfd_boolean strip_section = TRUE;
+
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
+       continue;
+
+      if (s == htab->elf.splt
+         || s == htab->elf.sgot)
+       {
+         /* Strip this section if we don't need it; see the
+            comment below.  */
+         /* We'd like to strip these sections if they aren't needed, but if
+            we've exported dynamic symbols from them we must leave them.
+            It's too late to tell BFD to get rid of the symbols.  */
+
+         if (htab->elf.hplt != NULL)
+           strip_section = FALSE;
+       }
+      else if (s == htab->elf.sgotplt
+              || s == htab->elf.iplt
+              || s == htab->elf.igotplt
+              || s == htab->plt_second
+              || s == htab->plt_got
+              || s == htab->plt_eh_frame
+              || s == htab->plt_got_eh_frame
+              || s == htab->plt_second_eh_frame
+              || s == htab->elf.sdynbss
+              || s == htab->elf.sdynrelro)
+       {
+         /* Strip these too.  */
+       }
+      else if (htab->is_reloc_section (bfd_get_section_name (dynobj, s)))
+       {
+         if (s->size != 0
+             && s != htab->elf.srelplt
+             && s != htab->srelplt2)
+           relocs = TRUE;
+
+         /* We use the reloc_count field as a counter if we need
+            to copy relocs into the output file.  */
+         if (s != htab->elf.srelplt)
+           s->reloc_count = 0;
+       }
+      else
+       {
+         /* It's not one of our sections, so don't allocate space.  */
+         continue;
+       }
+
+      if (s->size == 0)
+       {
+         /* If we don't need this section, strip it from the
+            output file.  This is mostly to handle .rel.bss and
+            .rel.plt.  We must create both sections in
+            create_dynamic_sections, because they must be created
+            before the linker maps input sections to output
+            sections.  The linker does that before
+            adjust_dynamic_symbol is called, and it is that
+            function which decides whether anything needs to go
+            into these sections.  */
+         if (strip_section)
+           s->flags |= SEC_EXCLUDE;
+         continue;
+       }
+
+      if ((s->flags & SEC_HAS_CONTENTS) == 0)
+       continue;
+
+      /* Allocate memory for the section contents.  We use bfd_zalloc
+        here in case unused entries are not reclaimed before the
+        section's contents are written out.  This should not happen,
+        but this way if it does, we get a R_386_NONE or R_X86_64_NONE
+        reloc instead of garbage.  */
+      s->contents = (unsigned char *) bfd_zalloc (dynobj, s->size);
+      if (s->contents == NULL)
+       return FALSE;
+    }
+
+  if (htab->plt_eh_frame != NULL
+      && htab->plt_eh_frame->contents != NULL)
+    {
+      memcpy (htab->plt_eh_frame->contents,
+             htab->plt.eh_frame_plt,
+             htab->plt_eh_frame->size);
+      bfd_put_32 (dynobj, htab->elf.splt->size,
+                 htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
+    }
+
+  if (htab->plt_got_eh_frame != NULL
+      && htab->plt_got_eh_frame->contents != NULL)
+    {
+      memcpy (htab->plt_got_eh_frame->contents,
+             htab->non_lazy_plt->eh_frame_plt,
+             htab->plt_got_eh_frame->size);
+      bfd_put_32 (dynobj, htab->plt_got->size,
+                 (htab->plt_got_eh_frame->contents
+                  + PLT_FDE_LEN_OFFSET));
+    }
+
+  if (htab->plt_second_eh_frame != NULL
+      && htab->plt_second_eh_frame->contents != NULL)
+    {
+      memcpy (htab->plt_second_eh_frame->contents,
+             htab->non_lazy_plt->eh_frame_plt,
+             htab->plt_second_eh_frame->size);
+      bfd_put_32 (dynobj, htab->plt_second->size,
+                 (htab->plt_second_eh_frame->contents
+                  + PLT_FDE_LEN_OFFSET));
+    }
+
+  if (htab->elf.dynamic_sections_created)
+    {
+      /* Add some entries to the .dynamic section.  We fill in the
+        values later, in elf_{i386,x86_64}_finish_dynamic_sections,
+        but we must add the entries now so that we get the correct
+        size for the .dynamic section.  The DT_DEBUG entry is filled
+        in by the dynamic linker and used by the debugger.  */
+#define add_dynamic_entry(TAG, VAL) \
+  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
+
+      if (bfd_link_executable (info))
+       {
+         if (!add_dynamic_entry (DT_DEBUG, 0))
+           return FALSE;
+       }
+
+      if (htab->elf.splt->size != 0)
+       {
+         /* DT_PLTGOT is used by prelink even if there is no PLT
+            relocation.  */
+         if (!add_dynamic_entry (DT_PLTGOT, 0))
+           return FALSE;
+       }
+
+      if (htab->elf.srelplt->size != 0)
+       {
+         if (!add_dynamic_entry (DT_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL, htab->dt_reloc)
+             || !add_dynamic_entry (DT_JMPREL, 0))
+           return FALSE;
+       }
+
+      if (htab->tlsdesc_plt
+         && (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
+             || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
+       return FALSE;
+
+      if (relocs)
+       {
+         if (!add_dynamic_entry (htab->dt_reloc, 0)
+             || !add_dynamic_entry (htab->dt_reloc_sz, 0)
+             || !add_dynamic_entry (htab->dt_reloc_ent,
+                                    htab->sizeof_reloc))
+           return FALSE;
+
+         /* If any dynamic relocs apply to a read-only section,
+            then we need a DT_TEXTREL entry.  */
+         if ((info->flags & DF_TEXTREL) == 0)
+           elf_link_hash_traverse (&htab->elf,
+                                   _bfd_x86_elf_readonly_dynrelocs,
+                                   info);
+
+         if ((info->flags & DF_TEXTREL) != 0)
+           {
+             if (htab->readonly_dynrelocs_against_ifunc)
+               {
+                 info->callbacks->einfo
+                   (_("%P%X: read-only segment has dynamic IFUNC relocations; recompile with -fPIC\n"));
+                 bfd_set_error (bfd_error_bad_value);
+                 return FALSE;
+               }
+
+             if (!add_dynamic_entry (DT_TEXTREL, 0))
+               return FALSE;
+           }
+       }
+      if (htab->is_vxworks
+         && !elf_vxworks_add_dynamic_entries (output_bfd, info))
+       return FALSE;
+    }
+#undef add_dynamic_entry
+
+  return TRUE;
+}
+
 bfd_boolean
 _bfd_x86_elf_always_size_sections (bfd *output_bfd,
                                   struct bfd_link_info *info)
@@ -515,19 +1443,12 @@ bfd_boolean
 _bfd_x86_elf_fixup_symbol (struct bfd_link_info *info,
                           struct elf_link_hash_entry *h)
 {
-  if (h->dynindx != -1)
+  if (h->dynindx != -1
+      && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, elf_x86_hash_entry (h)))
     {
-      const struct elf_backend_data *bed
-       = get_elf_backend_data (info->output_bfd);
-      if (UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
-                                          bed->target_id,
-                                          elf_x86_hash_entry (h)->has_got_reloc,
-                                          elf_x86_hash_entry (h)))
-       {
-         h->dynindx = -1;
-         _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
-                                 h->dynstr_index);
-       }
+      h->dynindx = -1;
+      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                             h->dynstr_index);
     }
   return TRUE;
 }
@@ -748,6 +1669,51 @@ _bfd_x86_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
+/* Return TRUE if a symbol is referenced locally.  It is similar to
+   SYMBOL_REFERENCES_LOCAL, but it also checks version script.  It
+   works in check_relocs.  */
+
+bfd_boolean
+_bfd_x86_elf_link_symbol_references_local (struct bfd_link_info *info,
+                                          struct elf_link_hash_entry *h)
+{
+  struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h);
+  struct elf_x86_link_hash_table *htab
+    = (struct elf_x86_link_hash_table *) info->hash;
+
+  if (eh->local_ref > 1)
+    return TRUE;
+
+  if (eh->local_ref == 1)
+    return FALSE;
+
+  /* Unversioned symbols defined in regular objects can be forced local
+     by linker version script.  A weak undefined symbol is forced local
+     if
+     1. It has non-default visibility.  Or
+     2. When building executable, there is no dynamic linker.  Or
+     3. or "-z nodynamic-undefined-weak" is used.
+   */
+  if (SYMBOL_REFERENCES_LOCAL (info, h)
+      || (h->root.type == bfd_link_hash_undefweak
+         && (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+             || (bfd_link_executable (info)
+                 && htab->interp == NULL)
+             || info->dynamic_undefined_weak == 0))
+      || ((h->def_regular || ELF_COMMON_DEF_P (h))
+         && h->versioned == unversioned
+         && info->version_info != NULL
+         && bfd_hide_sym_by_version (info->version_info,
+                                     h->root.root.string)))
+    {
+      eh->local_ref = 2;
+      return TRUE;
+    }
+
+  eh->local_ref = 1;
+  return FALSE;
+}
+
 /* Return the section that should be marked against GC for a given
    relocation. */
 
@@ -1152,8 +2118,7 @@ _bfd_x86_elf_merge_gnu_properties (struct bfd_link_info *info,
 
 bfd *
 _bfd_x86_elf_link_setup_gnu_properties
-  (struct bfd_link_info *info,
-   struct elf_x86_plt_layout_table *plt_layout)
+  (struct bfd_link_info *info, struct elf_x86_init_table *init_table)
 {
   bfd_boolean normal_target;
   bfd_boolean lazy_plt;
@@ -1225,16 +2190,18 @@ error_alignment:
 
   pbfd = _bfd_elf_link_setup_gnu_properties (info);
 
-  if (bfd_link_relocatable (info))
-    return pbfd;
-
   bed = get_elf_backend_data (info->output_bfd);
 
   htab = elf_x86_hash_table (info, bed->target_id);
   if (htab == NULL)
     return pbfd;
 
-  htab->is_vxworks = plt_layout->is_vxworks;
+  htab->is_vxworks = init_table->is_vxworks;
+  htab->r_info = init_table->r_info;
+  htab->r_sym = init_table->r_sym;
+
+  if (bfd_link_relocatable (info))
+    return pbfd;
 
   use_ibt_plt = info->ibtplt || info->ibt;
   if (!use_ibt_plt && pbfd != NULL)
@@ -1291,24 +2258,24 @@ error_alignment:
      still be used with LD_AUDIT or LD_PROFILE if PLT entry is used for
      canonical function address.  */
   htab->plt.has_plt0 = 1;
-  normal_target = plt_layout->normal_target;
+  normal_target = init_table->normal_target;
 
   if (normal_target)
     {
       if (use_ibt_plt)
        {
-         htab->lazy_plt = plt_layout->lazy_ibt_plt;
-         htab->non_lazy_plt = plt_layout->non_lazy_ibt_plt;
+         htab->lazy_plt = init_table->lazy_ibt_plt;
+         htab->non_lazy_plt = init_table->non_lazy_ibt_plt;
        }
       else
        {
-         htab->lazy_plt = plt_layout->lazy_plt;
-         htab->non_lazy_plt = plt_layout->non_lazy_plt;
+         htab->lazy_plt = init_table->lazy_plt;
+         htab->non_lazy_plt = init_table->non_lazy_plt;
        }
     }
   else
     {
-      htab->lazy_plt = plt_layout->lazy_plt;
+      htab->lazy_plt = init_table->lazy_plt;
       htab->non_lazy_plt = NULL;
     }
 
This page took 0.043158 seconds and 4 git commands to generate.