Move C-related declarations to compile-c.h
[deliverable/binutils-gdb.git] / bfd / elfxx-x86.c
index 5f55c948edc55bff8b0ccf52387f1af6163418cb..7ccfd2581526ea4e71044bef1fb1f127537c1d6b 100644 (file)
@@ -849,6 +849,54 @@ _bfd_x86_elf_compare_relocs (const void *ap, const void *bp)
     return 0;
 }
 
+/* Mark symbol, NAME, as locally defined by linker if it is referenced
+   and not defined in a relocatable object file.  */
+
+static void
+elf_x86_linker_defined (struct bfd_link_info *info, const char *name)
+{
+  struct elf_link_hash_entry *h;
+
+  h = elf_link_hash_lookup (elf_hash_table (info), name,
+                           FALSE, FALSE, FALSE);
+  if (h == NULL)
+    return;
+
+  while (h->root.type == bfd_link_hash_indirect)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  if (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
+      || (!h->def_regular && h->def_dynamic))
+    {
+      elf_x86_hash_entry (h)->local_ref = 2;
+      elf_x86_hash_entry (h)->linker_def = 1;
+    }
+}
+
+/* Hide a linker-defined symbol, NAME, with hidden visibility.  */
+
+static void
+elf_x86_hide_linker_defined (struct bfd_link_info *info,
+                            const char *name)
+{
+  struct elf_link_hash_entry *h;
+
+  h = elf_link_hash_lookup (elf_hash_table (info), name,
+                           FALSE, FALSE, FALSE);
+  if (h == NULL)
+    return;
+
+  while (h->root.type == bfd_link_hash_indirect)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+      || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+    _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+}
+
 bfd_boolean
 _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
 {
@@ -879,17 +927,23 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
 
          /* "__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_linker_defined (info, "__ehdr_start");
+
+         if (bfd_link_executable (info))
+           {
+             /* References to __bss_start, _end and _edata should be
+                locally resolved within executables.  */
+             elf_x86_linker_defined (info, "__bss_start");
+             elf_x86_linker_defined (info, "_end");
+             elf_x86_linker_defined (info, "_edata");
+           }
+         else
            {
-             elf_x86_hash_entry (h)->local_ref = 2;
-             elf_x86_hash_entry (h)->linker_def = 1;
+             /* Hide hidden __bss_start, _end and _edata in shared
+                libraries.  */
+             elf_x86_hide_linker_defined (info, "__bss_start");
+             elf_x86_hide_linker_defined (info, "_end");
+             elf_x86_hide_linker_defined (info, "_edata");
            }
        }
     }
@@ -1705,6 +1759,52 @@ _bfd_x86_elf_fixup_symbol (struct bfd_link_info *info,
   return TRUE;
 }
 
+/* Change the STT_GNU_IFUNC symbol defined in position-dependent
+   executable into the normal function symbol and set its address
+   to its PLT entry, which should be resolved by R_*_IRELATIVE at
+   run-time.  */
+
+void
+_bfd_x86_elf_link_fixup_ifunc_symbol (struct bfd_link_info *info,
+                                     struct elf_x86_link_hash_table *htab,
+                                     struct elf_link_hash_entry *h,
+                                     Elf_Internal_Sym *sym)
+{
+  if (bfd_link_pde (info)
+      && h->def_regular
+      && h->dynindx != -1
+      && h->plt.offset != (bfd_vma) -1
+      && h->type == STT_GNU_IFUNC
+      && h->pointer_equality_needed)
+    {
+      asection *plt_s;
+      bfd_vma plt_offset;
+      bfd *output_bfd = info->output_bfd;
+
+      if (htab->plt_second)
+       {
+         struct elf_x86_link_hash_entry *eh
+           = (struct elf_x86_link_hash_entry *) h;
+
+         plt_s = htab->plt_second;
+         plt_offset = eh->plt_second.offset;
+       }
+      else
+       {
+         plt_s = htab->elf.splt;
+         plt_offset = h->plt.offset;
+       }
+
+      sym->st_size = 0;
+      sym->st_info = ELF_ST_INFO (ELF_ST_BIND (sym->st_info), STT_FUNC);
+      sym->st_shndx
+       = _bfd_elf_section_from_bfd_section (output_bfd,
+                                            plt_s->output_section);
+      sym->st_value = (plt_s->output_section->vma
+                      + plt_s->output_offset + plt_offset);
+    }
+}
+
 /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
 
 bfd_boolean
@@ -1967,10 +2067,8 @@ _bfd_x86_elf_link_symbol_references_local (struct bfd_link_info *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)))
+         && _bfd_elf_link_hide_sym_by_version (info, h)))
     {
       eh->local_ref = 2;
       return TRUE;
@@ -2309,18 +2407,54 @@ _bfd_x86_elf_merge_gnu_properties (struct bfd_link_info *info,
   switch (pr_type)
     {
     case GNU_PROPERTY_X86_ISA_1_USED:
+      if (aprop == NULL || bprop == NULL)
+       {
+         /* Only one of APROP and BPROP can be NULL.  */
+         if (aprop != NULL)
+           {
+             /* Remove this property since the other input file doesn't
+                have it.  */
+             aprop->pr_kind = property_remove;
+             updated = TRUE;
+           }
+         break;
+       }
+      goto or_property;
+
     case GNU_PROPERTY_X86_ISA_1_NEEDED:
       if (aprop != NULL && bprop != NULL)
        {
+or_property:
          number = aprop->u.number;
          aprop->u.number = number | bprop->u.number;
-         updated = number != (unsigned int) aprop->u.number;
+         /* Remove the property if all bits are empty.  */
+         if (aprop->u.number == 0)
+           {
+             aprop->pr_kind = property_remove;
+             updated = TRUE;
+           }
+         else
+           updated = number != (unsigned int) aprop->u.number;
        }
       else
        {
-         /* Return TRUE if APROP is NULL to indicate that BPROP should
-            be added to ABFD.  */
-         updated = aprop == NULL;
+         /* Only one of APROP and BPROP can be NULL.  */
+         if (aprop != NULL)
+           {
+             if (aprop->u.number == 0)
+               {
+                 /* Remove APROP if all bits are empty.  */
+                 aprop->pr_kind = property_remove;
+                 updated = TRUE;
+               }
+           }
+         else
+           {
+             /* Return TRUE if APROP is NULL and all bits of BPROP
+                aren't empty to indicate that BPROP should be added
+                to ABFD.  */
+             updated = bprop->u.number != 0;
+           }
        }
       break;
 
@@ -2405,6 +2539,7 @@ _bfd_x86_elf_link_setup_gnu_properties
   const struct elf_backend_data *bed;
   unsigned int class_align = ABI_64_P (info->output_bfd) ? 3 : 2;
   unsigned int got_align;
+  bfd_boolean has_text = FALSE;
 
   features = 0;
   if (info->ibt)
@@ -2419,24 +2554,59 @@ _bfd_x86_elf_link_setup_gnu_properties
     if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour
        && bfd_count_sections (pbfd) != 0)
       {
+       if (!has_text)
+         {
+           /* Check if there is no non-empty text section.  */
+           sec = bfd_get_section_by_name (pbfd, ".text");
+           if (sec != NULL && sec->size != 0)
+             has_text = TRUE;
+         }
+
        ebfd = pbfd;
 
        if (elf_properties (pbfd) != NULL)
          break;
       }
 
-  if (ebfd != NULL && features)
+  bed = get_elf_backend_data (info->output_bfd);
+
+  htab = elf_x86_hash_table (info, bed->target_id);
+  if (htab == NULL)
+    return pbfd;
+
+  if (ebfd != NULL)
     {
-      /* If features is set, add GNU_PROPERTY_X86_FEATURE_1_IBT and
-        GNU_PROPERTY_X86_FEATURE_1_SHSTK.  */
-      prop = _bfd_elf_get_property (ebfd,
-                                   GNU_PROPERTY_X86_FEATURE_1_AND,
-                                   4);
-      prop->u.number |= features;
-      prop->pr_kind = property_number;
+      prop = NULL;
+      if (features)
+       {
+         /* If features is set, add GNU_PROPERTY_X86_FEATURE_1_IBT and
+            GNU_PROPERTY_X86_FEATURE_1_SHSTK.  */
+         prop = _bfd_elf_get_property (ebfd,
+                                       GNU_PROPERTY_X86_FEATURE_1_AND,
+                                       4);
+         prop->u.number |= features;
+         prop->pr_kind = property_number;
+       }
+      else if (has_text
+              && elf_properties (ebfd) == NULL
+              && elf_tdata (info->output_bfd)->o->build_id.sec == NULL
+              && !htab->elf.dynamic_sections_created
+              && !info->traditional_format
+              && (info->output_bfd->flags & D_PAGED) != 0
+              && info->separate_code)
+       {
+         /* If the separate code program header is needed, make sure
+            that the first read-only PT_LOAD segment has no code by
+            adding a GNU_PROPERTY_X86_ISA_1_NEEDED note.  */
+         prop = _bfd_elf_get_property (ebfd,
+                                       GNU_PROPERTY_X86_ISA_1_NEEDED,
+                                       4);
+         prop->u.number = GNU_PROPERTY_X86_ISA_1_486;
+         prop->pr_kind = property_number;
+       }
 
       /* Create the GNU property note section if needed.  */
-      if (pbfd == NULL)
+      if (prop != NULL && pbfd == NULL)
        {
          sec = bfd_make_section_with_flags (ebfd,
                                             NOTE_GNU_PROPERTY_SECTION_NAME,
@@ -2462,12 +2632,6 @@ error_alignment:
 
   pbfd = _bfd_elf_link_setup_gnu_properties (info);
 
-  bed = get_elf_backend_data (info->output_bfd);
-
-  htab = elf_x86_hash_table (info, bed->target_id);
-  if (htab == NULL)
-    return pbfd;
-
   htab->r_info = init_table->r_info;
   htab->r_sym = init_table->r_sym;
 
@@ -2518,7 +2682,9 @@ error_alignment:
               abfd = abfd->link.next)
            if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
                && (abfd->flags
-                   & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
+                   & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0
+               && bed->relocs_compatible (abfd->xvec,
+                                          info->output_bfd->xvec))
              {
                htab->elf.dynobj = abfd;
                dynobj = abfd;
This page took 0.033397 seconds and 4 git commands to generate.