Orphan output section with multiple input sections
[deliverable/binutils-gdb.git] / bfd / elflink.c
index bf28885548f7b953d2755f9cb41337a52d6ae305..1b41c793a978dd5d974c8e73927a5b8d85416b33 100644 (file)
@@ -54,6 +54,47 @@ struct elf_find_verdep_info
 static bfd_boolean _bfd_elf_fix_symbol_flags
   (struct elf_link_hash_entry *, struct elf_info_failed *);
 
+asection *
+_bfd_elf_section_for_symbol (struct elf_reloc_cookie *cookie,
+                            unsigned long r_symndx,
+                            bfd_boolean discard)
+{
+  if (r_symndx >= cookie->locsymcount
+      || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL)
+    {
+      struct elf_link_hash_entry *h;
+
+      h = cookie->sym_hashes[r_symndx - cookie->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;
+
+      if ((h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+          && discarded_section (h->root.u.def.section))
+        return h->root.u.def.section;
+      else
+       return NULL;
+    }
+  else
+    {
+      /* It's not a relocation against a global symbol,
+        but it could be a relocation against a local
+        symbol for a discarded section.  */
+      asection *isec;
+      Elf_Internal_Sym *isym;
+
+      /* Need to: get the symbol; get the section.  */
+      isym = &cookie->locsyms[r_symndx];
+      isec = bfd_section_from_elf_index (cookie->abfd, isym->st_shndx);
+      if (isec != NULL
+         && discard ? discarded_section (isec) : 1)
+       return isec;
+     }
+  return NULL;
+}
+
 /* Define a symbol in a dynamic linkage section.  */
 
 struct elf_link_hash_entry *
@@ -77,9 +118,9 @@ _bfd_elf_define_linkage_sym (bfd *abfd,
     }
 
   bh = &h->root;
+  bed = get_elf_backend_data (abfd);
   if (!_bfd_generic_link_add_one_symbol (info, abfd, name, BSF_GLOBAL,
-                                        sec, 0, NULL, FALSE,
-                                        get_elf_backend_data (abfd)->collect,
+                                        sec, 0, NULL, FALSE, bed->collect,
                                         &bh))
     return NULL;
   h = (struct elf_link_hash_entry *) bh;
@@ -90,7 +131,6 @@ _bfd_elf_define_linkage_sym (bfd *abfd,
   if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
     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;
 }
@@ -206,7 +246,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   /* A dynamically linked executable has a .interp section, but a
      shared library does not.  */
-  if (info->executable)
+  if (bfd_link_executable (info) && !info->nointerp)
     {
       s = bfd_make_section_anyway_with_flags (abfd, ".interp",
                                              flags | SEC_READONLY);
@@ -239,6 +279,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
+  elf_hash_table (info)->dynsym = s;
 
   s = bfd_make_section_anyway_with_flags (abfd, ".dynstr",
                                          flags | SEC_READONLY);
@@ -378,7 +419,7 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         be needed, we can discard it later.  We will never need this
         section when generating a shared object, since they do not use
         copy relocs.  */
-      if (! info->shared)
+      if (! bfd_link_pic (info))
        {
          s = bfd_make_section_anyway_with_flags (abfd,
                                                  (bed->rela_plts_and_copies_p
@@ -479,7 +520,7 @@ bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
   struct bfd_elf_dynamic_list *d = info->dynamic_list;
 
   /* It may be called more than once on the same H.  */
-  if(h->dynamic || info->relocatable)
+  if(h->dynamic || bfd_link_relocatable (info))
     return;
 
   if ((info->dynamic_data
@@ -583,7 +624,7 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
 
   /* STV_HIDDEN and STV_INTERNAL symbols must be STB_LOCAL in shared objects
      and executables.  */
-  if (!info->relocatable
+  if (!bfd_link_relocatable (info)
       && h->dynindx != -1
       && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
          || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
@@ -591,8 +632,9 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
 
   if ((h->def_dynamic
        || h->ref_dynamic
-       || info->shared
-       || (info->executable && elf_hash_table (info)->is_relocatable_executable))
+       || bfd_link_pic (info)
+       || (bfd_link_pde (info)
+          && elf_hash_table (info)->is_relocatable_executable))
       && h->dynindx == -1)
     {
       if (! bfd_elf_link_record_dynamic_symbol (info, h))
@@ -802,7 +844,8 @@ _bfd_elf_link_renumber_dynsyms (bfd *output_bfd,
 {
   unsigned long dynsymcount = 0;
 
-  if (info->shared || elf_hash_table (info)->is_relocatable_executable)
+  if (bfd_link_pic (info)
+      || elf_hash_table (info)->is_relocatable_executable)
     {
       const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
       asection *p;
@@ -845,7 +888,7 @@ _bfd_elf_link_renumber_dynsyms (bfd *output_bfd,
 
 static void
 elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
-                   const Elf_Internal_Sym *isym,
+                   const Elf_Internal_Sym *isym, asection *sec,
                    bfd_boolean definition, bfd_boolean dynamic)
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
@@ -866,7 +909,9 @@ 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)
+  else if (definition
+          && ELF_ST_VISIBILITY (isym->st_other) != STV_DEFAULT
+          && (sec->flags & SEC_READONLY) == 0)
     h->protected_def = 1;
 }
 
@@ -897,7 +942,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
                       bfd_boolean *skip,
                       bfd_boolean *override,
                       bfd_boolean *type_change_ok,
-                      bfd_boolean *size_change_ok)
+                      bfd_boolean *size_change_ok,
+                      bfd_boolean *matched)
 {
   asection *sec, *oldsec;
   struct elf_link_hash_entry *h;
@@ -908,6 +954,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
   bfd_boolean newweak, oldweak, newfunc, oldfunc;
   const struct elf_backend_data *bed;
+  char *new_version;
 
   *skip = FALSE;
   *override = FALSE;
@@ -926,6 +973,30 @@ _bfd_elf_merge_symbol (bfd *abfd,
 
   bed = get_elf_backend_data (abfd);
 
+  /* NEW_VERSION is the symbol version of the new symbol.  */
+  if (h->versioned != unversioned)
+    {
+      /* Symbol version is unknown or versioned.  */
+      new_version = strrchr (name, ELF_VER_CHR);
+      if (new_version)
+       {
+         if (h->versioned == unknown)
+           {
+             if (new_version > name && new_version[-1] != ELF_VER_CHR)
+               h->versioned = versioned_hidden;
+             else
+               h->versioned = versioned;
+           }
+         new_version += 1;
+         if (new_version[0] == '\0')
+           new_version = NULL;
+       }
+      else
+       h->versioned = unversioned;
+    }
+  else
+    new_version = NULL;
+
   /* For merging, we only care about real symbols.  But we need to make
      sure that indirect symbol dynamic flags are updated.  */
   hi = h;
@@ -933,6 +1004,44 @@ _bfd_elf_merge_symbol (bfd *abfd,
         || h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
+  if (!*matched)
+    {
+      if (hi == h || h->root.type == bfd_link_hash_new)
+       *matched = TRUE;
+      else
+       {
+         /* OLD_HIDDEN is true if the existing symbol is only visible
+            to the symbol with the same symbol version.  NEW_HIDDEN is
+            true if the new symbol is only visible to the symbol with
+            the same symbol version.  */
+         bfd_boolean old_hidden = h->versioned == versioned_hidden;
+         bfd_boolean new_hidden = hi->versioned == versioned_hidden;
+         if (!old_hidden && !new_hidden)
+           /* The new symbol matches the existing symbol if both
+              aren't hidden.  */
+           *matched = TRUE;
+         else
+           {
+             /* OLD_VERSION is the symbol version of the existing
+                symbol. */
+             char *old_version;
+
+             if (h->versioned >= versioned)
+               old_version = strrchr (h->root.root.string,
+                                      ELF_VER_CHR) + 1;
+             else
+                old_version = NULL;
+
+             /* The new symbol matches the existing symbol if they
+                have the same symbol version.  */
+             *matched = (old_version == new_version
+                         || (old_version != NULL
+                             && new_version != NULL
+                             && strcmp (old_version, new_version) == 0));
+           }
+       }
+    }
+
   /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the
      existing symbol.  */
 
@@ -1005,7 +1114,9 @@ _bfd_elf_merge_symbol (bfd *abfd,
        }
       else
        {
-         h->dynamic_def = 1;
+         /* Update the existing symbol only if they match. */
+         if (*matched)
+           h->dynamic_def = 1;
          hi->dynamic_def = 1;
        }
     }
@@ -1418,7 +1529,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       /* Merge st_other.  If the symbol already has a dynamic index,
         but visibility says it should not be visible, turn it into a
         local symbol.  */
-      elf_merge_st_other (abfd, h, sym, newdef, newdyn);
+      elf_merge_st_other (abfd, h, sym, sec, newdef, newdyn);
       if (h->dynindx != -1)
        switch (ELF_ST_VISIBILITY (h->other))
          {
@@ -1576,14 +1687,41 @@ _bfd_elf_add_default_symbol (bfd *abfd,
   char *p;
   size_t len, shortlen;
   asection *tmp_sec;
+  bfd_boolean matched;
+
+  if (h->versioned == unversioned || h->versioned == versioned_hidden)
+    return TRUE;
 
   /* If this symbol has a version, and it is the default version, we
      create an indirect symbol from the default name to the fully
      decorated name.  This will cause external references which do not
      specify a version to be bound to this version of the symbol.  */
   p = strchr (name, ELF_VER_CHR);
-  if (p == NULL || p[1] != ELF_VER_CHR)
-    return TRUE;
+  if (h->versioned == unknown)
+    {
+      if (p == NULL)
+       {
+         h->versioned = unversioned;
+         return TRUE;
+       }
+      else
+       {
+         if (p[1] != ELF_VER_CHR)
+           {
+             h->versioned = versioned_hidden;
+             return TRUE;
+           }
+         else
+           h->versioned = versioned;
+       }
+    }
+  else
+    {
+      /* PR ld/19073: We may see an unversioned definition after the
+        default version.  */
+      if (p == NULL)
+       return TRUE;
+    }
 
   bed = get_elf_backend_data (abfd);
   collect = bed->collect;
@@ -1602,10 +1740,11 @@ _bfd_elf_add_default_symbol (bfd *abfd,
      actually going to define an indirect symbol.  */
   type_change_ok = FALSE;
   size_change_ok = FALSE;
+  matched = TRUE;
   tmp_sec = sec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
                              &hi, poldbfd, NULL, NULL, &skip, &override,
-                             &type_change_ok, &size_change_ok))
+                             &type_change_ok, &size_change_ok, &matched))
     return FALSE;
 
   if (skip)
@@ -1613,12 +1752,17 @@ _bfd_elf_add_default_symbol (bfd *abfd,
 
   if (! override)
     {
-      bh = &hi->root;
-      if (! (_bfd_generic_link_add_one_symbol
-            (info, abfd, shortname, BSF_INDIRECT, bfd_ind_section_ptr,
-             0, name, FALSE, collect, &bh)))
-       return FALSE;
-      hi = (struct elf_link_hash_entry *) bh;
+      /* Add the default symbol if not performing a relocatable link.  */
+      if (! bfd_link_relocatable (info))
+       {
+         bh = &hi->root;
+         if (! (_bfd_generic_link_add_one_symbol
+                (info, abfd, shortname, BSF_INDIRECT,
+                 bfd_ind_section_ptr,
+                 0, name, FALSE, collect, &bh)))
+           return FALSE;
+         hi = (struct elf_link_hash_entry *) bh;
+       }
     }
   else
     {
@@ -1690,7 +1834,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
        {
          if (! dynamic)
            {
-             if (! info->executable
+             if (! bfd_link_executable (info)
                  || hi->def_dynamic
                  || hi->ref_dynamic)
                *dynsym = TRUE;
@@ -1720,7 +1864,7 @@ nondefault:
   tmp_sec = sec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
                              &hi, poldbfd, NULL, NULL, &skip, &override,
-                             &type_change_ok, &size_change_ok))
+                             &type_change_ok, &size_change_ok, &matched))
     return FALSE;
 
   if (skip)
@@ -1762,7 +1906,7 @@ nondefault:
            {
              if (! dynamic)
                {
-                 if (! info->executable
+                 if (! bfd_link_executable (info)
                      || hi->ref_dynamic)
                    *dynsym = TRUE;
                }
@@ -1930,26 +2074,14 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
   if (p != NULL && h->verinfo.vertree == NULL)
     {
       struct bfd_elf_version_tree *t;
-      bfd_boolean hidden;
-
-      hidden = TRUE;
 
-      /* There are two consecutive ELF_VER_CHR characters if this is
-        not a hidden symbol.  */
       ++p;
       if (*p == ELF_VER_CHR)
-       {
-         hidden = FALSE;
-         ++p;
-       }
+       ++p;
 
       /* If there is no version string, we can just return out.  */
       if (*p == '\0')
-       {
-         if (hidden)
-           h->hidden = 1;
-         return TRUE;
-       }
+       return TRUE;
 
       /* Look for the version.  If we find it, it is no longer weak.  */
       for (t = sinfo->info->version_info; t != NULL; t = t->next)
@@ -1997,7 +2129,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
 
       /* If we are building an application, we need to create a
         version node for this version.  */
-      if (t == NULL && info->executable)
+      if (t == NULL && bfd_link_executable (info))
        {
          struct bfd_elf_version_tree **pp;
          int version_index;
@@ -2045,9 +2177,6 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
          sinfo->failed = TRUE;
          return FALSE;
        }
-
-      if (hidden)
-       h->hidden = 1;
     }
 
   /* If we don't have a version for this symbol, see if we can find
@@ -2362,7 +2491,7 @@ bfd_boolean
 _bfd_elf_link_hash_fixup_symbol (struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h)
 {
-  if (info->pie
+  if (bfd_link_pie (info)
       && h->dynindx == -1
       && h->root.type == bfd_link_hash_undefweak)
     return bfd_elf_link_record_dynamic_symbol (info, h);
@@ -2465,7 +2594,7 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
      visibility.  If the symbol has hidden or internal visibility, we
      will force it local.  */
   if (h->needs_plt
-      && eif->info->shared
+      && bfd_link_pic (eif->info)
       && is_elf_hash_table (eif->info->hash)
       && (SYMBOLIC_BIND (eif->info, h)
          || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
@@ -2672,14 +2801,14 @@ _bfd_elf_adjust_dynamic_copy (struct bfd_link_info *info,
   /* 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;
-    }
+  /* No error if extern_protected_data is true.  */
+  if (h->protected_def
+      && (!info->extern_protected_data
+         || (info->extern_protected_data < 0
+             && !get_elf_backend_data (dynbss->owner)->extern_protected_data)))
+    info->callbacks->einfo
+      (_("%P: copy reloc against protected `%T' is dangerous\n"),
+       h->root.root.string);
 
   return TRUE;
 }
@@ -2737,7 +2866,8 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
 
   /* Identify the cases where name binding rules say that a
      visible symbol resolves locally.  */
-  binding_stays_local_p = info->executable || SYMBOLIC_BIND (info, h);
+  binding_stays_local_p = (bfd_link_executable (info)
+                          || SYMBOLIC_BIND (info, h));
 
   switch (ELF_ST_VISIBILITY (h->other))
     {
@@ -2822,7 +2952,7 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
   /* At this point, we know the symbol is defined and dynamic.  In an
      executable it must resolve locally, likewise when building symbolic
      shared libraries.  */
-  if (info->executable || SYMBOLIC_BIND (info, h))
+  if (bfd_link_executable (info) || SYMBOLIC_BIND (info, h))
     return TRUE;
 
   /* Now deal with defined dynamic symbols in shared libraries.  Ones
@@ -2836,8 +2966,12 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
 
   bed = get_elf_backend_data (hash_table->dynobj);
 
-  /* STV_PROTECTED non-function symbols are local.  */
-  if (!bed->is_function_type (h->type))
+  /* If extern_protected_data is false, STV_PROTECTED non-function
+     symbols are local.  */
+  if ((!info->extern_protected_data
+       || (info->extern_protected_data < 0
+          && !bed->extern_protected_data))
+      && !bed->is_function_type (h->type))
     return TRUE;
 
   /* Function pointer equality tests may require that STV_PROTECTED
@@ -2936,6 +3070,10 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
   if (abfd == NULL)
     return FALSE;
 
+  /* Return FALSE if the object has been claimed by plugin.  */
+  if (abfd->plugin_format == bfd_plugin_yes)
+    return FALSE;
+
   if (! bfd_check_format (abfd, bfd_object))
     return FALSE;
 
@@ -3116,7 +3254,7 @@ elf_sort_symbol (const void *arg1, const void *arg2)
     return vdiff > 0 ? 1 : -1;
   else
     {
-      long sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id;
+      int sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id;
       if (sdiff != 0)
        return sdiff > 0 ? 1 : -1;
     }
@@ -3301,7 +3439,7 @@ _bfd_elf_relocs_compatible (const bfd_target *input,
 
 /* Make a special call to the linker "notice" function to tell it that
    we are about to handle an as-needed lib, or have finished
-   processing the lib.  */ 
+   processing the lib.  */
 
 bfd_boolean
 _bfd_elf_notice_as_needed (bfd *ibfd,
@@ -3361,11 +3499,11 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       /* You can't use -r against a dynamic object.  Also, there's no
         hope of using a dynamic object which does not exactly match
         the format of the output file.  */
-      if (info->relocatable
+      if (bfd_link_relocatable (info)
          || !is_elf_hash_table (htab)
          || info->output_bfd->xvec != abfd->xvec)
        {
-         if (info->relocatable)
+         if (bfd_link_relocatable (info))
            bfd_set_error (bfd_error_invalid_operation);
          else
            bfd_set_error (bfd_error_wrong_format);
@@ -3438,7 +3576,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                  FALSE, bed->collect, NULL)))
            goto error_return;
 
-         if (!info->relocatable && info->executable)
+         if (bfd_link_executable (info))
            {
              /* Clobber the section size so that the warning does
                 not get copied into the output file.  */
@@ -3464,7 +3602,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
         are no input BFD's of the same format as the output, we can't
         make a shared library.  */
       if (!just_syms
-         && info->shared
+         && bfd_link_pic (info)
          && is_elf_hash_table (htab)
          && info->output_bfd->xvec == abfd->xvec
          && !htab->dynamic_sections_created)
@@ -3830,6 +3968,7 @@ error_free_dyn:
       bfd_boolean common;
       unsigned int old_alignment;
       bfd *old_bfd;
+      bfd_boolean matched;
 
       override = FALSE;
 
@@ -3915,7 +4054,7 @@ error_free_dyn:
        }
       else if (isym->st_shndx == SHN_COMMON
               && ELF_ST_TYPE (isym->st_info) == STT_TLS
-              && !info->relocatable)
+              && !bfd_link_relocatable (info))
        {
          asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
 
@@ -3964,6 +4103,7 @@ error_free_dyn:
       size_change_ok = FALSE;
       type_change_ok = bed->type_change_ok;
       old_weak = FALSE;
+      matched = FALSE;
       old_alignment = 0;
       old_bfd = NULL;
       new_sec = sec;
@@ -4083,7 +4223,7 @@ error_free_dyn:
 
          /* If this symbol has default visibility and the user has
             requested we not re-export it, then mark it as hidden.  */
-         if (definition
+         if (!bfd_is_und_section (sec)
              && !dynamic
              && abfd->no_export
              && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
@@ -4093,13 +4233,16 @@ error_free_dyn:
          if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
                                      sym_hash, &old_bfd, &old_weak,
                                      &old_alignment, &skip, &override,
-                                     &type_change_ok, &size_change_ok))
+                                     &type_change_ok, &size_change_ok,
+                                     &matched))
            goto error_free_vers;
 
          if (skip)
            continue;
 
-         if (override)
+         /* Override a definition only if the new symbol matches the
+            existing one.  */
+         if (override && matched)
            definition = FALSE;
 
          h = *sym_hash;
@@ -4207,7 +4350,7 @@ error_free_dyn:
              /* If the indirect symbol has been forced local, don't
                 make the real symbol dynamic.  */
              if ((h == hi || !hi->forced_local)
-                 && (! info->executable
+                 && (bfd_link_dll (info)
                      || h->def_dynamic
                      || h->ref_dynamic))
                dynsym = TRUE;
@@ -4356,10 +4499,12 @@ error_free_dyn:
            }
 
          /* Merge st_other field.  */
-         elf_merge_st_other (abfd, h, isym, definition, dynamic);
+         elf_merge_st_other (abfd, h, isym, sec, definition, dynamic);
 
          /* We don't want to make debug symbol dynamic.  */
-         if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
+         if (definition
+             && (sec->flags & SEC_DEBUGGING)
+             && !bfd_link_relocatable (info))
            dynsym = FALSE;
 
          /* Nor should we make plugin symbols dynamic.  */
@@ -4559,9 +4704,10 @@ error_free_dyn:
       old_tab = NULL;
     }
 
-  /* Now that all the symbols from this input file are created, handle
-     .symver foo, foo@BAR such that any relocs against foo become foo@BAR.  */
-  if (nondeflt_vers != NULL)
+  /* Now that all the symbols from this input file are created, if
+     not performing a relocatable link, handle .symver foo, foo@BAR
+     such that any relocs against foo become foo@BAR.  */
+  if (!bfd_link_relocatable (info) && nondeflt_vers != NULL)
     {
       bfd_size_type cnt, symidx;
 
@@ -4691,7 +4837,7 @@ error_free_dyn:
                i = idx + 1;
              else
                {
-                 long sdiff = slook->id - h->root.u.def.section->id;
+                 int sdiff = slook->id - h->root.u.def.section->id;
                  if (sdiff < 0)
                    j = idx;
                  else if (sdiff > 0)
@@ -5128,7 +5274,6 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
 {
   struct hash_codes_info *inf = (struct hash_codes_info *) data;
   const char *name;
-  char *p;
   unsigned long ha;
   char *alc = NULL;
 
@@ -5137,18 +5282,21 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
     return TRUE;
 
   name = h->root.root.string;
-  p = strchr (name, ELF_VER_CHR);
-  if (p != NULL)
+  if (h->versioned >= versioned)
     {
-      alc = (char *) bfd_malloc (p - name + 1);
-      if (alc == NULL)
+      char *p = strchr (name, ELF_VER_CHR);
+      if (p != NULL)
        {
-         inf->error = TRUE;
-         return FALSE;
+         alc = (char *) bfd_malloc (p - name + 1);
+         if (alc == NULL)
+           {
+             inf->error = TRUE;
+             return FALSE;
+           }
+         memcpy (alc, name, p - name);
+         alc[p - name] = '\0';
+         name = alc;
        }
-      memcpy (alc, name, p - name);
-      alc[p - name] = '\0';
-      name = alc;
     }
 
   /* Compute the hash value.  */
@@ -5196,7 +5344,6 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
 {
   struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
   const char *name;
-  char *p;
   unsigned long ha;
   char *alc = NULL;
 
@@ -5209,18 +5356,21 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
     return TRUE;
 
   name = h->root.root.string;
-  p = strchr (name, ELF_VER_CHR);
-  if (p != NULL)
+  if (h->versioned >= versioned)
     {
-      alc = (char *) bfd_malloc (p - name + 1);
-      if (alc == NULL)
+      char *p = strchr (name, ELF_VER_CHR);
+      if (p != NULL)
        {
-         s->error = TRUE;
-         return FALSE;
+         alc = (char *) bfd_malloc (p - name + 1);
+         if (alc == NULL)
+           {
+             s->error = TRUE;
+             return FALSE;
+           }
+         memcpy (alc, name, p - name);
+         alc[p - name] = '\0';
+         name = alc;
        }
-      memcpy (alc, name, p - name);
-      alc[p - name] = '\0';
-      name = alc;
     }
 
   /* Compute the hash value.  */
@@ -5559,7 +5709,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
   elf_hash_table (info)->init_plt_refcount
     = elf_hash_table (info)->init_plt_offset;
 
-  if (info->relocatable
+  if (bfd_link_relocatable (info)
       && !_bfd_elf_size_group_sections (info))
     return FALSE;
 
@@ -5602,7 +5752,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        }
       if (notesec || info->stacksize > 0)
        elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
-      if (notesec && exec && info->relocatable
+      if (notesec && exec && bfd_link_relocatable (info)
          && notesec->output_section != bfd_abs_section_ptr)
        notesec->output_section->flags |= SEC_CODE;
     }
@@ -5620,7 +5770,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       bfd_boolean all_defined;
 
       *sinterpptr = bfd_get_linker_section (dynobj, ".interp");
-      BFD_ASSERT (*sinterpptr != NULL || !info->executable);
+      BFD_ASSERT (*sinterpptr != NULL || !bfd_link_executable (info) || info->nointerp);
 
       if (soname != NULL)
        {
@@ -5708,7 +5858,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       /* If we are supposed to export all symbols into the dynamic symbol
         table (this is not the normal case), then do so.  */
       if (info->export_dynamic
-         || (info->executable && info->dynamic))
+         || (bfd_link_executable (info) && info->dynamic))
        {
          elf_link_hash_traverse (elf_hash_table (info),
                                  _bfd_elf_export_symbol,
@@ -5843,7 +5993,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       if (s != NULL && s->linker_has_input)
        {
          /* DT_PREINIT_ARRAY is not allowed in shared library.  */
-         if (! info->executable)
+         if (! bfd_link_executable (info))
            {
              bfd *sub;
              asection *o;
@@ -5907,6 +6057,9 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        }
     }
 
+  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
+    return FALSE;
+
   /* The backend must work out the sizes of all the other dynamic
      sections.  */
   if (dynobj != NULL
@@ -5914,9 +6067,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
     return FALSE;
 
-  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
-    return FALSE;
-
   if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
       unsigned long section_sym_count;
@@ -6177,7 +6327,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       if (info->flags_1)
        {
-         if (info->executable)
+         if (bfd_link_executable (info))
            info->flags_1 &= ~ (DF_1_INITFIRST
                                | DF_1_NODELETE
                                | DF_1_NOOPEN);
@@ -6403,7 +6553,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
         the final symbol table, because until then we do not know the
         correct value to give the symbols.  We built the .dynstr
         section as we went along in elf_link_add_object_symbols.  */
-      s = bfd_get_linker_section (dynobj, ".dynsym");
+      s = elf_hash_table (info)->dynsym;
       BFD_ASSERT (s != NULL);
       s->size = dynsymcount * bed->s->sizeof_sym;
 
@@ -6671,7 +6821,7 @@ merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
 /* Finish SHF_MERGE section merging.  */
 
 bfd_boolean
-_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
+_bfd_elf_merge_sections (bfd *obfd, struct bfd_link_info *info)
 {
   bfd *ibfd;
   asection *sec;
@@ -6680,7 +6830,10 @@ _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
     return FALSE;
 
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
-    if ((ibfd->flags & DYNAMIC) == 0)
+    if ((ibfd->flags & DYNAMIC) == 0
+       && bfd_get_flavour (ibfd) == bfd_target_elf_flavour
+       && (elf_elfheader (ibfd)->e_ident[EI_CLASS]
+           == get_elf_backend_data (obfd)->s->elfclass))
       for (sec = ibfd->sections; sec != NULL; sec = sec->next)
        if ((sec->flags & SEC_MERGE) != 0
            && !bfd_is_abs_section (sec->output_section))
@@ -6688,7 +6841,7 @@ _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
            struct bfd_elf_section_data *secdata;
 
            secdata = elf_section_data (sec);
-           if (! _bfd_add_merge_section (abfd,
+           if (! _bfd_add_merge_section (obfd,
                                          &elf_hash_table (info)->merge_info,
                                          sec, &secdata->sec_info))
              return FALSE;
@@ -6697,7 +6850,7 @@ _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
          }
 
   if (elf_hash_table (info)->merge_info != NULL)
-    _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
+    _bfd_merge_sections (obfd, info, elf_hash_table (info)->merge_info,
                         merge_sections_remove_hook);
   return TRUE;
 }
@@ -6754,14 +6907,18 @@ _bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
   struct elf_link_hash_table *htab;
 
   /* Copy down any references that we may have already seen to the
-     symbol which just became indirect.  */
+     symbol which just became indirect if DIR isn't a hidden versioned
+     symbol.  */
 
-  dir->ref_dynamic |= ind->ref_dynamic;
-  dir->ref_regular |= ind->ref_regular;
-  dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
-  dir->non_got_ref |= ind->non_got_ref;
-  dir->needs_plt |= ind->needs_plt;
-  dir->pointer_equality_needed |= ind->pointer_equality_needed;
+  if (dir->versioned != versioned_hidden)
+    {
+      dir->ref_dynamic |= ind->ref_dynamic;
+      dir->ref_regular |= ind->ref_regular;
+      dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
+      dir->non_got_ref |= ind->non_got_ref;
+      dir->needs_plt |= ind->needs_plt;
+      dir->pointer_equality_needed |= ind->pointer_equality_needed;
+    }
 
   if (ind->root.type != bfd_link_hash_indirect)
     return;
@@ -7394,9 +7551,7 @@ struct elf_final_link_info
   /* Output BFD.  */
   bfd *output_bfd;
   /* Symbol string table.  */
-  struct bfd_strtab_hash *symstrtab;
-  /* .dynsym section.  */
-  asection *dynsym_sec;
+  struct elf_strtab_hash *symstrtab;
   /* .hash section.  */
   asection *hash_sec;
   /* symbol version section (.gnu.version).  */
@@ -7421,16 +7576,8 @@ struct elf_final_link_info
   /* Array large enough to hold a section pointer for each local
      symbol of any input BFD.  */
   asection **sections;
-  /* Buffer to hold swapped out symbols.  */
-  bfd_byte *symbuf;
-  /* And one for symbol section indices.  */
+  /* Buffer for SHT_SYMTAB_SHNDX section.  */
   Elf_External_Sym_Shndx *symshndxbuf;
-  /* Number of swapped out symbols in buffer.  */
-  size_t symbuf_count;
-  /* Number of symbols which fit in symbuf.  */
-  size_t symbuf_size;
-  /* And same for symshndxbuf.  */
-  size_t shndxbuf_size;
   /* Number of STT_FILE syms seen.  */
   size_t filesym_count;
 };
@@ -7441,8 +7588,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;
 };
@@ -7793,28 +7938,34 @@ put_value (bfd_vma size,
 {
   location += (size - chunksz);
 
-  for (; size; size -= chunksz, location -= chunksz, x >>= (chunksz * 8))
+  for (; size; size -= chunksz, location -= chunksz)
     {
       switch (chunksz)
        {
-       default:
-       case 0:
-         abort ();
        case 1:
          bfd_put_8 (input_bfd, x, location);
+         x >>= 8;
          break;
        case 2:
          bfd_put_16 (input_bfd, x, location);
+         x >>= 16;
          break;
        case 4:
          bfd_put_32 (input_bfd, x, location);
+         /* Computed this way because x >>= 32 is undefined if x is a 32-bit value.  */
+         x >>= 16;
+         x >>= 16;
          break;
-       case 8:
 #ifdef BFD64
+       case 8:
          bfd_put_64 (input_bfd, x, location);
-#else
-         abort ();
+         /* Computed this way because x >>= 64 is undefined if x is a 64-bit value.  */
+         x >>= 32;
+         x >>= 32;
+         break;
 #endif
+       default:
+         abort ();
          break;
        }
     }
@@ -7961,10 +8112,12 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd,
   return r;
 }
 
-/* qsort comparison functions sorting external relocs by r_offset.  */
+/* Functions to read r_offset from external (target order) reloc
+   entry.  Faster than bfd_getl32 et al, because we let the compiler
+   know the value is aligned.  */
 
-static int
-cmp_ext32l_r_offset (const void *p, const void *q)
+static bfd_vma
+ext32l_r_offset (const void *p)
 {
   union aligned32
   {
@@ -7972,27 +8125,17 @@ cmp_ext32l_r_offset (const void *p, const void *q)
     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;
+    = (const union aligned32 *) &((const Elf32_External_Rel *) p)->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;
+  return aval;
 }
 
-static int
-cmp_ext32b_r_offset (const void *p, const void *q)
+static bfd_vma
+ext32b_r_offset (const void *p)
 {
   union aligned32
   {
@@ -8000,28 +8143,18 @@ cmp_ext32b_r_offset (const void *p, const void *q)
     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;
+    = (const union aligned32 *) &((const Elf32_External_Rel *) p)->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;
+  return aval;
 }
 
 #ifdef BFD_HOST_64_BIT
-static int
-cmp_ext64l_r_offset (const void *p, const void *q)
+static bfd_vma
+ext64l_r_offset (const void *p)
 {
   union aligned64
   {
@@ -8029,9 +8162,7 @@ cmp_ext64l_r_offset (const void *p, const void *q)
     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;
+    = (const union aligned64 *) &((const Elf64_External_Rel *) p)->r_offset;
 
   uint64_t aval = (  (uint64_t) a->c[0]
                   | (uint64_t) a->c[1] << 8
@@ -8041,23 +8172,11 @@ cmp_ext64l_r_offset (const void *p, const void *q)
                   | (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;
+  return aval;
 }
 
-static int
-cmp_ext64b_r_offset (const void *p, const void *q)
+static bfd_vma
+ext64b_r_offset (const void *p)
 {
   union aligned64
   {
@@ -8065,9 +8184,7 @@ cmp_ext64b_r_offset (const void *p, const void *q)
     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;
+    = (const union aligned64 *) &((const Elf64_External_Rel *) p)->r_offset;
 
   uint64_t aval = (  (uint64_t) a->c[0] << 56
                   | (uint64_t) a->c[1] << 48
@@ -8077,19 +8194,7 @@ cmp_ext64b_r_offset (const void *p, const void *q)
                   | (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;
+  return aval;
 }
 #endif
 
@@ -8098,7 +8203,7 @@ cmp_ext64b_r_offset (const void *p, const void *q)
    referenced must be updated.  Update all the relocations found in
    RELDATA.  */
 
-static void
+static bfd_boolean
 elf_link_adjust_relocs (bfd *abfd,
                        struct bfd_elf_section_reloc_data *reldata,
                        bfd_boolean sort)
@@ -8158,16 +8263,20 @@ elf_link_adjust_relocs (bfd *abfd,
       (*swap_out) (abfd, irela, erela);
     }
 
-  if (sort)
+  if (sort && count != 0)
     {
-      int (*compare) (const void *, const void *);
+      bfd_vma (*ext_r_off) (const void *);
+      bfd_vma r_off;
+      size_t elt_size;
+      bfd_byte *base, *end, *p, *loc;
+      bfd_byte *buf = NULL;
 
       if (bed->s->arch_size == 32)
        {
          if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)
-           compare = cmp_ext32l_r_offset;
+           ext_r_off = ext32l_r_offset;
          else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG)
-           compare = cmp_ext32b_r_offset;
+           ext_r_off = ext32b_r_offset;
          else
            abort ();
        }
@@ -8175,17 +8284,96 @@ elf_link_adjust_relocs (bfd *abfd,
        {
 #ifdef BFD_HOST_64_BIT
          if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)
-           compare = cmp_ext64l_r_offset;
+           ext_r_off = ext64l_r_offset;
          else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG)
-           compare = cmp_ext64b_r_offset;
+           ext_r_off = ext64b_r_offset;
          else
 #endif
            abort ();
        }
-      qsort (reldata->hdr->contents, count, reldata->hdr->sh_entsize, compare);
+
+      /*  Must use a stable sort here.  A modified insertion sort,
+         since the relocs are mostly sorted already.  */
+      elt_size = reldata->hdr->sh_entsize;
+      base = reldata->hdr->contents;
+      end = base + count * elt_size;
+      if (elt_size > sizeof (Elf64_External_Rela))
+       abort ();
+
+      /* Ensure the first element is lowest.  This acts as a sentinel,
+        speeding the main loop below.  */
+      r_off = (*ext_r_off) (base);
+      for (p = loc = base; (p += elt_size) < end; )
+       {
+         bfd_vma r_off2 = (*ext_r_off) (p);
+         if (r_off > r_off2)
+           {
+             r_off = r_off2;
+             loc = p;
+           }
+       }
+      if (loc != base)
+       {
+         /* Don't just swap *base and *loc as that changes the order
+            of the original base[0] and base[1] if they happen to
+            have the same r_offset.  */
+         bfd_byte onebuf[sizeof (Elf64_External_Rela)];
+         memcpy (onebuf, loc, elt_size);
+         memmove (base + elt_size, base, loc - base);
+         memcpy (base, onebuf, elt_size);
+       }
+
+      for (p = base + elt_size; (p += elt_size) < end; )
+       {
+         /* base to p is sorted, *p is next to insert.  */
+         r_off = (*ext_r_off) (p);
+         /* Search the sorted region for location to insert.  */
+         loc = p - elt_size;
+         while (r_off < (*ext_r_off) (loc))
+           loc -= elt_size;
+         loc += elt_size;
+         if (loc != p)
+           {
+             /* Chances are there is a run of relocs to insert here,
+                from one of more input files.  Files are not always
+                linked in order due to the way elf_link_input_bfd is
+                called.  See pr17666.  */
+             size_t sortlen = p - loc;
+             bfd_vma r_off2 = (*ext_r_off) (loc);
+             size_t runlen = elt_size;
+             size_t buf_size = 96 * 1024;
+             while (p + runlen < end
+                    && (sortlen <= buf_size
+                        || runlen + elt_size <= buf_size)
+                    && r_off2 > (*ext_r_off) (p + runlen))
+               runlen += elt_size;
+             if (buf == NULL)
+               {
+                 buf = bfd_malloc (buf_size);
+                 if (buf == NULL)
+                   return FALSE;
+               }
+             if (runlen < sortlen)
+               {
+                 memcpy (buf, p, runlen);
+                 memmove (loc + runlen, loc, sortlen);
+                 memcpy (loc, buf, runlen);
+               }
+             else
+               {
+                 memcpy (buf, loc, sortlen);
+                 memmove (loc, p, runlen);
+                 memcpy (loc + runlen, buf, sortlen);
+               }
+             p += runlen - elt_size;
+           }
+       }
+      /* Hashes are no longer valid.  */
       free (reldata->hashes);
       reldata->hashes = NULL;
+      free (buf);
     }
+  return TRUE;
 }
 
 struct elf_link_sort_rela
@@ -8516,47 +8704,21 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
   return ret;
 }
 
-/* Flush the output symbols to the file.  */
-
-static bfd_boolean
-elf_link_flush_output_syms (struct elf_final_link_info *flinfo,
-                           const struct elf_backend_data *bed)
-{
-  if (flinfo->symbuf_count > 0)
-    {
-      Elf_Internal_Shdr *hdr;
-      file_ptr pos;
-      bfd_size_type amt;
-
-      hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
-      pos = hdr->sh_offset + hdr->sh_size;
-      amt = flinfo->symbuf_count * bed->s->sizeof_sym;
-      if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) != 0
-         || bfd_bwrite (flinfo->symbuf, amt, flinfo->output_bfd) != amt)
-       return FALSE;
-
-      hdr->sh_size += amt;
-      flinfo->symbuf_count = 0;
-    }
-
-  return TRUE;
-}
-
-/* Add a symbol to the output symbol table.  */
+/* Add a symbol to the output symbol string table.  */
 
 static int
-elf_link_output_sym (struct elf_final_link_info *flinfo,
-                    const char *name,
-                    Elf_Internal_Sym *elfsym,
-                    asection *input_sec,
-                    struct elf_link_hash_entry *h)
-{
-  bfd_byte *dest;
-  Elf_External_Sym_Shndx *destshndx;
+elf_link_output_symstrtab (struct elf_final_link_info *flinfo,
+                          const char *name,
+                          Elf_Internal_Sym *elfsym,
+                          asection *input_sec,
+                          struct elf_link_hash_entry *h)
+{
   int (*output_symbol_hook)
     (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
      struct elf_link_hash_entry *);
+  struct elf_link_hash_table *hash_table;
   const struct elf_backend_data *bed;
+  bfd_size_type strtabsize;
 
   BFD_ASSERT (elf_onesymtab (flinfo->output_bfd));
 
@@ -8569,49 +8731,119 @@ elf_link_output_sym (struct elf_final_link_info *flinfo,
        return ret;
     }
 
-  if (name == NULL || *name == '\0')
-    elfsym->st_name = 0;
-  else if (input_sec->flags & SEC_EXCLUDE)
-    elfsym->st_name = 0;
+  if (name == NULL
+      || *name == '\0'
+      || (input_sec->flags & SEC_EXCLUDE))
+    elfsym->st_name = (unsigned long) -1;
   else
     {
-      elfsym->st_name = (unsigned long) _bfd_stringtab_add (flinfo->symstrtab,
-                                                           name, TRUE, FALSE);
+      /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
+        to get the final offset for st_name.  */
+      elfsym->st_name
+       = (unsigned long) _bfd_elf_strtab_add (flinfo->symstrtab,
+                                              name, FALSE);
       if (elfsym->st_name == (unsigned long) -1)
        return 0;
     }
 
-  if (flinfo->symbuf_count >= flinfo->symbuf_size)
+  hash_table = elf_hash_table (flinfo->info);
+  strtabsize = hash_table->strtabsize;
+  if (strtabsize <= hash_table->strtabcount)
     {
-      if (! elf_link_flush_output_syms (flinfo, bed))
+      strtabsize += strtabsize;
+      hash_table->strtabsize = strtabsize;
+      strtabsize *= sizeof (*hash_table->strtab);
+      hash_table->strtab
+       = (struct elf_sym_strtab *) bfd_realloc (hash_table->strtab,
+                                                strtabsize);
+      if (hash_table->strtab == NULL)
        return 0;
     }
+  hash_table->strtab[hash_table->strtabcount].sym = *elfsym;
+  hash_table->strtab[hash_table->strtabcount].dest_index
+    = hash_table->strtabcount;
+  hash_table->strtab[hash_table->strtabcount].destshndx_index
+    = flinfo->symshndxbuf ? bfd_get_symcount (flinfo->output_bfd) : 0;
+
+  bfd_get_symcount (flinfo->output_bfd) += 1;
+  hash_table->strtabcount += 1;
+
+  return 1;
+}
+
+/* Swap symbols out to the symbol table and flush the output symbols to
+   the file.  */
+
+static bfd_boolean
+elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
+{
+  struct elf_link_hash_table *hash_table = elf_hash_table (flinfo->info);
+  bfd_size_type amt, i;
+  const struct elf_backend_data *bed;
+  bfd_byte *symbuf;
+  Elf_Internal_Shdr *hdr;
+  file_ptr pos;
+  bfd_boolean ret;
+
+  if (!hash_table->strtabcount)
+    return TRUE;
+
+  BFD_ASSERT (elf_onesymtab (flinfo->output_bfd));
+
+  bed = get_elf_backend_data (flinfo->output_bfd);
 
-  dest = flinfo->symbuf + flinfo->symbuf_count * bed->s->sizeof_sym;
-  destshndx = flinfo->symshndxbuf;
-  if (destshndx != NULL)
+  amt = bed->s->sizeof_sym * hash_table->strtabcount;
+  symbuf = (bfd_byte *) bfd_malloc (amt);
+  if (symbuf == NULL)
+    return FALSE;
+
+  if (flinfo->symshndxbuf)
     {
-      if (bfd_get_symcount (flinfo->output_bfd) >= flinfo->shndxbuf_size)
+      amt = (sizeof (Elf_External_Sym_Shndx)
+            * (bfd_get_symcount (flinfo->output_bfd)));
+      flinfo->symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
+      if (flinfo->symshndxbuf == NULL)
        {
-         bfd_size_type amt;
-
-         amt = flinfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
-         destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx,
-                                                             amt * 2);
-         if (destshndx == NULL)
-           return 0;
-         flinfo->symshndxbuf = destshndx;
-         memset ((char *) destshndx + amt, 0, amt);
-         flinfo->shndxbuf_size *= 2;
+         free (symbuf);
+         return FALSE;
        }
-      destshndx += bfd_get_symcount (flinfo->output_bfd);
     }
 
-  bed->s->swap_symbol_out (flinfo->output_bfd, elfsym, dest, destshndx);
-  flinfo->symbuf_count += 1;
-  bfd_get_symcount (flinfo->output_bfd) += 1;
+  for (i = 0; i < hash_table->strtabcount; i++)
+    {
+      struct elf_sym_strtab *elfsym = &hash_table->strtab[i];
+      if (elfsym->sym.st_name == (unsigned long) -1)
+       elfsym->sym.st_name = 0;
+      else
+       elfsym->sym.st_name
+         = (unsigned long) _bfd_elf_strtab_offset (flinfo->symstrtab,
+                                                   elfsym->sym.st_name);
+      bed->s->swap_symbol_out (flinfo->output_bfd, &elfsym->sym,
+                              ((bfd_byte *) symbuf
+                               + (elfsym->dest_index
+                                  * bed->s->sizeof_sym)),
+                              (flinfo->symshndxbuf
+                               + elfsym->destshndx_index));
+    }
+
+  hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
+  pos = hdr->sh_offset + hdr->sh_size;
+  amt = hash_table->strtabcount * bed->s->sizeof_sym;
+  if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) == 0
+      && bfd_bwrite (symbuf, amt, flinfo->output_bfd) == amt)
+    {
+      hdr->sh_size += amt;
+      ret = TRUE;
+    }
+  else
+    ret = FALSE;
 
-  return 1;
+  free (symbuf);
+
+  free (hash_table->strtab);
+  hash_table->strtab = NULL;
+
+  return ret;
 }
 
 /* Return TRUE if the dynamic symbol SYM in ABFD is supported.  */
@@ -8808,6 +9040,16 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
   const struct elf_backend_data *bed;
   long indx;
   int ret;
+  /* A symbol is bound locally if it is forced local or it is locally
+     defined, hidden versioned, not referenced by shared library and
+     not exported when linking executable.  */
+  bfd_boolean local_bind = (h->forced_local
+                           || (bfd_link_executable (flinfo->info)
+                               && !flinfo->info->export_dynamic
+                               && !h->dynamic
+                               && !h->ref_dynamic
+                               && h->def_regular
+                               && h->versioned == versioned_hidden));
 
   if (h->root.type == bfd_link_hash_warning)
     {
@@ -8819,33 +9061,12 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
   /* Decide whether to output this symbol in this pass.  */
   if (eoinfo->localsyms)
     {
-      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))
+      if (!local_bind)
        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
     {
-      if (h->forced_local)
+      if (local_bind)
        return TRUE;
     }
 
@@ -8888,8 +9109,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 
   /* We should also warn if a forced local symbol is referenced from
      shared libraries.  */
-  if (!flinfo->info->relocatable
-      && flinfo->info->executable
+  if (bfd_link_executable (flinfo->info)
       && h->forced_local
       && h->ref_dynamic
       && h->def_regular
@@ -8925,8 +9145,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)
@@ -8952,12 +9173,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
@@ -8967,7 +9187,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
   sym.st_value = 0;
   sym.st_size = h->size;
   sym.st_other = h->other;
-  if (h->forced_local)
+  if (local_bind)
     {
       sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
       /* Turn off visibility on local symbol.  */
@@ -9003,19 +9223,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);
@@ -9033,7 +9240,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
               but in nonrelocatable files they are virtual
               addresses.  */
            sym.st_value = h->root.u.def.value + input_sec->output_offset;
-           if (!flinfo->info->relocatable)
+           if (!bfd_link_relocatable (flinfo->info))
              {
                sym.st_value += input_sec->output_section->vma;
                if (h->type == STT_TLS)
@@ -9077,10 +9284,10 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
      STT_GNU_IFUNC symbol must go through PLT.  */
   if ((h->type == STT_GNU_IFUNC
        && h->def_regular
-       && !flinfo->info->relocatable)
+       && !bfd_link_relocatable (flinfo->info))
       || ((h->dynindx != -1
           || h->forced_local)
-         && ((flinfo->info->shared
+         && ((bfd_link_pic (flinfo->info)
               && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak))
              || !h->forced_local)
@@ -9130,7 +9337,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 
   /* If a non-weak symbol with non-default visibility is not defined
      locally, it is a fatal error.  */
-  if (!flinfo->info->relocatable
+  if (!bfd_link_relocatable (flinfo->info)
       && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
       && ELF_ST_BIND (sym.st_info) != STB_WEAK
       && h->root.type == bfd_link_hash_undefined
@@ -9153,7 +9360,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We already know the symbol index.  We also fill in
      the entry in the .hash section.  */
-  if (flinfo->dynsym_sec != NULL
+  if (elf_hash_table (flinfo->info)->dynsym != NULL
       && h->dynindx != -1
       && elf_hash_table (flinfo->info)->dynamic_sections_created)
     {
@@ -9161,8 +9368,14 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 
       /* Since there is no version information in the dynamic string,
         if there is no version info in symbol version section, we will
-        have a run-time problem.  */
-      if (h->verinfo.verdef == NULL)
+        have a run-time problem if not linking executable, referenced
+        by shared library, not locally defined, or not bound locally.
+      */
+      if (h->verinfo.verdef == NULL
+         && !local_bind
+         && (!bfd_link_executable (flinfo->info)
+             || h->ref_dynamic
+             || !h->def_regular))
        {
          char *p = strrchr (h->root.root.string, ELF_VER_CHR);
 
@@ -9177,7 +9390,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
        }
 
       sym.st_name = h->dynstr_index;
-      esym = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
+      esym = (elf_hash_table (flinfo->info)->dynsym->contents
+             + h->dynindx * bed->s->sizeof_sym);
       if (!check_dynsym (flinfo->output_bfd, &sym))
        {
          eoinfo->failed = TRUE;
@@ -9232,7 +9446,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
                iversym.vs_vers++;
            }
 
-         if (h->hidden)
+         /* Turn on VERSYM_HIDDEN only if the hidden versioned symbol is
+            defined locally.  */
+         if (h->versioned == versioned_hidden && h->def_regular)
            iversym.vs_vers |= VERSYM_HIDDEN;
 
          eversym = (Elf_External_Versym *) flinfo->symver_sec->contents;
@@ -9241,13 +9457,46 @@ 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
+          && !bfd_link_relocatable (flinfo->info))
+    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_symstrtab (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);
+  ret = elf_link_output_symstrtab (flinfo, h->root.root.string, &sym,
+                                  input_sec, h);
   if (ret == 0)
     {
       eoinfo->failed = TRUE;
@@ -9273,6 +9522,7 @@ elf_section_ignore_discarded_relocs (asection *sec)
     {
     case SEC_INFO_TYPE_STABS:
     case SEC_INFO_TYPE_EH_FRAME:
+    case SEC_INFO_TYPE_EH_FRAME_ENTRY:
       return TRUE;
     default:
       break;
@@ -9468,8 +9718,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)
@@ -9512,7 +9763,8 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
           && (bfd_hash_lookup (flinfo->info->keep_hash, name, FALSE, FALSE)
               == NULL))
          || (((flinfo->info->discard == discard_sec_merge
-               && (isec->flags & SEC_MERGE) && !flinfo->info->relocatable)
+               && (isec->flags & SEC_MERGE)
+               && !bfd_link_relocatable (flinfo->info))
               || flinfo->info->discard == discard_l)
              && bfd_is_local_label_name (input_bfd, name)))
        continue;
@@ -9539,10 +9791,11 @@ 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->lto_output ? NULL
-                                    : input_bfd->filename),
-                                   &osym, bfd_abs_section_ptr, NULL))
+         if (!elf_link_output_symstrtab (flinfo,
+                                         (input_bfd->lto_output ? NULL
+                                          : input_bfd->filename),
+                                         &osym, bfd_abs_section_ptr,
+                                         NULL))
            return FALSE;
        }
 
@@ -9562,7 +9815,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
         output_section.  Any special sections must be set up to meet
         these requirements.  */
       osym.st_value += isec->output_offset;
-      if (!flinfo->info->relocatable)
+      if (!bfd_link_relocatable (flinfo->info))
        {
          osym.st_value += isec->output_section->vma;
          if (ELF_ST_TYPE (osym.st_info) == STT_TLS)
@@ -9574,7 +9827,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
        }
 
       indx = bfd_get_symcount (output_bfd);
-      ret = elf_link_output_sym (flinfo, name, &osym, isec, NULL);
+      ret = elf_link_output_symstrtab (flinfo, name, &osym, isec, NULL);
       if (ret == 0)
        return FALSE;
       else if (ret == 1)
@@ -9606,7 +9859,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
          continue;
        }
 
-      if (flinfo->info->relocatable
+      if (bfd_link_relocatable (flinfo->info)
          && (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP)
        {
          /* Deal with the group signature symbol.  */
@@ -9657,7 +9910,8 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                  sym.st_value += o->output_offset;
 
                  indx = bfd_get_symcount (output_bfd);
-                 ret = elf_link_output_sym (flinfo, name, &sym, o, NULL);
+                 ret = elf_link_output_symstrtab (flinfo, name, &sym, o,
+                                                  NULL);
                  if (ret == 0)
                    return FALSE;
                  else if (ret == 1)
@@ -9828,7 +10082,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                }
 
              if ((s_type == STT_RELC || s_type == STT_SRELC)
-                 && !flinfo->info->relocatable)
+                 && !bfd_link_relocatable (flinfo->info))
                {
                  bfd_vma val;
                  bfd_vma dot = (rel->r_offset
@@ -9918,7 +10172,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
            return FALSE;
 
          if (ret == 2
-             || flinfo->info->relocatable
+             || bfd_link_relocatable (flinfo->info)
              || flinfo->info->emitrelocations)
            {
              Elf_Internal_Rela *irela;
@@ -9949,7 +10203,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              rel_hash_list = rel_hash;
              rela_hash_list = NULL;
              last_offset = o->output_offset;
-             if (!flinfo->info->relocatable)
+             if (!bfd_link_relocatable (flinfo->info))
                last_offset += o->output_section->vma;
              for (next_erel = 0; irela < irelaend; irela++, next_erel++)
                {
@@ -9989,7 +10243,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                  irela->r_offset += o->output_offset;
 
                  /* Relocs in an executable have to be virtual addresses.  */
-                 if (!flinfo->info->relocatable)
+                 if (!bfd_link_relocatable (flinfo->info))
                    irela->r_offset += o->output_section->vma;
 
                  last_offset = irela->r_offset;
@@ -10117,7 +10371,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                            return FALSE;
 
                          sym.st_value += sec->output_offset;
-                         if (!flinfo->info->relocatable)
+                         if (!bfd_link_relocatable (flinfo->info))
                            {
                              sym.st_value += osec->vma;
                              if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
@@ -10132,8 +10386,9 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                            }
 
                          indx = bfd_get_symcount (output_bfd);
-                         ret = elf_link_output_sym (flinfo, name, &sym, sec,
-                                                    NULL);
+                         ret = elf_link_output_symstrtab (flinfo, name,
+                                                          &sym, sec,
+                                                          NULL);
                          if (ret == 0)
                            return FALSE;
                          else if (ret == 1)
@@ -10203,6 +10458,14 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              return FALSE;
          }
          break;
+       case SEC_INFO_TYPE_EH_FRAME_ENTRY:
+         {
+           if (! _bfd_elf_write_section_eh_frame_entry (output_bfd,
+                                                        flinfo->info,
+                                                        o, contents))
+             return FALSE;
+         }
+         break;
        default:
          {
            /* FIXME: octets_per_byte.  */
@@ -10384,7 +10647,7 @@ elf_reloc_link_order (bfd *output_bfd,
      relocatable file, and is a virtual address in an executable
      file.  */
   offset = link_order->offset;
-  if (! info->relocatable)
+  if (! bfd_link_relocatable (info))
     offset += output_section->vma;
 
   for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
@@ -10572,7 +10835,7 @@ elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo)
   asection *o;
 
   if (flinfo->symstrtab != NULL)
-    _bfd_stringtab_free (flinfo->symstrtab);
+    _bfd_elf_strtab_free (flinfo->symstrtab);
   if (flinfo->contents != NULL)
     free (flinfo->contents);
   if (flinfo->external_relocs != NULL)
@@ -10589,8 +10852,6 @@ elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo)
     free (flinfo->indices);
   if (flinfo->sections != NULL)
     free (flinfo->sections);
-  if (flinfo->symbuf != NULL)
-    free (flinfo->symbuf);
   if (flinfo->symshndxbuf != NULL)
     free (flinfo->symshndxbuf);
   for (o = obfd->sections; o != NULL; o = o->next)
@@ -10637,30 +10898,28 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! is_elf_hash_table (info->hash))
     return FALSE;
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     abfd->flags |= DYNAMIC;
 
   dynamic = elf_hash_table (info)->dynamic_sections_created;
   dynobj = elf_hash_table (info)->dynobj;
 
-  emit_relocs = (info->relocatable
+  emit_relocs = (bfd_link_relocatable (info)
                 || info->emitrelocations);
 
   flinfo.info = info;
   flinfo.output_bfd = abfd;
-  flinfo.symstrtab = _bfd_elf_stringtab_init ();
+  flinfo.symstrtab = _bfd_elf_strtab_init ();
   if (flinfo.symstrtab == NULL)
     return FALSE;
 
   if (! dynamic)
     {
-      flinfo.dynsym_sec = NULL;
       flinfo.hash_sec = NULL;
       flinfo.symver_sec = NULL;
     }
   else
     {
-      flinfo.dynsym_sec = bfd_get_linker_section (dynobj, ".dynsym");
       flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash");
       /* Note that dynsym_sec can be NULL (on VMS).  */
       flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version");
@@ -10675,10 +10934,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   flinfo.internal_syms = NULL;
   flinfo.indices = NULL;
   flinfo.sections = NULL;
-  flinfo.symbuf = NULL;
   flinfo.symshndxbuf = NULL;
-  flinfo.symbuf_count = 0;
-  flinfo.shndxbuf_size = 0;
   flinfo.filesym_count = 0;
 
   /* The object attributes have been merged.  Remove the input
@@ -10759,7 +11015,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                   to count particular types of relocs.  Of course,
                   reloc sections themselves can't have relocations.  */
                reloc_count = 0;
-             else if (info->relocatable || info->emitrelocations)
+             else if (emit_relocs)
                reloc_count = sec->reloc_count;
              else if (bed->elf_backend_count_relocs)
                reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
@@ -10786,7 +11042,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                    max_sym_count = sym_count;
 
                  if (sym_count > max_sym_shndx_count
-                     && elf_symtab_shndx (sec->owner) != 0)
+                     && elf_symtab_shndx_list (sec->owner) != NULL)
                    max_sym_shndx_count = sym_count;
 
                  if ((sec->flags & SEC_RELOC) != 0)
@@ -10811,8 +11067,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
          o->reloc_count += reloc_count;
 
-         if (p->type == bfd_indirect_link_order
-             && (info->relocatable || info->emitrelocations))
+         if (p->type == bfd_indirect_link_order && emit_relocs)
            {
              if (esdi->rel.hdr)
                esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
@@ -10847,7 +11102,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        o->vma = 0;
     }
 
-  if (! info->relocatable && merged)
+  if (! bfd_link_relocatable (info) && merged)
     elf_link_hash_traverse (elf_hash_table (info),
                            _bfd_elf_link_sec_merge_syms, abfd);
 
@@ -10878,6 +11133,21 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
         to count upwards while actually outputting the relocations.  */
       esdo->rel.count = 0;
       esdo->rela.count = 0;
+
+      if (esdo->this_hdr.sh_offset == (file_ptr) -1)
+       {
+         /* Cache the section contents so that they can be compressed
+            later.  Use bfd_malloc since it will be freed by
+            bfd_compress_section_contents.  */
+         unsigned char *contents = esdo->this_hdr.contents;
+         if ((o->flags & SEC_ELF_COMPRESS) == 0 || contents != NULL)
+           abort ();
+         contents
+           = (unsigned char *) bfd_malloc (esdo->this_hdr.sh_size);
+         if (contents == NULL)
+           goto error_return;
+         esdo->this_hdr.contents = contents;
+       }
     }
 
   /* We have now assigned file positions for all the sections except
@@ -10895,27 +11165,18 @@ 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;
 
-  /* 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)
-    flinfo.symbuf_size = 20;
-  else
-    flinfo.symbuf_size = max_sym_count;
-  amt = flinfo.symbuf_size;
-  amt *= bed->s->sizeof_sym;
-  flinfo.symbuf = (bfd_byte *) bfd_malloc (amt);
-  if (flinfo.symbuf == NULL)
+  if (max_sym_count < 20)
+    max_sym_count = 20;
+  elf_hash_table (info)->strtabsize = max_sym_count;
+  amt = max_sym_count * sizeof (struct elf_sym_strtab);
+  elf_hash_table (info)->strtab
+    = (struct elf_sym_strtab *) bfd_malloc (amt);
+  if (elf_hash_table (info)->strtab == NULL)
     goto error_return;
-  if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
-    {
-      /* Wild guess at number of output symbols.  realloc'd as needed.  */
-      amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
-      flinfo.shndxbuf_size = amt;
-      amt *= sizeof (Elf_External_Sym_Shndx);
-      flinfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
-      if (flinfo.symshndxbuf == NULL)
-       goto error_return;
-    }
+  /* The real buffer will be allocated in elf_link_swap_symbols_out.  */
+  flinfo.symshndxbuf
+    = (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF)
+       ? (Elf_External_Sym_Shndx *) -1 : NULL);
 
   if (info->strip != strip_all || emit_relocs)
     {
@@ -10935,8 +11196,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       elfsym.st_other = 0;
       elfsym.st_shndx = SHN_UNDEF;
       elfsym.st_target_internal = 0;
-      if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr,
-                              NULL) != 1)
+      if (elf_link_output_symstrtab (&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
@@ -10957,9 +11218,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            {
              o->target_index = bfd_get_symcount (abfd);
              elfsym.st_shndx = i;
-             if (!info->relocatable)
+             if (!bfd_link_relocatable (info))
                elfsym.st_value = o->vma;
-             if (elf_link_output_sym (&flinfo, NULL, &elfsym, o, NULL) != 1)
+             if (elf_link_output_symstrtab (&flinfo, NULL, &elfsym, o,
+                                            NULL) != 1)
                goto error_return;
            }
        }
@@ -11058,6 +11320,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        return FALSE;
     }
 
+  if (!_bfd_elf_fixup_eh_frame_hdr (info))
+    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
@@ -11158,21 +11423,11 @@ 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
@@ -11183,7 +11438,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
         struct elf_link_hash_entry *);
 
       if (! ((*bed->elf_backend_output_arch_local_syms)
-            (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym)))
+            (abfd, info, &flinfo,
+             (out_sym_func) elf_link_output_symstrtab)))
        return FALSE;
     }
 
@@ -11196,15 +11452,17 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
   if (dynamic
-      && flinfo.dynsym_sec != NULL
-      && flinfo.dynsym_sec->output_section != bfd_abs_section_ptr)
+      && elf_hash_table (info)->dynsym != NULL
+      && (elf_hash_table (info)->dynsym->output_section
+         != bfd_abs_section_ptr))
     {
       Elf_Internal_Sym sym;
-      bfd_byte *dynsym = flinfo.dynsym_sec->contents;
+      bfd_byte *dynsym = elf_hash_table (info)->dynsym->contents;
       long last_local = 0;
 
       /* Write out the section symbols for the output sections.  */
-      if (info->shared || elf_hash_table (info)->is_relocatable_executable)
+      if (bfd_link_pic (info)
+         || elf_hash_table (info)->is_relocatable_executable)
        {
          asection *s;
 
@@ -11272,7 +11530,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            }
        }
 
-      elf_section_data (flinfo.dynsym_sec->output_section)->this_hdr.sh_info =
+      elf_section_data (elf_hash_table (info)->dynsym->output_section)->this_hdr.sh_info =
        last_local + 1;
     }
 
@@ -11294,12 +11552,16 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
         struct elf_link_hash_entry *);
 
       if (! ((*bed->elf_backend_output_arch_syms)
-            (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym)))
+            (abfd, info, &flinfo,
+             (out_sym_func) elf_link_output_symstrtab)))
        return FALSE;
     }
 
-  /* Flush all symbols to the file.  */
-  if (! elf_link_flush_output_syms (&flinfo, bed))
+  /* Finalize the .strtab section.  */
+  _bfd_elf_strtab_finalize (flinfo.symstrtab);
+
+  /* Swap out the .strtab section. */
+  if (!elf_link_swap_symbols_out (&flinfo))
     return FALSE;
 
   /* Now we know the size of the symtab section.  */
@@ -11310,8 +11572,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       Elf_Internal_Shdr *symstrtab_hdr;
       file_ptr off = symtab_hdr->sh_offset + symtab_hdr->sh_size;
 
-      symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-      if (symtab_shndx_hdr->sh_name != 0)
+      symtab_shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr;
+      if (symtab_shndx_hdr != NULL && symtab_shndx_hdr->sh_name != 0)
        {
          symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
          symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
@@ -11332,7 +11594,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       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_size = _bfd_elf_strtab_size (flinfo.symstrtab);
       symstrtab_hdr->sh_entsize = 0;
       symstrtab_hdr->sh_link = 0;
       symstrtab_hdr->sh_info = 0;
@@ -11344,7 +11606,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       elf_next_file_pos (abfd) = off;
 
       if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
-         || ! _bfd_stringtab_emit (abfd, flinfo.symstrtab))
+         || ! _bfd_elf_strtab_emit (abfd, flinfo.symstrtab))
        return FALSE;
     }
 
@@ -11357,10 +11619,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        continue;
 
       sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o);
-      if (esdo->rel.hdr != NULL)
-       elf_link_adjust_relocs (abfd, &esdo->rel, sort);
-      if (esdo->rela.hdr != NULL)
-       elf_link_adjust_relocs (abfd, &esdo->rela, sort);
+      if (esdo->rel.hdr != NULL
+         && !elf_link_adjust_relocs (abfd, &esdo->rel, sort))
+       return FALSE;
+      if (esdo->rela.hdr != NULL
+         && !elf_link_adjust_relocs (abfd, &esdo->rela, sort))
+       return FALSE;
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
@@ -11551,7 +11815,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        goto error_return;
 
       /* Check for DT_TEXTREL (late, in case the backend removes it).  */
-      if (((info->warn_shared_textrel && info->shared)
+      if (((info->warn_shared_textrel && bfd_link_pic (info))
           || info->error_textrel)
          && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
        {
@@ -11618,7 +11882,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        }
     }
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     {
       bfd_boolean failed = FALSE;
 
@@ -11802,8 +12066,6 @@ _bfd_elf_gc_mark_hook (asection *sec,
                       struct elf_link_hash_entry *h,
                       Elf_Internal_Sym *sym)
 {
-  const char *sec_name;
-
   if (h != NULL)
     {
       switch (h->root.type)
@@ -11815,33 +12077,6 @@ _bfd_elf_gc_mark_hook (asection *sec,
        case bfd_link_hash_common:
          return h->root.u.c.p->section;
 
-       case bfd_link_hash_undefined:
-       case bfd_link_hash_undefweak:
-         /* To work around a glibc bug, keep all XXX input sections
-            when there is an as yet undefined reference to __start_XXX
-            or __stop_XXX symbols.  The linker will later define such
-            symbols for orphan input sections that have a name
-            representable as a C identifier.  */
-         if (strncmp (h->root.root.string, "__start_", 8) == 0)
-           sec_name = h->root.root.string + 8;
-         else if (strncmp (h->root.root.string, "__stop_", 7) == 0)
-           sec_name = h->root.root.string + 7;
-         else
-           sec_name = NULL;
-
-         if (sec_name && *sec_name != '\0')
-           {
-             bfd *i;
-
-             for (i = info->input_bfds; i; i = i->link.next)
-               {
-                 sec = bfd_get_section_by_name (i, sec_name);
-                 if (sec)
-                   sec->flags |= SEC_KEEP;
-               }
-           }
-         break;
-
        default:
          break;
        }
@@ -11859,7 +12094,8 @@ _bfd_elf_gc_mark_hook (asection *sec,
 asection *
 _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
                       elf_gc_mark_hook_fn gc_mark_hook,
-                      struct elf_reloc_cookie *cookie)
+                      struct elf_reloc_cookie *cookie,
+                      bfd_boolean *start_stop)
 {
   unsigned long r_symndx;
   struct elf_link_hash_entry *h;
@@ -11888,6 +12124,38 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
         handling copy relocs.  */
       if (h->u.weakdef != NULL)
        h->u.weakdef->mark = 1;
+
+      if (start_stop != NULL
+         && (h->root.type == bfd_link_hash_undefined
+             || h->root.type == bfd_link_hash_undefweak))
+       {
+         /* To work around a glibc bug, mark all XXX input sections
+            when there is an as yet undefined reference to __start_XXX
+            or __stop_XXX symbols.  The linker will later define such
+            symbols for orphan input sections that have a name
+            representable as a C identifier.  */
+         const char *sec_name = NULL;
+         if (strncmp (h->root.root.string, "__start_", 8) == 0)
+           sec_name = h->root.root.string + 8;
+         else if (strncmp (h->root.root.string, "__stop_", 7) == 0)
+           sec_name = h->root.root.string + 7;
+
+         if (sec_name != NULL && *sec_name != '\0')
+           {
+             bfd *i;
+
+             for (i = info->input_bfds; i != NULL; i = i->link.next)
+               {
+                 asection *s = bfd_get_section_by_name (i, sec_name);
+                 if (s != NULL && !s->gc_mark)
+                   {
+                     *start_stop = TRUE;
+                     return s;
+                   }
+               }
+           }
+       }
+
       return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
     }
 
@@ -11906,15 +12174,22 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
                        struct elf_reloc_cookie *cookie)
 {
   asection *rsec;
+  bfd_boolean start_stop = FALSE;
 
-  rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
-  if (rsec && !rsec->gc_mark)
+  rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie, &start_stop);
+  while (rsec != NULL)
     {
-      if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
-         || (rsec->owner->flags & DYNAMIC) != 0)
-       rsec->gc_mark = 1;
-      else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
-       return FALSE;
+      if (!rsec->gc_mark)
+       {
+         if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
+             || (rsec->owner->flags & DYNAMIC) != 0)
+           rsec->gc_mark = 1;
+         else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
+           return FALSE;
+       }
+      if (!start_stop)
+       break;
+      rsec = bfd_get_next_section_by_name (rsec->owner, rsec);
     }
   return TRUE;
 }
@@ -11977,6 +12252,11 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
        }
     }
 
+  eh_frame = elf_section_eh_frame_entry (sec);
+  if (ret && eh_frame && !eh_frame->gc_mark)
+    if (!_bfd_elf_gc_mark (info, eh_frame, gc_mark_hook))
+      ret = FALSE;
+
   return ret;
 }
 
@@ -12107,7 +12387,6 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
                                isec->name, ilen) == 0)
                  {
                    dsec->gc_mark = 0;
-                   break;
                  }
              }
          }
@@ -12165,7 +12444,8 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
     {
       asection *o;
 
-      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+      if (bfd_get_flavour (sub) != bfd_target_elf_flavour
+         || !(*bed->relocs_compatible) (sub->xvec, abfd->xvec))
        continue;
 
       for (o = sub->sections; o != NULL; o = o->next)
@@ -12356,12 +12636,12 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
          || ((h->def_regular || ELF_COMMON_DEF_P (h))
              && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
              && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
-             && (!info->executable
+             && (!bfd_link_executable (info)
                  || info->export_dynamic
                  || (h->dynamic
                      && d != NULL
                      && (*d->match) (&d->head, NULL, h->root.root.string)))
-             && (strchr (h->root.root.string, ELF_VER_CHR) != NULL
+             && (h->versioned >= versioned
                  || !bfd_hide_sym_by_version (info->version_info,
                                               h->root.root.string)))))
     h->root.u.def.section->flags |= SEC_KEEP;
@@ -12392,6 +12672,36 @@ _bfd_elf_gc_keep (struct bfd_link_info *info)
     }
 }
 
+bfd_boolean
+bfd_elf_parse_eh_frame_entries (bfd *abfd ATTRIBUTE_UNUSED,
+                               struct bfd_link_info *info)
+{
+  bfd *ibfd = info->input_bfds;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      asection *sec;
+      struct elf_reloc_cookie cookie;
+
+      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+       continue;
+
+      if (!init_reloc_cookie (&cookie, info, ibfd))
+       return FALSE;
+
+      for (sec = ibfd->sections; sec; sec = sec->next)
+       {
+         if (CONST_STRNEQ (bfd_section_name (ibfd, sec), ".eh_frame_entry")
+             && init_reloc_cookie_rels (&cookie, info, ibfd, sec))
+           {
+             _bfd_elf_parse_eh_frame_entry (info, sec, &cookie);
+             fini_reloc_cookie_rels (&cookie, sec);
+           }
+       }
+    }
+  return TRUE;
+}
+
 /* Do mark and sweep of unused sections.  */
 
 bfd_boolean
@@ -12415,7 +12725,9 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
 
   /* Try to parse each bfd's .eh_frame section.  Point elf_eh_frame_section
      at the .eh_frame section if we can mark the FDEs individually.  */
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
+  for (sub = info->input_bfds;
+       info->eh_frame_hdr_type != COMPACT_EH_HDR && sub != NULL;
+       sub = sub->link.next)
     {
       asection *sec;
       struct elf_reloc_cookie cookie;
@@ -12428,7 +12740,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
              && (sec->flags & SEC_LINKER_CREATED) == 0)
            elf_eh_frame_section (sub) = sec;
          fini_reloc_cookie_for_section (&cookie, sec);
-         sec = bfd_get_next_section_by_name (sec);
+         sec = bfd_get_next_section_by_name (NULL, sec);
        }
     }
 
@@ -12452,7 +12764,8 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
     {
       asection *o;
 
-      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+      if (bfd_get_flavour (sub) != bfd_target_elf_flavour
+         || !(*bed->relocs_compatible) (sub->xvec, abfd->xvec))
        continue;
 
       /* Start at sections marked with SEC_KEEP (ref _bfd_elf_gc_keep).
@@ -12918,7 +13231,9 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
        }
     }
 
-  o = bfd_get_section_by_name (output_bfd, ".eh_frame");
+  o = NULL;
+  if (info->eh_frame_hdr_type != COMPACT_EH_HDR)
+    o = bfd_get_section_by_name (output_bfd, ".eh_frame");
   if (o != NULL)
     {
       asection *i;
@@ -12966,8 +13281,11 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
        }
     }
 
-  if (info->eh_frame_hdr
-      && !info->relocatable
+  if (info->eh_frame_hdr_type == COMPACT_EH_HDR)
+    _bfd_elf_end_eh_frame_parsing (info);
+
+  if (info->eh_frame_hdr_type
+      && !bfd_link_relocatable (info)
       && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info))
     changed = 1;
 
@@ -13272,7 +13590,7 @@ _bfd_elf_copy_link_hash_symbol_type (bfd *abfd,
   ehdest->target_internal = ehsrc->target_internal;
 
   isym.st_other = ehsrc->other;
-  elf_merge_st_other (abfd, ehdest, &isym, TRUE, FALSE);
+  elf_merge_st_other (abfd, ehdest, &isym, NULL, TRUE, FALSE);
 }
 
 /* Append a RELA relocation REL to section S in BFD.  */
This page took 0.058655 seconds and 4 git commands to generate.