Strip undefined symbols from .symtab
[deliverable/binutils-gdb.git] / bfd / elflink.c
index c1e794868c3861e755a21198473f106da0e36515..0cd85f1d94c28db63dea3e16ed98452d0763ae35 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linking support for BFD.
-   Copyright (C) 1995-2014 Free Software Foundation, Inc.
+   Copyright (C) 1995-2015 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -20,6 +20,7 @@
 
 #include "sysdep.h"
 #include "bfd.h"
+#include "bfd_stdint.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #define ARCH_SIZE 0
@@ -84,6 +85,7 @@ _bfd_elf_define_linkage_sym (bfd *abfd,
   h = (struct elf_link_hash_entry *) bh;
   h->def_regular = 1;
   h->non_elf = 0;
+  h->root.linker_def = 1;
   h->type = STT_OBJECT;
   if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
     h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
@@ -760,6 +762,7 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
                                   asection *p)
 {
   struct elf_link_hash_table *htab;
+  asection *ip;
 
   switch (elf_section_data (p)->this_hdr.sh_type)
     {
@@ -775,18 +778,9 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
       if (htab->text_index_section != NULL)
        return p != htab->text_index_section && p != htab->data_index_section;
 
-      if (strcmp (p->name, ".got") == 0
-         || strcmp (p->name, ".got.plt") == 0
-         || strcmp (p->name, ".plt") == 0)
-       {
-         asection *ip;
-
-         if (htab->dynobj != NULL
+      return (htab->dynobj != NULL
              && (ip = bfd_get_linker_section (htab->dynobj, p->name)) != NULL
-             && ip->output_section == p)
-           return TRUE;
-       }
-      return FALSE;
+             && ip->output_section == p);
 
       /* There shouldn't be section relative relocations
         against any other section.  */
@@ -872,6 +866,8 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
       if (symvis - 1 < hvis - 1)
        h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1));
     }
+  else if (definition && ELF_ST_VISIBILITY (isym->st_other) != STV_DEFAULT)
+    h->protected_def = 1;
 }
 
 /* This function is called when we want to merge a new symbol with an
@@ -1832,7 +1828,9 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
   if (!h->def_dynamic
       || h->def_regular
       || h->dynindx == -1
-      || h->verinfo.verdef == NULL)
+      || h->verinfo.verdef == NULL
+      || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd)
+         & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED)))
     return TRUE;
 
   /* See if we already know about this version.  */
@@ -2283,8 +2281,8 @@ _bfd_elf_link_size_reloc_section (bfd *abfd,
     {
       struct elf_link_hash_entry **p;
 
-      p = (struct elf_link_hash_entry **)
-          bfd_zmalloc (reldata->count * sizeof (struct elf_link_hash_entry *));
+      p = ((struct elf_link_hash_entry **)
+          bfd_zmalloc (reldata->count * sizeof (*p)));
       if (p == NULL)
        return FALSE;
 
@@ -2634,7 +2632,8 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
    DYNBSS.  */
 
 bfd_boolean
-_bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h,
+_bfd_elf_adjust_dynamic_copy (struct bfd_link_info *info,
+                             struct elf_link_hash_entry *h,
                              asection *dynbss)
 {
   unsigned int power_of_two;
@@ -2673,6 +2672,15 @@ _bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h,
   /* Increment the size of DYNBSS to make room for the symbol.  */
   dynbss->size += h->size;
 
+  if (h->protected_def)
+    {
+      info->callbacks->einfo
+       (_("%P: copy reloc against protected `%T' is invalid\n"),
+        h->root.root.string);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
   return TRUE;
 }
 
@@ -4077,8 +4085,7 @@ error_free_dyn:
             requested we not re-export it, then mark it as hidden.  */
          if (definition
              && !dynamic
-             && (abfd->no_export
-                 || (abfd->my_archive && abfd->my_archive->no_export))
+             && abfd->no_export
              && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
            isym->st_other = (STV_HIDDEN
                              | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
@@ -4376,8 +4383,8 @@ error_free_dyn:
                    {
                      amt = ((isymend - isym + 1)
                             * sizeof (struct elf_link_hash_entry *));
-                     nondeflt_vers =
-                          (struct elf_link_hash_entry **) bfd_malloc (amt);
+                     nondeflt_vers
+                       = (struct elf_link_hash_entry **) bfd_malloc (amt);
                      if (!nondeflt_vers)
                        goto error_free_vers;
                    }
@@ -4443,7 +4450,7 @@ error_free_dyn:
                }
 
              elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
-                  (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);
+               (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);
 
              add_needed = TRUE;
              ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
@@ -4852,8 +4859,7 @@ error_free_dyn:
       /* Add this bfd to the loaded list.  */
       struct elf_link_loaded_list *n;
 
-      n = (struct elf_link_loaded_list *)
-          bfd_alloc (abfd, sizeof (struct elf_link_loaded_list));
+      n = (struct elf_link_loaded_list *) bfd_alloc (abfd, sizeof (*n));
       if (n == NULL)
        goto error_return;
       n->abfd = abfd;
@@ -5414,7 +5420,7 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
            {
              best_chlen = max;
              best_size = i;
-              no_improvement_count = 0;
+             no_improvement_count = 0;
            }
          /* PR 11843: Avoid futile long searches for the best bucket size
             when there are a large number of symbols.  */
@@ -6708,7 +6714,7 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
   if (entry == NULL)
     {
       entry = (struct bfd_hash_entry *)
-          bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
+       bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
       if (entry == NULL)
        return entry;
     }
@@ -7259,10 +7265,10 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
       if (count1 == 0 || count2 == 0 || count1 != count2)
        goto done;
 
-      symtable1 = (struct elf_symbol *)
-          bfd_malloc (count1 * sizeof (struct elf_symbol));
-      symtable2 = (struct elf_symbol *)
-          bfd_malloc (count2 * sizeof (struct elf_symbol));
+      symtable1
+       = (struct elf_symbol *) bfd_malloc (count1 * sizeof (*symtable1));
+      symtable2
+       = (struct elf_symbol *) bfd_malloc (count2 * sizeof (*symtable2));
       if (symtable1 == NULL || symtable2 == NULL)
        goto done;
 
@@ -7435,8 +7441,6 @@ struct elf_outext_info
 {
   bfd_boolean failed;
   bfd_boolean localsyms;
-  bfd_boolean need_second_pass;
-  bfd_boolean second_pass;
   bfd_boolean file_sym_done;
   struct elf_final_link_info *flinfo;
 };
@@ -7955,6 +7959,138 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd,
   return r;
 }
 
+/* qsort comparison functions sorting external relocs by r_offset.  */
+
+static int
+cmp_ext32l_r_offset (const void *p, const void *q)
+{
+  union aligned32
+  {
+    uint32_t v;
+    unsigned char c[4];
+  };
+  const union aligned32 *a
+    = (const union aligned32 *) ((const Elf32_External_Rel *) p)->r_offset;
+  const union aligned32 *b
+    = (const union aligned32 *) ((const Elf32_External_Rel *) q)->r_offset;
+
+  uint32_t aval = (  (uint32_t) a->c[0]
+                  | (uint32_t) a->c[1] << 8
+                  | (uint32_t) a->c[2] << 16
+                  | (uint32_t) a->c[3] << 24);
+  uint32_t bval = (  (uint32_t) b->c[0]
+                  | (uint32_t) b->c[1] << 8
+                  | (uint32_t) b->c[2] << 16
+                  | (uint32_t) b->c[3] << 24);
+  if (aval < bval)
+    return -1;
+  else if (aval > bval)
+    return 1;
+  return 0;
+}
+
+static int
+cmp_ext32b_r_offset (const void *p, const void *q)
+{
+  union aligned32
+  {
+    uint32_t v;
+    unsigned char c[4];
+  };
+  const union aligned32 *a
+    = (const union aligned32 *) ((const Elf32_External_Rel *) p)->r_offset;
+  const union aligned32 *b
+    = (const union aligned32 *) ((const Elf32_External_Rel *) q)->r_offset;
+
+  uint32_t aval = (  (uint32_t) a->c[0] << 24
+                  | (uint32_t) a->c[1] << 16
+                  | (uint32_t) a->c[2] << 8
+                  | (uint32_t) a->c[3]);
+  uint32_t bval = (  (uint32_t) b->c[0] << 24
+                  | (uint32_t) b->c[1] << 16
+                  | (uint32_t) b->c[2] << 8
+                  | (uint32_t) b->c[3]);
+  if (aval < bval)
+    return -1;
+  else if (aval > bval)
+    return 1;
+  return 0;
+}
+
+#ifdef BFD_HOST_64_BIT
+static int
+cmp_ext64l_r_offset (const void *p, const void *q)
+{
+  union aligned64
+  {
+    uint64_t v;
+    unsigned char c[8];
+  };
+  const union aligned64 *a
+    = (const union aligned64 *) ((const Elf64_External_Rel *) p)->r_offset;
+  const union aligned64 *b
+    = (const union aligned64 *) ((const Elf64_External_Rel *) q)->r_offset;
+
+  uint64_t aval = (  (uint64_t) a->c[0]
+                  | (uint64_t) a->c[1] << 8
+                  | (uint64_t) a->c[2] << 16
+                  | (uint64_t) a->c[3] << 24
+                  | (uint64_t) a->c[4] << 32
+                  | (uint64_t) a->c[5] << 40
+                  | (uint64_t) a->c[6] << 48
+                  | (uint64_t) a->c[7] << 56);
+  uint64_t bval = (  (uint64_t) b->c[0]
+                  | (uint64_t) b->c[1] << 8
+                  | (uint64_t) b->c[2] << 16
+                  | (uint64_t) b->c[3] << 24
+                  | (uint64_t) b->c[4] << 32
+                  | (uint64_t) b->c[5] << 40
+                  | (uint64_t) b->c[6] << 48
+                  | (uint64_t) b->c[7] << 56);
+  if (aval < bval)
+    return -1;
+  else if (aval > bval)
+    return 1;
+  return 0;
+}
+
+static int
+cmp_ext64b_r_offset (const void *p, const void *q)
+{
+  union aligned64
+  {
+    uint64_t v;
+    unsigned char c[8];
+  };
+  const union aligned64 *a
+    = (const union aligned64 *) ((const Elf64_External_Rel *) p)->r_offset;
+  const union aligned64 *b
+    = (const union aligned64 *) ((const Elf64_External_Rel *) q)->r_offset;
+
+  uint64_t aval = (  (uint64_t) a->c[0] << 56
+                  | (uint64_t) a->c[1] << 48
+                  | (uint64_t) a->c[2] << 40
+                  | (uint64_t) a->c[3] << 32
+                  | (uint64_t) a->c[4] << 24
+                  | (uint64_t) a->c[5] << 16
+                  | (uint64_t) a->c[6] << 8
+                  | (uint64_t) a->c[7]);
+  uint64_t bval = (  (uint64_t) b->c[0] << 56
+                  | (uint64_t) b->c[1] << 48
+                  | (uint64_t) b->c[2] << 40
+                  | (uint64_t) b->c[3] << 32
+                  | (uint64_t) b->c[4] << 24
+                  | (uint64_t) b->c[5] << 16
+                  | (uint64_t) b->c[6] << 8
+                  | (uint64_t) b->c[7]);
+  if (aval < bval)
+    return -1;
+  else if (aval > bval)
+    return 1;
+  return 0;
+}
+#endif
+
 /* When performing a relocatable link, the input relocations are
    preserved.  But, if they reference global symbols, the indices
    referenced must be updated.  Update all the relocations found in
@@ -7962,7 +8098,8 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd,
 
 static void
 elf_link_adjust_relocs (bfd *abfd,
-                       struct bfd_elf_section_reloc_data *reldata)
+                       struct bfd_elf_section_reloc_data *reldata,
+                       bfd_boolean sort)
 {
   unsigned int i;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
@@ -8018,6 +8155,35 @@ elf_link_adjust_relocs (bfd *abfd,
                           | (irela[j].r_info & r_type_mask));
       (*swap_out) (abfd, irela, erela);
     }
+
+  if (sort)
+    {
+      int (*compare) (const void *, const void *);
+
+      if (bed->s->arch_size == 32)
+       {
+         if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)
+           compare = cmp_ext32l_r_offset;
+         else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG)
+           compare = cmp_ext32b_r_offset;
+         else
+           abort ();
+       }
+      else
+       {
+#ifdef BFD_HOST_64_BIT
+         if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)
+           compare = cmp_ext64l_r_offset;
+         else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG)
+           compare = cmp_ext64b_r_offset;
+         else
+#endif
+           abort ();
+       }
+      qsort (reldata->hdr->contents, count, reldata->hdr->sh_entsize, compare);
+      free (reldata->hashes);
+      reldata->hashes = NULL;
+    }
 }
 
 struct elf_link_sort_rela
@@ -8390,6 +8556,8 @@ elf_link_output_sym (struct elf_final_link_info *flinfo,
      struct elf_link_hash_entry *);
   const struct elf_backend_data *bed;
 
+  BFD_ASSERT (elf_onesymtab (flinfo->output_bfd));
+
   bed = get_elf_backend_data (flinfo->output_bfd);
   output_symbol_hook = bed->elf_backend_link_output_symbol_hook;
   if (output_symbol_hook != NULL)
@@ -8427,7 +8595,7 @@ elf_link_output_sym (struct elf_final_link_info *flinfo,
 
          amt = flinfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
          destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx,
-                                                              amt * 2);
+                                                             amt * 2);
          if (destshndx == NULL)
            return 0;
          flinfo->symshndxbuf = destshndx;
@@ -8651,27 +8819,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
     {
       if (!h->forced_local)
        return TRUE;
-      if (eoinfo->second_pass
-         && !((h->root.type == bfd_link_hash_defined
-               || h->root.type == bfd_link_hash_defweak)
-              && h->root.u.def.section->output_section != NULL))
-       return TRUE;
-
-      if (!eoinfo->file_sym_done
-         && (eoinfo->second_pass ? eoinfo->flinfo->filesym_count == 1
-                                 : eoinfo->flinfo->filesym_count > 1))
-       {
-         /* Output a FILE symbol so that following locals are not associated
-            with the wrong input file.  */
-         memset (&sym, 0, sizeof (sym));
-         sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
-         sym.st_shndx = SHN_ABS;
-         if (!elf_link_output_sym (eoinfo->flinfo, NULL, &sym,
-                                   bfd_und_section_ptr, NULL))
-           return FALSE;
-
-         eoinfo->file_sym_done = TRUE;
-       }
     }
   else
     {
@@ -8755,8 +8902,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
      a regular file, or that we have been told to strip.  However, if
      h->indx is set to -2, the symbol is used by a reloc and we must
      output it.  */
+  strip = FALSE;
   if (h->indx == -2)
-    strip = FALSE;
+    ;
   else if ((h->def_dynamic
            || h->ref_dynamic
            || h->root.type == bfd_link_hash_new)
@@ -8773,7 +8921,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
            || h->root.type == bfd_link_hash_defweak)
           && ((flinfo->info->strip_discarded
                && discarded_section (h->root.u.def.section))
-              || (h->root.u.def.section->owner != NULL
+              || ((h->root.u.def.section->flags & SEC_LINKER_CREATED) == 0
+                  && h->root.u.def.section->owner != NULL
                   && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)))
     strip = TRUE;
   else if ((h->root.type == bfd_link_hash_undefined
@@ -8781,12 +8930,11 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
           && h->root.u.undef.abfd != NULL
           && (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0)
     strip = TRUE;
-  else
-    strip = FALSE;
 
   /* If we're stripping it, and it's not a dynamic symbol, there's
-     nothing else to do unless it is a forced local symbol or a
-     STT_GNU_IFUNC symbol.  */
+     nothing else to do.   However, if it is a forced local symbol or
+     an ifunc symbol we need to give the backend finish_dynamic_symbol
+     function a chance to make it dynamic.  */
   if (strip
       && h->dynindx == -1
       && h->type != STT_GNU_IFUNC
@@ -8832,19 +8980,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
        input_sec = h->root.u.def.section;
        if (input_sec->output_section != NULL)
          {
-           if (eoinfo->localsyms && flinfo->filesym_count == 1)
-             {
-               bfd_boolean second_pass_sym
-                 = (input_sec->owner == flinfo->output_bfd
-                    || input_sec->owner == NULL
-                    || (input_sec->flags & SEC_LINKER_CREATED) != 0
-                    || (input_sec->owner->flags & BFD_LINKER_CREATED) != 0);
-
-               eoinfo->need_second_pass |= second_pass_sym;
-               if (eoinfo->second_pass != second_pass_sym)
-                 return TRUE;
-             }
-
            sym.st_shndx =
              _bfd_elf_section_from_bfd_section (flinfo->output_bfd,
                                                 input_sec->output_section);
@@ -8870,12 +9005,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
                    asection *tls_sec = elf_hash_table (flinfo->info)->tls_sec;
                    if (tls_sec != NULL)
                      sym.st_value -= tls_sec->vma;
-                   else
-                     {
-                       /* The TLS section may have been garbage collected.  */
-                       BFD_ASSERT (flinfo->info->gc_sections
-                                   && !input_sec->gc_mark);
-                     }
                  }
              }
          }
@@ -9050,7 +9179,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 
          if (!h->def_regular)
            {
-             if (h->verinfo.verdef == NULL)
+             if (h->verinfo.verdef == NULL
+                 || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd)
+                     & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED)))
                iversym.vs_vers = 0;
              else
                iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1;
@@ -9074,10 +9205,42 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
        }
     }
 
-  /* If we're stripping it, then it was just a dynamic symbol, and
-     there's nothing else to do.  */
-  if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
+  /* If the symbol is undefined, and we didn't output it to .dynsym,
+     strip it from .symtab too.  Obviously we can't do this for
+     relocatable output or when needed for --emit-relocs.  */
+  else if (input_sec == bfd_und_section_ptr
+          && h->indx != -2
+          && !flinfo->info->relocatable)
     return TRUE;
+  /* Also strip others that we couldn't earlier due to dynamic symbol
+     processing.  */
+  if (strip)
+    return TRUE;
+  if ((input_sec->flags & SEC_EXCLUDE) != 0)
+    return TRUE;
+
+  /* Output a FILE symbol so that following locals are not associated
+     with the wrong input file.  We need one for forced local symbols
+     if we've seen more than one FILE symbol or when we have exactly
+     one FILE symbol but global symbols are present in a file other
+     than the one with the FILE symbol.  We also need one if linker
+     defined symbols are present.  In practice these conditions are
+     always met, so just emit the FILE symbol unconditionally.  */
+  if (eoinfo->localsyms
+      && !eoinfo->file_sym_done
+      && eoinfo->flinfo->filesym_count != 0)
+    {
+      Elf_Internal_Sym fsym;
+
+      memset (&fsym, 0, sizeof (fsym));
+      fsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+      fsym.st_shndx = SHN_ABS;
+      if (!elf_link_output_sym (eoinfo->flinfo, NULL, &fsym,
+                               bfd_und_section_ptr, NULL))
+       return FALSE;
+
+      eoinfo->file_sym_done = TRUE;
+    }
 
   indx = bfd_get_symcount (flinfo->output_bfd);
   ret = elf_link_output_sym (flinfo, h->root.root.string, &sym, input_sec, h);
@@ -9301,8 +9464,9 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
       *ppsection = isec;
 
-      /* Don't output the first, undefined, symbol.  */
-      if (ppsection == flinfo->sections)
+      /* Don't output the first, undefined, symbol.  In fact, don't
+        output any undefined local symbol.  */
+      if (isec == bfd_und_section_ptr)
        continue;
 
       if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
@@ -9352,6 +9516,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
       if (ELF_ST_TYPE (isym->st_info) == STT_FILE)
        {
+         if (input_bfd->lto_output)
+           /* -flto puts a temp file name here.  This means builds
+              are not reproducible.  Discard the symbol.  */
+           continue;
          have_file_sym = TRUE;
          flinfo->filesym_count += 1;
        }
@@ -9368,8 +9536,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
          memset (&osym, 0, sizeof (osym));
          osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
          osym.st_shndx = SHN_ABS;
-         if (!elf_link_output_sym (flinfo, input_bfd->filename, &osym,
-                                   bfd_abs_section_ptr, NULL))
+         if (!elf_link_output_sym (flinfo,
+                                   (input_bfd->lto_output ? NULL
+                                    : input_bfd->filename),
+                                   &osym, bfd_abs_section_ptr, NULL))
            return FALSE;
        }
 
@@ -9619,6 +9789,24 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
                  s_type = h->type;
 
+                 /* If a plugin symbol is referenced from a non-IR file,
+                    mark the symbol as undefined.  Note that the
+                    linker may attach linker created dynamic sections
+                    to the plugin bfd.  Symbols defined in linker
+                    created sections are not plugin symbols.  */
+                 if (h->root.non_ir_ref
+                     && (h->root.type == bfd_link_hash_defined
+                         || h->root.type == bfd_link_hash_defweak)
+                     && (h->root.u.def.section->flags
+                         & SEC_LINKER_CREATED) == 0
+                     && h->root.u.def.section->owner != NULL
+                     && (h->root.u.def.section->owner->flags
+                         & BFD_PLUGIN) != 0)
+                   {
+                     h->root.type = bfd_link_hash_undefined;
+                     h->root.u.undef.abfd = h->root.u.def.section->owner;
+                   }
+
                  ps = NULL;
                  if (h->root.type == bfd_link_hash_defined
                      || h->root.type == bfd_link_hash_defweak)
@@ -10155,7 +10343,7 @@ elf_reloc_link_order (bfd *output_bfd,
 
       size = (bfd_size_type) bfd_get_reloc_size (howto);
       buf = (bfd_byte *) bfd_zmalloc (size);
-      if (buf == NULL)
+      if (buf == NULL && size != 0)
        return FALSE;
       rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
       switch (rstat)
@@ -10429,12 +10617,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   bfd_size_type max_internal_reloc_count;
   bfd_size_type max_sym_count;
   bfd_size_type max_sym_shndx_count;
-  file_ptr off;
   Elf_Internal_Sym elfsym;
   unsigned int i;
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Shdr *symtab_shndx_hdr;
-  Elf_Internal_Shdr *symstrtab_hdr;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
   bfd_boolean merged;
@@ -10665,7 +10851,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   /* Figure out the file positions for everything but the symbol table
      and the relocs.  We set symcount to force assign_section_numbers
      to create a symbol table.  */
-  bfd_get_symcount (abfd) = info->strip == strip_all ? 0 : 1;
+  bfd_get_symcount (abfd) = info->strip != strip_all || emit_relocs;
   BFD_ASSERT (! abfd->output_has_begun);
   if (! _bfd_elf_compute_section_file_positions (abfd, info))
     goto error_return;
@@ -10691,12 +10877,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       esdo->rela.count = 0;
     }
 
-  _bfd_elf_assign_file_positions_for_relocs (abfd);
-
   /* We have now assigned file positions for all the sections except
-     .symtab and .strtab.  We start the .symtab section at the current
-     file position, and write directly to it.  We build the .strtab
-     section in memory.  */
+     .symtab, .strtab, and non-loaded reloc sections.  We start the
+     .symtab section at the current file position, and write directly
+     to it.  We build the .strtab section in memory.  */
   bfd_get_symcount (abfd) = 0;
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   /* sh_name is set in prep_headers.  */
@@ -10708,13 +10892,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   /* sh_offset is set just below.  */
   symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
 
-  off = elf_next_file_pos (abfd);
-  off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
-
-  /* Note that at this point elf_next_file_pos (abfd) is
-     incorrect.  We do not yet know the size of the .symtab section.
-     We correct next_file_pos below, after we do know the size.  */
-
   /* Allocate a buffer to hold swapped out symbols.  This is to avoid
      continuously seeking to the right position in the file.  */
   if (! info->keep_memory || max_sym_count < 20)
@@ -10737,11 +10914,18 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        goto error_return;
     }
 
-  /* Start writing out the symbol table.  The first symbol is always a
-     dummy symbol.  */
-  if (info->strip != strip_all
-      || emit_relocs)
+  if (info->strip != strip_all || emit_relocs)
     {
+      file_ptr off = elf_next_file_pos (abfd);
+
+      _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
+
+      /* Note that at this point elf_next_file_pos (abfd) is
+        incorrect.  We do not yet know the size of the .symtab section.
+        We correct next_file_pos below, after we do know the size.  */
+
+      /* Start writing out the symbol table.  The first symbol is always a
+        dummy symbol.  */
       elfsym.st_value = 0;
       elfsym.st_size = 0;
       elfsym.st_info = 0;
@@ -10751,16 +10935,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr,
                               NULL) != 1)
        goto error_return;
-    }
 
-  /* Output a symbol for each section.  We output these even if we are
-     discarding local symbols, since they are used for relocs.  These
-     symbols have no names.  We store the index of each one in the
-     index field of the section, so that we can find it again when
-     outputting relocs.  */
-  if (info->strip != strip_all
-      || emit_relocs)
-    {
+      /* Output a symbol for each section.  We output these even if we are
+        discarding local symbols, since they are used for relocs.  These
+        symbols have no names.  We store the index of each one in the
+        index field of the section, so that we can find it again when
+        outputting relocs.  */
+
       elfsym.st_size = 0;
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
       elfsym.st_other = 0;
@@ -10974,24 +11155,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   eoinfo.failed = FALSE;
   eoinfo.flinfo = &flinfo;
   eoinfo.localsyms = TRUE;
-  eoinfo.need_second_pass = FALSE;
-  eoinfo.second_pass = FALSE;
   eoinfo.file_sym_done = FALSE;
   bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
     return FALSE;
 
-  if (eoinfo.need_second_pass)
-    {
-      eoinfo.second_pass = TRUE;
-      bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
-      if (eoinfo.failed)
-       return FALSE;
-    }
-
   /* If backend needs to output some local symbols not present in the hash
      table, do it now.  */
-  if (bed->elf_backend_output_arch_local_syms)
+  if (bed->elf_backend_output_arch_local_syms
+      && (info->strip != strip_all || emit_relocs))
     {
       typedef int (*out_sym_func)
        (void *, const char *, Elf_Internal_Sym *, asection *,
@@ -11101,7 +11273,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   /* If backend needs to output some symbols not present in the hash
      table, do it now.  */
-  if (bed->elf_backend_output_arch_syms)
+  if (bed->elf_backend_output_arch_syms
+      && (info->strip != strip_all || emit_relocs))
     {
       typedef int (*out_sym_func)
        (void *, const char *, Elf_Internal_Sym *, asection *,
@@ -11117,45 +11290,46 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     return FALSE;
 
   /* Now we know the size of the symtab section.  */
-  off += symtab_hdr->sh_size;
-
-  symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-  if (symtab_shndx_hdr->sh_name != 0)
+  if (bfd_get_symcount (abfd) > 0)
     {
-      symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
-      symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
-      symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
-      amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx);
-      symtab_shndx_hdr->sh_size = amt;
+      /* Finish up and write out the symbol string table (.strtab)
+        section.  */
+      Elf_Internal_Shdr *symstrtab_hdr;
+      file_ptr off = symtab_hdr->sh_offset + symtab_hdr->sh_size;
 
-      off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr,
-                                                      off, TRUE);
+      symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+      if (symtab_shndx_hdr->sh_name != 0)
+       {
+         symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
+         symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+         symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+         amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx);
+         symtab_shndx_hdr->sh_size = amt;
 
-      if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
-         || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
-       return FALSE;
-    }
+         off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr,
+                                                          off, TRUE);
 
+         if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
+             || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
+           return FALSE;
+       }
 
-  /* Finish up and write out the symbol string table (.strtab)
-     section.  */
-  symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
-  /* sh_name was set in prep_headers.  */
-  symstrtab_hdr->sh_type = SHT_STRTAB;
-  symstrtab_hdr->sh_flags = 0;
-  symstrtab_hdr->sh_addr = 0;
-  symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab);
-  symstrtab_hdr->sh_entsize = 0;
-  symstrtab_hdr->sh_link = 0;
-  symstrtab_hdr->sh_info = 0;
-  /* sh_offset is set just below.  */
-  symstrtab_hdr->sh_addralign = 1;
+      symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
+      /* sh_name was set in prep_headers.  */
+      symstrtab_hdr->sh_type = SHT_STRTAB;
+      symstrtab_hdr->sh_flags = 0;
+      symstrtab_hdr->sh_addr = 0;
+      symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab);
+      symstrtab_hdr->sh_entsize = 0;
+      symstrtab_hdr->sh_link = 0;
+      symstrtab_hdr->sh_info = 0;
+      /* sh_offset is set just below.  */
+      symstrtab_hdr->sh_addralign = 1;
 
-  off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, TRUE);
-  elf_next_file_pos (abfd) = off;
+      off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr,
+                                                      off, TRUE);
+      elf_next_file_pos (abfd) = off;
 
-  if (bfd_get_symcount (abfd) > 0)
-    {
       if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
          || ! _bfd_stringtab_emit (abfd, flinfo.symstrtab))
        return FALSE;
@@ -11165,13 +11339,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
+      bfd_boolean sort;
       if ((o->flags & SEC_RELOC) == 0)
        continue;
 
+      sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o);
       if (esdo->rel.hdr != NULL)
-       elf_link_adjust_relocs (abfd, &esdo->rel);
+       elf_link_adjust_relocs (abfd, &esdo->rel, sort);
       if (esdo->rela.hdr != NULL)
-       elf_link_adjust_relocs (abfd, &esdo->rela);
+       elf_link_adjust_relocs (abfd, &esdo->rela, sort);
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
@@ -11418,6 +11594,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            {
              /* The contents of the .dynstr section are actually in a
                 stringtab.  */
+             file_ptr off;
+
              off = elf_section_data (o->output_section)->this_hdr.sh_offset;
              if (bfd_seek (abfd, off, SEEK_SET) != 0
                  || ! _bfd_elf_strtab_emit (abfd,
@@ -11681,6 +11859,12 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
       || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL)
     {
       h = cookie->sym_hashes[r_symndx - cookie->extsymoff];
+      if (h == NULL)
+       {
+         info->callbacks->einfo (_("%F%P: corrupt input: %B\n"),
+                                 sec->owner);
+         return NULL;
+       }
       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;
@@ -11783,6 +11967,47 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
   return ret;
 }
 
+/* Scan and mark sections in a special or debug section group.  */
+
+static void
+_bfd_elf_gc_mark_debug_special_section_group (asection *grp)
+{
+  /* Point to first section of section group.  */
+  asection *ssec;
+  /* Used to iterate the section group.  */
+  asection *msec;
+
+  bfd_boolean is_special_grp = TRUE;
+  bfd_boolean is_debug_grp = TRUE;
+
+  /* First scan to see if group contains any section other than debug
+     and special section.  */
+  ssec = msec = elf_next_in_group (grp);
+  do
+    {
+      if ((msec->flags & SEC_DEBUGGING) == 0)
+       is_debug_grp = FALSE;
+
+      if ((msec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) != 0)
+       is_special_grp = FALSE;
+
+      msec = elf_next_in_group (msec);
+    }
+  while (msec != ssec);
+
+  /* If this is a pure debug section group or pure special section group,
+     keep all sections in this group.  */
+  if (is_debug_grp || is_special_grp)
+    {
+      do
+       {
+         msec->gc_mark = 1;
+         msec = elf_next_in_group (msec);
+       }
+      while (msec != ssec);
+    }
+}
+
 /* Keep debug and special sections.  */
 
 bfd_boolean
@@ -11823,13 +12048,17 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
        continue;
 
       /* Keep debug and special sections like .comment when they are
-        not part of a group, or when we have single-member groups.  */
+        not part of a group.  Also keep section groups that contain
+        just debug sections or special sections.  */
       for (isec = ibfd->sections; isec != NULL; isec = isec->next)
-       if ((elf_next_in_group (isec) == NULL
-            || elf_next_in_group (isec) == isec)
-           && ((isec->flags & SEC_DEBUGGING) != 0
-               || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0))
-         isec->gc_mark = 1;
+       {
+         if ((isec->flags & SEC_GROUP) != 0)
+           _bfd_elf_gc_mark_debug_special_section_group (isec);
+         else if (((isec->flags & SEC_DEBUGGING) != 0
+                   || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
+                  && elf_next_in_group (isec) == NULL)
+           isec->gc_mark = 1;
+       }
 
       if (! debug_frag_seen)
        continue;
@@ -11888,7 +12117,7 @@ elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
   if (!h->mark
       && (((h->root.type == bfd_link_hash_defined
            || h->root.type == bfd_link_hash_defweak)
-          && !(h->def_regular
+          && !((h->def_regular || ELF_COMMON_DEF_P (h))
                && h->root.u.def.section->gc_mark))
          || h->root.type == bfd_link_hash_undefined
          || h->root.type == bfd_link_hash_undefweak))
@@ -12111,7 +12340,7 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
       && (h->ref_dynamic
-         || (h->def_regular
+         || ((h->def_regular || ELF_COMMON_DEF_P (h))
              && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
              && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
              && (!info->executable
@@ -12278,8 +12507,8 @@ bfd_elf_gc_record_vtinherit (bfd *abfd,
  win:
   if (!child->vtable)
     {
-      child->vtable = (struct elf_link_virtual_table_entry *)
-          bfd_zalloc (abfd, sizeof (*child->vtable));
+      child->vtable = ((struct elf_link_virtual_table_entry *)
+                      bfd_zalloc (abfd, sizeof (*child->vtable)));
       if (!child->vtable)
        return FALSE;
     }
@@ -12311,8 +12540,8 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
 
   if (!h->vtable)
     {
-      h->vtable = (struct elf_link_virtual_table_entry *)
-          bfd_zalloc (abfd, sizeof (*h->vtable));
+      h->vtable = ((struct elf_link_virtual_table_entry *)
+                  bfd_zalloc (abfd, sizeof (*h->vtable)));
       if (!h->vtable)
        return FALSE;
     }
@@ -12604,10 +12833,10 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
 
          if ((h->root.type == bfd_link_hash_defined
               || h->root.type == bfd_link_hash_defweak)
-             && discarded_section (h->root.u.def.section))
+             && (h->root.u.def.section->owner != rcookie->abfd
+                 || h->root.u.def.section->kept_section != NULL
+                 || discarded_section (h->root.u.def.section)))
            return TRUE;
-         else
-           return FALSE;
        }
       else
        {
@@ -12620,7 +12849,9 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
          /* Need to: get the symbol; get the section.  */
          isym = &rcookie->locsyms[r_symndx];
          isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
-         if (isec != NULL && discarded_section (isec))
+         if (isec != NULL
+             && (isec->kept_section != NULL
+                 || discarded_section (isec)))
            return TRUE;
        }
       return FALSE;
@@ -12674,9 +12905,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
        }
     }
 
-  o = NULL;
-  if (!info->relocatable)
-    o = bfd_get_section_by_name (output_bfd, ".eh_frame");
+  o = bfd_get_section_by_name (output_bfd, ".eh_frame");
   if (o != NULL)
     {
       asection *i;
@@ -12970,11 +13199,11 @@ _bfd_elf_get_dynamic_reloc_section (bfd *       abfd,
    string table associated with ABFD.  */
 
 asection *
-_bfd_elf_make_dynamic_reloc_section (asection *         sec,
-                                    bfd *              dynobj,
-                                    unsigned int       alignment,
-                                    bfd *              abfd,
-                                    bfd_boolean        is_rela)
+_bfd_elf_make_dynamic_reloc_section (asection *sec,
+                                    bfd *dynobj,
+                                    unsigned int alignment,
+                                    bfd *abfd,
+                                    bfd_boolean is_rela)
 {
   asection * reloc_sec = elf_section_data (sec)->sreloc;
 
This page took 0.040834 seconds and 4 git commands to generate.