Delete duplicate target short-cuts to dynamic sections
[external/binutils.git] / bfd / elflink.c
index b432384..daf4b82 100644 (file)
 #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.  */
@@ -145,8 +149,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;
@@ -204,7 +207,24 @@ _bfd_elf_link_create_dynstrtab (bfd *abfd, struct bfd_link_info *info)
 
   hash_table = elf_hash_table (info);
   if (hash_table->dynobj == NULL)
-    hash_table->dynobj = abfd;
+    {
+      /* We may not set dynobj, an input file holding linker created
+        dynamic sections to abfd, which may be a dynamic object with
+        its own dynamic sections.  We need to find a normal input file
+        to hold linker created sections if possible.  */
+      if ((abfd->flags & (DYNAMIC | BFD_PLUGIN)) != 0)
+       {
+         bfd *ibfd;
+         for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
+           if ((ibfd->flags
+                & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
+             {
+               abfd = ibfd;
+               break;
+             }
+       }
+      hash_table->dynobj = abfd;
+    }
 
   if (hash_table->dynstr == NULL)
     {
@@ -451,7 +471,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
@@ -502,7 +522,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;
     }
@@ -681,7 +701,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)];
@@ -736,7 +756,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;
 
@@ -883,16 +903,17 @@ _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,
                          &dynsymcount);
 
-  /* There is an unused NULL entry at the head of the table which
-     we must account for in our count.  We always create the dynsym
-     section, even if it is empty, with dynamic sections.  */
-  if (elf_hash_table (info)->dynamic_sections_created)
-    ++dynsymcount;
+  /* There is an unused NULL entry at the head of the table which we
+     must account for in our count even if the table is empty since it
+     is intended for the mandatory DT_SYMTAB tag (.dynsym section) in
+     .dynamic section.  */
+  dynsymcount++;
 
   elf_hash_table (info)->dynsymcount = dynsymcount;
   return dynsymcount;
@@ -1185,21 +1206,20 @@ _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 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 (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)))))
+      && (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))
     {
       *skip = TRUE;
       return TRUE;
@@ -1238,22 +1258,26 @@ _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);
       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);
       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);
       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);
@@ -1464,10 +1488,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;
 
@@ -1625,9 +1647,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.  */
@@ -1767,6 +1788,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.  */
@@ -1894,7 +1940,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);
     }
@@ -2066,7 +2113,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;
@@ -2156,8 +2202,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;
@@ -2187,7 +2233,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);
@@ -2275,7 +2322,8 @@ 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,
@@ -2286,7 +2334,8 @@ elf_link_read_relocs_from_section (bfd *abfd,
        }
       else if (r_symndx != STN_UNDEF)
        {
-         (*_bfd_error_handler)
+         _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,
@@ -2476,7 +2525,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);
@@ -2758,7 +2808,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);
 
@@ -3075,9 +3125,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;
@@ -3087,15 +3137,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;
@@ -3195,14 +3255,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)
@@ -3370,7 +3430,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;
 
@@ -3402,7 +3462,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;
 
@@ -3552,16 +3612,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;
@@ -3577,8 +3637,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;
@@ -3615,6 +3674,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);
 
@@ -3943,7 +4003,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;
@@ -4022,8 +4083,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++)
        {
@@ -4065,6 +4127,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;
@@ -4075,6 +4138,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)
@@ -4125,6 +4189,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)
@@ -4252,7 +4317,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);
@@ -4288,7 +4354,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);
@@ -4360,6 +4427,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.  */
@@ -4368,6 +4440,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;
@@ -4505,7 +4582,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)
@@ -4531,13 +4609,15 @@ 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);
                  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,
@@ -4553,7 +4633,8 @@ 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,
@@ -4588,7 +4669,8 @@ 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);
@@ -4689,7 +4771,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);
@@ -4735,7 +4818,9 @@ 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;
@@ -4748,9 +4833,6 @@ error_free_dyn:
              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
@@ -4811,7 +4893,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)
        {
@@ -4882,7 +4964,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;
@@ -5072,6 +5155,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)
@@ -5253,7 +5338,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;
 
@@ -5691,11 +5776,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;
     }
@@ -5742,14 +5829,14 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                               struct bfd_link_info *info,
                               asection **sinterpptr)
 {
-  bfd_size_type soname_indx;
+  size_t soname_indx;
   bfd *dynobj;
   const struct elf_backend_data *bed;
   struct elf_info_failed asvinfo;
 
   *sinterpptr = NULL;
 
-  soname_indx = (bfd_size_type) -1;
+  soname_indx = (size_t) -1;
 
   if (!is_elf_hash_table (info->hash))
     return TRUE;
@@ -5830,7 +5917,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        {
          soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                             soname, TRUE);
-         if (soname_indx == (bfd_size_type) -1
+         if (soname_indx == (size_t) -1
              || !_bfd_elf_add_dynamic_entry (info, DT_SONAME, soname_indx))
            return FALSE;
        }
@@ -5844,12 +5931,12 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       if (rpath != NULL)
        {
-         bfd_size_type indx;
+         size_t indx;
          bfd_vma tag;
 
          indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
                                      TRUE);
-         if (indx == (bfd_size_type) -1)
+         if (indx == (size_t) -1)
            return FALSE;
 
          tag = info->new_dtags ? DT_RUNPATH : DT_RPATH;
@@ -5859,11 +5946,11 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       if (filter_shlib != NULL)
        {
-         bfd_size_type indx;
+         size_t indx;
 
          indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                      filter_shlib, TRUE);
-         if (indx == (bfd_size_type) -1
+         if (indx == (size_t) -1
              || !_bfd_elf_add_dynamic_entry (info, DT_FILTER, indx))
            return FALSE;
        }
@@ -5874,11 +5961,11 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
          for (p = auxiliary_filters; *p != NULL; p++)
            {
-             bfd_size_type indx;
+             size_t indx;
 
              indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                          *p, TRUE);
-             if (indx == (bfd_size_type) -1
+             if (indx == (size_t) -1
                  || !_bfd_elf_add_dynamic_entry (info, DT_AUXILIARY, indx))
                return FALSE;
            }
@@ -5886,22 +5973,22 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       if (audit != NULL)
        {
-         bfd_size_type indx;
+         size_t indx;
 
          indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, audit,
                                      TRUE);
-         if (indx == (bfd_size_type) -1
+         if (indx == (size_t) -1
              || !_bfd_elf_add_dynamic_entry (info, DT_AUDIT, indx))
            return FALSE;
        }
 
       if (depaudit != NULL)
        {
-         bfd_size_type indx;
+         size_t indx;
 
          indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, depaudit,
                                      TRUE);
-         if (indx == (bfd_size_type) -1
+         if (indx == (size_t) -1
              || !_bfd_elf_add_dynamic_entry (info, DT_DEPAUDIT, indx))
            return FALSE;
        }
@@ -5991,7 +6078,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;
@@ -6059,7 +6146,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                    if (elf_section_data (o)->this_hdr.sh_type
                        == SHT_PREINIT_ARRAY)
                      {
-                       (*_bfd_error_handler)
+                       _bfd_error_handler
                          (_("%B: .preinit_array section is not allowed in DSO"),
                           sub);
                        break;
@@ -6209,7 +6296,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);
@@ -6219,13 +6306,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;
            }
@@ -6444,7 +6531,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
              {
                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)
@@ -6457,7 +6544,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                                            ? elf_dt_name (t->vn_bfd)
                                            : lbasename (t->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);
@@ -6476,7 +6563,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                    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)
+                   if (indx == (size_t) -1)
                      return FALSE;
                    a->vna_name = indx;
                    if (a->vna_nextptr == NULL)
@@ -6589,8 +6676,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
       /* Work out the size of the symbol version section.  */
       s = bfd_get_linker_section (dynobj, ".gnu.version");
       BFD_ASSERT (s != NULL);
-      if (dynsymcount != 0
-         && (s->flags & SEC_EXCLUDE) == 0)
+      if ((s->flags & SEC_EXCLUDE) == 0)
        {
          s->size = dynsymcount * sizeof (Elf_External_Versym);
          s->contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
@@ -6611,17 +6697,14 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
       BFD_ASSERT (s != NULL);
       s->size = dynsymcount * bed->s->sizeof_sym;
 
-      if (dynsymcount != 0)
-       {
-         s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
-         if (s->contents == NULL)
-           return FALSE;
+      s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
+      if (s->contents == NULL)
+       return FALSE;
 
-         /* The first entry in .dynsym is a dummy symbol.
-            Clear all the section syms, in case we don't output them all.  */
-         ++section_sym_count;
-         memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym);
-       }
+      /* The first entry in .dynsym is a dummy symbol.  Clear all the
+        section syms, in case we don't output them all.  */
+      ++section_sym_count;
+      memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym);
 
       elf_hash_table (info)->bucketcount = 0;
 
@@ -7259,7 +7342,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;
 };
 
@@ -7293,12 +7376,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)
@@ -7345,7 +7428,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));
 
@@ -7363,12 +7446,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;
 
@@ -7431,7 +7514,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;
 
@@ -7829,6 +7912,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);
 }
@@ -7875,6 +7959,7 @@ eval_symbol (bfd_vma *result,
 
     case 'S':
       symbol_is_section = TRUE;
+      /* Fall through.  */
     case 's':
       ++sym;
       symlen = strtol (sym, (char **) symp, 10);
@@ -8265,6 +8350,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)
 {
@@ -8323,6 +8409,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 *);
@@ -8505,6 +8594,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;
@@ -8520,7 +8610,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
@@ -8541,8 +8631,9 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
                    /* Section size is only divisible by rela.  */
                    if (use_rela_initialised && (use_rela == FALSE))
                      {
-                       _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;
                      }
@@ -8558,8 +8649,9 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
                /* Section size is only divisible by rel.  */
                if (use_rela_initialised && (use_rela == TRUE))
                  {
-                   _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;
                  }
@@ -8571,9 +8663,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;
              }
@@ -8595,8 +8688,9 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
                    /* Section size is only divisible by rela.  */
                    if (use_rela_initialised && (use_rela == FALSE))
                      {
-                       _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;
                      }
@@ -8612,8 +8706,9 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
                /* Section size is only divisible by rel.  */
                if (use_rela_initialised && (use_rela == TRUE))
                  {
-                   _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;
                  }
@@ -8625,9 +8720,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;
              }
@@ -8703,8 +8799,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)
          {
@@ -8740,6 +8835,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)
       {
@@ -8748,8 +8872,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;
@@ -8838,7 +8961,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;
@@ -8859,8 +8983,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)
        {
@@ -8916,7 +9040,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);
@@ -8955,7 +9080,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;
@@ -8977,9 +9103,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;
@@ -9175,19 +9301,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
@@ -9209,16 +9331,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, def_bfd,
+                         h->root.root.string);
       bfd_set_error (bfd_error_bad_value);
       eoinfo->failed = TRUE;
       return FALSE;
@@ -9297,7 +9422,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);
@@ -9451,12 +9577,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;
@@ -9486,7 +9615,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;
@@ -10090,7 +10220,8 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
            {
              if (o->size != 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);
@@ -10137,7 +10268,8 @@ 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);
@@ -10222,6 +10354,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);
@@ -10697,9 +10830,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;
        }
     }
@@ -10734,13 +10866,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;
        }
 
@@ -10815,6 +10943,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;
     }
@@ -10894,13 +11023,16 @@ 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;
        }
@@ -10938,6 +11070,108 @@ 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;
+
+  flags = bfd_get_file_flags (abfd);
+  flags &= ~HAS_RELOC;
+  if (!bfd_set_start_address (implib_bfd, 0)
+      || !bfd_set_file_flags (implib_bfd, flags))
+    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)
 {
@@ -11521,7 +11755,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);
                    }
@@ -11588,7 +11823,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     {
       Elf_Internal_Sym sym;
       bfd_byte *dynsym = elf_hash_table (info)->dynsym->contents;
-      long last_local = 0;
+
+      o = elf_hash_table (info)->dynsym->output_section;
+      elf_section_data (o)->this_hdr.sh_info
+       = elf_hash_table (info)->local_dynsymcount + 1;
 
       /* Write out the section symbols for the output sections.  */
       if (bfd_link_pic (info)
@@ -11618,8 +11856,6 @@ 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);
            }
        }
@@ -11652,16 +11888,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.  */
@@ -11740,6 +11970,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)
     {
@@ -11750,10 +11987,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
@@ -11836,35 +12073,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";
@@ -11887,21 +12126,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:
@@ -12217,6 +12457,55 @@ _bfd_elf_gc_mark_hook (asection *sec,
   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.  */
@@ -12255,34 +12544,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;
            }
        }
 
@@ -12602,6 +12876,7 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
          o->flags |= SEC_EXCLUDE;
 
          if (info->print_gc_sections && o->size != 0)
+           /* xgettext:c-format */
            _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name);
 
          /* But we also have to update some of the relocation
@@ -12797,7 +13072,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;
     }
 }
@@ -12846,7 +13122,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;
     }
 
@@ -12930,7 +13206,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
@@ -12955,8 +13231,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;
 
@@ -13203,7 +13480,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)