* config/tc-mips.c (mips_set_options): Add ase_dsp for DSP instructions.
[deliverable/binutils-gdb.git] / bfd / elflink.c
index a1c02325d1fd19f5943b7bd57213684afe22bf31..4414f0df61b4a2ddbe4cbc7a60f076b6d1e0135a 100644 (file)
@@ -16,7 +16,7 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
 #include "safe-ctype.h"
 #include "libiberty.h"
 
+/* Define a symbol in a dynamic linkage section.  */
+
+struct elf_link_hash_entry *
+_bfd_elf_define_linkage_sym (bfd *abfd,
+                            struct bfd_link_info *info,
+                            asection *sec,
+                            const char *name)
+{
+  struct elf_link_hash_entry *h;
+  struct bfd_link_hash_entry *bh;
+  const struct elf_backend_data *bed;
+
+  h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
+  if (h != NULL)
+    {
+      /* Zap symbol defined in an as-needed lib that wasn't linked.
+        This is a symptom of a larger problem:  Absolute symbols
+        defined in shared libraries can't be overridden, because we
+        lose the link to the bfd which is via the symbol section.  */
+      h->root.type = bfd_link_hash_new;
+    }
+
+  bh = &h->root;
+  if (!_bfd_generic_link_add_one_symbol (info, abfd, name, BSF_GLOBAL,
+                                        sec, 0, NULL, FALSE,
+                                        get_elf_backend_data (abfd)->collect,
+                                        &bh))
+    return NULL;
+  h = (struct elf_link_hash_entry *) bh;
+  h->def_regular = 1;
+  h->type = STT_OBJECT;
+  h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+
+  bed = get_elf_backend_data (abfd);
+  (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+  return h;
+}
+
 bfd_boolean
 _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
 {
   flagword flags;
   asection *s;
   struct elf_link_hash_entry *h;
-  struct bfd_link_hash_entry *bh;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   int ptralign;
 
@@ -59,17 +96,15 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
 
   flags = bed->dynamic_sec_flags;
 
-  s = bfd_make_section (abfd, ".got");
+  s = bfd_make_section_with_flags (abfd, ".got", flags);
   if (s == NULL
-      || !bfd_set_section_flags (abfd, s, flags)
       || !bfd_set_section_alignment (abfd, s, ptralign))
     return FALSE;
 
   if (bed->want_got_plt)
     {
-      s = bfd_make_section (abfd, ".got.plt");
+      s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
       if (s == NULL
-         || !bfd_set_section_flags (abfd, s, flags)
          || !bfd_set_section_alignment (abfd, s, ptralign))
        return FALSE;
     }
@@ -80,25 +115,14 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
         (or .got.plt) section.  We don't do this in the linker script
         because we don't want to define the symbol if we are not creating
         a global offset table.  */
-      bh = NULL;
-      if (!(_bfd_generic_link_add_one_symbol
-           (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
-            bed->got_symbol_offset, NULL, FALSE, bed->collect, &bh)))
-       return FALSE;
-      h = (struct elf_link_hash_entry *) bh;
-      h->def_regular = 1;
-      h->type = STT_OBJECT;
-      h->other = STV_HIDDEN;
-
-      if (! info->executable
-         && ! bfd_elf_link_record_dynamic_symbol (info, h))
-       return FALSE;
-
+      h = _bfd_elf_define_linkage_sym (abfd, info, s, "_GLOBAL_OFFSET_TABLE_");
       elf_hash_table (info)->hgot = h;
+      if (h == NULL)
+       return FALSE;
     }
 
   /* The first bit of the global offset table is the header.  */
-  s->size += bed->got_header_size + bed->got_symbol_offset;
+  s->size += bed->got_header_size;
 
   return TRUE;
 }
@@ -134,8 +158,6 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 {
   flagword flags;
   register asection *s;
-  struct elf_link_hash_entry *h;
-  struct bfd_link_hash_entry *bh;
   const struct elf_backend_data *bed;
 
   if (! is_elf_hash_table (info->hash))
@@ -156,17 +178,17 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
      shared library does not.  */
   if (info->executable)
     {
-      s = bfd_make_section (abfd, ".interp");
-      if (s == NULL
-         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY))
+      s = bfd_make_section_with_flags (abfd, ".interp",
+                                      flags | SEC_READONLY);
+      if (s == NULL)
        return FALSE;
     }
 
   if (! info->traditional_format)
     {
-      s = bfd_make_section (abfd, ".eh_frame_hdr");
+      s = bfd_make_section_with_flags (abfd, ".eh_frame_hdr",
+                                      flags | SEC_READONLY);
       if (s == NULL
-         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
          || ! bfd_set_section_alignment (abfd, s, 2))
        return FALSE;
       elf_hash_table (info)->eh_info.hdr_sec = s;
@@ -174,38 +196,37 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   /* Create sections to hold version informations.  These are removed
      if they are not needed.  */
-  s = bfd_make_section (abfd, ".gnu.version_d");
+  s = bfd_make_section_with_flags (abfd, ".gnu.version_d",
+                                  flags | SEC_READONLY);
   if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section (abfd, ".gnu.version");
+  s = bfd_make_section_with_flags (abfd, ".gnu.version",
+                                  flags | SEC_READONLY);
   if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, 1))
     return FALSE;
 
-  s = bfd_make_section (abfd, ".gnu.version_r");
+  s = bfd_make_section_with_flags (abfd, ".gnu.version_r",
+                                  flags | SEC_READONLY);
   if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section (abfd, ".dynsym");
+  s = bfd_make_section_with_flags (abfd, ".dynsym",
+                                  flags | SEC_READONLY);
   if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section (abfd, ".dynstr");
-  if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY))
+  s = bfd_make_section_with_flags (abfd, ".dynstr",
+                                  flags | SEC_READONLY);
+  if (s == NULL)
     return FALSE;
 
-  s = bfd_make_section (abfd, ".dynamic");
+  s = bfd_make_section_with_flags (abfd, ".dynamic", flags);
   if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags)
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
@@ -215,32 +236,12 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
      section.  We don't want to define it if there is no .dynamic
      section, since on some ELF platforms the start up code examines it
      to decide how to initialize the process.  */
-  h = elf_link_hash_lookup (elf_hash_table (info), "_DYNAMIC",
-                           FALSE, FALSE, FALSE);
-  if (h != NULL)
-    {
-      /* Zap symbol defined in an as-needed lib that wasn't linked.
-        This is a symptom of a larger problem:  Absolute symbols
-        defined in shared libraries can't be overridden, because we
-        lose the link to the bfd which is via the symbol section.  */
-      h->root.type = bfd_link_hash_new;
-    }
-  bh = &h->root;
-  if (! (_bfd_generic_link_add_one_symbol
-        (info, abfd, "_DYNAMIC", BSF_GLOBAL, s, 0, NULL, FALSE,
-         get_elf_backend_data (abfd)->collect, &bh)))
+  if (!_bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC"))
     return FALSE;
-  h = (struct elf_link_hash_entry *) bh;
-  h->def_regular = 1;
-  h->type = STT_OBJECT;
 
-  if (! info->executable
-      && ! bfd_elf_link_record_dynamic_symbol (info, h))
-    return FALSE;
-
-  s = bfd_make_section (abfd, ".hash");
+  s = bfd_make_section_with_flags (abfd, ".hash",
+                                  flags | SEC_READONLY);
   if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
   elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
@@ -280,36 +281,23 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (bed->plt_readonly)
     pltflags |= SEC_READONLY;
 
-  s = bfd_make_section (abfd, ".plt");
+  s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
   if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, pltflags)
       || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
     return FALSE;
 
-  if (bed->want_plt_sym)
-    {
-      /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
-        .plt section.  */
-      struct elf_link_hash_entry *h;
-      struct bfd_link_hash_entry *bh = NULL;
-
-      if (! (_bfd_generic_link_add_one_symbol
-            (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, 0, NULL,
-             FALSE, get_elf_backend_data (abfd)->collect, &bh)))
-       return FALSE;
-      h = (struct elf_link_hash_entry *) bh;
-      h->def_regular = 1;
-      h->type = STT_OBJECT;
-
-      if (! info->executable
-         && ! bfd_elf_link_record_dynamic_symbol (info, h))
-       return FALSE;
-    }
+  /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
+     .plt section.  */
+  if (bed->want_plt_sym
+      && !_bfd_elf_define_linkage_sym (abfd, info, s,
+                                      "_PROCEDURE_LINKAGE_TABLE_"))
+    return FALSE;
 
-  s = bfd_make_section (abfd,
-                       bed->default_use_rela_p ? ".rela.plt" : ".rel.plt");
+  s = bfd_make_section_with_flags (abfd,
+                                  (bed->default_use_rela_p
+                                   ? ".rela.plt" : ".rel.plt"),
+                                  flags | SEC_READONLY);
   if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
@@ -324,9 +312,10 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         image and use a R_*_COPY reloc to tell the dynamic linker to
         initialize them at run time.  The linker script puts the .dynbss
         section into the .bss section of the final image.  */
-      s = bfd_make_section (abfd, ".dynbss");
-      if (s == NULL
-         || ! bfd_set_section_flags (abfd, s, SEC_ALLOC | SEC_LINKER_CREATED))
+      s = bfd_make_section_with_flags (abfd, ".dynbss",
+                                      (SEC_ALLOC
+                                       | SEC_LINKER_CREATED));
+      if (s == NULL)
        return FALSE;
 
       /* The .rel[a].bss section holds copy relocs.  This section is not
@@ -342,11 +331,11 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         copy relocs.  */
       if (! info->shared)
        {
-         s = bfd_make_section (abfd,
-                               (bed->default_use_rela_p
-                                ? ".rela.bss" : ".rel.bss"));
+         s = bfd_make_section_with_flags (abfd,
+                                          (bed->default_use_rela_p
+                                           ? ".rela.bss" : ".rel.bss"),
+                                          flags | SEC_READONLY);
          if (s == NULL
-             || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
              || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
            return FALSE;
        }
@@ -435,8 +424,7 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
    this in case some dynamic object refers to this symbol.  */
 
 bfd_boolean
-bfd_elf_record_link_assignment (bfd *output_bfd ATTRIBUTE_UNUSED,
-                               struct bfd_link_info *info,
+bfd_elf_record_link_assignment (struct bfd_link_info *info,
                                const char *name,
                                bfd_boolean provide)
 {
@@ -747,7 +735,8 @@ _bfd_elf_link_renumber_dynsyms (bfd *output_bfd,
   if (dynsymcount != 0)
     ++dynsymcount;
 
-  return elf_hash_table (info)->dynsymcount = dynsymcount;
+  elf_hash_table (info)->dynsymcount = dynsymcount;
+  return dynsymcount;
 }
 
 /* This function is called when we want to define a new symbol.  It
@@ -783,6 +772,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   bfd *oldbfd;
   bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
   bfd_boolean newweak, oldweak;
+  const struct elf_backend_data *bed;
 
   *skip = FALSE;
   *override = FALSE;
@@ -922,7 +912,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
 
       if (h->type == STT_TLS)
        {
-         ntbfd = abfd; 
+         ntbfd = abfd;
          ntsec = sec;
          ntdef = newdef;
          tbfd = oldbfd;
@@ -1124,6 +1114,19 @@ _bfd_elf_merge_symbol (bfd *abfd,
   else
     olddyncommon = FALSE;
 
+  /* We now know everything about the old and new symbols.  We ask the
+     backend to check if we can merge them.  */
+  bed = get_elf_backend_data (abfd);
+  if (bed->merge_symbol
+      && !bed->merge_symbol (info, sym_hash, h, sym, psec, pvalue,
+                            pold_alignment, skip, override,
+                            type_change_ok, size_change_ok,
+                            &newdyn, &newdef, &newdyncommon, &newweak,
+                            abfd, &sec,
+                            &olddyn, &olddef, &olddyncommon, &oldweak,
+                            oldbfd, &oldsec))
+    return FALSE;
+
   /* If both the old and the new symbols look like common symbols in a
      dynamic object, set the size of the symbol to the larger of the
      two.  */
@@ -1190,8 +1193,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
   /* Handle the special case of an old common symbol merging with a
      new symbol which looks like a common symbol in a shared object.
      We change *PSEC and *PVALUE to make the new symbol look like a
-     common symbol, and let _bfd_generic_link_add_one_symbol will do
-     the right thing.  */
+     common symbol, and let _bfd_generic_link_add_one_symbol do the
+     right thing.  */
 
   if (newdyncommon
       && h->root.type == bfd_link_hash_common)
@@ -1200,10 +1203,14 @@ _bfd_elf_merge_symbol (bfd *abfd,
       newdef = FALSE;
       newdyncommon = FALSE;
       *pvalue = sym->st_size;
-      *psec = sec = bfd_com_section_ptr;
+      *psec = sec = bed->common_section (oldsec);
       *size_change_ok = TRUE;
     }
 
+  /* Skip weak definitions of symbols that are already defined.  */
+  if (newdef && olddef && newweak)
+    *skip = TRUE;
+
   /* If the old symbol is from a dynamic object, and the new symbol is
      a definition which is not from a dynamic object, then the new
      symbol overrides the old symbol.  Symbols from regular files
@@ -1774,7 +1781,6 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
                  d = (*t->match) (&t->locals, NULL, alc);
                  if (d != NULL
                      && h->dynindx != -1
-                     && info->shared
                      && ! info->export_dynamic)
                    (*bed->elf_backend_hide_symbol) (info, h, TRUE);
                }
@@ -1901,7 +1907,6 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
        {
          h->verinfo.vertree = local_ver;
          if (h->dynindx != -1
-             && info->shared
              && ! info->export_dynamic)
            {
              (*bed->elf_backend_hide_symbol) (info, h, TRUE);
@@ -2134,7 +2139,9 @@ bfd_boolean
 _bfd_elf_link_output_relocs (bfd *output_bfd,
                             asection *input_section,
                             Elf_Internal_Shdr *input_rel_hdr,
-                            Elf_Internal_Rela *internal_relocs)
+                            Elf_Internal_Rela *internal_relocs,
+                            struct elf_link_hash_entry **rel_hash
+                              ATTRIBUTE_UNUSED)
 {
   Elf_Internal_Rela *irela;
   Elf_Internal_Rela *irelaend;
@@ -2360,8 +2367,8 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
 
   if (h->root.type == bfd_link_hash_warning)
     {
-      h->plt = elf_hash_table (eif->info)->init_offset;
-      h->got = elf_hash_table (eif->info)->init_offset;
+      h->got = elf_hash_table (eif->info)->init_got_offset;
+      h->plt = elf_hash_table (eif->info)->init_plt_offset;
 
       /* When warning symbols are created, they **replace** the "real"
         entry in the hash table, thus we never get to see the real
@@ -2390,7 +2397,7 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
          || (!h->ref_regular
              && (h->u.weakdef == NULL || h->u.weakdef->dynindx == -1))))
     {
-      h->plt = elf_hash_table (eif->info)->init_offset;
+      h->plt = elf_hash_table (eif->info)->init_plt_offset;
       return TRUE;
     }
 
@@ -2640,6 +2647,8 @@ static bfd_boolean
 is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
                                  Elf_Internal_Sym *sym)
 {
+  const struct elf_backend_data *bed;
+
   /* Local symbols do not count, but target specific ones might.  */
   if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
       && ELF_ST_BIND (sym->st_info) < STB_LOOS)
@@ -2655,7 +2664,8 @@ is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
 
   /* If the symbol is defined in the common section, then
      it is a common definition and so does not count.  */
-  if (sym->st_shndx == SHN_COMMON)
+  bed = get_elf_backend_data (abfd);
+  if (bed->common_definition (sym))
     return FALSE;
 
   /* If the symbol is in a target specific section then we
@@ -3547,6 +3557,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       bfd_boolean type_change_ok;
       bfd_boolean new_weakdef;
       bfd_boolean override;
+      bfd_boolean common;
       unsigned int old_alignment;
       bfd *old_bfd;
 
@@ -3556,6 +3567,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       sec = NULL;
       value = isym->st_value;
       *sym_hash = NULL;
+      common = bed->common_definition (isym);
 
       bind = ELF_ST_BIND (isym->st_info);
       if (bind == STB_LOCAL)
@@ -3568,8 +3580,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
        }
       else if (bind == STB_GLOBAL)
        {
-         if (isym->st_shndx != SHN_UNDEF
-             && isym->st_shndx != SHN_COMMON)
+         if (isym->st_shndx != SHN_UNDEF && !common)
            flags = BSF_GLOBAL;
        }
       else if (bind == STB_WEAK)
@@ -3589,7 +3600,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          else if (sec->kept_section)
            {
              /* Symbols from discarded section are undefined, and have
-                default visibility.  */
+                default visibility.  */
              sec = bfd_und_section_ptr;
              isym->st_shndx = SHN_UNDEF;
              isym->st_other = STV_DEFAULT
@@ -3624,12 +3635,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 
          if (tcomm == NULL)
            {
-             tcomm = bfd_make_section (abfd, ".tcommon");
-             if (tcomm == NULL
-                 || !bfd_set_section_flags (abfd, tcomm, (SEC_ALLOC
-                                                          | SEC_IS_COMMON
-                                                          | SEC_LINKER_CREATED
-                                                          | SEC_THREAD_LOCAL)))
+             tcomm = bfd_make_section_with_flags (abfd, ".tcommon",
+                                                  (SEC_ALLOC
+                                                   | SEC_IS_COMMON
+                                                   | SEC_LINKER_CREATED
+                                                   | SEC_THREAD_LOCAL));
+             if (tcomm == NULL)
                goto error_free_vers;
            }
          sec = tcomm;
@@ -3686,11 +3697,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 
          /* If this is a hidden symbol, or if it is not version
             1, we append the version name to the symbol name.
-            However, we do not modify a non-hidden absolute
-            symbol, because it might be the version symbol
-            itself.  FIXME: What if it isn't?  */
+            However, we do not modify a non-hidden absolute symbol
+            if it is not a function, because it might be the version
+            symbol itself.  FIXME: What if it isn't?  */
          if ((iver.vs_vers & VERSYM_HIDDEN) != 0
-             || (vernum > 1 && ! bfd_is_abs_section (sec)))
+             || (vernum > 1 && (! bfd_is_abs_section (sec)
+                                || ELF_ST_TYPE (isym->st_info) == STT_FUNC)))
            {
              const char *verstr;
              size_t namelen, verlen, newlen;
@@ -3859,13 +3871,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
        }
 
       /* Set the alignment of a common symbol.  */
-      if ((isym->st_shndx == SHN_COMMON
-          || bfd_is_com_section (sec))
+      if ((common || bfd_is_com_section (sec))
          && h->root.type == bfd_link_hash_common)
        {
          unsigned int align;
 
-         if (isym->st_shndx == SHN_COMMON)
+         if (common)
            align = bfd_log2 (isym->st_value);
          else
            {
@@ -3891,7 +3902,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
             definition or a common symbol is ignored due to the old
             normal definition. We need to make sure the maximum
             alignment is maintained.  */
-         if ((old_alignment || isym->st_shndx == SHN_COMMON)
+         if ((old_alignment || common)
              && h->root.type != bfd_link_hash_common)
            {
              unsigned int common_align;
@@ -4984,7 +4995,10 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* Any syms created from now on start with -1 in
      got.refcount/offset and plt.refcount/offset.  */
-  elf_hash_table (info)->init_refcount = elf_hash_table (info)->init_offset;
+  elf_hash_table (info)->init_got_refcount
+    = elf_hash_table (info)->init_got_offset;
+  elf_hash_table (info)->init_plt_refcount
+    = elf_hash_table (info)->init_plt_offset;
 
   /* The backend may have to create some sections regardless of whether
      we're dynamic or not.  */
@@ -5010,6 +5024,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       asection *dynstr;
       struct bfd_elf_version_tree *t;
       struct bfd_elf_version_expr *d;
+      asection *s;
       bfd_boolean all_defined;
 
       *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
@@ -5213,7 +5228,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            return FALSE;
        }
 
-      if (bfd_get_section_by_name (output_bfd, ".preinit_array") != NULL)
+      s = bfd_get_section_by_name (output_bfd, ".preinit_array");
+      if (s != NULL && s->linker_has_input)
        {
          /* DT_PREINIT_ARRAY is not allowed in shared library.  */
          if (! info->executable)
@@ -5241,13 +5257,15 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
              || !_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAYSZ, 0))
            return FALSE;
        }
-      if (bfd_get_section_by_name (output_bfd, ".init_array") != NULL)
+      s = bfd_get_section_by_name (output_bfd, ".init_array");
+      if (s != NULL && s->linker_has_input)
        {
          if (!_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAY, 0)
              || !_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAYSZ, 0))
            return FALSE;
        }
-      if (bfd_get_section_by_name (output_bfd, ".fini_array") != NULL)
+      s = bfd_get_section_by_name (output_bfd, ".fini_array");
+      if (s != NULL && s->linker_has_input)
        {
          if (!_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAY, 0)
              || !_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAYSZ, 0))
@@ -5282,12 +5300,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
-      bfd_size_type dynsymcount;
       unsigned long section_sym_count;
       asection *s;
-      size_t bucketcount = 0;
-      size_t hash_entry_size;
-      unsigned int dtagcount;
 
       /* Set up the version definition section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
@@ -5302,7 +5316,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        verdefs = verdefs->next;
 
       if (verdefs == NULL && !info->create_default_symver)
-       _bfd_strip_section_from_output (info, s);
+       s->flags |= SEC_EXCLUDE;
       else
        {
          unsigned int cdefs;
@@ -5379,7 +5393,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            {
              bfd_size_type indx;
 
-             name = basename (output_bfd->filename);
+             name = lbasename (output_bfd->filename);
              def.vd_hash = bfd_elf_hash (name);
              indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                          name, FALSE);
@@ -5556,7 +5570,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                                &sinfo);
 
        if (elf_tdata (output_bfd)->verref == NULL)
-         _bfd_strip_section_from_output (info, s);
+         s->flags |= SEC_EXCLUDE;
        else
          {
            Elf_Internal_Verneed *t;
@@ -5602,7 +5616,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                            elf_dt_name (t->vn_bfd) != NULL
                                            ? elf_dt_name (t->vn_bfd)
-                                           : basename (t->vn_bfd->filename),
+                                           : lbasename (t->vn_bfd->filename),
                                            FALSE);
                if (indx == (bfd_size_type) -1)
                  return FALSE;
@@ -5645,6 +5659,37 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
          }
       }
 
+      if ((elf_tdata (output_bfd)->cverrefs == 0
+          && elf_tdata (output_bfd)->cverdefs == 0)
+         || _bfd_elf_link_renumber_dynsyms (output_bfd, info,
+                                            &section_sym_count) == 0)
+       {
+         s = bfd_get_section_by_name (dynobj, ".gnu.version");
+         s->flags |= SEC_EXCLUDE;
+       }
+    }
+  return TRUE;
+}
+
+bfd_boolean
+bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
+{
+  if (!is_elf_hash_table (info->hash))
+    return TRUE;
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      bfd *dynobj;
+      const struct elf_backend_data *bed;
+      asection *s;
+      bfd_size_type dynsymcount;
+      unsigned long section_sym_count;
+      size_t bucketcount = 0;
+      size_t hash_entry_size;
+      unsigned int dtagcount;
+
+      dynobj = elf_hash_table (info)->dynobj;
+
       /* Assign dynsym indicies.  In a shared library we generate a
         section symbol for each output section, which come first.
         Next come all of the back-end allocated local dynamic syms,
@@ -5656,17 +5701,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       /* Work out the size of the symbol version section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version");
       BFD_ASSERT (s != NULL);
-      if (dynsymcount == 0
-         || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL
-             && !info->create_default_symver))
-       {
-         _bfd_strip_section_from_output (info, s);
-         /* The DYNSYMCOUNT might have changed if we were going to
-            output a dynamic symbol table entry for S.  */
-         dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info,
-                                                       &section_sym_count);
-       }
-      else
+      if (dynsymcount != 0
+         && (s->flags & SEC_EXCLUDE) == 0)
        {
          s->size = dynsymcount * sizeof (Elf_External_Versym);
          s->contents = bfd_zalloc (output_bfd, s->size);
@@ -5685,6 +5721,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
         section as we went along in elf_link_add_object_symbols.  */
       s = bfd_get_section_by_name (dynobj, ".dynsym");
       BFD_ASSERT (s != NULL);
+      bed = get_elf_backend_data (output_bfd);
       s->size = dynsymcount * bed->s->sizeof_sym;
 
       if (dynsymcount != 0)
@@ -5950,7 +5987,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
   count = reldyn->size / ext_size;
 
   size = 0;
-  for (lo = reldyn->link_order_head; lo != NULL; lo = lo->next)
+  for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
     if (lo->type == bfd_indirect_link_order)
       {
        asection *o = lo->u.indirect.section;
@@ -5975,7 +6012,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
   else
     r_sym_mask = ~(bfd_vma) 0xffffffff;
 
-  for (lo = reldyn->link_order_head; lo != NULL; lo = lo->next)
+  for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
     if (lo->type == bfd_indirect_link_order)
       {
        bfd_byte *erel, *erelend;
@@ -6025,7 +6062,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
 
   qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2);
 
-  for (lo = reldyn->link_order_head; lo != NULL; lo = lo->next)
+  for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
     if (lo->type == bfd_indirect_link_order)
       {
        bfd_byte *erel, *erelend;
@@ -6358,7 +6395,9 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
     {
       (*_bfd_error_handler)
        (_("%B: %s symbol `%s' in %B is referenced by DSO"),
-        finfo->output_bfd, h->root.u.def.section->owner,
+        finfo->output_bfd,
+        h->root.u.def.section == bfd_abs_section_ptr
+        ? finfo->output_bfd : h->root.u.def.section->owner,
         ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
         ? "internal"
         : ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
@@ -6472,7 +6511,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
 
     case bfd_link_hash_common:
       input_sec = h->root.u.c.p->section;
-      sym.st_shndx = SHN_COMMON;
+      sym.st_shndx = bed->common_section_index (input_sec);
       sym.st_value = 1 << h->root.u.c.p->alignment_power;
       break;
 
@@ -6647,12 +6686,6 @@ elf_section_ignore_discarded_relocs (asection *sec)
   return FALSE;
 }
 
-enum action_discarded
-  {
-    COMPLAIN = 1,
-    PRETEND = 2
-  };
-
 /* Return a mask saying how ld should treat relocations in SEC against
    symbols defined in discarded sections.  If this function returns
    COMPLAIN set, ld will issue a warning message.  If this function
@@ -6662,8 +6695,8 @@ enum action_discarded
    zero the reloc (at least that is the intent, but some cooperation by
    the target dependent code is needed, particularly for REL targets).  */
 
-static unsigned int
-elf_action_discarded (asection *sec)
+unsigned int
+_bfd_elf_default_action_discarded (asection *sec)
 {
   if (sec->flags & SEC_DEBUGGING)
     return PRETEND;
@@ -6674,12 +6707,6 @@ elf_action_discarded (asection *sec)
   if (strcmp (".gcc_except_table", sec->name) == 0)
     return 0;
 
-  if (strcmp (".PARISC.unwind", sec->name) == 0)
-    return 0;
-
-  if (strcmp (".fixup", sec->name) == 0)
-    return 0;
-
   return COMPLAIN | PRETEND;
 }
 
@@ -6759,8 +6786,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
     return TRUE;
 
   emit_relocs = (finfo->info->relocatable
-                || finfo->info->emitrelocations
-                || bed->elf_backend_emit_relocs);
+                || finfo->info->emitrelocations);
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   if (elf_bad_symtab (input_bfd))
@@ -7000,7 +7026,7 @@ 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;
-             unsigned int action = elf_action_discarded (o);
+             unsigned int action = (*bed->action_discarded) (o);
 
              rel = internal_relocs;
              relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
@@ -7035,7 +7061,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                          bfd_set_error (bfd_error_bad_value);
                          return FALSE;
                        }
-                     
+
                      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;
@@ -7062,14 +7088,10 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                    {
                      BFD_ASSERT (r_symndx != 0);
                      if (action & COMPLAIN)
-                       {
-                         (*_bfd_error_handler)
-                           (_("`%s' referenced in section `%A' of %B: "
-                              "defined in discarded section `%A' of %B"),
-                            o, input_bfd, sec, sec->owner, sym_name);
-                         bfd_set_error (bfd_error_bad_value);
-                         return FALSE;
-                       }
+                       (*finfo->info->callbacks->einfo)
+                         (_("%X`%s' referenced in section `%A' of %B: "
+                            "defined in discarded section `%A' of %B\n"),
+                          sym_name, o, input_bfd, sec, sec->owner);
 
                      /* Try to do the best we can to support buggy old
                         versions of gcc.  If we've warned, or this is
@@ -7140,10 +7162,9 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
              Elf_Internal_Rela *irelaend;
              bfd_vma last_offset;
              struct elf_link_hash_entry **rel_hash;
+             struct elf_link_hash_entry **rel_hash_list;
              Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2;
              unsigned int next_erel;
-             bfd_boolean (*reloc_emitter)
-               (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *);
              bfd_boolean rela_normal;
 
              input_rel_hdr = &elf_section_data (o)->rel_hdr;
@@ -7158,6 +7179,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
              rel_hash = (elf_section_data (o->output_section)->rel_hashes
                          + elf_section_data (o->output_section)->rel_count
                          + elf_section_data (o->output_section)->rel_count2);
+             rel_hash_list = rel_hash;
              last_offset = o->output_offset;
              if (!finfo->info->relocatable)
                last_offset += o->output_section->vma;
@@ -7340,16 +7362,11 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                }
 
              /* Swap out the relocs.  */
-             if (bed->elf_backend_emit_relocs
-                 && !(finfo->info->relocatable
-                      || finfo->info->emitrelocations))
-               reloc_emitter = bed->elf_backend_emit_relocs;
-             else
-               reloc_emitter = _bfd_elf_link_output_relocs;
-
              if (input_rel_hdr->sh_size != 0
-                 && ! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
-                                        internal_relocs))
+                 && !bed->elf_backend_emit_relocs (output_bfd, o,
+                                                   input_rel_hdr,
+                                                   internal_relocs,
+                                                   rel_hash_list))
                return FALSE;
 
              input_rel_hdr2 = elf_section_data (o)->rel_hdr2;
@@ -7357,8 +7374,11 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                {
                  internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
                                      * bed->s->int_rels_per_ext_rel);
-                 if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr2,
-                                         internal_relocs))
+                 rel_hash_list += NUM_SHDR_ENTRIES (input_rel_hdr);
+                 if (!bed->elf_backend_emit_relocs (output_bfd, o,
+                                                    input_rel_hdr2,
+                                                    internal_relocs,
+                                                    rel_hash_list))
                    return FALSE;
                }
            }
@@ -7645,10 +7665,10 @@ elf_fixup_link_order (bfd *abfd, asection *o)
   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)
+  for (p = o->map_head.link_order; p != NULL; p = p->next)
     {
       if (p->type == bfd_indirect_link_order
          && (bfd_get_flavour ((sub = p->u.indirect.section->owner))
@@ -7677,12 +7697,12 @@ elf_fixup_link_order (bfd *abfd, asection *o)
       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)
+
+  for (p = o->map_head.link_order; p != NULL; p = p->next)
     {
       sections[seen_linkorder++] = p;
     }
@@ -7796,7 +7816,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       struct bfd_elf_section_data *esdo = elf_section_data (o);
       o->reloc_count = 0;
 
-      for (p = o->link_order_head; p != NULL; p = p->next)
+      for (p = o->map_head.link_order; p != NULL; p = p->next)
        {
          unsigned int reloc_count = 0;
          struct bfd_elf_section_data *esdi = NULL;
@@ -8136,7 +8156,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            {
              struct bfd_link_order *o;
 
-             for (o = sec->link_order_head; o != NULL; o = o->next)
+             for (o = sec->map_head.link_order; o != NULL; o = o->next)
                if (size < o->offset + o->size)
                  size = o->offset + o->size;
            }
@@ -8178,7 +8198,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     sub->output_has_begun = FALSE;
   for (o = abfd->sections; o != NULL; o = o->next)
     {
-      for (p = o->link_order_head; p != NULL; p = p->next)
+      for (p = o->map_head.link_order; p != NULL; p = p->next)
        {
          if (p->type == bfd_indirect_link_order
              && (bfd_get_flavour ((sub = p->u.indirect.section->owner))
@@ -8714,6 +8734,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
                  gc_mark_hook_fn gc_mark_hook)
 {
   bfd_boolean ret;
+  bfd_boolean is_eh;
   asection *group_sec;
 
   sec->gc_mark = 1;
@@ -8726,6 +8747,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
 
   /* Look through the section relocs.  */
   ret = TRUE;
+  is_eh = strcmp (sec->name, ".eh_frame") == 0;
   if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
     {
       Elf_Internal_Rela *relstart, *rel, *relend;
@@ -8802,6 +8824,8 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
            {
              if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
                rsec->gc_mark = 1;
+             else if (is_eh)
+               rsec->gc_mark_from_eh = 1;
              else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
                {
                  ret = FALSE;
@@ -8828,19 +8852,26 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
 
 /* Sweep symbols in swept sections.  Called via elf_link_hash_traverse.  */
 
+struct elf_gc_sweep_symbol_info {
+  struct bfd_link_info *info;
+  void (*hide_symbol) (struct bfd_link_info *, struct elf_link_hash_entry *,
+                      bfd_boolean);
+};
+
 static bfd_boolean
-elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *idxptr)
+elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
 {
-  int *idx = idxptr;
-
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-  if (h->dynindx != -1
-      && ((h->root.type != bfd_link_hash_defined
-          && h->root.type != bfd_link_hash_defweak)
-         || h->root.u.def.section->gc_mark))
-    h->dynindx = (*idx)++;
+  if ((h->root.type == bfd_link_hash_defined
+       || h->root.type == bfd_link_hash_defweak)
+      && !h->root.u.def.section->gc_mark
+      && !(h->root.u.def.section->owner->flags & DYNAMIC))
+    {
+      struct elf_gc_sweep_symbol_info *inf = data;
+      (*inf->hide_symbol) (inf->info, h, TRUE);
+    }
 
   return TRUE;
 }
@@ -8851,9 +8882,13 @@ typedef bfd_boolean (*gc_sweep_hook_fn)
   (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
 
 static bfd_boolean
-elf_gc_sweep (struct bfd_link_info *info, gc_sweep_hook_fn gc_sweep_hook)
+elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
 {
   bfd *sub;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  gc_sweep_hook_fn gc_sweep_hook = bed->gc_sweep_hook;
+  unsigned long section_sym_count;
+  struct elf_gc_sweep_symbol_info sweep_info;
 
   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
@@ -8883,7 +8918,9 @@ elf_gc_sweep (struct bfd_link_info *info, gc_sweep_hook_fn gc_sweep_hook)
          /* But we also have to update some of the relocation
             info we collected before.  */
          if (gc_sweep_hook
-             && (o->flags & SEC_RELOC) && o->reloc_count > 0)
+             && (o->flags & SEC_RELOC) != 0
+             && o->reloc_count > 0
+             && !bfd_is_abs_section (o->output_section))
            {
              Elf_Internal_Rela *internal_relocs;
              bfd_boolean r;
@@ -8908,14 +8945,12 @@ elf_gc_sweep (struct bfd_link_info *info, gc_sweep_hook_fn gc_sweep_hook)
   /* Remove the symbols that were in the swept sections from the dynamic
      symbol table.  GCFIXME: Anyone know how to get them out of the
      static symbol table as well?  */
-  {
-    int i = 0;
-
-    elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol, &i);
-
-    elf_hash_table (info)->dynsymcount = i;
-  }
+  sweep_info.info = info;
+  sweep_info.hide_symbol = bed->elf_backend_hide_symbol;
+  elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol,
+                         &sweep_info);
 
+  _bfd_elf_link_renumber_dynsyms (abfd, info, &section_sym_count);
   return TRUE;
 }
 
@@ -9030,45 +9065,30 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
   return TRUE;
 }
 
-/* Mark sections containing dynamically referenced symbols.  This is called
-   through elf_link_hash_traverse.  */
+/* Mark sections containing dynamically referenced symbols.  When
+   building shared libraries, we must assume that any visible symbol is
+   referenced.  */
 
 static bfd_boolean
-elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h,
-                               void *okp ATTRIBUTE_UNUSED)
+elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
 {
+  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
-      && h->ref_dynamic)
+      && (h->ref_dynamic
+         || (info->shared
+             && h->def_regular
+             && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
+             && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN)))
     h->root.u.def.section->flags |= SEC_KEEP;
 
   return TRUE;
 }
-/* Mark sections containing global symbols.  This is called through
-   elf_link_hash_traverse.  */
-
-static bfd_boolean
-elf_mark_used_section (struct elf_link_hash_entry *h,
-                      void *data ATTRIBUTE_UNUSED)
-{
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  if (h->root.type == bfd_link_hash_defined
-      || h->root.type == bfd_link_hash_defweak)
-    {
-      asection *s = h->root.u.def.section;
-      if (s != NULL && s->output_section != NULL)
-       s->output_section->flags |= SEC_KEEP;
-    }
 
-  return TRUE;
-}
 /* Do mark and sweep of unused sections.  */
 
 bfd_boolean
@@ -9080,21 +9100,9 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
     (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
      struct elf_link_hash_entry *h, Elf_Internal_Sym *);
 
-  if (!info->gc_sections)
-    {
-      /* If we are called when info->gc_sections is 0, we will mark
-        all sections containing global symbols for non-relocatable
-        link.  */
-      if (!info->relocatable)
-       elf_link_hash_traverse (elf_hash_table (info),
-                               elf_mark_used_section, NULL);
-      return TRUE;
-    }
-
   if (!get_elf_backend_data (abfd)->can_gc_sections
       || info->relocatable
       || info->emitrelocations
-      || info->shared
       || !is_elf_hash_table (info->hash))
     {
       (*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
@@ -9119,9 +9127,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
   if (elf_hash_table (info)->dynamic_sections_created)
     elf_link_hash_traverse (elf_hash_table (info),
                            elf_gc_mark_dynamic_ref_symbol,
-                           &ok);
-  if (!ok)
-    return FALSE;
+                           info);
 
   /* Grovel through relocs to find out who stays ...  */
   gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook;
@@ -9133,25 +9139,55 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
        continue;
 
       for (o = sub->sections; o != NULL; o = o->next)
-       {
-         if (o->flags & SEC_KEEP)
-           {
-             /* _bfd_elf_discard_section_eh_frame knows how to discard
-                orphaned FDEs so don't mark sections referenced by the
-                EH frame section.  */  
-             if (strcmp (o->name, ".eh_frame") == 0)
-               o->gc_mark = 1;
-             else if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
-               return FALSE;
-           }
-       }
+       if ((o->flags & SEC_KEEP) != 0 && !o->gc_mark)
+         if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
+           return FALSE;
     }
 
-  /* ... and mark SEC_EXCLUDE for those that go.  */
-  if (!elf_gc_sweep (info, get_elf_backend_data (abfd)->gc_sweep_hook))
-    return FALSE;
+  /* ... again for sections marked from eh_frame.  */
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      asection *o;
 
-  return TRUE;
+      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+       continue;
+
+      /* Keep .gcc_except_table.* if the associated .text.* is
+        marked.  This isn't very nice, but the proper solution,
+        splitting .eh_frame up and using comdat doesn't pan out 
+        easily due to needing special relocs to handle the
+        difference of two symbols in separate sections.
+        Don't keep code sections referenced by .eh_frame.  */
+      for (o = sub->sections; o != NULL; o = o->next)
+       if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
+         {
+           if (strncmp (o->name, ".gcc_except_table.", 18) == 0)
+             {
+               unsigned long len;
+               char *fn_name;
+               asection *fn_text;
+
+               len = strlen (o->name + 18) + 1;
+               fn_name = bfd_malloc (len + 6);
+               if (fn_name == NULL)
+                 return FALSE;
+               memcpy (fn_name, ".text.", 6);
+               memcpy (fn_name + 6, o->name + 18, len);
+               fn_text = bfd_get_section_by_name (sub, fn_name);
+               free (fn_name);
+               if (fn_text == NULL || !fn_text->gc_mark)
+                 continue;
+             }
+
+           /* If not using specially named exception table section,
+              then keep whatever we are using.  */
+           if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
+             return FALSE;
+         }
+    }
+
+  /* ... and mark SEC_EXCLUDE for those that go.  */
+  return elf_gc_sweep (abfd, info);
 }
 \f
 /* Called from check_relocs to record the existence of a VTINHERIT reloc.  */
@@ -9735,7 +9771,7 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
             which we are really going to use.  */
          sec->output_section = bfd_abs_section_ptr;
          sec->kept_section = l->sec;
-         
+
          if (flags & SEC_GROUP)
            {
              asection *first = elf_next_in_group (sec);
@@ -9801,23 +9837,20 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
   bfd_section_already_linked_table_insert (already_linked_list, sec);
 }
 
-/* Set NAME to VAL if the symbol exists and is undefined.  */
+bfd_boolean
+_bfd_elf_common_definition (Elf_Internal_Sym *sym)
+{
+  return sym->st_shndx == SHN_COMMON;
+}
 
-void
-_bfd_elf_provide_symbol (struct bfd_link_info *info, const char *name,
-                        bfd_vma val)
+unsigned int
+_bfd_elf_common_section_index (asection *sec ATTRIBUTE_UNUSED)
 {
-  struct elf_link_hash_entry *h;
-  h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE,
-                           FALSE);
-  if (h != NULL && h->root.type == bfd_link_hash_undefined)
-    {
-      h->root.type = bfd_link_hash_defined;
-      h->root.u.def.section = bfd_abs_section_ptr;
-      h->root.u.def.value = val;
-      h->def_regular = 1;
-      h->type = STT_OBJECT;
-      h->other = STV_HIDDEN | (h->other & ~ ELF_ST_VISIBILITY (-1));
-      h->forced_local = 1;
-    }
+  return SHN_COMMON;
+}
+
+asection *
+_bfd_elf_common_section (asection *sec ATTRIBUTE_UNUSED)
+{
+  return bfd_com_section_ptr;
 }
This page took 0.05313 seconds and 4 git commands to generate.