Add CRX insns: pushx, popx
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 354cfbbe5a5e90ce718ff23c07ea025e533ce6b2..2e958cf249adfa4b1e3854b35cba1faa229daab2 100644 (file)
@@ -1859,10 +1859,14 @@ elf_link_read_relocs_from_section (bfd *abfd,
        r_symndx >>= 24;
       if ((size_t) r_symndx >= nsyms)
        {
+         char *sec_name = bfd_get_section_ident (sec);
          (*_bfd_error_handler)
            (_("%s: bad reloc symbol index (0x%lx >= 0x%lx) for offset 0x%lx in section `%s'"),
             bfd_archive_filename (abfd), (unsigned long) r_symndx,
-            (unsigned long) nsyms, irela->r_offset, sec->name);
+            (unsigned long) nsyms, irela->r_offset,
+            sec_name ? sec_name : sec->name);
+         if (sec_name)
+           free (sec_name);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }
@@ -2048,11 +2052,14 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
     }
   else
     {
+      char *sec_name = bfd_get_section_ident (input_section);
       (*_bfd_error_handler)
        (_("%s: relocation size mismatch in %s section %s"),
         bfd_get_filename (output_bfd),
         bfd_archive_filename (input_section->owner),
-        input_section->name);
+        sec_name ? sec_name : input_section->name);
+      if (sec_name)
+       free (sec_name);
       bfd_set_error (bfd_error_wrong_object_format);
       return FALSE;
     }
@@ -2449,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.  */
@@ -2897,6 +2908,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
      const char **, flagword *, asection **, bfd_vma *);
   bfd_boolean (*check_relocs)
     (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
+  bfd_boolean (*check_directives)
+    (bfd *, struct bfd_link_info *);
   bfd_boolean collect;
   Elf_Internal_Shdr *hdr;
   bfd_size_type symcount;
@@ -3055,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)
@@ -3837,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)
@@ -4046,6 +4074,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       free (sorted_sym_hash);
     }
 
+  check_directives = get_elf_backend_data (abfd)->check_directives;
+  if (check_directives)
+    check_directives (abfd, info);
+
   /* If this object is the same format as the output object, and it is
      not a shared library, then let the backend look through the
      relocs.
@@ -5805,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;
 
@@ -6073,11 +6105,14 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
                                                 input_sec->output_section);
            if (sym.st_shndx == SHN_BAD)
              {
+               char *sec_name = bfd_get_section_ident (input_sec);
                (*_bfd_error_handler)
                  (_("%s: could not find output section %s for input section %s"),
                   bfd_get_filename (finfo->output_bfd),
                   input_sec->output_section->name,
-                  input_sec->name);
+                  sec_name ? sec_name : input_sec->name);
+               if (sec_name)
+                 free (sec_name);
                eoinfo->failed = TRUE;
                return FALSE;
              }
@@ -6258,18 +6293,22 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
   return TRUE;
 }
 
+/* Return TRUE if special handling is done for relocs in SEC against
+   symbols defined in discarded sections.  */
+
 static bfd_boolean
 elf_section_ignore_discarded_relocs (asection *sec)
 {
   const struct elf_backend_data *bed;
 
-  if (strncmp (".stab", sec->name, 5) == 0
-      && (!sec->name[5] ||
-         (sec->name[5] == '.' && ISDIGIT (sec->name[6]))))
-    return TRUE;
-
-  if (strcmp (".eh_frame", sec->name) == 0)
-    return TRUE;
+  switch (sec->sec_info_type)
+    {
+    case ELF_INFO_TYPE_STABS:
+    case ELF_INFO_TYPE_EH_FRAME:
+      return TRUE;
+    default:
+      break;
+    }
 
   bed = get_elf_backend_data (sec->owner);
   if (bed->elf_backend_ignore_discarded_relocs != NULL
@@ -6279,6 +6318,29 @@ elf_section_ignore_discarded_relocs (asection *sec)
   return FALSE;
 }
 
+/* Return TRUE if we should complain about a reloc in SEC against a
+   symbol defined in a discarded section.  */
+
+static bfd_boolean
+elf_section_complain_discarded (asection *sec)
+{
+  if (strncmp (".stab", sec->name, 5) == 0
+      && (!sec->name[5] ||
+         (sec->name[5] == '.' && ISDIGIT (sec->name[6]))))
+    return FALSE;
+
+  if (strcmp (".eh_frame", sec->name) == 0)
+    return FALSE;
+
+  if (strcmp (".gcc_except_table", sec->name) == 0)
+    return FALSE;
+
+  if (strcmp (".PARISC.unwind", sec->name) == 0)
+    return FALSE;
+
+  return TRUE;
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.
    This is so that we only have to read the local symbols once, and
@@ -6551,95 +6613,95 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
          if (!elf_section_ignore_discarded_relocs (o))
            {
              Elf_Internal_Rela *rel, *relend;
+             bfd_boolean complain = elf_section_complain_discarded (o);
 
              rel = internal_relocs;
              relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
              for ( ; rel < relend; rel++)
                {
                  unsigned long r_symndx = rel->r_info >> r_sym_shift;
-                 asection *sec;
+                 asection **ps, *sec;
+                 struct elf_link_hash_entry *h = NULL;
+                 const char *sym_name;
 
                  if (r_symndx >= locsymcount
                      || (elf_bad_symtab (input_bfd)
                          && finfo->sections[r_symndx] == NULL))
                    {
-                     struct elf_link_hash_entry *h;
-
                      h = sym_hashes[r_symndx - extsymoff];
                      while (h->root.type == bfd_link_hash_indirect
                             || h->root.type == bfd_link_hash_warning)
                        h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-                     /* Complain if the definition comes from a
-                        discarded section.  */
-                     sec = h->root.u.def.section;
-                     if ((h->root.type == bfd_link_hash_defined
-                          || h->root.type == bfd_link_hash_defweak)
-                         && elf_discarded_section (sec))
-                       {
-                         if ((o->flags & SEC_DEBUGGING) != 0)
-                           {
-                             BFD_ASSERT (r_symndx != 0);
-                             /* Try to preserve debug information.  */
-                             if ((o->flags & SEC_DEBUGGING) != 0
-                                 && sec->kept_section != NULL
-                                 && sec->size == sec->kept_section->size)
-                               h->root.u.def.section
-                                 = sec->kept_section;
-                             else
-                               memset (rel, 0, sizeof (*rel));
-                           }
-                         else
-                           finfo->info->callbacks->error_handler
-                             (LD_DEFINITION_IN_DISCARDED_SECTION,
-                              _("%T: discarded in section `%s' from %s\n"),
-                              h->root.root.string,
-                              h->root.root.string,
-                              h->root.u.def.section->name,
-                              bfd_archive_filename (h->root.u.def.section->owner));
-                       }
+                     if (h->root.type != bfd_link_hash_defined
+                         && h->root.type != bfd_link_hash_defweak)
+                       continue;
+
+                     ps = &h->root.u.def.section;
+                     sym_name = h->root.root.string;
                    }
                  else
                    {
-                     sec = finfo->sections[r_symndx];
+                     Elf_Internal_Sym *sym = isymbuf + r_symndx;
+                     ps = &finfo->sections[r_symndx];
+                     sym_name = bfd_elf_local_sym_name (input_bfd, sym);
+                   }
 
-                     if (sec != NULL && elf_discarded_section (sec))
+                 /* Complain if the definition comes from a
+                    discarded section.  */
+                 if ((sec = *ps) != NULL && elf_discarded_section (sec))
+                   {
+                     if ((o->flags & SEC_DEBUGGING) != 0)
                        {
-                         if ((o->flags & SEC_DEBUGGING) != 0
-                             || (sec->flags & SEC_LINK_ONCE) != 0)
+                         BFD_ASSERT (r_symndx != 0);
+
+                         /* Try to preserve debug information.
+                            FIXME: This is quite broken.  Modifying
+                            the symbol here means we will be changing
+                            all uses of the symbol, not just those in
+                            debug sections.  The only thing that makes
+                            this half reasonable is that debug sections
+                            tend to come after other sections.  Of
+                            course, that doesn't help with globals.
+                            ??? All link-once sections of the same name
+                            ought to define the same set of symbols, so
+                            it would seem that globals ought to always
+                            be defined in the kept section.  */
+                         if (sec->kept_section != NULL
+                             && sec->size == sec->kept_section->size)
                            {
-                             BFD_ASSERT (r_symndx != 0);
-                             /* Try to preserve debug information.  */
-                             if ((o->flags & SEC_DEBUGGING) != 0
-                                 && sec->kept_section != NULL
-                                 && sec->size == sec->kept_section->size)
-                               finfo->sections[r_symndx]
-                                 = sec->kept_section;
-                             else
-                               {
-                                 rel->r_info &= r_type_mask;
-                                 rel->r_addend = 0;
-                               }
-                           }
-                         else
-                           {
-                             static int count;
-                             int ok;
-                             char *buf;
-
-                             ok = asprintf (&buf, "local symbol %d",
-                                            count++);
-                             if (ok <= 0)
-                               buf = (char *) "local symbol";
-                             finfo->info->callbacks->error_handler
-                               (LD_DEFINITION_IN_DISCARDED_SECTION,
-                                _("%T: discarded in section `%s' from %s\n"),
-                                buf, buf, sec->name,
-                                bfd_archive_filename (input_bfd));
-                             if (ok != -1)
-                               free (buf);
+                             *ps = sec->kept_section;
+                             continue;
                            }
                        }
+                     else if (complain)
+                       {
+                         char *r_sec
+                           = bfd_get_section_ident (o);
+                         char *d_sec
+                           = bfd_get_section_ident (sec);
+                         finfo->info->callbacks->error_handler
+                           (LD_DEFINITION_IN_DISCARDED_SECTION,
+                            _("`%T' referenced in section `%s' of %B: "
+                              "defined in discarded section `%s' of %B\n"),
+                            sym_name, sym_name,
+                            r_sec ? r_sec : o->name, input_bfd,
+                            d_sec ? d_sec : sec->name, sec->owner);
+                         if (r_sec)
+                           free (r_sec);
+                         if (d_sec)
+                           free (d_sec);
+                       }
+
+                     /* Remove the symbol reference from the reloc, but
+                        don't kill the reloc completely.  This is so that
+                        a zero value will be written into the section,
+                        which may have non-zero contents put there by the
+                        assembler.  Zero in things like an eh_frame fde
+                        pc_begin allows stack unwinders to recognize the
+                        fde as bogus.  */
+                     rel->r_info &= r_type_mask;
+                     rel->r_addend = 0;
                    }
                }
            }
@@ -7110,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
@@ -7569,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
@@ -8551,6 +8734,7 @@ bfd_elf_gc_record_vtinherit (bfd *abfd,
   struct elf_link_hash_entry **search, *child;
   bfd_size_type extsymcount;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  char *sec_name;
 
   /* The sh_info field of the symtab header tells us where the
      external symbols start.  We don't care about the local symbols at
@@ -8574,8 +8758,10 @@ bfd_elf_gc_record_vtinherit (bfd *abfd,
        goto win;
     }
 
+  sec_name = bfd_get_section_ident (sec);
   (*_bfd_error_handler) ("%s: %s+%lu: No symbol found for INHERIT",
-                        bfd_archive_filename (abfd), sec->name,
+                        bfd_archive_filename (abfd),
+                        sec_name ? sec_name : sec->name,
                         (unsigned long) offset);
   bfd_set_error (bfd_error_invalid_operation);
   return FALSE;
@@ -8973,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.030675 seconds and 4 git commands to generate.