[ARC] ARC_PC32 dynamic reloc incorrectly generated.
[deliverable/binutils-gdb.git] / bfd / elflink.c
index a6b3c944080339c300badc18ace995a218a2572c..1b447bb785081844b2d577f364586d67c81328ce 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linking support for BFD.
-   Copyright (C) 1995-2016 Free Software Foundation, Inc.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 #include "safe-ctype.h"
 #include "libiberty.h"
 #include "objalloc.h"
+#if BFD_SUPPORTS_PLUGINS
+#include "plugin-api.h"
+#include "plugin.h"
+#endif
 
 /* This struct is used to pass information to routines called via
    elf_link_hash_traverse which must return failure.  */
@@ -115,15 +119,18 @@ _bfd_elf_define_linkage_sym (bfd *abfd,
         defined in shared libraries can't be overridden, because we
         lose the link to the bfd which is via the symbol section.  */
       h->root.type = bfd_link_hash_new;
+      bh = &h->root;
     }
+  else
+    bh = NULL;
 
-  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, bed->collect,
                                         &bh))
     return NULL;
   h = (struct elf_link_hash_entry *) bh;
+  BFD_ASSERT (h != NULL);
   h->def_regular = 1;
   h->non_elf = 0;
   h->root.linker_def = 1;
@@ -145,8 +152,7 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
   struct elf_link_hash_table *htab = elf_hash_table (info);
 
   /* This function may be called more than once.  */
-  s = bfd_get_linker_section (abfd, ".got");
-  if (s != NULL)
+  if (htab->sgot != NULL)
     return TRUE;
 
   flags = bed->dynamic_sec_flags;
@@ -421,9 +427,22 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         initialize them at run time.  The linker script puts the .dynbss
         section into the .bss section of the final image.  */
       s = bfd_make_section_anyway_with_flags (abfd, ".dynbss",
-                                             (SEC_ALLOC | SEC_LINKER_CREATED));
+                                             SEC_ALLOC | SEC_LINKER_CREATED);
       if (s == NULL)
        return FALSE;
+      htab->sdynbss = s;
+
+      if (bed->want_dynrelro)
+       {
+         /* Similarly, but for symbols that were originally in read-only
+            sections.  This section doesn't really need to have contents,
+            but make it like other .data.rel.ro sections.  */
+         s = bfd_make_section_anyway_with_flags (abfd, ".data.rel.ro",
+                                                 flags);
+         if (s == NULL)
+           return FALSE;
+         htab->sdynrelro = s;
+       }
 
       /* The .rel[a].bss section holds copy relocs.  This section is not
         normally needed.  We need to create it here, though, so that the
@@ -436,7 +455,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 (! bfd_link_pic (info))
+      if (bfd_link_executable (info))
        {
          s = bfd_make_section_anyway_with_flags (abfd,
                                                  (bed->rela_plts_and_copies_p
@@ -445,6 +464,20 @@ _bfd_elf_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;
+         htab->srelbss = s;
+
+         if (bed->want_dynrelro)
+           {
+             s = (bfd_make_section_anyway_with_flags
+                  (abfd, (bed->rela_plts_and_copies_p
+                          ? ".rela.data.rel.ro" : ".rel.data.rel.ro"),
+                   flags | SEC_READONLY));
+             if (s == NULL
+                 || ! bfd_set_section_alignment (abfd, s,
+                                                 bed->s->log_file_align))
+               return FALSE;
+             htab->sreldynrelro = s;
+           }
        }
     }
 
@@ -468,7 +501,7 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
       struct elf_strtab_hash *dynstr;
       char *p;
       const char *name;
-      bfd_size_type indx;
+      size_t indx;
 
       /* XXX: The ABI draft says the linker must turn hidden and
         internal symbols into STB_LOCAL symbols when producing the
@@ -519,7 +552,7 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
       if (p != NULL)
        *p = ELF_VER_CHR;
 
-      if (indx == (bfd_size_type) -1)
+      if (indx == (size_t) -1)
        return FALSE;
       h->dynstr_index = indx;
     }
@@ -547,7 +580,7 @@ bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
               && (ELF_ST_TYPE (sym->st_info) == STT_OBJECT
                   || ELF_ST_TYPE (sym->st_info) == STT_COMMON))))
       || (d != NULL
-         && h->root.type == bfd_link_hash_new
+         && h->non_elf
          && (*d->match) (&d->head, NULL, h->root.root.string)))
     h->dynamic = 1;
 }
@@ -574,6 +607,9 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
   if (h == NULL)
     return provide;
 
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
   if (h->versioned == unknown)
     {
       /* Set versioned if symbol version is unknown.  */
@@ -587,6 +623,14 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
        }
     }
 
+  /* Symbols defined in a linker script but not referenced anywhere
+     else will have non_elf set.  */
+  if (h->non_elf)
+    {
+      bfd_elf_link_mark_dynamic_symbol (info, h, NULL);
+      h->non_elf = 0;
+    }
+
   switch (h->root.type)
     {
     case bfd_link_hash_defined:
@@ -603,8 +647,6 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
        bfd_link_repair_undef_list (&htab->root);
       break;
     case bfd_link_hash_new:
-      bfd_elf_link_mark_dynamic_symbol (info, h, NULL);
-      h->non_elf = 0;
       break;
     case bfd_link_hash_indirect:
       /* We had a versioned symbol in a dynamic library.  We make the
@@ -621,9 +663,9 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
       hv->root.u.i.link = (struct bfd_link_hash_entry *) h;
       (*bed->elf_backend_copy_indirect_symbol) (info, h, hv);
       break;
-    case bfd_link_hash_warning:
-      abort ();
-      break;
+    default:
+      BFD_FAIL ();
+      return FALSE;
     }
 
   /* If this symbol is being provided by the linker script, and it is
@@ -644,6 +686,9 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
       && !h->def_regular)
     h->verinfo.verdef = NULL;
 
+  /* Make sure this symbol is not garbage collected.  */
+  h->mark = 1;
+
   h->def_regular = 1;
 
   if (hidden)
@@ -698,7 +743,7 @@ bfd_elf_link_record_local_dynamic_symbol (struct bfd_link_info *info,
   struct elf_link_local_dynamic_entry *entry;
   struct elf_link_hash_table *eht;
   struct elf_strtab_hash *dynstr;
-  unsigned long dynstr_index;
+  size_t dynstr_index;
   char *name;
   Elf_External_Sym_Shndx eshndx;
   char esym[sizeof (Elf64_External_Sym)];
@@ -753,7 +798,7 @@ bfd_elf_link_record_local_dynamic_symbol (struct bfd_link_info *info,
     }
 
   dynstr_index = _bfd_elf_strtab_add (dynstr, name, FALSE);
-  if (dynstr_index == (unsigned long) -1)
+  if (dynstr_index == (size_t) -1)
     return 0;
   entry->isym.st_name = dynstr_index;
 
@@ -900,6 +945,7 @@ _bfd_elf_link_renumber_dynsyms (bfd *output_bfd,
       for (p = elf_hash_table (info)->dynlocal; p ; p = p->next)
        p->dynindx = ++dynsymcount;
     }
+  elf_hash_table (info)->local_dynsymcount = dynsymcount;
 
   elf_link_hash_traverse (elf_hash_table (info),
                          elf_link_renumber_hash_table_dynsyms,
@@ -1202,24 +1248,50 @@ _bfd_elf_merge_symbol (bfd *abfd,
   oldfunc = (h->type != STT_NOTYPE
             && bed->is_function_type (h->type));
 
-  /* When we try to create a default indirect symbol from the dynamic
-     definition with the default version, we skip it if its type and
-     the type of existing regular definition mismatch.  */
-  if (pold_alignment == NULL
-      && newdyn
-      && newdef
-      && !olddyn
-      && (((olddef || h->root.type == bfd_link_hash_common)
-          && ELF_ST_TYPE (sym->st_info) != h->type
-          && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
-          && h->type != STT_NOTYPE
-          && !(newfunc && oldfunc))
-         || (olddef
-             && ((h->type == STT_GNU_IFUNC)
-                 != (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))))
-    {
-      *skip = TRUE;
-      return TRUE;
+  if (!(newfunc && oldfunc)
+      && ELF_ST_TYPE (sym->st_info) != h->type
+      && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
+      && h->type != STT_NOTYPE
+      && (newdef || bfd_is_com_section (sec))
+      && (olddef || h->root.type == bfd_link_hash_common))
+    {
+      /* If creating a default indirect symbol ("foo" or "foo@") from
+        a dynamic versioned definition ("foo@@") skip doing so if
+        there is an existing regular definition with a different
+        type.  We don't want, for example, a "time" variable in the
+        executable overriding a "time" function in a shared library.  */
+      if (newdyn
+         && !olddyn)
+       {
+         *skip = TRUE;
+         return TRUE;
+       }
+
+      /* When adding a symbol from a regular object file after we have
+        created indirect symbols, undo the indirection and any
+        dynamic state.  */
+      if (hi != h
+         && !newdyn
+         && olddyn)
+       {
+         h = hi;
+         (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+         h->forced_local = 0;
+         h->ref_dynamic = 0;
+         h->def_dynamic = 0;
+         h->dynamic_def = 0;
+         if (h->root.u.undef.next || info->hash->undefs_tail == &h->root)
+           {
+             h->root.type = bfd_link_hash_undefined;
+             h->root.u.undef.abfd = abfd;
+           }
+         else
+           {
+             h->root.type = bfd_link_hash_new;
+             h->root.u.undef.abfd = NULL;
+           }
+         return TRUE;
+       }
     }
 
   /* Check TLS symbols.  We don't check undefined symbols introduced
@@ -1255,25 +1327,29 @@ _bfd_elf_merge_symbol (bfd *abfd,
        }
 
       if (tdef && ntdef)
-       (*_bfd_error_handler)
+       _bfd_error_handler
+         /* xgettext:c-format */
          (_("%s: TLS definition in %B section %A "
             "mismatches non-TLS definition in %B section %A"),
-          tbfd, tsec, ntbfd, ntsec, h->root.root.string);
+          h->root.root.string, tbfd, tsec, ntbfd, ntsec);
       else if (!tdef && !ntdef)
-       (*_bfd_error_handler)
+       _bfd_error_handler
+         /* xgettext:c-format */
          (_("%s: TLS reference in %B "
             "mismatches non-TLS reference in %B"),
-          tbfd, ntbfd, h->root.root.string);
+          h->root.root.string, tbfd, ntbfd);
       else if (tdef)
-       (*_bfd_error_handler)
+       _bfd_error_handler
+         /* xgettext:c-format */
          (_("%s: TLS definition in %B section %A "
             "mismatches non-TLS reference in %B"),
-          tbfd, tsec, ntbfd, h->root.root.string);
+          h->root.root.string, tbfd, tsec, ntbfd);
       else
-       (*_bfd_error_handler)
+       _bfd_error_handler
+         /* xgettext:c-format */
          (_("%s: TLS reference in %B "
             "mismatches non-TLS definition in %B section %A"),
-          tbfd, ntbfd, ntsec, h->root.root.string);
+          h->root.root.string, tbfd, ntbfd, ntsec);
 
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
@@ -1481,10 +1557,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
         the old symbol override the new one as normally happens with
         symbols defined in dynamic objects.  */
 
-      if (! ((*info->callbacks->multiple_common)
-            (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
-       return FALSE;
-
+      (*info->callbacks->multiple_common) (info, &h->root, abfd,
+                                          bfd_link_hash_common, sym->st_size);
       if (sym->st_size > h->size)
        h->size = sym->st_size;
 
@@ -1503,16 +1577,13 @@ _bfd_elf_merge_symbol (bfd *abfd,
      represent variables; this can cause confusion in principle, but
      any such confusion would seem to indicate an erroneous program or
      shared library.  We also permit a common symbol in a regular
-     object to override a weak symbol in a shared object.  A common
-     symbol in executable also overrides a symbol in a shared object.  */
+     object to override a weak symbol in a shared object.  */
 
   if (newdyn
       && newdef
       && (olddef
          || (h->root.type == bfd_link_hash_common
-             && (newweak
-                 || newfunc
-                 || (!olddyn && bfd_link_executable (info))))))
+             && (newweak || newfunc))))
     {
       *override = TRUE;
       newdef = FALSE;
@@ -1642,9 +1713,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
       /* It would be best if we could set the hash table entry to a
         common symbol, but we don't know what to use for the section
         or the alignment.  */
-      if (! ((*info->callbacks->multiple_common)
-            (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
-       return FALSE;
+      (*info->callbacks->multiple_common) (info, &h->root, abfd,
+                                          bfd_link_hash_common, sym->st_size);
 
       /* If the presumed common symbol in the dynamic object is
         larger, pretend that the new symbol has its size.  */
@@ -1784,6 +1854,31 @@ _bfd_elf_add_default_symbol (bfd *abfd,
   if (skip)
     goto nondefault;
 
+  if (hi->def_regular)
+    {
+      /* If the undecorated symbol will have a version added by a
+        script different to H, then don't indirect to/from the
+        undecorated symbol.  This isn't ideal because we may not yet
+        have seen symbol versions, if given by a script on the
+        command line rather than via --version-script.  */
+      if (hi->verinfo.vertree == NULL && info->version_info != NULL)
+       {
+         bfd_boolean hide;
+
+         hi->verinfo.vertree
+           = bfd_find_version_for_sym (info->version_info,
+                                       hi->root.root.string, &hide);
+         if (hi->verinfo.vertree != NULL && hide)
+           {
+             (*bed->elf_backend_hide_symbol) (info, hi, TRUE);
+             goto nondefault;
+           }
+       }
+      if (hi->verinfo.vertree != NULL
+         && strcmp (p + 1 + (p[1] == '@'), hi->verinfo.vertree->name) != 0)
+       goto nondefault;
+    }
+
   if (! override)
     {
       /* Add the default symbol if not performing a relocatable link.  */
@@ -1911,7 +2006,8 @@ nondefault:
         overridden by a versioned definition.  */
       if (hi->root.type != bfd_link_hash_defined
          && hi->root.type != bfd_link_hash_defweak)
-       (*_bfd_error_handler)
+       _bfd_error_handler
+         /* xgettext:c-format */
          (_("%B: unexpected redefinition of indirect versioned symbol `%s'"),
           abfd, shortname);
     }
@@ -2083,7 +2179,6 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
   const struct elf_backend_data *bed;
   struct elf_info_failed eif;
   char *p;
-  bfd_size_type amt;
 
   sinfo = (struct elf_info_failed *) data;
   info = sinfo->info;
@@ -2173,8 +2268,8 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
          if (h->dynindx == -1)
            return TRUE;
 
-         amt = sizeof *t;
-         t = (struct bfd_elf_version_tree *) bfd_zalloc (info->output_bfd, amt);
+         t = (struct bfd_elf_version_tree *) bfd_zalloc (info->output_bfd,
+                                                         sizeof *t);
          if (t == NULL)
            {
              sinfo->failed = TRUE;
@@ -2204,7 +2299,8 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
        {
          /* We could not find the version for a symbol when
             generating a shared archive.  Return an error.  */
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: version node not found for symbol %s"),
             info->output_bfd, h->root.root.string);
          bfd_set_error (bfd_error_bad_value);
@@ -2292,22 +2388,25 @@ elf_link_read_relocs_from_section (bfd *abfd,
        {
          if ((size_t) r_symndx >= nsyms)
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
                   " for offset 0x%lx in section `%A'"),
-                abfd, sec,
-                (unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
+                abfd, (unsigned long) r_symndx, (unsigned long) nsyms,
+                irela->r_offset, sec);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
            }
        }
       else if (r_symndx != STN_UNDEF)
        {
-         (*_bfd_error_handler)
-           (_("%B: non-zero symbol index (0x%lx) for offset 0x%lx in section `%A'"
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%B: non-zero symbol index (0x%lx)"
+              " for offset 0x%lx in section `%A'"
               " when the object file has no symbol table"),
-            abfd, sec,
-            (unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
+            abfd, (unsigned long) r_symndx, (unsigned long) nsyms,
+            irela->r_offset, sec);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }
@@ -2351,8 +2450,7 @@ _bfd_elf_link_read_relocs (bfd *abfd,
     {
       bfd_size_type size;
 
-      size = o->reloc_count;
-      size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
+      size = (bfd_size_type) o->reloc_count * sizeof (Elf_Internal_Rela);
       if (keep_memory)
        internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
       else
@@ -2493,7 +2591,8 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
     }
   else
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
+       /* xgettext:c-format */
        (_("%B: relocation size mismatch in %B section %A"),
         output_bfd, input_section->owner, input_section);
       bfd_set_error (bfd_error_wrong_format);
@@ -2621,18 +2720,35 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
       && (h->root.u.def.section->owner->flags & (DYNAMIC | BFD_PLUGIN)) == 0)
     h->def_regular = 1;
 
+  /* If a weak undefined symbol has non-default visibility, we also
+     hide it from the dynamic linker.  */
+  if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+      && h->root.type == bfd_link_hash_undefweak)
+    (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
+
+  /* A hidden versioned symbol in executable should be forced local if
+     it is is locally defined, not referenced by shared library and not
+     exported.  */
+  else if (bfd_link_executable (eif->info)
+          && h->versioned == versioned_hidden
+          && !eif->info->export_dynamic
+          && !h->dynamic
+          && !h->ref_dynamic
+          && h->def_regular)
+    (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
+
   /* If -Bsymbolic was used (which means to bind references to global
      symbols to the definition within the shared object), and this
      symbol was defined in a regular object, then it actually doesn't
      need a PLT entry.  Likewise, if the symbol has non-default
      visibility.  If the symbol has hidden or internal visibility, we
      will force it local.  */
-  if (h->needs_plt
-      && bfd_link_pic (eif->info)
-      && is_elf_hash_table (eif->info->hash)
-      && (SYMBOLIC_BIND (eif->info, h)
-         || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
-      && h->def_regular)
+  else if (h->needs_plt
+          && bfd_link_pic (eif->info)
+          && is_elf_hash_table (eif->info->hash)
+          && (SYMBOLIC_BIND (eif->info, h)
+              || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+          && h->def_regular)
     {
       bfd_boolean force_local;
 
@@ -2641,12 +2757,6 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
       (*bed->elf_backend_hide_symbol) (eif->info, h, force_local);
     }
 
-  /* If a weak undefined symbol has non-default visibility, we also
-     hide it from the dynamic linker.  */
-  if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-      && h->root.type == bfd_link_hash_undefweak)
-    (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
-
   /* If this is a weak defined symbol in a dynamic object, and we know
      the real definition in the dynamic object, copy interesting flags
      over to the real definition.  */
@@ -2698,6 +2808,24 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
   if (! _bfd_elf_fix_symbol_flags (h, eif))
     return FALSE;
 
+  if (h->root.type == bfd_link_hash_undefweak)
+    {
+      if (eif->info->dynamic_undefined_weak == 0)
+       _bfd_elf_link_hash_hide_symbol (eif->info, h, TRUE);
+      else if (eif->info->dynamic_undefined_weak > 0
+              && h->ref_regular
+              && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+              && !bfd_hide_sym_by_version (eif->info->version_info,
+                                           h->root.root.string))
+       {
+         if (!bfd_elf_link_record_dynamic_symbol (eif->info, h))
+           {
+             eif->failed = TRUE;
+             return FALSE;
+           }
+       }
+    }
+
   /* If this symbol does not require a PLT entry, and it is not
      defined by a dynamic object, or is not referenced by a regular
      object, ignore it.  We do have to handle a weak defined symbol,
@@ -2775,7 +2903,7 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
   if (h->size == 0
       && h->type == STT_NOTYPE
       && !h->needs_plt)
-    (*_bfd_error_handler)
+    _bfd_error_handler
       (_("warning: type and size of dynamic symbol `%s' are not defined"),
        h->root.root.string);
 
@@ -2940,10 +3068,10 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
    to resolve local to the current module, and false otherwise.  Differs
    from (the inverse of) _bfd_elf_dynamic_symbol_p in the treatment of
    undefined symbols.  The two functions are virtually identical except
-   for the place where forced_local and dynindx == -1 are tested.  If
-   either of those tests are true, _bfd_elf_dynamic_symbol_p will say
-   the symbol is local, while _bfd_elf_symbol_refs_local_p will say
-   the symbol is local only for defined symbols.
+   for the place where dynindx == -1 is tested.  If that test is true,
+   _bfd_elf_dynamic_symbol_p will say the symbol is local, while
+   _bfd_elf_symbol_refs_local_p will say the symbol is local only for
+   defined symbols.
    It might seem that _bfd_elf_dynamic_symbol_p could be rewritten as
    !_bfd_elf_symbol_refs_local_p, except that targets differ in their
    treatment of undefined weak symbols.  For those that do not make
@@ -2966,6 +3094,10 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
       || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
     return TRUE;
 
+  /* Forced local symbols resolve locally.  */
+  if (h->forced_local)
+    return TRUE;
+
   /* Common symbols that become definitions don't get the DEF_REGULAR
      flag set, so test it first, and don't bail out.  */
   if (ELF_COMMON_DEF_P (h))
@@ -2975,11 +3107,7 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
   else if (!h->def_regular)
     return FALSE;
 
-  /* Forced local symbols resolve locally.  */
-  if (h->forced_local)
-    return TRUE;
-
-  /* As do non-dynamic symbols.  */
+  /* Non-dynamic symbols resolve locally.  */
   if (h->dynindx == -1)
     return TRUE;
 
@@ -3092,9 +3220,9 @@ static bfd_boolean
 elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
 {
   Elf_Internal_Shdr * hdr;
-  bfd_size_type symcount;
-  bfd_size_type extsymcount;
-  bfd_size_type extsymoff;
+  size_t symcount;
+  size_t extsymcount;
+  size_t extsymoff;
   Elf_Internal_Sym *isymbuf;
   Elf_Internal_Sym *isym;
   Elf_Internal_Sym *isymend;
@@ -3104,15 +3232,25 @@ 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;
 
-  /* Select the appropriate symbol table.  */
-  if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
+  /* Select the appropriate symbol table.  If we don't know if the
+     object file is an IR object, give linker LTO plugin a chance to
+     get the correct symbol table.  */
+  if (abfd->plugin_format == bfd_plugin_yes
+#if BFD_SUPPORTS_PLUGINS
+      || (abfd->plugin_format == bfd_plugin_unknown
+         && bfd_link_plugin_object_p (abfd))
+#endif
+      )
+    {
+      /* Use the IR symbol table if the object has been claimed by
+        plugin.  */
+      abfd = abfd->plugin_dummy_bfd;
+      hdr = &elf_tdata (abfd)->symtab_hdr;
+    }
+  else if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
     hdr = &elf_tdata (abfd)->symtab_hdr;
   else
     hdr = &elf_tdata (abfd)->dynsymtab_hdr;
@@ -3212,14 +3350,14 @@ elf_add_dt_needed_tag (bfd *abfd,
                       bfd_boolean do_it)
 {
   struct elf_link_hash_table *hash_table;
-  bfd_size_type strindex;
+  size_t strindex;
 
   if (!_bfd_elf_link_create_dynstrtab (abfd, info))
     return -1;
 
   hash_table = elf_hash_table (info);
   strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
-  if (strindex == (bfd_size_type) -1)
+  if (strindex == (size_t) -1)
     return -1;
 
   if (_bfd_elf_strtab_refcount (hash_table->dynstr, strindex) != 1)
@@ -3387,7 +3525,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
     {
       asection *s;
       bfd_byte *p;
-      bfd_size_type i;
+      size_t i;
       Elf_Internal_Verdef def;
       Elf_Internal_Verdaux defaux;
 
@@ -3419,7 +3557,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
     {
       asection *s;
       bfd_byte *p;
-      bfd_size_type i;
+      size_t i;
       Elf_Internal_Verneed need;
       Elf_Internal_Vernaux needaux;
 
@@ -3569,16 +3707,16 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 {
   Elf_Internal_Ehdr *ehdr;
   Elf_Internal_Shdr *hdr;
-  bfd_size_type symcount;
-  bfd_size_type extsymcount;
-  bfd_size_type extsymoff;
+  size_t symcount;
+  size_t extsymcount;
+  size_t extsymoff;
   struct elf_link_hash_entry **sym_hash;
   bfd_boolean dynamic;
   Elf_External_Versym *extversym = NULL;
   Elf_External_Versym *ever;
   struct elf_link_hash_entry *weaks;
   struct elf_link_hash_entry **nondeflt_vers = NULL;
-  bfd_size_type nondeflt_vers_cnt = 0;
+  size_t nondeflt_vers_cnt = 0;
   Elf_Internal_Sym *isymbuf = NULL;
   Elf_Internal_Sym *isym;
   Elf_Internal_Sym *isymend;
@@ -3594,8 +3732,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   void *old_ent;
   struct bfd_link_hash_entry *old_undefs = NULL;
   struct bfd_link_hash_entry *old_undefs_tail = NULL;
-  long old_dynsymcount = 0;
-  bfd_size_type old_dynstr_size = 0;
+  void *old_strtab = NULL;
   size_t tabsize = 0;
   asection *s;
   bfd_boolean just_syms;
@@ -3632,6 +3769,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          || (bed->elf_machine_alt2 != 0
              && ehdr->e_machine == bed->elf_machine_alt2)))
     info->callbacks->einfo
+      /* xgettext:c-format */
       (_("%P: alternate ELF machine code found (%d) in %B, expecting %d\n"),
        ehdr->e_machine, abfd, bed->elf_machine_code);
 
@@ -3718,6 +3856,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       if (!just_syms
          && (bfd_link_pic (info)
              || (!bfd_link_relocatable (info)
+                 && info->nointerp
                  && (info->export_dynamic || info->dynamic)))
          && is_elf_hash_table (htab)
          && info->output_bfd->xvec == abfd->xvec
@@ -3734,6 +3873,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       const char *soname = NULL;
       char *audit = NULL;
       struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
+      const Elf_Internal_Phdr *phdr;
       int ret;
 
       /* ld --just-symbols and dynamic objects don't mix very well.
@@ -3883,6 +4023,21 @@ error_free_dyn:
          *pn = rpath;
        }
 
+      /* If we have a PT_GNU_RELRO program header, mark as read-only
+        all sections contained fully therein.  This makes relro
+        shared library sections appear as they will at run-time.  */
+      phdr = elf_tdata (abfd)->phdr + elf_elfheader (abfd)->e_phnum;
+      while (--phdr >= elf_tdata (abfd)->phdr)
+       if (phdr->p_type == PT_GNU_RELRO)
+         {
+           for (s = abfd->sections; s != NULL; s = s->next)
+             if ((s->flags & SEC_ALLOC) != 0
+                 && s->vma >= phdr->p_vaddr
+                 && s->vma + s->size <= phdr->p_vaddr + phdr->p_memsz)
+               s->flags |= SEC_READONLY;
+           break;
+         }
+
       /* We do not want to include any of the sections in a dynamic
         object in the output file.  We hack by simply clobbering the
         list of sections in the BFD.  This could be handled more
@@ -3960,7 +4115,8 @@ error_free_dyn:
        {
          /* We store a pointer to the hash table entry for each
             external symbol.  */
-         amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+         amt = extsymcount;
+         amt *= sizeof (struct elf_link_hash_entry *);
          sym_hash = (struct elf_link_hash_entry **) bfd_zalloc (abfd, amt);
          if (sym_hash == NULL)
            goto error_free_sym;
@@ -4039,8 +4195,9 @@ error_free_dyn:
       old_table = htab->root.table.table;
       old_size = htab->root.table.size;
       old_count = htab->root.table.count;
-      old_dynsymcount = htab->dynsymcount;
-      old_dynstr_size = _bfd_elf_strtab_size (htab->dynstr);
+      old_strtab = _bfd_elf_strtab_save (htab->dynstr);
+      if (old_strtab == NULL)
+       goto error_free_vers;
 
       for (i = 0; i < htab->root.table.size; i++)
        {
@@ -4082,6 +4239,7 @@ error_free_dyn:
       bfd_boolean old_weak;
       bfd_boolean override;
       bfd_boolean common;
+      bfd_boolean discarded;
       unsigned int old_alignment;
       bfd *old_bfd;
       bfd_boolean matched;
@@ -4092,6 +4250,7 @@ error_free_dyn:
       sec = NULL;
       value = isym->st_value;
       common = bed->common_definition (isym);
+      discarded = FALSE;
 
       bind = ELF_ST_BIND (isym->st_info);
       switch (bind)
@@ -4142,6 +4301,7 @@ error_free_dyn:
              /* Symbols from discarded section are undefined.  We keep
                 its visibility.  */
              sec = bfd_und_section_ptr;
+             discarded = TRUE;
              isym->st_shndx = SHN_UNDEF;
            }
          else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
@@ -4269,7 +4429,8 @@ error_free_dyn:
 
                  if (verstr == NULL)
                    {
-                     (*_bfd_error_handler)
+                     _bfd_error_handler
+                       /* xgettext:c-format */
                        (_("%B: %s: invalid version %u (max %d)"),
                         abfd, name, vernum,
                         elf_tdata (abfd)->cverdefs);
@@ -4305,7 +4466,8 @@ error_free_dyn:
                    }
                  if (verstr == NULL)
                    {
-                     (*_bfd_error_handler)
+                     _bfd_error_handler
+                       /* xgettext:c-format */
                        (_("%B: %s: invalid needed version %d"),
                         abfd, name, vernum);
                      bfd_set_error (bfd_error_bad_value);
@@ -4377,6 +4539,11 @@ error_free_dyn:
              (struct bfd_link_hash_entry **) sym_hash)))
        goto error_free_vers;
 
+      if ((flags & BSF_GNU_UNIQUE)
+         && (abfd->flags & DYNAMIC) == 0
+         && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+       elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_unique;
+
       h = *sym_hash;
       /* We need to make sure that indirect symbol dynamic flags are
         updated.  */
@@ -4385,6 +4552,11 @@ error_free_dyn:
             || h->root.type == bfd_link_hash_warning)
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
+      /* Setting the index to -3 tells elf_link_output_extsym that
+        this symbol is defined in a discarded section.  */
+      if (discarded)
+       h->indx = -3;
+
       *sym_hash = h;
 
       new_weak = (flags & BSF_WEAK) != 0;
@@ -4522,7 +4694,8 @@ error_free_dyn:
 
              symbol_align = ffs (h->root.u.def.value) - 1;
              if (h->root.u.def.section->owner != NULL
-                 && (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
+                 && (h->root.u.def.section->owner->flags
+                      & (DYNAMIC | BFD_PLUGIN)) == 0)
                {
                  normal_align = h->root.u.def.section->alignment_power;
                  if (normal_align > symbol_align)
@@ -4548,17 +4721,19 @@ error_free_dyn:
                {
                  /* PR binutils/2735 */
                  if (normal_bfd == NULL)
-                   (*_bfd_error_handler)
+                   _bfd_error_handler
+                     /* xgettext:c-format */
                      (_("Warning: alignment %u of common symbol `%s' in %B is"
                         " greater than the alignment (%u) of its section %A"),
-                      common_bfd, h->root.u.def.section,
-                      1 << common_align, name, 1 << normal_align);
+                      1 << common_align, name, common_bfd,
+                      1 << normal_align, h->root.u.def.section);
                  else
-                   (*_bfd_error_handler)
+                   _bfd_error_handler
+                     /* xgettext:c-format */
                      (_("Warning: alignment %u of symbol `%s' in %B"
                         " is smaller than %u in %B"),
-                      normal_bfd, common_bfd,
-                      1 << normal_align, name, 1 << common_align);
+                      1 << normal_align, name, normal_bfd,
+                      1 << common_align, common_bfd);
                }
            }
 
@@ -4570,12 +4745,12 @@ error_free_dyn:
              if (h->size != 0
                  && h->size != isym->st_size
                  && ! size_change_ok)
-               (*_bfd_error_handler)
+               _bfd_error_handler
+                 /* xgettext:c-format */
                  (_("Warning: size of symbol `%s' changed"
                     " from %lu in %B to %lu in %B"),
-                  old_bfd, abfd,
-                  name, (unsigned long) h->size,
-                  (unsigned long) isym->st_size);
+                  name, (unsigned long) h->size, old_bfd,
+                  (unsigned long) isym->st_size, abfd);
 
              h->size = isym->st_size;
            }
@@ -4605,10 +4780,11 @@ error_free_dyn:
              if (h->type != type)
                {
                  if (h->type != STT_NOTYPE && ! type_change_ok)
-                   (*_bfd_error_handler)
+                   /* xgettext:c-format */
+                   _bfd_error_handler
                      (_("Warning: type of symbol `%s' changed"
                         " from %d to %d in %B"),
-                      abfd, name, h->type, type);
+                      name, h->type, type, abfd);
 
                  h->type = type;
                }
@@ -4706,7 +4882,8 @@ error_free_dyn:
              if (old_bfd != NULL
                  && (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0)
                {
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
+                   /* xgettext:c-format */
                    (_("%B: undefined reference to symbol '%s'"),
                     old_bfd, name);
                  bfd_set_error (bfd_error_missing_dso);
@@ -4752,22 +4929,22 @@ error_free_dyn:
       memcpy (htab->root.table.table, old_tab, tabsize);
       htab->root.undefs = old_undefs;
       htab->root.undefs_tail = old_undefs_tail;
-      _bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size);
+      _bfd_elf_strtab_restore (htab->dynstr, old_strtab);
+      free (old_strtab);
+      old_strtab = NULL;
       for (i = 0; i < htab->root.table.size; i++)
        {
          struct bfd_hash_entry *p;
          struct elf_link_hash_entry *h;
          bfd_size_type size;
          unsigned int alignment_power;
+         unsigned int non_ir_ref_dynamic;
 
          for (p = htab->root.table.table[i]; p != NULL; p = p->next)
            {
              h = (struct elf_link_hash_entry *) p;
              if (h->root.type == bfd_link_hash_warning)
                h = (struct elf_link_hash_entry *) h->root.u.i.link;
-             if (h->dynindx >= old_dynsymcount
-                 && h->dynstr_index < old_dynstr_size)
-               _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index);
 
              /* Preserve the maximum alignment and size for common
                 symbols even if this dynamic lib isn't on DT_NEEDED
@@ -4783,6 +4960,10 @@ error_free_dyn:
                  size = 0;
                  alignment_power = 0;
                }
+             /* Preserve non_ir_ref_dynamic so that this symbol
+                will be exported when the dynamic lib becomes needed
+                in the second pass.  */
+             non_ir_ref_dynamic = h->root.non_ir_ref_dynamic;
              memcpy (p, old_ent, htab->root.table.entsize);
              old_ent = (char *) old_ent + htab->root.table.entsize;
              h = (struct elf_link_hash_entry *) p;
@@ -4799,6 +4980,7 @@ error_free_dyn:
                  if (alignment_power > h->root.u.c.p->alignment_power)
                    h->root.u.c.p->alignment_power = alignment_power;
                }
+             h->root.non_ir_ref_dynamic = non_ir_ref_dynamic;
            }
        }
 
@@ -4828,7 +5010,7 @@ error_free_dyn:
      such that any relocs against foo become foo@BAR.  */
   if (!bfd_link_relocatable (info) && nondeflt_vers != NULL)
     {
-      bfd_size_type cnt, symidx;
+      size_t cnt, symidx;
 
       for (cnt = 0; cnt < nondeflt_vers_cnt; ++cnt)
        {
@@ -4899,7 +5081,8 @@ error_free_dyn:
       /* Since we have to search the whole symbol list for each weak
         defined symbol, search time for N weak defined symbols will be
         O(N^2). Binary search will cut it down to O(NlogN).  */
-      amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+      amt = extsymcount;
+      amt *= sizeof (struct elf_link_hash_entry *);
       sorted_sym_hash = (struct elf_link_hash_entry **) bfd_malloc (amt);
       if (sorted_sym_hash == NULL)
        goto error_return;
@@ -5089,6 +5272,8 @@ error_free_dyn:
  error_free_vers:
   if (old_tab != NULL)
     free (old_tab);
+  if (old_strtab != NULL)
+    free (old_strtab);
   if (nondeflt_vers != NULL)
     free (nondeflt_vers);
   if (extversym != NULL)
@@ -5270,7 +5455,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
 
          if (!(*info->callbacks
                ->add_archive_element) (info, element, symdef->name, &element))
-           goto error_return;
+           continue;
          if (!bfd_link_add_symbols (element, info))
            goto error_return;
 
@@ -5708,11 +5893,13 @@ bfd_elf_stack_segment_size (bfd *output_bfd,
       /* The symbol has no type if specified on the command line.  */
       h->type = STT_OBJECT;
       if (info->stacksize)
-       (*_bfd_error_handler) (_("%B: stack size specified and %s set"),
-                              output_bfd, legacy_symbol);
+       /* xgettext:c-format */
+       _bfd_error_handler (_("%B: stack size specified and %s set"),
+                           output_bfd, legacy_symbol);
       else if (h->root.u.def.section != bfd_abs_section_ptr)
-       (*_bfd_error_handler) (_("%B: %s not absolute"),
-                              output_bfd, legacy_symbol);
+       /* xgettext:c-format */
+       _bfd_error_handler (_("%B: %s not absolute"),
+                           output_bfd, legacy_symbol);
       else
        info->stacksize = h->root.u.def.value;
     }
@@ -5743,6 +5930,38 @@ bfd_elf_stack_segment_size (bfd *output_bfd,
   return TRUE;
 }
 
+/* Sweep symbols in swept sections.  Called via elf_link_hash_traverse.  */
+
+struct elf_gc_sweep_symbol_info
+{
+  struct bfd_link_info *info;
+  void (*hide_symbol) (struct bfd_link_info *, struct elf_link_hash_entry *,
+                      bfd_boolean);
+};
+
+static bfd_boolean
+elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
+{
+  if (!h->mark
+      && (((h->root.type == bfd_link_hash_defined
+           || h->root.type == bfd_link_hash_defweak)
+          && !((h->def_regular || ELF_COMMON_DEF_P (h))
+               && h->root.u.def.section->gc_mark))
+         || h->root.type == bfd_link_hash_undefined
+         || h->root.type == bfd_link_hash_undefweak))
+    {
+      struct elf_gc_sweep_symbol_info *inf;
+
+      inf = (struct elf_gc_sweep_symbol_info *) data;
+      (*inf->hide_symbol) (inf->info, h, TRUE);
+      h->def_regular = 0;
+      h->ref_regular = 0;
+      h->ref_regular_nonweak = 0;
+    }
+
+  return TRUE;
+}
+
 /* Set up the sizes and contents of the ELF dynamic sections.  This is
    called by the ELF linker emulation before_allocation routine.  We
    must set the sizes of the sections before the linker sets the
@@ -5759,201 +5978,69 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                               struct bfd_link_info *info,
                               asection **sinterpptr)
 {
-  bfd_size_type soname_indx;
   bfd *dynobj;
   const struct elf_backend_data *bed;
-  struct elf_info_failed asvinfo;
 
   *sinterpptr = NULL;
 
-  soname_indx = (bfd_size_type) -1;
-
   if (!is_elf_hash_table (info->hash))
     return TRUE;
 
-  bed = get_elf_backend_data (output_bfd);
-
-  /* Any syms created from now on start with -1 in
-     got.refcount/offset and plt.refcount/offset.  */
-  elf_hash_table (info)->init_got_refcount
-    = elf_hash_table (info)->init_got_offset;
-  elf_hash_table (info)->init_plt_refcount
-    = elf_hash_table (info)->init_plt_offset;
-
-  if (bfd_link_relocatable (info)
-      && !_bfd_elf_size_group_sections (info))
-    return FALSE;
-
-  /* The backend may have to create some sections regardless of whether
-     we're dynamic or not.  */
-  if (bed->elf_backend_always_size_sections
-      && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
-    return FALSE;
-
-  /* Determine any GNU_STACK segment requirements, after the backend
-     has had a chance to set a default segment size.  */
-  if (info->execstack)
-    elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
-  else if (info->noexecstack)
-    elf_stack_flags (output_bfd) = PF_R | PF_W;
-  else
-    {
-      bfd *inputobj;
-      asection *notesec = NULL;
-      int exec = 0;
-
-      for (inputobj = info->input_bfds;
-          inputobj;
-          inputobj = inputobj->link.next)
-       {
-         asection *s;
-
-         if (inputobj->flags
-             & (DYNAMIC | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED))
-           continue;
-         s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
-         if (s)
-           {
-             if (s->flags & SEC_CODE)
-               exec = PF_X;
-             notesec = s;
-           }
-         else if (bed->default_execstack)
-           exec = PF_X;
-       }
-      if (notesec || info->stacksize > 0)
-       elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
-      if (notesec && exec && bfd_link_relocatable (info)
-         && notesec->output_section != bfd_abs_section_ptr)
-       notesec->output_section->flags |= SEC_CODE;
-    }
-
   dynobj = elf_hash_table (info)->dynobj;
 
   if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
-      struct elf_info_failed eif;
-      struct elf_link_hash_entry *h;
-      asection *dynstr;
+      struct bfd_elf_version_tree *verdefs;
+      struct elf_info_failed asvinfo;
       struct bfd_elf_version_tree *t;
       struct bfd_elf_version_expr *d;
-      asection *s;
+      struct elf_info_failed eif;
       bfd_boolean all_defined;
+      asection *s;
+      size_t soname_indx;
 
-      *sinterpptr = bfd_get_linker_section (dynobj, ".interp");
-      BFD_ASSERT (*sinterpptr != NULL || !bfd_link_executable (info) || info->nointerp);
+      eif.info = info;
+      eif.failed = FALSE;
 
-      if (soname != NULL)
+      /* 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
+         || (bfd_link_executable (info) && info->dynamic))
        {
-         soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                            soname, TRUE);
-         if (soname_indx == (bfd_size_type) -1
-             || !_bfd_elf_add_dynamic_entry (info, DT_SONAME, soname_indx))
+         elf_link_hash_traverse (elf_hash_table (info),
+                                 _bfd_elf_export_symbol,
+                                 &eif);
+         if (eif.failed)
            return FALSE;
        }
 
-      if (info->symbolic)
+      if (soname != NULL)
        {
-         if (!_bfd_elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
+         soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                            soname, TRUE);
+         if (soname_indx == (size_t) -1
+             || !_bfd_elf_add_dynamic_entry (info, DT_SONAME, soname_indx))
            return FALSE;
-         info->flags |= DF_SYMBOLIC;
        }
+      else
+       soname_indx = (size_t) -1;
 
-      if (rpath != NULL)
-       {
-         bfd_size_type indx;
-         bfd_vma tag;
+      /* Make all global versions with definition.  */
+      for (t = info->version_info; t != NULL; t = t->next)
+       for (d = t->globals.list; d != NULL; d = d->next)
+         if (!d->symver && d->literal)
+           {
+             const char *verstr, *name;
+             size_t namelen, verlen, newlen;
+             char *newname, *p, leading_char;
+             struct elf_link_hash_entry *newh;
 
-         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
-                                     TRUE);
-         if (indx == (bfd_size_type) -1)
-           return FALSE;
-
-         tag = info->new_dtags ? DT_RUNPATH : DT_RPATH;
-         if (!_bfd_elf_add_dynamic_entry (info, tag, indx))
-           return FALSE;
-       }
-
-      if (filter_shlib != NULL)
-       {
-         bfd_size_type indx;
-
-         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                     filter_shlib, TRUE);
-         if (indx == (bfd_size_type) -1
-             || !_bfd_elf_add_dynamic_entry (info, DT_FILTER, indx))
-           return FALSE;
-       }
-
-      if (auxiliary_filters != NULL)
-       {
-         const char * const *p;
-
-         for (p = auxiliary_filters; *p != NULL; p++)
-           {
-             bfd_size_type indx;
-
-             indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                         *p, TRUE);
-             if (indx == (bfd_size_type) -1
-                 || !_bfd_elf_add_dynamic_entry (info, DT_AUXILIARY, indx))
-               return FALSE;
-           }
-       }
-
-      if (audit != NULL)
-       {
-         bfd_size_type indx;
-
-         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, audit,
-                                     TRUE);
-         if (indx == (bfd_size_type) -1
-             || !_bfd_elf_add_dynamic_entry (info, DT_AUDIT, indx))
-           return FALSE;
-       }
-
-      if (depaudit != NULL)
-       {
-         bfd_size_type indx;
-
-         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, depaudit,
-                                     TRUE);
-         if (indx == (bfd_size_type) -1
-             || !_bfd_elf_add_dynamic_entry (info, DT_DEPAUDIT, indx))
-           return FALSE;
-       }
-
-      eif.info = info;
-      eif.failed = FALSE;
-
-      /* 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
-         || (bfd_link_executable (info) && info->dynamic))
-       {
-         elf_link_hash_traverse (elf_hash_table (info),
-                                 _bfd_elf_export_symbol,
-                                 &eif);
-         if (eif.failed)
-           return FALSE;
-       }
-
-      /* Make all global versions with definition.  */
-      for (t = info->version_info; t != NULL; t = t->next)
-       for (d = t->globals.list; d != NULL; d = d->next)
-         if (!d->symver && d->literal)
-           {
-             const char *verstr, *name;
-             size_t namelen, verlen, newlen;
-             char *newname, *p, leading_char;
-             struct elf_link_hash_entry *newh;
-
-             leading_char = bfd_get_symbol_leading_char (output_bfd);
-             name = d->pattern;
-             namelen = strlen (name) + (leading_char != '\0');
-             verstr = t->name;
-             verlen = strlen (verstr);
-             newlen = namelen + verlen + 3;
+             leading_char = bfd_get_symbol_leading_char (output_bfd);
+             name = d->pattern;
+             namelen = strlen (name) + (leading_char != '\0');
+             verstr = t->name;
+             verlen = strlen (verstr);
+             newlen = namelen + verlen + 3;
 
              newname = (char *) bfd_malloc (newlen);
              if (newname == NULL)
@@ -6008,7 +6095,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            for (d = t->globals.list; d != NULL; d = d->next)
              if (d->literal && !d->symver && !d->script)
                {
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
                    (_("%s: undefined version: %s"),
                     d->pattern, t->name);
                  all_defined = FALSE;
@@ -6021,129 +6108,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            }
        }
 
-      /* Find all symbols which were defined in a dynamic object and make
-        the backend pick a reasonable value for them.  */
-      elf_link_hash_traverse (elf_hash_table (info),
-                             _bfd_elf_adjust_dynamic_symbol,
-                             &eif);
-      if (eif.failed)
-       return FALSE;
-
-      /* Add some entries to the .dynamic section.  We fill in some of the
-        values later, in bfd_elf_final_link, but we must add the entries
-        now so that we know the final size of the .dynamic section.  */
-
-      /* If there are initialization and/or finalization functions to
-        call then add the corresponding DT_INIT/DT_FINI entries.  */
-      h = (info->init_function
-          ? elf_link_hash_lookup (elf_hash_table (info),
-                                  info->init_function, FALSE,
-                                  FALSE, FALSE)
-          : NULL);
-      if (h != NULL
-         && (h->ref_regular
-             || h->def_regular))
-       {
-         if (!_bfd_elf_add_dynamic_entry (info, DT_INIT, 0))
-           return FALSE;
-       }
-      h = (info->fini_function
-          ? elf_link_hash_lookup (elf_hash_table (info),
-                                  info->fini_function, FALSE,
-                                  FALSE, FALSE)
-          : NULL);
-      if (h != NULL
-         && (h->ref_regular
-             || h->def_regular))
-       {
-         if (!_bfd_elf_add_dynamic_entry (info, DT_FINI, 0))
-           return FALSE;
-       }
-
-      s = bfd_get_section_by_name (output_bfd, ".preinit_array");
-      if (s != NULL && s->linker_has_input)
-       {
-         /* DT_PREINIT_ARRAY is not allowed in shared library.  */
-         if (! bfd_link_executable (info))
-           {
-             bfd *sub;
-             asection *o;
-
-             for (sub = info->input_bfds; sub != NULL;
-                  sub = sub->link.next)
-               if (bfd_get_flavour (sub) == bfd_target_elf_flavour)
-                 for (o = sub->sections; o != NULL; o = o->next)
-                   if (elf_section_data (o)->this_hdr.sh_type
-                       == SHT_PREINIT_ARRAY)
-                     {
-                       (*_bfd_error_handler)
-                         (_("%B: .preinit_array section is not allowed in DSO"),
-                          sub);
-                       break;
-                     }
-
-             bfd_set_error (bfd_error_nonrepresentable_section);
-             return FALSE;
-           }
-
-         if (!_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAY, 0)
-             || !_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAYSZ, 0))
-           return FALSE;
-       }
-      s = bfd_get_section_by_name (output_bfd, ".init_array");
-      if (s != NULL && s->linker_has_input)
-       {
-         if (!_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAY, 0)
-             || !_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAYSZ, 0))
-           return FALSE;
-       }
-      s = bfd_get_section_by_name (output_bfd, ".fini_array");
-      if (s != NULL && s->linker_has_input)
-       {
-         if (!_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAY, 0)
-             || !_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAYSZ, 0))
-           return FALSE;
-       }
-
-      dynstr = bfd_get_linker_section (dynobj, ".dynstr");
-      /* If .dynstr is excluded from the link, we don't want any of
-        these tags.  Strictly, we should be checking each section
-        individually;  This quick check covers for the case where
-        someone does a /DISCARD/ : { *(*) }.  */
-      if (dynstr != NULL && dynstr->output_section != bfd_abs_section_ptr)
-       {
-         bfd_size_type strsize;
-
-         strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
-         if ((info->emit_hash
-              && !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0))
-             || (info->emit_gnu_hash
-                 && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0))
-             || !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0)
-             || !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0)
-             || !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize)
-             || !_bfd_elf_add_dynamic_entry (info, DT_SYMENT,
-                                             bed->s->sizeof_sym))
-           return FALSE;
-       }
-    }
-
-  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
-      && bed->elf_backend_size_dynamic_sections != NULL
-      && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
-    return FALSE;
-
-  if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
-    {
-      unsigned long section_sym_count;
-      struct bfd_elf_version_tree *verdefs;
-      asection *s;
-
       /* Set up the version definition section.  */
       s = bfd_get_linker_section (dynobj, ".gnu.version_d");
       BFD_ASSERT (s != NULL);
@@ -6162,7 +6126,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        {
          unsigned int cdefs;
          bfd_size_type size;
-         struct bfd_elf_version_tree *t;
          bfd_byte *p;
          Elf_Internal_Verdef def;
          Elf_Internal_Verdaux defaux;
@@ -6226,7 +6189,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                             + sizeof (Elf_External_Verdaux));
            }
 
-         if (soname_indx != (bfd_size_type) -1)
+         if (soname_indx != (size_t) -1)
            {
              _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
                                      soname_indx);
@@ -6236,13 +6199,13 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            }
          else
            {
-             bfd_size_type indx;
+             size_t indx;
 
              name = lbasename (output_bfd->filename);
              def.vd_hash = bfd_elf_hash (name);
              indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                          name, FALSE);
-             if (indx == (bfd_size_type) -1)
+             if (indx == (size_t) -1)
                return FALSE;
              defaux.vda_name = indx;
            }
@@ -6378,34 +6341,9 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                }
            }
 
-         if (!_bfd_elf_add_dynamic_entry (info, DT_VERDEF, 0)
-             || !_bfd_elf_add_dynamic_entry (info, DT_VERDEFNUM, cdefs))
-           return FALSE;
-
          elf_tdata (output_bfd)->cverdefs = cdefs;
        }
 
-      if ((info->new_dtags && info->flags) || (info->flags & DF_STATIC_TLS))
-       {
-         if (!_bfd_elf_add_dynamic_entry (info, DT_FLAGS, info->flags))
-           return FALSE;
-       }
-      else if (info->flags & DF_BIND_NOW)
-       {
-         if (!_bfd_elf_add_dynamic_entry (info, DT_BIND_NOW, 0))
-           return FALSE;
-       }
-
-      if (info->flags_1)
-       {
-         if (bfd_link_executable (info))
-           info->flags_1 &= ~ (DF_1_INITFIRST
-                               | DF_1_NODELETE
-                               | DF_1_NOOPEN);
-         if (!_bfd_elf_add_dynamic_entry (info, DT_FLAGS_1, info->flags_1))
-           return FALSE;
-       }
-
       /* Work out the size of the version reference section.  */
 
       s = bfd_get_linker_section (dynobj, ".gnu.version_r");
@@ -6429,7 +6367,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
          s->flags |= SEC_EXCLUDE;
        else
          {
-           Elf_Internal_Verneed *t;
+           Elf_Internal_Verneed *vn;
            unsigned int size;
            unsigned int crefs;
            bfd_byte *p;
@@ -6437,15 +6375,15 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            /* Build the version dependency section.  */
            size = 0;
            crefs = 0;
-           for (t = elf_tdata (output_bfd)->verref;
-                t != NULL;
-                t = t->vn_nextref)
+           for (vn = elf_tdata (output_bfd)->verref;
+                vn != NULL;
+                vn = vn->vn_nextref)
              {
                Elf_Internal_Vernaux *a;
 
                size += sizeof (Elf_External_Verneed);
                ++crefs;
-               for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+               for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
                  size += sizeof (Elf_External_Vernaux);
              }
 
@@ -6455,71 +6393,392 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
              return FALSE;
 
            p = s->contents;
-           for (t = elf_tdata (output_bfd)->verref;
-                t != NULL;
-                t = t->vn_nextref)
+           for (vn = elf_tdata (output_bfd)->verref;
+                vn != NULL;
+                vn = vn->vn_nextref)
              {
                unsigned int caux;
                Elf_Internal_Vernaux *a;
-               bfd_size_type indx;
+               size_t indx;
 
                caux = 0;
-               for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+               for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
                  ++caux;
 
-               t->vn_version = VER_NEED_CURRENT;
-               t->vn_cnt = caux;
+               vn->vn_version = VER_NEED_CURRENT;
+               vn->vn_cnt = caux;
                indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                           elf_dt_name (t->vn_bfd) != NULL
-                                           ? elf_dt_name (t->vn_bfd)
-                                           : lbasename (t->vn_bfd->filename),
+                                           elf_dt_name (vn->vn_bfd) != NULL
+                                           ? elf_dt_name (vn->vn_bfd)
+                                           : lbasename (vn->vn_bfd->filename),
                                            FALSE);
-               if (indx == (bfd_size_type) -1)
+               if (indx == (size_t) -1)
                  return FALSE;
-               t->vn_file = indx;
-               t->vn_aux = sizeof (Elf_External_Verneed);
-               if (t->vn_nextref == NULL)
-                 t->vn_next = 0;
+               vn->vn_file = indx;
+               vn->vn_aux = sizeof (Elf_External_Verneed);
+               if (vn->vn_nextref == NULL)
+                 vn->vn_next = 0;
                else
-                 t->vn_next = (sizeof (Elf_External_Verneed)
+                 vn->vn_next = (sizeof (Elf_External_Verneed)
                                + caux * sizeof (Elf_External_Vernaux));
 
-               _bfd_elf_swap_verneed_out (output_bfd, t,
+               _bfd_elf_swap_verneed_out (output_bfd, vn,
                                           (Elf_External_Verneed *) p);
                p += sizeof (Elf_External_Verneed);
 
-               for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
-                 {
-                   a->vna_hash = bfd_elf_hash (a->vna_nodename);
-                   indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                               a->vna_nodename, FALSE);
-                   if (indx == (bfd_size_type) -1)
-                     return FALSE;
-                   a->vna_name = indx;
-                   if (a->vna_nextptr == NULL)
-                     a->vna_next = 0;
-                   else
-                     a->vna_next = sizeof (Elf_External_Vernaux);
+               for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
+                 {
+                   a->vna_hash = bfd_elf_hash (a->vna_nodename);
+                   indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                               a->vna_nodename, FALSE);
+                   if (indx == (size_t) -1)
+                     return FALSE;
+                   a->vna_name = indx;
+                   if (a->vna_nextptr == NULL)
+                     a->vna_next = 0;
+                   else
+                     a->vna_next = sizeof (Elf_External_Vernaux);
+
+                   _bfd_elf_swap_vernaux_out (output_bfd, a,
+                                              (Elf_External_Vernaux *) p);
+                   p += sizeof (Elf_External_Vernaux);
+                 }
+             }
+
+           elf_tdata (output_bfd)->cverrefs = crefs;
+         }
+      }
+    }
+
+  bed = get_elf_backend_data (output_bfd);
+
+  if (info->gc_sections && bed->can_gc_sections)
+    {
+      struct elf_gc_sweep_symbol_info sweep_info;
+      unsigned long section_sym_count;
+
+      /* Remove the symbols that were in the swept sections from the
+        dynamic symbol table.  GCFIXME: Anyone know how to get them
+        out of the static symbol table as well?  */
+      sweep_info.info = info;
+      sweep_info.hide_symbol = bed->elf_backend_hide_symbol;
+      elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol,
+                             &sweep_info);
+
+      /* We need to reassign dynsym indices now that symbols may have
+        been removed.  See the call in `bfd_elf_size_dynsym_hash_dynstr'
+        for the details of the conditions used here.  */
+      if (elf_hash_table (info)->dynamic_sections_created
+         || bed->always_renumber_dynsyms)
+       _bfd_elf_link_renumber_dynsyms (output_bfd, info, &section_sym_count);
+    }
+
+  /* Any syms created from now on start with -1 in
+     got.refcount/offset and plt.refcount/offset.  */
+  elf_hash_table (info)->init_got_refcount
+    = elf_hash_table (info)->init_got_offset;
+  elf_hash_table (info)->init_plt_refcount
+    = elf_hash_table (info)->init_plt_offset;
+
+  if (bfd_link_relocatable (info)
+      && !_bfd_elf_size_group_sections (info))
+    return FALSE;
+
+  /* The backend may have to create some sections regardless of whether
+     we're dynamic or not.  */
+  if (bed->elf_backend_always_size_sections
+      && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
+    return FALSE;
+
+  /* Determine any GNU_STACK segment requirements, after the backend
+     has had a chance to set a default segment size.  */
+  if (info->execstack)
+    elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
+  else if (info->noexecstack)
+    elf_stack_flags (output_bfd) = PF_R | PF_W;
+  else
+    {
+      bfd *inputobj;
+      asection *notesec = NULL;
+      int exec = 0;
+
+      for (inputobj = info->input_bfds;
+          inputobj;
+          inputobj = inputobj->link.next)
+       {
+         asection *s;
+
+         if (inputobj->flags
+             & (DYNAMIC | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED))
+           continue;
+         s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
+         if (s)
+           {
+             if (s->flags & SEC_CODE)
+               exec = PF_X;
+             notesec = s;
+           }
+         else if (bed->default_execstack)
+           exec = PF_X;
+       }
+      if (notesec || info->stacksize > 0)
+       elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
+      if (notesec && exec && bfd_link_relocatable (info)
+         && notesec->output_section != bfd_abs_section_ptr)
+       notesec->output_section->flags |= SEC_CODE;
+    }
+
+  if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
+    {
+      struct elf_info_failed eif;
+      struct elf_link_hash_entry *h;
+      asection *dynstr;
+      asection *s;
+
+      *sinterpptr = bfd_get_linker_section (dynobj, ".interp");
+      BFD_ASSERT (*sinterpptr != NULL || !bfd_link_executable (info) || info->nointerp);
+
+      if (info->symbolic)
+       {
+         if (!_bfd_elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
+           return FALSE;
+         info->flags |= DF_SYMBOLIC;
+       }
+
+      if (rpath != NULL)
+       {
+         size_t indx;
+         bfd_vma tag;
+
+         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
+                                     TRUE);
+         if (indx == (size_t) -1)
+           return FALSE;
+
+         tag = info->new_dtags ? DT_RUNPATH : DT_RPATH;
+         if (!_bfd_elf_add_dynamic_entry (info, tag, indx))
+           return FALSE;
+       }
+
+      if (filter_shlib != NULL)
+       {
+         size_t indx;
+
+         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                     filter_shlib, TRUE);
+         if (indx == (size_t) -1
+             || !_bfd_elf_add_dynamic_entry (info, DT_FILTER, indx))
+           return FALSE;
+       }
+
+      if (auxiliary_filters != NULL)
+       {
+         const char * const *p;
+
+         for (p = auxiliary_filters; *p != NULL; p++)
+           {
+             size_t indx;
+
+             indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                         *p, TRUE);
+             if (indx == (size_t) -1
+                 || !_bfd_elf_add_dynamic_entry (info, DT_AUXILIARY, indx))
+               return FALSE;
+           }
+       }
+
+      if (audit != NULL)
+       {
+         size_t indx;
+
+         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, audit,
+                                     TRUE);
+         if (indx == (size_t) -1
+             || !_bfd_elf_add_dynamic_entry (info, DT_AUDIT, indx))
+           return FALSE;
+       }
+
+      if (depaudit != NULL)
+       {
+         size_t indx;
+
+         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, depaudit,
+                                     TRUE);
+         if (indx == (size_t) -1
+             || !_bfd_elf_add_dynamic_entry (info, DT_DEPAUDIT, indx))
+           return FALSE;
+       }
+
+      eif.info = info;
+      eif.failed = FALSE;
+
+      /* Find all symbols which were defined in a dynamic object and make
+        the backend pick a reasonable value for them.  */
+      elf_link_hash_traverse (elf_hash_table (info),
+                             _bfd_elf_adjust_dynamic_symbol,
+                             &eif);
+      if (eif.failed)
+       return FALSE;
+
+      /* Add some entries to the .dynamic section.  We fill in some of the
+        values later, in bfd_elf_final_link, but we must add the entries
+        now so that we know the final size of the .dynamic section.  */
+
+      /* If there are initialization and/or finalization functions to
+        call then add the corresponding DT_INIT/DT_FINI entries.  */
+      h = (info->init_function
+          ? elf_link_hash_lookup (elf_hash_table (info),
+                                  info->init_function, FALSE,
+                                  FALSE, FALSE)
+          : NULL);
+      if (h != NULL
+         && (h->ref_regular
+             || h->def_regular))
+       {
+         if (!_bfd_elf_add_dynamic_entry (info, DT_INIT, 0))
+           return FALSE;
+       }
+      h = (info->fini_function
+          ? elf_link_hash_lookup (elf_hash_table (info),
+                                  info->fini_function, FALSE,
+                                  FALSE, FALSE)
+          : NULL);
+      if (h != NULL
+         && (h->ref_regular
+             || h->def_regular))
+       {
+         if (!_bfd_elf_add_dynamic_entry (info, DT_FINI, 0))
+           return FALSE;
+       }
+
+      s = bfd_get_section_by_name (output_bfd, ".preinit_array");
+      if (s != NULL && s->linker_has_input)
+       {
+         /* DT_PREINIT_ARRAY is not allowed in shared library.  */
+         if (! bfd_link_executable (info))
+           {
+             bfd *sub;
+             asection *o;
+
+             for (sub = info->input_bfds; sub != NULL;
+                  sub = sub->link.next)
+               if (bfd_get_flavour (sub) == bfd_target_elf_flavour)
+                 for (o = sub->sections; o != NULL; o = o->next)
+                   if (elf_section_data (o)->this_hdr.sh_type
+                       == SHT_PREINIT_ARRAY)
+                     {
+                       _bfd_error_handler
+                         (_("%B: .preinit_array section is not allowed in DSO"),
+                          sub);
+                       break;
+                     }
+
+             bfd_set_error (bfd_error_nonrepresentable_section);
+             return FALSE;
+           }
+
+         if (!_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAY, 0)
+             || !_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAYSZ, 0))
+           return FALSE;
+       }
+      s = bfd_get_section_by_name (output_bfd, ".init_array");
+      if (s != NULL && s->linker_has_input)
+       {
+         if (!_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAY, 0)
+             || !_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAYSZ, 0))
+           return FALSE;
+       }
+      s = bfd_get_section_by_name (output_bfd, ".fini_array");
+      if (s != NULL && s->linker_has_input)
+       {
+         if (!_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAY, 0)
+             || !_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAYSZ, 0))
+           return FALSE;
+       }
+
+      dynstr = bfd_get_linker_section (dynobj, ".dynstr");
+      /* If .dynstr is excluded from the link, we don't want any of
+        these tags.  Strictly, we should be checking each section
+        individually;  This quick check covers for the case where
+        someone does a /DISCARD/ : { *(*) }.  */
+      if (dynstr != NULL && dynstr->output_section != bfd_abs_section_ptr)
+       {
+         bfd_size_type strsize;
+
+         strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
+         if ((info->emit_hash
+              && !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0))
+             || (info->emit_gnu_hash
+                 && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0))
+             || !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0)
+             || !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0)
+             || !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize)
+             || !_bfd_elf_add_dynamic_entry (info, DT_SYMENT,
+                                             bed->s->sizeof_sym))
+           return FALSE;
+       }
+    }
+
+  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
+      && bed->elf_backend_size_dynamic_sections != NULL
+      && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
+    return FALSE;
+
+  if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
+    {
+      unsigned long section_sym_count;
+
+      if (elf_tdata (output_bfd)->cverdefs)
+       {
+         unsigned int crefs = elf_tdata (output_bfd)->cverdefs;
+
+         if (!_bfd_elf_add_dynamic_entry (info, DT_VERDEF, 0)
+             || !_bfd_elf_add_dynamic_entry (info, DT_VERDEFNUM, crefs))
+           return FALSE;
+       }
+
+      if ((info->new_dtags && info->flags) || (info->flags & DF_STATIC_TLS))
+       {
+         if (!_bfd_elf_add_dynamic_entry (info, DT_FLAGS, info->flags))
+           return FALSE;
+       }
+      else if (info->flags & DF_BIND_NOW)
+       {
+         if (!_bfd_elf_add_dynamic_entry (info, DT_BIND_NOW, 0))
+           return FALSE;
+       }
 
-                   _bfd_elf_swap_vernaux_out (output_bfd, a,
-                                              (Elf_External_Vernaux *) p);
-                   p += sizeof (Elf_External_Vernaux);
-                 }
-             }
+      if (info->flags_1)
+       {
+         if (bfd_link_executable (info))
+           info->flags_1 &= ~ (DF_1_INITFIRST
+                               | DF_1_NODELETE
+                               | DF_1_NOOPEN);
+         if (!_bfd_elf_add_dynamic_entry (info, DT_FLAGS_1, info->flags_1))
+           return FALSE;
+       }
 
-           if (!_bfd_elf_add_dynamic_entry (info, DT_VERNEED, 0)
-               || !_bfd_elf_add_dynamic_entry (info, DT_VERNEEDNUM, crefs))
-             return FALSE;
+      if (elf_tdata (output_bfd)->cverrefs)
+       {
+         unsigned int crefs = elf_tdata (output_bfd)->cverrefs;
 
-           elf_tdata (output_bfd)->cverrefs = crefs;
-         }
-      }
+         if (!_bfd_elf_add_dynamic_entry (info, DT_VERNEED, 0)
+             || !_bfd_elf_add_dynamic_entry (info, DT_VERNEEDNUM, crefs))
+           return FALSE;
+       }
 
       if ((elf_tdata (output_bfd)->cverrefs == 0
           && elf_tdata (output_bfd)->cverdefs == 0)
          || _bfd_elf_link_renumber_dynsyms (output_bfd, info,
                                             &section_sym_count) == 0)
        {
+         asection *s;
+
          s = bfd_get_linker_section (dynobj, ".gnu.version");
          s->flags |= SEC_EXCLUDE;
        }
@@ -6578,6 +6837,8 @@ bfd_boolean
 bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
 {
   const struct elf_backend_data *bed;
+  unsigned long section_sym_count;
+  bfd_size_type dynsymcount;
 
   if (!is_elf_hash_table (info->hash))
     return TRUE;
@@ -6585,24 +6846,30 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
   bed = get_elf_backend_data (output_bfd);
   (*bed->elf_backend_init_index_section) (output_bfd, info);
 
+  /* Assign dynsym indices.  In a shared library we generate a section
+     symbol for each output section, which come first.  Next come all
+     of the back-end allocated local dynamic syms, followed by the rest
+     of the global symbols.
+
+     This is usually not needed for static binaries, however backends
+     can request to always do it, e.g. the MIPS backend uses dynamic
+     symbol counts to lay out GOT, which will be produced in the
+     presence of GOT relocations even in static binaries (holding fixed
+     data in that case, to satisfy those relocations).  */
+
+  if (elf_hash_table (info)->dynamic_sections_created
+      || bed->always_renumber_dynsyms)
+    dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info,
+                                                 &section_sym_count);
+
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       bfd *dynobj;
       asection *s;
-      bfd_size_type dynsymcount;
-      unsigned long section_sym_count;
       unsigned int dtagcount;
 
       dynobj = elf_hash_table (info)->dynobj;
 
-      /* Assign dynsym indicies.  In a shared library we generate a
-        section symbol for each output section, which come first.
-        Next come all of the back-end allocated local dynamic syms,
-        followed by the rest of the global symbols.  */
-
-      dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info,
-                                                   &section_sym_count);
-
       /* Work out the size of the symbol version section.  */
       s = bfd_get_linker_section (dynobj, ".gnu.version");
       BFD_ASSERT (s != NULL);
@@ -6974,18 +7241,15 @@ _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 if DIR isn't a hidden versioned
-     symbol.  */
+     symbol which just became indirect.  */
 
   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;
-    }
+    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;
@@ -7036,9 +7300,10 @@ _bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
       h->forced_local = 1;
       if (h->dynindx != -1)
        {
-         h->dynindx = -1;
          _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
                                  h->dynstr_index);
+         h->dynindx = -1;
+         h->dynstr_index = 0;
        }
     }
 }
@@ -7272,7 +7537,7 @@ struct elf_symbuf_symbol
 struct elf_symbuf_head
 {
   struct elf_symbuf_symbol *ssym;
-  bfd_size_type count;
+  size_t count;
   unsigned int st_shndx;
 };
 
@@ -7306,12 +7571,12 @@ elf_sym_name_compare (const void *arg1, const void *arg2)
 }
 
 static struct elf_symbuf_head *
-elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
+elf_create_symbuf (size_t symcount, Elf_Internal_Sym *isymbuf)
 {
   Elf_Internal_Sym **ind, **indbufend, **indbuf;
   struct elf_symbuf_symbol *ssym;
   struct elf_symbuf_head *ssymbuf, *ssymhead;
-  bfd_size_type i, shndx_count, total_size;
+  size_t i, shndx_count, total_size;
 
   indbuf = (Elf_Internal_Sym **) bfd_malloc2 (symcount, sizeof (*indbuf));
   if (indbuf == NULL)
@@ -7358,7 +7623,7 @@ elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
       ssym->st_other = (*ind)->st_other;
       ssymhead->count++;
     }
-  BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count
+  BFD_ASSERT ((size_t) (ssymhead - ssymbuf) == shndx_count
              && (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf)
                  == total_size));
 
@@ -7376,12 +7641,12 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
   bfd *bfd1, *bfd2;
   const struct elf_backend_data *bed1, *bed2;
   Elf_Internal_Shdr *hdr1, *hdr2;
-  bfd_size_type symcount1, symcount2;
+  size_t symcount1, symcount2;
   Elf_Internal_Sym *isymbuf1, *isymbuf2;
   struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
   Elf_Internal_Sym *isym, *isymend;
   struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
-  bfd_size_type count1, count2, i;
+  size_t count1, count2, i;
   unsigned int shndx1, shndx2;
   bfd_boolean result;
 
@@ -7444,7 +7709,7 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
   if (ssymbuf1 != NULL && ssymbuf2 != NULL)
     {
       /* Optimized faster version.  */
-      bfd_size_type lo, hi, mid;
+      size_t lo, hi, mid;
       struct elf_symbol *symp;
       struct elf_symbuf_symbol *ssym, *ssymend;
 
@@ -7842,6 +8107,7 @@ resolve_section (const char *name,
 static void
 undefined_reference (const char *reftype, const char *name)
 {
+  /* xgettext:c-format */
   _bfd_error_handler (_("undefined %s reference in complex symbol: %s"),
                      reftype, name);
 }
@@ -7888,6 +8154,7 @@ eval_symbol (bfd_vma *result,
 
     case 'S':
       symbol_is_section = TRUE;
+      /* Fall through.  */
     case 's':
       ++sym;
       symlen = strtol (sym, (char **) symp, 10);
@@ -8278,6 +8545,7 @@ ext64b_r_offset (const void *p)
 
 static bfd_boolean
 elf_link_adjust_relocs (bfd *abfd,
+                       asection *sec,
                        struct bfd_elf_section_reloc_data *reldata,
                        bfd_boolean sort)
 {
@@ -8336,6 +8604,9 @@ elf_link_adjust_relocs (bfd *abfd,
       (*swap_out) (abfd, irela, erela);
     }
 
+  if (bed->elf_backend_update_relocs)
+    (*bed->elf_backend_update_relocs) (sec, reldata);
+
   if (sort && count != 0)
     {
       bfd_vma (*ext_r_off) (const void *);
@@ -8518,6 +8789,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
   struct elf_link_sort_rela *sq;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   int i2e = bed->s->int_rels_per_ext_rel;
+  unsigned int opb = bfd_octets_per_byte (abfd);
   void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *);
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
   struct bfd_link_order *lo;
@@ -8533,7 +8805,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
       bfd_boolean use_rela_initialised = FALSE;
 
       /* This is just here to stop gcc from complaining.
-        It's initialization checking code is not perfect.  */
+        Its initialization checking code is not perfect.  */
       use_rela = TRUE;
 
       /* Both sections are present.  Examine the sizes
@@ -8552,10 +8824,11 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
                else
                  {
                    /* Section size is only divisible by rela.  */
-                   if (use_rela_initialised && (use_rela == FALSE))
+                   if (use_rela_initialised && !use_rela)
                      {
-                       _bfd_error_handler
-                         (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+                       _bfd_error_handler (_("%B: Unable to sort relocs - "
+                                             "they are in more than one size"),
+                                           abfd);
                        bfd_set_error (bfd_error_invalid_operation);
                        return 0;
                      }
@@ -8569,10 +8842,11 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
            else if ((o->size % bed->s->sizeof_rel) == 0)
              {
                /* Section size is only divisible by rel.  */
-               if (use_rela_initialised && (use_rela == TRUE))
+               if (use_rela_initialised && use_rela)
                  {
-                   _bfd_error_handler
-                     (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+                   _bfd_error_handler (_("%B: Unable to sort relocs - "
+                                         "they are in more than one size"),
+                                       abfd);
                    bfd_set_error (bfd_error_invalid_operation);
                    return 0;
                  }
@@ -8584,9 +8858,10 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
              }
            else
              {
-               /* The section size is not divisible by either - something is wrong.  */
-               _bfd_error_handler
-                 (_("%B: Unable to sort relocs - they are of an unknown size"), abfd);
+               /* The section size is not divisible by either -
+                  something is wrong.  */
+               _bfd_error_handler (_("%B: Unable to sort relocs - "
+                                     "they are of an unknown size"), abfd);
                bfd_set_error (bfd_error_invalid_operation);
                return 0;
              }
@@ -8606,10 +8881,11 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
                else
                  {
                    /* Section size is only divisible by rela.  */
-                   if (use_rela_initialised && (use_rela == FALSE))
+                   if (use_rela_initialised && !use_rela)
                      {
-                       _bfd_error_handler
-                         (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+                       _bfd_error_handler (_("%B: Unable to sort relocs - "
+                                             "they are in more than one size"),
+                                           abfd);
                        bfd_set_error (bfd_error_invalid_operation);
                        return 0;
                      }
@@ -8623,10 +8899,11 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
            else if ((o->size % bed->s->sizeof_rel) == 0)
              {
                /* Section size is only divisible by rel.  */
-               if (use_rela_initialised && (use_rela == TRUE))
+               if (use_rela_initialised && use_rela)
                  {
-                   _bfd_error_handler
-                     (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+                   _bfd_error_handler (_("%B: Unable to sort relocs - "
+                                         "they are in more than one size"),
+                                       abfd);
                    bfd_set_error (bfd_error_invalid_operation);
                    return 0;
                  }
@@ -8638,9 +8915,10 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
              }
            else
              {
-               /* The section size is not divisible by either - something is wrong.  */
-               _bfd_error_handler
-                 (_("%B: Unable to sort relocs - they are of an unknown size"), abfd);
+               /* The section size is not divisible by either -
+                  something is wrong.  */
+               _bfd_error_handler (_("%B: Unable to sort relocs - "
+                                     "they are of an unknown size"), abfd);
                bfd_set_error (bfd_error_invalid_operation);
                return 0;
              }
@@ -8716,8 +8994,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
          }
        erel = o->contents;
        erelend = o->contents + o->size;
-       /* FIXME: octets_per_byte.  */
-       p = sort + o->output_offset / ext_size * sort_elt;
+       p = sort + o->output_offset * opb / ext_size * sort_elt;
 
        while (erel < erelend)
          {
@@ -8753,6 +9030,35 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
 
   qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2);
 
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+  if (htab->srelplt && htab->srelplt->output_section == dynamic_relocs)
+    {
+      /* We have plt relocs in .rela.dyn.  */
+      sq = (struct elf_link_sort_rela *) sort;
+      for (i = 0; i < count; i++)
+       if (sq[count - i - 1].type != reloc_class_plt)
+         break;
+      if (i != 0 && htab->srelplt->size == i * ext_size)
+       {
+         struct bfd_link_order **plo;
+         /* Put srelplt link_order last.  This is so the output_offset
+            set in the next loop is correct for DT_JMPREL.  */
+         for (plo = &dynamic_relocs->map_head.link_order; *plo != NULL; )
+           if ((*plo)->type == bfd_indirect_link_order
+               && (*plo)->u.indirect.section == htab->srelplt)
+             {
+               lo = *plo;
+               *plo = lo->next;
+             }
+           else
+             plo = &(*plo)->next;
+         *plo = lo;
+         lo->next = NULL;
+         dynamic_relocs->map_tail.link_order = lo;
+       }
+    }
+
+  p = sort;
   for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next)
     if (lo->type == bfd_indirect_link_order)
       {
@@ -8761,8 +9067,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
 
        erel = o->contents;
        erelend = o->contents + o->size;
-       /* FIXME: octets_per_byte.  */
-       p = sort + o->output_offset / ext_size * sort_elt;
+       o->output_offset = (p - sort) / sort_elt * ext_size / opb;
        while (erel < erelend)
          {
            struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
@@ -8851,7 +9156,8 @@ 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;
+  bfd_size_type amt;
+  size_t i;
   const struct elf_backend_data *bed;
   bfd_byte *symbuf;
   Elf_Internal_Shdr *hdr;
@@ -8872,8 +9178,8 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
 
   if (flinfo->symshndxbuf)
     {
-      amt = (sizeof (Elf_External_Sym_Shndx)
-            * (bfd_get_symcount (flinfo->output_bfd)));
+      amt = sizeof (Elf_External_Sym_Shndx);
+      amt *= bfd_get_symcount (flinfo->output_bfd);
       flinfo->symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
       if (flinfo->symshndxbuf == NULL)
        {
@@ -8929,7 +9235,8 @@ check_dynsym (bfd *abfd, Elf_Internal_Sym *sym)
     {
       /* The gABI doesn't support dynamic symbols in output sections
         beyond 64k.  */
-      (*_bfd_error_handler)
+      _bfd_error_handler
+       /* xgettext:c-format */
        (_("%B: Too many sections: %d (>= %d)"),
         abfd, bfd_count_sections (abfd), SHN_LORESERVE & 0xffff);
       bfd_set_error (bfd_error_nonrepresentable_section);
@@ -8968,7 +9275,8 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
     case bfd_link_hash_undefined:
     case bfd_link_hash_undefweak:
       abfd = h->root.u.undef.abfd;
-      if ((abfd->flags & DYNAMIC) == 0
+      if (abfd == NULL
+         || (abfd->flags & DYNAMIC) == 0
          || (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) == 0)
        return FALSE;
       break;
@@ -8990,9 +9298,9 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
     {
       bfd *input;
       Elf_Internal_Shdr *hdr;
-      bfd_size_type symcount;
-      bfd_size_type extsymcount;
-      bfd_size_type extsymoff;
+      size_t symcount;
+      size_t extsymcount;
+      size_t extsymoff;
       Elf_Internal_Shdr *versymhdr;
       Elf_Internal_Sym *isym;
       Elf_Internal_Sym *isymend;
@@ -9136,16 +9444,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
   long indx;
   int ret;
   unsigned int type;
-  /* 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)
     {
@@ -9157,12 +9455,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 (!local_bind)
+      if (!h->forced_local)
        return TRUE;
     }
   else
     {
-      if (local_bind)
+      if (h->forced_local)
        return TRUE;
     }
 
@@ -9188,19 +9486,15 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
          && (!h->ref_regular || flinfo->info->gc_sections)
          && !elf_link_check_versioned_symbol (flinfo->info, bed, h)
          && flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
-       {
-         if (!(flinfo->info->callbacks->undefined_symbol
-               (flinfo->info, h->root.root.string,
-                h->ref_regular ? NULL : h->root.u.undef.abfd,
-                NULL, 0,
-                (flinfo->info->unresolved_syms_in_shared_libs
-                 == RM_GENERATE_ERROR))))
-           {
-             bfd_set_error (bfd_error_bad_value);
-             eoinfo->failed = TRUE;
-             return FALSE;
-           }
-       }
+       (*flinfo->info->callbacks->undefined_symbol)
+         (flinfo->info, h->root.root.string,
+          h->ref_regular ? NULL : h->root.u.undef.abfd,
+          NULL, 0,
+          flinfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR);
+
+      /* Strip a global symbol defined in a discarded section.  */
+      if (h->indx == -3)
+       return TRUE;
     }
 
   /* We should also warn if a forced local symbol is referenced from
@@ -9222,16 +9516,19 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
        hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
 
       if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
+       /* xgettext:c-format */
        msg = _("%B: internal symbol `%s' in %B is referenced by DSO");
       else if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+       /* xgettext:c-format */
        msg = _("%B: hidden symbol `%s' in %B is referenced by DSO");
       else
+       /* xgettext:c-format */
        msg = _("%B: local symbol `%s' in %B is referenced by DSO");
       def_bfd = flinfo->output_bfd;
       if (hi->root.u.def.section != bfd_abs_section_ptr)
        def_bfd = hi->root.u.def.section->owner;
-      (*_bfd_error_handler) (msg, flinfo->output_bfd, def_bfd,
-                            h->root.root.string);
+      _bfd_error_handler (msg, flinfo->output_bfd,
+                         h->root.root.string, def_bfd);
       bfd_set_error (bfd_error_bad_value);
       eoinfo->failed = TRUE;
       return FALSE;
@@ -9310,7 +9607,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
                                                 input_sec->output_section);
            if (sym.st_shndx == SHN_BAD)
              {
-               (*_bfd_error_handler)
+               _bfd_error_handler
+                 /* xgettext:c-format */
                  (_("%B: could not find output section %A for input section %A"),
                   flinfo->output_bfd, input_sec->output_section, input_sec);
                bfd_set_error (bfd_error_nonrepresentable_section);
@@ -9379,7 +9677,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
        abort ();
       }
 
-  if (local_bind)
+  if (h->forced_local)
     {
       sym.st_info = ELF_ST_INFO (STB_LOCAL, type);
       /* Turn off visibility on local symbol.  */
@@ -9464,12 +9762,15 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
       const char *msg;
 
       if (ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED)
+       /* xgettext:c-format */
        msg = _("%B: protected symbol `%s' isn't defined");
       else if (ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL)
+       /* xgettext:c-format */
        msg = _("%B: internal symbol `%s' isn't defined");
       else
+       /* xgettext:c-format */
        msg = _("%B: hidden symbol `%s' isn't defined");
-      (*_bfd_error_handler) (msg, flinfo->output_bfd, h->root.root.string);
+      _bfd_error_handler (msg, flinfo->output_bfd, h->root.root.string);
       bfd_set_error (bfd_error_bad_value);
       eoinfo->failed = TRUE;
       return FALSE;
@@ -9487,10 +9788,8 @@ 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 not linking executable, referenced
-        by shared library, not locally defined, or not bound locally.
-      */
+        by shared library, or not bound locally.  */
       if (h->verinfo.verdef == NULL
-         && !local_bind
          && (!bfd_link_executable (flinfo->info)
              || h->ref_dynamic
              || !h->def_regular))
@@ -9499,7 +9798,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 
          if (p && p [1] != '\0')
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: No symbol version section for versioned symbol `%s'"),
                 flinfo->output_bfd, h->root.root.string);
              eoinfo->failed = TRUE;
@@ -9977,7 +10277,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
          continue;
        }
 
-      if (bfd_link_relocatable (flinfo->info)
+      if (!flinfo->info->resolve_section_groups
          && (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP)
        {
          /* Deal with the group signature symbol.  */
@@ -9985,6 +10285,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
          unsigned long symndx = sec_data->this_hdr.sh_info;
          asection *osec = o->output_section;
 
+         BFD_ASSERT (bfd_link_relocatable (flinfo->info));
          if (symndx >= locsymcount
              || (elf_bad_symtab (input_bfd)
                  && flinfo->sections[symndx] == NULL))
@@ -10101,9 +10402,11 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                                 ".fini_array") == 0))
              && (o->name[6] == 0 || o->name[6] == '.'))
            {
-             if (o->size != o->reloc_count * address_size)
+             if (o->size * bed->s->int_rels_per_ext_rel
+                 != o->reloc_count * address_size)
                {
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
+                   /* xgettext:c-format */
                    (_("error: %B: size of section %A is not "
                       "multiple of address size"),
                     input_bfd, o);
@@ -10124,7 +10427,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
             relocs against removed link-once sections.  */
 
          rel = internal_relocs;
-         relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
+         relend = rel + o->reloc_count;
          for ( ; rel < relend; rel++)
            {
              unsigned long r_symndx = rel->r_info >> r_sym_shift;
@@ -10150,10 +10453,11 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                      char buffer [32];
 
                      sprintf_vma (buffer, rel->r_info);
-                     (*_bfd_error_handler)
+                     _bfd_error_handler
+                       /* xgettext:c-format */
                        (_("error: %B contains a reloc (0x%s) for section %A "
                           "that references a non-existent global symbol"),
-                        input_bfd, o, buffer);
+                        input_bfd, buffer, o);
                      bfd_set_error (bfd_error_bad_value);
                      return FALSE;
                    }
@@ -10169,7 +10473,8 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                     linker may attach linker created dynamic sections
                     to the plugin bfd.  Symbols defined in linker
                     created sections are not plugin symbols.  */
-                 if (h->root.non_ir_ref
+                 if ((h->root.non_ir_ref_regular
+                      || h->root.non_ir_ref_dynamic)
                      && (h->root.type == bfd_link_hash_defined
                          || h->root.type == bfd_link_hash_defweak)
                      && (h->root.u.def.section->flags
@@ -10235,6 +10540,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                      BFD_ASSERT (r_symndx != STN_UNDEF);
                      if (action_discarded & COMPLAIN)
                        (*flinfo->info->callbacks->einfo)
+                         /* xgettext:c-format */
                          (_("%X`%s' referenced in section `%A' of %B: "
                             "defined in discarded section `%A' of %B\n"),
                           sym_name, o, input_bfd, sec, sec->owner);
@@ -10310,7 +10616,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              /* Adjust the reloc addresses and symbol indices.  */
 
              irela = internal_relocs;
-             irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
+             irelaend = irela + o->reloc_count;
              rel_hash = esdo->rel.hashes + esdo->rel.count;
              /* We start processing the REL relocs, if any.  When we reach
                 IRELAMID in the loop, we switch to the RELA relocs.  */
@@ -10710,9 +11016,8 @@ elf_reloc_link_order (bfd *output_bfd,
        }
       else
        {
-         if (! ((*info->callbacks->unattached_reloc)
-                (info, link_order->u.reloc.p->u.name, NULL, NULL, 0)))
-           return FALSE;
+         (*info->callbacks->unattached_reloc)
+           (info, link_order->u.reloc.p->u.name, NULL, NULL, 0);
          indx = 0;
        }
     }
@@ -10747,13 +11052,9 @@ elf_reloc_link_order (bfd *output_bfd,
                                         link_order->u.reloc.p->u.section);
          else
            sym_name = link_order->u.reloc.p->u.name;
-         if (! ((*info->callbacks->reloc_overflow)
-                (info, NULL, sym_name, howto->name, addend, NULL,
-                 NULL, (bfd_vma) 0)))
-           {
-             free (buf);
-             return FALSE;
-           }
+         (*info->callbacks->reloc_overflow) (info, NULL, sym_name,
+                                             howto->name, addend, NULL, NULL,
+                                             (bfd_vma) 0);
          break;
        }
 
@@ -10828,6 +11129,7 @@ elf_get_linked_section_vma (struct bfd_link_order *p)
        = get_elf_backend_data (s->owner);
       if (bed->link_order_error_handler)
        bed->link_order_error_handler
+         /* xgettext:c-format */
          (_("%B: warning: sh_link not set for section `%A'"), s->owner, s);
       return 0;
     }
@@ -10907,13 +11209,15 @@ elf_fixup_link_order (bfd *abfd, asection *o)
       if (seen_other && seen_linkorder)
        {
          if (other_sec && linkorder_sec)
-           (*_bfd_error_handler) (_("%A has both ordered [`%A' in %B] and unordered [`%A' in %B] sections"),
-                                  o, linkorder_sec,
-                                  linkorder_sec->owner, other_sec,
-                                  other_sec->owner);
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("%A has both ordered [`%A' in %B] "
+                "and unordered [`%A' in %B] sections"),
+              o, linkorder_sec, linkorder_sec->owner,
+              other_sec, other_sec->owner);
          else
-           (*_bfd_error_handler) (_("%A has both ordered and unordered sections"),
-                                  o);
+           _bfd_error_handler
+             (_("%A has both ordered and unordered sections"), o);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }
@@ -10951,6 +11255,109 @@ elf_fixup_link_order (bfd *abfd, asection *o)
   return TRUE;
 }
 
+/* Generate an import library in INFO->implib_bfd from symbols in ABFD.
+   Returns TRUE upon success, FALSE otherwise.  */
+
+static bfd_boolean
+elf_output_implib (bfd *abfd, struct bfd_link_info *info)
+{
+  bfd_boolean ret = FALSE;
+  bfd *implib_bfd;
+  const struct elf_backend_data *bed;
+  flagword flags;
+  enum bfd_architecture arch;
+  unsigned int mach;
+  asymbol **sympp = NULL;
+  long symsize;
+  long symcount;
+  long src_count;
+  elf_symbol_type *osymbuf;
+
+  implib_bfd = info->out_implib_bfd;
+  bed = get_elf_backend_data (abfd);
+
+  if (!bfd_set_format (implib_bfd, bfd_object))
+    return FALSE;
+
+  /* Use flag from executable but make it a relocatable object.  */
+  flags = bfd_get_file_flags (abfd);
+  flags &= ~HAS_RELOC;
+  if (!bfd_set_start_address (implib_bfd, 0)
+      || !bfd_set_file_flags (implib_bfd, flags & ~EXEC_P))
+    return FALSE;
+
+  /* Copy architecture of output file to import library file.  */
+  arch = bfd_get_arch (abfd);
+  mach = bfd_get_mach (abfd);
+  if (!bfd_set_arch_mach (implib_bfd, arch, mach)
+      && (abfd->target_defaulted
+         || bfd_get_arch (abfd) != bfd_get_arch (implib_bfd)))
+    return FALSE;
+
+  /* Get symbol table size.  */
+  symsize = bfd_get_symtab_upper_bound (abfd);
+  if (symsize < 0)
+    return FALSE;
+
+  /* Read in the symbol table.  */
+  sympp = (asymbol **) xmalloc (symsize);
+  symcount = bfd_canonicalize_symtab (abfd, sympp);
+  if (symcount < 0)
+    goto free_sym_buf;
+
+  /* Allow the BFD backend to copy any private header data it
+     understands from the output BFD to the import library BFD.  */
+  if (! bfd_copy_private_header_data (abfd, implib_bfd))
+    goto free_sym_buf;
+
+  /* Filter symbols to appear in the import library.  */
+  if (bed->elf_backend_filter_implib_symbols)
+    symcount = bed->elf_backend_filter_implib_symbols (abfd, info, sympp,
+                                                      symcount);
+  else
+    symcount = _bfd_elf_filter_global_symbols (abfd, info, sympp, symcount);
+  if (symcount == 0)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      _bfd_error_handler (_("%B: no symbol found for import library"),
+                         implib_bfd);
+      goto free_sym_buf;
+    }
+
+
+  /* Make symbols absolute.  */
+  osymbuf = (elf_symbol_type *) bfd_alloc2 (implib_bfd, symcount,
+                                           sizeof (*osymbuf));
+  for (src_count = 0; src_count < symcount; src_count++)
+    {
+      memcpy (&osymbuf[src_count], (elf_symbol_type *) sympp[src_count],
+             sizeof (*osymbuf));
+      osymbuf[src_count].symbol.section = bfd_abs_section_ptr;
+      osymbuf[src_count].internal_elf_sym.st_shndx = SHN_ABS;
+      osymbuf[src_count].symbol.value += sympp[src_count]->section->vma;
+      osymbuf[src_count].internal_elf_sym.st_value =
+       osymbuf[src_count].symbol.value;
+      sympp[src_count] = &osymbuf[src_count].symbol;
+    }
+
+  bfd_set_symtab (implib_bfd, sympp, symcount);
+
+  /* Allow the BFD backend to copy any private data it understands
+     from the output BFD to the import library BFD.  This is done last
+     to permit the routine to look at the filtered symbol table.  */
+  if (! bfd_copy_private_bfd_data (abfd, implib_bfd))
+    goto free_sym_buf;
+
+  if (!bfd_close (implib_bfd))
+    goto free_sym_buf;
+
+  ret = TRUE;
+
+free_sym_buf:
+  free (sympp);
+  return ret;
+}
+
 static void
 elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo)
 {
@@ -11016,15 +11423,16 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   asection *attr_section = NULL;
   bfd_vma attr_size = 0;
   const char *std_attrs_section;
+  struct elf_link_hash_table *htab = elf_hash_table (info);
 
-  if (! is_elf_hash_table (info->hash))
+  if (!is_elf_hash_table (htab))
     return FALSE;
 
   if (bfd_link_pic (info))
     abfd->flags |= DYNAMIC;
 
-  dynamic = elf_hash_table (info)->dynamic_sections_created;
-  dynobj = elf_hash_table (info)->dynobj;
+  dynamic = htab->dynamic_sections_created;
+  dynobj = htab->dynobj;
 
   emit_relocs = (bfd_link_relocatable (info)
                 || info->emitrelocations);
@@ -11121,7 +11529,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              asection *sec;
 
              sec = p->u.indirect.section;
-             esdi = elf_section_data (sec);
 
              /* Mark all sections which are to be included in the
                 link.  This will normally be every section.  We need
@@ -11132,37 +11539,18 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              if (sec->flags & SEC_MERGE)
                merged = TRUE;
 
-             if (esdo->this_hdr.sh_type == SHT_REL
-                 || esdo->this_hdr.sh_type == SHT_RELA)
-               /* Some backends use reloc_count in relocation sections
-                  to count particular types of relocs.  Of course,
-                  reloc sections themselves can't have relocations.  */
-               reloc_count = 0;
-             else if (emit_relocs)
-               {
-                 reloc_count = sec->reloc_count;
-                 if (bed->elf_backend_count_additional_relocs)
-                   {
-                     int c;
-                     c = (*bed->elf_backend_count_additional_relocs) (sec);
-                     additional_reloc_count += c;
-                   }
-               }
-             else if (bed->elf_backend_count_relocs)
-               reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
-
              if (sec->rawsize > max_contents_size)
                max_contents_size = sec->rawsize;
              if (sec->size > max_contents_size)
                max_contents_size = sec->size;
 
-             /* We are interested in just local symbols, not all
-                symbols.  */
              if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour
                  && (sec->owner->flags & DYNAMIC) == 0)
                {
                  size_t sym_count;
 
+                 /* We are interested in just local symbols, not all
+                    symbols.  */
                  if (elf_bad_symtab (sec->owner))
                    sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size
                                 / bed->s->sizeof_sym);
@@ -11176,6 +11564,27 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                      && elf_symtab_shndx_list (sec->owner) != NULL)
                    max_sym_shndx_count = sym_count;
 
+                 if (esdo->this_hdr.sh_type == SHT_REL
+                     || esdo->this_hdr.sh_type == SHT_RELA)
+                   /* Some backends use reloc_count in relocation sections
+                      to count particular types of relocs.  Of course,
+                      reloc sections themselves can't have relocations.  */
+                   ;
+                 else if (emit_relocs)
+                   {
+                     reloc_count = sec->reloc_count;
+                     if (bed->elf_backend_count_additional_relocs)
+                       {
+                         int c;
+                         c = (*bed->elf_backend_count_additional_relocs) (sec);
+                         additional_reloc_count += c;
+                       }
+                   }
+                 else if (bed->elf_backend_count_relocs)
+                   reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
+
+                 esdi = elf_section_data (sec);
+
                  if ((sec->flags & SEC_RELOC) != 0)
                    {
                      size_t ext_size = 0;
@@ -11241,8 +11650,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     }
 
   if (! bfd_link_relocatable (info) && merged)
-    elf_link_hash_traverse (elf_hash_table (info),
-                           _bfd_elf_link_sec_merge_syms, abfd);
+    elf_link_hash_traverse (htab, _bfd_elf_link_sec_merge_syms, abfd);
 
   /* Figure out the file positions for everything but the symbol table
      and the relocs.  We set symcount to force assign_section_numbers
@@ -11305,11 +11713,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   if (max_sym_count < 20)
     max_sym_count = 20;
-  elf_hash_table (info)->strtabsize = max_sym_count;
+  htab->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)
+  htab->strtab = (struct elf_sym_strtab *) bfd_malloc (amt);
+  if (htab->strtab == NULL)
     goto error_return;
   /* The real buffer will be allocated in elf_link_swap_symbols_out.  */
   flinfo.symshndxbuf
@@ -11383,8 +11790,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   if (max_internal_reloc_count != 0)
     {
-      amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
-      amt *= sizeof (Elf_Internal_Rela);
+      amt = max_internal_reloc_count * sizeof (Elf_Internal_Rela);
       flinfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
       if (flinfo.internal_relocs == NULL)
        goto error_return;
@@ -11421,12 +11827,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        goto error_return;
     }
 
-  if (elf_hash_table (info)->tls_sec)
+  if (htab->tls_sec)
     {
       bfd_vma base, end = 0;
       asection *sec;
 
-      for (sec = elf_hash_table (info)->tls_sec;
+      for (sec = htab->tls_sec;
           sec && (sec->flags & SEC_THREAD_LOCAL);
           sec = sec->next)
        {
@@ -11442,13 +11848,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            }
          end = sec->vma + size;
        }
-      base = elf_hash_table (info)->tls_sec->vma;
+      base = htab->tls_sec->vma;
       /* Only align end of TLS section if static TLS doesn't have special
         alignment requirements.  */
       if (bed->static_tls_alignment == 1)
-       end = align_power (end,
-                          elf_hash_table (info)->tls_sec->alignment_power);
-      elf_hash_table (info)->tls_size = end - base;
+       end = align_power (end, htab->tls_sec->alignment_power);
+      htab->tls_size = end - base;
     }
 
   /* Reorder SHF_LINK_ORDER sections.  */
@@ -11534,7 +11939,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                        }
 
                      bfd_set_error (bfd_error_wrong_format);
-                     (*_bfd_error_handler)
+                     _bfd_error_handler
+                       /* xgettext:c-format */
                        (_("%B: file class %s incompatible with %s"),
                         sub, iclass, oclass);
                    }
@@ -11595,17 +12001,18 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
   if (dynamic
-      && elf_hash_table (info)->dynsym != NULL
-      && (elf_hash_table (info)->dynsym->output_section
-         != bfd_abs_section_ptr))
+      && htab->dynsym != NULL
+      && htab->dynsym->output_section != bfd_abs_section_ptr)
     {
       Elf_Internal_Sym sym;
-      bfd_byte *dynsym = elf_hash_table (info)->dynsym->contents;
-      long last_local = 0;
+      bfd_byte *dynsym = htab->dynsym->contents;
+
+      o = htab->dynsym->output_section;
+      elf_section_data (o)->this_hdr.sh_info = htab->local_dynsymcount + 1;
 
       /* Write out the section symbols for the output sections.  */
       if (bfd_link_pic (info)
-         || elf_hash_table (info)->is_relocatable_executable)
+         || htab->is_relocatable_executable)
        {
          asection *s;
 
@@ -11631,17 +12038,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                return FALSE;
              sym.st_value = s->vma;
              dest = dynsym + dynindx * bed->s->sizeof_sym;
-             if (last_local < dynindx)
-               last_local = dynindx;
              bed->s->swap_symbol_out (abfd, &sym, dest, 0);
            }
        }
 
       /* Write out the local dynsyms.  */
-      if (elf_hash_table (info)->dynlocal)
+      if (htab->dynlocal)
        {
          struct elf_link_local_dynamic_entry *e;
-         for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
+         for (e = htab->dynlocal; e ; e = e->next)
            {
              asection *s;
              bfd_byte *dest;
@@ -11665,16 +12070,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                                  + e->isym.st_value);
                }
 
-             if (last_local < e->dynindx)
-               last_local = e->dynindx;
-
              dest = dynsym + e->dynindx * bed->s->sizeof_sym;
              bed->s->swap_symbol_out (abfd, &sym, dest, 0);
            }
        }
-
-      elf_section_data (elf_hash_table (info)->dynsym->output_section)->this_hdr.sh_info =
-       last_local + 1;
     }
 
   /* We get the global symbols from the hash table.  */
@@ -11712,24 +12111,28 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     {
       /* Finish up and write out the symbol string table (.strtab)
         section.  */
-      Elf_Internal_Shdr *symstrtab_hdr;
+      Elf_Internal_Shdr *symstrtab_hdr = NULL;
       file_ptr off = symtab_hdr->sh_offset + symtab_hdr->sh_size;
 
-      symtab_shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr;
-      if (symtab_shndx_hdr != NULL && symtab_shndx_hdr->sh_name != 0)
+      if (elf_symtab_shndx_list (abfd))
        {
-         symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
-         symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
-         symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
-         amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx);
-         symtab_shndx_hdr->sh_size = amt;
+         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);
+             symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+             amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx);
+             symtab_shndx_hdr->sh_size = amt;
 
-         off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr,
-                                                          off, TRUE);
+             off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr,
+                                                              off, TRUE);
 
-         if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
-             || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
-           return FALSE;
+             if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
+                 || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
+               return FALSE;
+           }
        }
 
       symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
@@ -11753,6 +12156,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        return FALSE;
     }
 
+  if (info->out_implib_bfd && !elf_output_implib (abfd, info))
+    {
+      _bfd_error_handler (_("%B: failed to generate import library"),
+                         info->out_implib_bfd);
+      return FALSE;
+    }
+
   /* Adjust the relocs to have the correct symbol indices.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
@@ -11763,10 +12173,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
       sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o);
       if (esdo->rel.hdr != NULL
-         && !elf_link_adjust_relocs (abfd, &esdo->rel, sort))
+         && !elf_link_adjust_relocs (abfd, o, &esdo->rel, sort))
        return FALSE;
       if (esdo->rela.hdr != NULL
-         && !elf_link_adjust_relocs (abfd, &esdo->rela, sort))
+         && !elf_link_adjust_relocs (abfd, o, &esdo->rela, sort))
        return FALSE;
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
@@ -11794,6 +12204,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          Elf_Internal_Dyn dyn;
          const char *name;
          unsigned int type;
+         bfd_size_type sh_size;
+         bfd_vma sh_addr;
 
          bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
 
@@ -11825,8 +12237,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              {
                struct elf_link_hash_entry *h;
 
-               h = elf_link_hash_lookup (elf_hash_table (info), name,
-                                         FALSE, FALSE, TRUE);
+               h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE);
                if (h != NULL
                    && (h->root.type == bfd_link_hash_defined
                        || h->root.type == bfd_link_hash_defweak))
@@ -11849,35 +12260,37 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
            case DT_PREINIT_ARRAYSZ:
              name = ".preinit_array";
-             goto get_size;
+             goto get_out_size;
            case DT_INIT_ARRAYSZ:
              name = ".init_array";
-             goto get_size;
+             goto get_out_size;
            case DT_FINI_ARRAYSZ:
              name = ".fini_array";
-           get_size:
+           get_out_size:
              o = bfd_get_section_by_name (abfd, name);
              if (o == NULL)
                {
-                 (*_bfd_error_handler)
-                   (_("%B: could not find output section %s"), abfd, name);
+                 _bfd_error_handler
+                   (_("could not find section %s"), name);
                  goto error_return;
                }
              if (o->size == 0)
-               (*_bfd_error_handler)
+               _bfd_error_handler
                  (_("warning: %s section has zero size"), name);
              dyn.d_un.d_val = o->size;
              break;
 
            case DT_PREINIT_ARRAY:
              name = ".preinit_array";
-             goto get_vma;
+             goto get_out_vma;
            case DT_INIT_ARRAY:
              name = ".init_array";
-             goto get_vma;
+             goto get_out_vma;
            case DT_FINI_ARRAY:
              name = ".fini_array";
-             goto get_vma;
+           get_out_vma:
+             o = bfd_get_section_by_name (abfd, name);
+             goto do_vma;
 
            case DT_HASH:
              name = ".hash";
@@ -11900,21 +12313,22 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            case DT_VERSYM:
              name = ".gnu.version";
            get_vma:
-             o = bfd_get_section_by_name (abfd, name);
+             o = bfd_get_linker_section (dynobj, name);
+           do_vma:
              if (o == NULL)
                {
-                 (*_bfd_error_handler)
-                   (_("%B: could not find output section %s"), abfd, name);
+                 _bfd_error_handler
+                   (_("could not find section %s"), name);
                  goto error_return;
                }
              if (elf_section_data (o->output_section)->this_hdr.sh_type == SHT_NOTE)
                {
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
                    (_("warning: section '%s' is being made into a note"), name);
                  bfd_set_error (bfd_error_nonrepresentable_section);
                  goto error_return;
                }
-             dyn.d_un.d_ptr = o->vma;
+             dyn.d_un.d_ptr = o->output_section->vma + o->output_offset;
              break;
 
            case DT_REL:
@@ -11925,8 +12339,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                type = SHT_REL;
              else
                type = SHT_RELA;
-             dyn.d_un.d_val = 0;
-             dyn.d_un.d_ptr = 0;
+             sh_size = 0;
+             sh_addr = 0;
              for (i = 1; i < elf_numsections (abfd); i++)
                {
                  Elf_Internal_Shdr *hdr;
@@ -11935,16 +12349,42 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                  if (hdr->sh_type == type
                      && (hdr->sh_flags & SHF_ALLOC) != 0)
                    {
-                     if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
-                       dyn.d_un.d_val += hdr->sh_size;
-                     else
-                       {
-                         if (dyn.d_un.d_ptr == 0
-                             || hdr->sh_addr < dyn.d_un.d_ptr)
-                           dyn.d_un.d_ptr = hdr->sh_addr;
-                       }
+                     sh_size += hdr->sh_size;
+                     if (sh_addr == 0
+                         || sh_addr > hdr->sh_addr)
+                       sh_addr = hdr->sh_addr;
                    }
                }
+
+             if (bed->dtrel_excludes_plt && htab->srelplt != NULL)
+               {
+                 /* Don't count procedure linkage table relocs in the
+                    overall reloc count.  */
+                 sh_size -= htab->srelplt->size;
+                 if (sh_size == 0)
+                   /* If the size is zero, make the address zero too.
+                      This is to avoid a glibc bug.  If the backend
+                      emits DT_RELA/DT_RELASZ even when DT_RELASZ is
+                      zero, then we'll put DT_RELA at the end of
+                      DT_JMPREL.  glibc will interpret the end of
+                      DT_RELA matching the end of DT_JMPREL as the
+                      case where DT_RELA includes DT_JMPREL, and for
+                      LD_BIND_NOW will decide that processing DT_RELA
+                      will process the PLT relocs too.  Net result:
+                      No PLT relocs applied.  */
+                   sh_addr = 0;
+
+                 /* If .rela.plt is the first .rela section, exclude
+                    it from DT_RELA.  */
+                 else if (sh_addr == (htab->srelplt->output_section->vma
+                                      + htab->srelplt->output_offset))
+                   sh_addr += htab->srelplt->size;
+               }
+
+             if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
+               dyn.d_un.d_val = sh_size;
+             else
+               dyn.d_un.d_ptr = sh_addr;
              break;
            }
          bed->s->swap_dyn_out (dynobj, &dyn, dyncon);
@@ -11997,9 +12437,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                 created by _bfd_elf_link_create_dynamic_sections.  */
              continue;
            }
-         if (elf_hash_table (info)->stab_info.stabstr == o)
+         if (htab->stab_info.stabstr == o)
            continue;
-         if (elf_hash_table (info)->eh_info.hdr_sec == o)
+         if (htab->eh_info.hdr_sec == o)
            continue;
          if (strcmp (o->name, ".dynstr") != 0)
            {
@@ -12018,26 +12458,26 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              off = elf_section_data (o->output_section)->this_hdr.sh_offset;
              if (bfd_seek (abfd, off, SEEK_SET) != 0
-                 || ! _bfd_elf_strtab_emit (abfd,
-                                            elf_hash_table (info)->dynstr))
+                 || !_bfd_elf_strtab_emit (abfd, htab->dynstr))
                goto error_return;
            }
        }
     }
 
-  if (bfd_link_relocatable (info))
+  if (!info->resolve_section_groups)
     {
       bfd_boolean failed = FALSE;
 
+      BFD_ASSERT (bfd_link_relocatable (info));
       bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed);
       if (failed)
        goto error_return;
     }
 
   /* If we have optimized stabs strings, output them.  */
-  if (elf_hash_table (info)->stab_info.stabstr != NULL)
+  if (htab->stab_info.stabstr != NULL)
     {
-      if (! _bfd_write_stab_strings (abfd, &elf_hash_table (info)->stab_info))
+      if (!_bfd_write_stab_strings (abfd, &htab->stab_info))
        goto error_return;
     }
 
@@ -12134,8 +12574,6 @@ init_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
                        struct bfd_link_info *info, bfd *abfd,
                        asection *sec)
 {
-  const struct elf_backend_data *bed;
-
   if (sec->reloc_count == 0)
     {
       cookie->rels = NULL;
@@ -12143,15 +12581,12 @@ init_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
     }
   else
     {
-      bed = get_elf_backend_data (abfd);
-
       cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
                                                info->keep_memory);
       if (cookie->rels == NULL)
        return FALSE;
       cookie->rel = cookie->rels;
-      cookie->relend = (cookie->rels
-                       + sec->reloc_count * bed->s->int_rels_per_ext_rel);
+      cookie->relend = cookie->rels + sec->reloc_count;
     }
   cookie->rel = cookie->rels;
   return TRUE;
@@ -12230,6 +12665,73 @@ _bfd_elf_gc_mark_hook (asection *sec,
   return NULL;
 }
 
+/* Return the global debug definition section.  */
+
+static asection *
+elf_gc_mark_debug_section (asection *sec ATTRIBUTE_UNUSED,
+                          struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                          Elf_Internal_Rela *rel ATTRIBUTE_UNUSED,
+                          struct elf_link_hash_entry *h,
+                          Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
+{
+  if (h != NULL
+      && (h->root.type == bfd_link_hash_defined
+         || h->root.type == bfd_link_hash_defweak)
+      && (h->root.u.def.section->flags & SEC_DEBUGGING) != 0)
+    return h->root.u.def.section;
+
+  return NULL;
+}
+
+/* For undefined __start_<name> and __stop_<name> symbols, return the
+   first input section matching <name>.  Return NULL otherwise.  */
+
+asection *
+_bfd_elf_is_start_stop (const struct bfd_link_info *info,
+                       struct elf_link_hash_entry *h)
+{
+  asection *s;
+  const char *sec_name;
+
+  if (h->root.type != bfd_link_hash_undefined
+      && h->root.type != bfd_link_hash_undefweak)
+    return NULL;
+
+  s = h->root.u.undef.section;
+  if (s != NULL)
+    {
+      if (s == (asection *) 0 - 1)
+       return NULL;
+      return s;
+    }
+
+  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)
+       {
+         s = bfd_get_section_by_name (i, sec_name);
+         if (s != NULL)
+           {
+             h->root.u.undef.section = s;
+             break;
+           }
+       }
+    }
+
+  if (s == NULL)
+    h->root.u.undef.section = (asection *) 0 - 1;
+
+  return s;
+}
+
 /* COOKIE->rel describes a relocation against section SEC, which is
    a section we've decided to keep.  Return the section that contains
    the relocation symbol, or NULL if no section contains it.  */
@@ -12268,34 +12770,19 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
       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))
+      if (start_stop != NULL)
        {
          /* 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;
+         asection *s = _bfd_elf_is_start_stop (info, h);
 
-         if (sec_name != NULL && *sec_name != '\0')
+         if (s != NULL)
            {
-             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;
-                   }
-               }
+             *start_stop = !s->gc_mark;
+             return s;
            }
        }
 
@@ -12457,6 +12944,7 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
       asection *isec;
       bfd_boolean some_kept;
       bfd_boolean debug_frag_seen;
+      bfd_boolean has_kept_debug_info;
 
       if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
        continue;
@@ -12464,22 +12952,24 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
       /* Ensure all linker created sections are kept,
         see if any other section is already marked,
         and note if we have any fragmented debug sections.  */
-      debug_frag_seen = some_kept = FALSE;
+      debug_frag_seen = some_kept = has_kept_debug_info = FALSE;
       for (isec = ibfd->sections; isec != NULL; isec = isec->next)
        {
          if ((isec->flags & SEC_LINKER_CREATED) != 0)
            isec->gc_mark = 1;
-         else if (isec->gc_mark)
+         else if (isec->gc_mark
+                  && (isec->flags & SEC_ALLOC) != 0
+                  && elf_section_type (isec) != SHT_NOTE)
            some_kept = TRUE;
 
-         if (debug_frag_seen == FALSE
+         if (!debug_frag_seen
              && (isec->flags & SEC_DEBUGGING)
              && CONST_STRNEQ (isec->name, ".debug_line."))
            debug_frag_seen = TRUE;
        }
 
-      /* If no section in this file will be kept, then we can
-        toss out the debug and special sections.  */
+      /* If no non-note alloc section in this file will be kept, then
+        we can toss out the debug and special sections.  */
       if (!some_kept)
        continue;
 
@@ -12494,78 +12984,53 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
                    || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
                   && elf_next_in_group (isec) == NULL)
            isec->gc_mark = 1;
+         if (isec->gc_mark && (isec->flags & SEC_DEBUGGING) != 0)
+           has_kept_debug_info = TRUE;
        }
 
-      if (! debug_frag_seen)
-       continue;
-
       /* Look for CODE sections which are going to be discarded,
         and find and discard any fragmented debug sections which
         are associated with that code section.  */
-      for (isec = ibfd->sections; isec != NULL; isec = isec->next)
-       if ((isec->flags & SEC_CODE) != 0
-           && isec->gc_mark == 0)
-         {
-           unsigned int ilen;
-           asection *dsec;
+      if (debug_frag_seen)
+       for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+         if ((isec->flags & SEC_CODE) != 0
+             && isec->gc_mark == 0)
+           {
+             unsigned int ilen;
+             asection *dsec;
 
-           ilen = strlen (isec->name);
+             ilen = strlen (isec->name);
 
-           /* Association is determined by the name of the debug section
-              containing the name of the code section as a suffix.  For
-              example .debug_line.text.foo is a debug section associated
-              with .text.foo.  */
-           for (dsec = ibfd->sections; dsec != NULL; dsec = dsec->next)
-             {
-               unsigned int dlen;
+             /* Association is determined by the name of the debug
+                section containing the name of the code section as
+                a suffix.  For example .debug_line.text.foo is a
+                debug section associated with .text.foo.  */
+             for (dsec = ibfd->sections; dsec != NULL; dsec = dsec->next)
+               {
+                 unsigned int dlen;
 
-               if (dsec->gc_mark == 0
-                   || (dsec->flags & SEC_DEBUGGING) == 0)
-                 continue;
+                 if (dsec->gc_mark == 0
+                     || (dsec->flags & SEC_DEBUGGING) == 0)
+                   continue;
 
-               dlen = strlen (dsec->name);
+                 dlen = strlen (dsec->name);
 
-               if (dlen > ilen
-                   && strncmp (dsec->name + (dlen - ilen),
-                               isec->name, ilen) == 0)
-                 {
+                 if (dlen > ilen
+                     && strncmp (dsec->name + (dlen - ilen),
+                                 isec->name, ilen) == 0)
                    dsec->gc_mark = 0;
-                 }
-             }
+               }
          }
-    }
-  return TRUE;
-}
-
-/* Sweep symbols in swept sections.  Called via elf_link_hash_traverse.  */
-
-struct elf_gc_sweep_symbol_info
-{
-  struct bfd_link_info *info;
-  void (*hide_symbol) (struct bfd_link_info *, struct elf_link_hash_entry *,
-                      bfd_boolean);
-};
-
-static bfd_boolean
-elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
-{
-  if (!h->mark
-      && (((h->root.type == bfd_link_hash_defined
-           || h->root.type == bfd_link_hash_defweak)
-          && !((h->def_regular || ELF_COMMON_DEF_P (h))
-               && h->root.u.def.section->gc_mark))
-         || h->root.type == bfd_link_hash_undefined
-         || h->root.type == bfd_link_hash_undefweak))
-    {
-      struct elf_gc_sweep_symbol_info *inf;
 
-      inf = (struct elf_gc_sweep_symbol_info *) data;
-      (*inf->hide_symbol) (inf->info, h, TRUE);
-      h->def_regular = 0;
-      h->ref_regular = 0;
-      h->ref_regular_nonweak = 0;
+      /* Mark debug sections referenced by kept debug sections.  */
+      if (has_kept_debug_info)
+       for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+         if (isec->gc_mark
+             && (isec->flags & SEC_DEBUGGING) != 0)
+           if (!_bfd_elf_gc_mark (info, isec,
+                                  elf_gc_mark_debug_section))
+             return FALSE;
     }
-
   return TRUE;
 }
 
@@ -12580,8 +13045,6 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
   bfd *sub;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   gc_sweep_hook_fn gc_sweep_hook = bed->gc_sweep_hook;
-  unsigned long section_sym_count;
-  struct elf_gc_sweep_symbol_info sweep_info;
 
   for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     {
@@ -12615,7 +13078,9 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
          o->flags |= SEC_EXCLUDE;
 
          if (info->print_gc_sections && o->size != 0)
-           _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name);
+           /* xgettext:c-format */
+           _bfd_error_handler (_("Removing unused section '%A' in file '%B'"),
+                               o, sub);
 
          /* But we also have to update some of the relocation
             info we collected before.  */
@@ -12646,15 +13111,6 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
        }
     }
 
-  /* Remove the symbols that were in the swept sections from the dynamic
-     symbol table.  GCFIXME: Anyone know how to get them out of the
-     static symbol table as well?  */
-  sweep_info.info = info;
-  sweep_info.hide_symbol = bed->elf_backend_hide_symbol;
-  elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol,
-                         &sweep_info);
-
-  _bfd_elf_link_renumber_dynsyms (abfd, info, &section_sym_count);
   return TRUE;
 }
 
@@ -12743,7 +13199,7 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
   bed = get_elf_backend_data (sec->owner);
   log_file_align = bed->s->log_file_align;
 
-  relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+  relend = relstart + sec->reloc_count;
 
   for (rel = relstart; rel < relend; ++rel)
     if (rel->r_offset >= hstart && rel->r_offset < hend)
@@ -12780,6 +13236,7 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
              && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
              && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
              && (!bfd_link_executable (info)
+                 || info->gc_keep_exported
                  || info->export_dynamic
                  || (h->dynamic
                      && d != NULL
@@ -12810,7 +13267,8 @@ _bfd_elf_gc_keep (struct bfd_link_info *info)
       if (h != NULL
          && (h->root.type == bfd_link_hash_defined
              || h->root.type == bfd_link_hash_defweak)
-         && !bfd_is_abs_section (h->root.u.def.section))
+         && !bfd_is_abs_section (h->root.u.def.section)
+         && !bfd_is_und_section (h->root.u.def.section))
        h->root.u.def.section->flags |= SEC_KEEP;
     }
 }
@@ -12859,7 +13317,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
   if (!bed->can_gc_sections
       || !is_elf_hash_table (info->hash))
     {
-      (*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
+      _bfd_error_handler(_("Warning: gc-sections option ignored"));
       return TRUE;
     }
 
@@ -12898,7 +13356,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
     return FALSE;
 
   /* Mark dynamically referenced symbols.  */
-  if (htab->dynamic_sections_created)
+  if (htab->dynamic_sections_created || info->gc_keep_exported)
     elf_link_hash_traverse (htab, bed->gc_mark_dynamic_ref, info);
 
   /* Grovel through relocs to find out who stays ...  */
@@ -12943,7 +13401,7 @@ bfd_elf_gc_record_vtinherit (bfd *abfd,
 {
   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
   struct elf_link_hash_entry **search, *child;
-  bfd_size_type extsymcount;
+  size_t extsymcount;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   /* The sh_info field of the symtab header tells us where the
@@ -12968,8 +13426,9 @@ bfd_elf_gc_record_vtinherit (bfd *abfd,
        goto win;
     }
 
-  (*_bfd_error_handler) ("%B: %A+%lu: No symbol found for INHERIT",
-                        abfd, sec, (unsigned long) offset);
+  /* xgettext:c-format */
+  _bfd_error_handler (_("%B: %A+%lu: No symbol found for INHERIT"),
+                     abfd, sec, (unsigned long) offset);
   bfd_set_error (bfd_error_invalid_operation);
   return FALSE;
 
@@ -13216,7 +13675,7 @@ bfd_elf_gc_common_finalize_got_offsets (bfd *abfd,
   for (i = info->input_bfds; i; i = i->link.next)
     {
       bfd_signed_vma *local_got;
-      bfd_size_type j, locsymcount;
+      size_t j, locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
 
       if (bfd_get_flavour (i) != bfd_target_elf_flavour)
@@ -13380,6 +13839,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
   if (o != NULL)
     {
       asection *i;
+      int eh_changed = 0;
 
       for (i = o->map_head.s; i != NULL; i = i->map_head.s)
        {
@@ -13397,10 +13857,17 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
          if (_bfd_elf_discard_section_eh_frame (abfd, info, i,
                                                 bfd_elf_reloc_symbol_deleted_p,
                                                 &cookie))
-           changed = 1;
+           {
+             eh_changed = 1;
+             if (i->size != i->rawsize)
+               changed = 1;
+           }
 
          fini_reloc_cookie_for_section (&cookie, i);
        }
+      if (eh_changed)
+       elf_link_hash_traverse (elf_hash_table (info),
+                               _bfd_elf_adjust_eh_frame_global_symbol, NULL);
     }
 
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
This page took 0.075286 seconds and 4 git commands to generate.