Add CRX insns: pushx, popx
[deliverable/binutils-gdb.git] / bfd / elflink.c
index a6dafae2b11852dff30fda4cf1d8607ed10f854b..2e958cf249adfa4b1e3854b35cba1faa229daab2 100644 (file)
@@ -2456,9 +2456,13 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
   if (h == NULL)
     return TRUE;
 
+  /* Common symbols that become definitions don't get the DEF_REGULAR
+     flag set, so test it first, and don't bail out.  */
+  if (ELF_COMMON_DEF_P (h))
+    /* Do nothing.  */;
   /* If we don't have a definition in a regular file, then we can't
      resolve locally.  The sym is either undefined or dynamic.  */
-  if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+  else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
     return FALSE;
 
   /* Forced local symbols resolve locally.  */
@@ -3064,8 +3068,13 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       /* If this dynamic lib was specified on the command line with
         --as-needed in effect, then we don't want to add a DT_NEEDED
         tag unless the lib is actually used.  Similary for libs brought
-        in by another lib's DT_NEEDED.  */
-      add_needed = elf_dyn_lib_class (abfd) == DYN_NORMAL;
+        in by another lib's DT_NEEDED.  When --no-add-needed is used
+        on a dynamic lib, we don't want to add a DT_NEEDED entry for
+        any dynamic library in DT_NEEDED tags in the dynamic lib at
+        all.  */
+      add_needed = (elf_dyn_lib_class (abfd)
+                   & (DYN_AS_NEEDED | DYN_DT_NEEDED
+                      | DYN_NO_NEEDED)) == 0;
 
       s = bfd_get_section_by_name (abfd, ".dynamic");
       if (s != NULL)
@@ -3846,7 +3855,17 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 
              /* A symbol from a library loaded via DT_NEEDED of some
                 other library is referenced by a regular object.
-                Add a DT_NEEDED entry for it.  */
+                Add a DT_NEEDED entry for it.  Issue an error if
+                --no-add-needed is used.  */
+             if ((elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0)
+               {
+                 (*_bfd_error_handler)
+                   (_("%s: invalid DSO for symbol `%s' definition"),
+                    bfd_archive_filename (abfd), name);
+                 bfd_set_error (bfd_error_bad_value);
+                 goto error_free_vers;
+               }
+
              add_needed = TRUE;
              ret = elf_add_dt_needed_tag (info, soname, add_needed);
              if (ret < 0)
@@ -5818,7 +5837,7 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
     case bfd_link_hash_undefweak:
       abfd = h->root.u.undef.abfd;
       if ((abfd->flags & DYNAMIC) == 0
-         || elf_dyn_lib_class (abfd) != DYN_DT_NEEDED)
+         || (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) == 0)
        return FALSE;
       break;
 
@@ -7153,6 +7172,120 @@ elf_reloc_link_order (bfd *output_bfd,
   return TRUE;
 }
 
+
+/* Get the output vma of the section pointed to by the sh_link field.  */
+
+static bfd_vma
+elf_get_linked_section_vma (struct bfd_link_order *p)
+{
+  Elf_Internal_Shdr **elf_shdrp;
+  asection *s;
+  int elfsec;
+
+  s = p->u.indirect.section;
+  elf_shdrp = elf_elfsections (s->owner);
+  elfsec = _bfd_elf_section_from_bfd_section (s->owner, s);
+  elfsec = elf_shdrp[elfsec]->sh_link;
+  s = elf_shdrp[elfsec]->bfd_section;
+  return s->output_section->vma + s->output_offset;
+}
+
+
+/* Compare two sections based on the locations of the sections they are
+   linked to.  Used by elf_fixup_link_order.  */
+
+static int
+compare_link_order (const void * a, const void * b)
+{
+  bfd_vma apos;
+  bfd_vma bpos;
+
+  apos = elf_get_linked_section_vma (*(struct bfd_link_order **)a);
+  bpos = elf_get_linked_section_vma (*(struct bfd_link_order **)b);
+  if (apos < bpos)
+    return -1;
+  return apos > bpos;
+}
+
+
+/* Looks for sections with SHF_LINK_ORDER set.  Rearranges them into the same
+   order as their linked sections.  Returns false if this could not be done
+   because an output section includes both ordered and unordered
+   sections.  Ideally we'd do this in the linker proper.  */
+
+static bfd_boolean
+elf_fixup_link_order (bfd *abfd, asection *o)
+{
+  int seen_linkorder;
+  int seen_other;
+  int n;
+  struct bfd_link_order *p;
+  bfd *sub;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  int elfsec;
+  struct bfd_link_order **sections;
+  asection *s;
+  bfd_vma offset;
+  
+  seen_other = 0;
+  seen_linkorder = 0;
+  for (p = o->link_order_head; p != NULL; p = p->next)
+    {
+      if (p->type == bfd_indirect_link_order
+         && (bfd_get_flavour ((sub = p->u.indirect.section->owner))
+             == bfd_target_elf_flavour)
+         && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass)
+       {
+         s = p->u.indirect.section;
+         elfsec = _bfd_elf_section_from_bfd_section (sub, s);
+         if (elfsec != -1
+             && elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER)
+           seen_linkorder++;
+         else
+           seen_other++;
+       }
+      else
+       seen_other++;
+    }
+
+  if (!seen_linkorder)
+    return TRUE;
+
+  if (seen_other && seen_linkorder)
+    {
+      (*_bfd_error_handler) (_("%s: has both ordered and unordered sections"),
+                            o->name);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+  
+  sections = (struct bfd_link_order **)
+    xmalloc (seen_linkorder * sizeof (struct bfd_link_order *));
+  seen_linkorder = 0;
+  
+  for (p = o->link_order_head; p != NULL; p = p->next)
+    {
+      sections[seen_linkorder++] = p;
+    }
+  /* Sort the input sections in the order of their linked section.  */
+  qsort (sections, seen_linkorder, sizeof (struct bfd_link_order *),
+        compare_link_order);
+
+  /* Change the offsets of the sections.  */
+  offset = 0;
+  for (n = 0; n < seen_linkorder; n++)
+    {
+      s = sections[n]->u.indirect.section;
+      offset &= ~(bfd_vma)((1 << s->alignment_power) - 1);
+      s->output_offset = offset;
+      sections[n]->offset = offset;
+      offset += sections[n]->size;
+    }
+
+  return TRUE;
+}
+
+
 /* Do the final step of an ELF link.  */
 
 bfd_boolean
@@ -7612,6 +7745,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       elf_hash_table (info)->tls_size = end - base;
     }
 
+  /* Reorder SHF_LINK_ORDER sections.  */
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if (!elf_fixup_link_order (abfd, o))
+       return FALSE;
+    }
+
   /* Since ELF permits relocations to be against local symbols, we
      must have the local symbols available when we do the relocations.
      Since we would rather only read the local symbols once, and we
@@ -9019,3 +9159,89 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 
   return ret;
 }
+
+void
+_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
+{
+  flagword flags;
+  const char *name;
+  struct bfd_section_already_linked *l;
+  struct bfd_section_already_linked_hash_entry *already_linked_list;
+
+  flags = sec->flags;
+  if ((flags & SEC_LINK_ONCE) == 0)
+    return;
+
+  /* FIXME: When doing a relocatable link, we may have trouble
+     copying relocations in other sections that refer to local symbols
+     in the section being discarded.  Those relocations will have to
+     be converted somehow; as of this writing I'm not sure that any of
+     the backends handle that correctly.
+
+     It is tempting to instead not discard link once sections when
+     doing a relocatable link (technically, they should be discarded
+     whenever we are building constructors).  However, that fails,
+     because the linker winds up combining all the link once sections
+     into a single large link once section, which defeats the purpose
+     of having link once sections in the first place.
+
+     Also, not merging link once sections in a relocatable link
+     causes trouble for MIPS ELF, which relies on link once semantics
+     to handle the .reginfo section correctly.  */
+
+  name = bfd_get_section_name (abfd, sec);
+
+  already_linked_list = bfd_section_already_linked_table_lookup (name);
+
+  for (l = already_linked_list->entry; l != NULL; l = l->next)
+    {
+      /* We may have 3 different sections on the list: group section,
+        comdat section and linkonce section. SEC may be a linkonce or
+        group section. We match a group section with a group section,
+        a linkonce section with a linkonce section, and ignore comdat
+        section.  */
+      if ((sec->flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
+         && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
+       {
+         /* The section has already been linked.  See if we should
+             issue a warning.  */
+         switch (flags & SEC_LINK_DUPLICATES)
+           {
+           default:
+             abort ();
+
+           case SEC_LINK_DUPLICATES_DISCARD:
+             break;
+
+           case SEC_LINK_DUPLICATES_ONE_ONLY:
+             (*_bfd_error_handler)
+               (_("%s: %s: warning: ignoring duplicate section `%s'\n"),
+                bfd_archive_filename (abfd), name);
+             break;
+
+           case SEC_LINK_DUPLICATES_SAME_SIZE:
+             if (sec->size != l->sec->size)
+               (*_bfd_error_handler)
+                 (_("%s: %s: warning: duplicate section `%s' has different size\n"),
+                  bfd_archive_filename (abfd), name);
+             break;
+           }
+
+         /* Set the output_section field so that lang_add_section
+            does not create a lang_input_section structure for this
+            section.  Since there might be a symbol in the section
+            being discarded, we must retain a pointer to the section
+            which we are really going to use.  */
+         sec->output_section = bfd_abs_section_ptr;
+         sec->kept_section = l->sec;
+         
+         if (flags & SEC_GROUP)
+           bfd_elf_discard_group (abfd, sec);
+
+         return;
+       }
+    }
+
+  /* This is the first section with this name.  Record it.  */
+  bfd_section_already_linked_table_insert (already_linked_list, sec);
+}
This page took 0.027314 seconds and 4 git commands to generate.