]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elflink.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / bfd / elflink.c
index 60a3c2216f3f10f26c90ae3cccdb88fe65b74411..1dfed2fdd1508bcf33cb82c7e25ed7f289f292bd 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linking support for BFD.
-   Copyright (C) 1995-2020 Free Software Foundation, Inc.
+   Copyright (C) 1995-2021 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 #include "plugin.h"
 #endif
 
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
 /* This struct is used to pass information to routines called via
    elf_link_hash_traverse which must return failure.  */
 
@@ -505,6 +512,16 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
       const char *name;
       size_t indx;
 
+      if (h->root.type == bfd_link_hash_defined
+         || h->root.type == bfd_link_hash_defweak)
+       {
+         /* An IR symbol should not be made dynamic.  */
+         if (h->root.u.def.section != NULL
+             && h->root.u.def.section->owner != NULL
+             && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)
+           return TRUE;
+       }
+
       /* XXX: The ABI draft says the linker must turn hidden and
         internal symbols into STB_LOCAL symbols when producing the
         DSO. However, if ld.so honors st_other in the dynamic table,
@@ -989,7 +1006,7 @@ _bfd_elf_link_renumber_dynsyms (bfd *output_bfd,
 
 static void
 elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
-                   const Elf_Internal_Sym *isym, asection *sec,
+                   unsigned int st_other, asection *sec,
                    bfd_boolean definition, bfd_boolean dynamic)
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
@@ -997,12 +1014,12 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
   /* If st_other has a processor-specific meaning, specific
      code might be needed here.  */
   if (bed->elf_backend_merge_symbol_attribute)
-    (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
+    (*bed->elf_backend_merge_symbol_attribute) (h, st_other, definition,
                                                dynamic);
 
   if (!dynamic)
     {
-      unsigned symvis = ELF_ST_VISIBILITY (isym->st_other);
+      unsigned symvis = ELF_ST_VISIBILITY (st_other);
       unsigned hvis = ELF_ST_VISIBILITY (h->other);
 
       /* Keep the most constraining visibility.  Leave the remainder
@@ -1011,7 +1028,7 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
        h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1));
     }
   else if (definition
-          && ELF_ST_VISIBILITY (isym->st_other) != STV_DEFAULT
+          && ELF_ST_VISIBILITY (st_other) != STV_DEFAULT
           && (sec->flags & SEC_READONLY) == 0)
     h->protected_def = 1;
 }
@@ -1041,7 +1058,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
                       bfd_boolean *pold_weak,
                       unsigned int *pold_alignment,
                       bfd_boolean *skip,
-                      bfd_boolean *override,
+                      bfd **override,
                       bfd_boolean *type_change_ok,
                       bfd_boolean *size_change_ok,
                       bfd_boolean *matched)
@@ -1059,7 +1076,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   bfd_boolean default_sym = *matched;
 
   *skip = FALSE;
-  *override = FALSE;
+  *override = NULL;
 
   sec = *psec;
   bind = ELF_ST_BIND (sym->st_info);
@@ -1635,7 +1652,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
          || (h->root.type == bfd_link_hash_common
              && (newweak || newfunc))))
     {
-      *override = TRUE;
+      *override = abfd;
       newdef = FALSE;
       newdyncommon = FALSE;
 
@@ -1661,7 +1678,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   if (newdyncommon
       && h->root.type == bfd_link_hash_common)
     {
-      *override = TRUE;
+      *override = oldbfd;
       newdef = FALSE;
       newdyncommon = FALSE;
       *pvalue = sym->st_size;
@@ -1684,7 +1701,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       /* Merge st_other.  If the symbol already has a dynamic index,
         but visibility says it should not be visible, turn it into a
         local symbol.  */
-      elf_merge_st_other (abfd, h, sym, sec, newdef, newdyn);
+      elf_merge_st_other (abfd, h, sym->st_other, sec, newdef, newdyn);
       if (h->dynindx != -1)
        switch (ELF_ST_VISIBILITY (h->other))
          {
@@ -1837,7 +1854,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
   const struct elf_backend_data *bed;
   bfd_boolean collect;
   bfd_boolean dynamic;
-  bfd_boolean override;
+  bfd *override;
   char *p;
   size_t len, shortlen;
   asection *tmp_sec;
@@ -2011,6 +2028,10 @@ _bfd_elf_add_default_symbol (bfd *abfd,
       ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
       (*bed->elf_backend_copy_indirect_symbol) (info, ht, hi);
 
+      /* If we first saw a reference to SHORTNAME with non-default
+        visibility, merge that visibility to the @@VER symbol.  */
+      elf_merge_st_other (abfd, ht, hi->other, sec, TRUE, dynamic);
+
       /* A reference to the SHORTNAME symbol from a dynamic library
         will be satisfied by the versioned symbol at runtime.  In
         effect, we have a reference to the versioned symbol.  */
@@ -2057,9 +2078,26 @@ _bfd_elf_add_default_symbol (bfd *abfd,
     return FALSE;
 
   if (skip)
-    return TRUE;
-
-  if (override)
+    {
+      if (!dynamic
+         && h->root.type == bfd_link_hash_defweak
+         && hi->root.type == bfd_link_hash_defined)
+       {
+         /* We are handling a weak sym@@ver and attempting to define
+            a weak sym@ver, but _bfd_elf_merge_symbol said to skip the
+            new weak sym@ver because there is already a strong sym@ver.
+            However, sym@ver and sym@@ver are really the same symbol.
+            The existing strong sym@ver ought to override sym@@ver.  */
+         h->root.type = bfd_link_hash_defined;
+         h->root.u.def.section = hi->root.u.def.section;
+         h->root.u.def.value = hi->root.u.def.value;
+         hi->root.type = bfd_link_hash_indirect;
+         hi->root.u.i.link = &h->root;
+       }
+      else
+       return TRUE;
+    }
+  else if (override)
     {
       /* Here SHORTNAME is a versioned name, so we don't expect to see
         the type of override we do in the case above unless it is
@@ -2070,6 +2108,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
          /* xgettext:c-format */
          (_("%pB: unexpected redefinition of indirect versioned symbol `%s'"),
           abfd, shortname);
+      return TRUE;
     }
   else
     {
@@ -2079,32 +2118,36 @@ _bfd_elf_add_default_symbol (bfd *abfd,
              bfd_ind_section_ptr, 0, name, FALSE, collect, &bh)))
        return FALSE;
       hi = (struct elf_link_hash_entry *) bh;
+    }
 
-      /* If there is a duplicate definition somewhere, then HI may not
-        point to an indirect symbol.  We will have reported an error
-        to the user in that case.  */
+  /* If there is a duplicate definition somewhere, then HI may not
+     point to an indirect symbol.  We will have reported an error
+     to the user in that case.  */
+  if (hi->root.type == bfd_link_hash_indirect)
+    {
+      (*bed->elf_backend_copy_indirect_symbol) (info, h, hi);
+      h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
+      hi->dynamic_def |= h->dynamic_def;
 
-      if (hi->root.type == bfd_link_hash_indirect)
-       {
-         (*bed->elf_backend_copy_indirect_symbol) (info, h, hi);
-         h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
-         hi->dynamic_def |= h->dynamic_def;
+      /* If we first saw a reference to @VER symbol with
+        non-default visibility, merge that visibility to the
+        @@VER symbol.  */
+      elf_merge_st_other (abfd, h, hi->other, sec, TRUE, dynamic);
 
-         /* See if the new flags lead us to realize that the symbol
-            must be dynamic.  */
-         if (! *dynsym)
+      /* See if the new flags lead us to realize that the symbol
+        must be dynamic.  */
+      if (! *dynsym)
+       {
+         if (! dynamic)
            {
-             if (! dynamic)
-               {
-                 if (! bfd_link_executable (info)
-                     || hi->ref_dynamic)
-                   *dynsym = TRUE;
-               }
-             else
-               {
-                 if (hi->ref_regular)
-                   *dynsym = TRUE;
-               }
+             if (! bfd_link_executable (info)
+                 || hi->ref_dynamic)
+               *dynsym = TRUE;
+           }
+         else
+           {
+             if (hi->ref_regular)
+               *dynsym = TRUE;
            }
        }
     }
@@ -3762,6 +3805,11 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
   _bfd_elf_strtab_finalize (dynstr);
   size = _bfd_elf_strtab_size (dynstr);
 
+  /* Allow the linker to examine the dynsymtab now it's fully populated.  */
+
+  if (info->callbacks->examine_strtab)
+    info->callbacks->examine_strtab (dynstr);
+
   bed = get_elf_backend_data (dynobj);
   sdyn = bfd_get_linker_section (dynobj, ".dynamic");
   BFD_ASSERT (sdyn != NULL);
@@ -4467,7 +4515,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
              h = (struct elf_link_hash_entry *) p;
              entsize += htab->root.table.entsize;
              if (h->root.type == bfd_link_hash_warning)
-               entsize += htab->root.table.entsize;
+               {
+                 entsize += htab->root.table.entsize;
+                 h = (struct elf_link_hash_entry *) h->root.u.i.link;
+               }
+             if (h->root.type == bfd_link_hash_common)
+               entsize += sizeof (*h->root.u.c.p);
            }
        }
 
@@ -4511,14 +4564,20 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 
          for (p = htab->root.table.table[i]; p != NULL; p = p->next)
            {
-             memcpy (old_ent, p, htab->root.table.entsize);
-             old_ent = (char *) old_ent + htab->root.table.entsize;
              h = (struct elf_link_hash_entry *) p;
+             memcpy (old_ent, h, htab->root.table.entsize);
+             old_ent = (char *) old_ent + htab->root.table.entsize;
              if (h->root.type == bfd_link_hash_warning)
                {
-                 memcpy (old_ent, h->root.u.i.link, htab->root.table.entsize);
+                 h = (struct elf_link_hash_entry *) h->root.u.i.link;
+                 memcpy (old_ent, h, htab->root.table.entsize);
                  old_ent = (char *) old_ent + htab->root.table.entsize;
                }
+             if (h->root.type == bfd_link_hash_common)
+               {
+                 memcpy (old_ent, h->root.u.c.p, sizeof (*h->root.u.c.p));
+                 old_ent = (char *) old_ent + sizeof (*h->root.u.c.p);
+               }
            }
        }
     }
@@ -4561,7 +4620,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       bfd_boolean type_change_ok;
       bfd_boolean new_weak;
       bfd_boolean old_weak;
-      bfd_boolean override;
+      bfd *override;
       bfd_boolean common;
       bfd_boolean discarded;
       unsigned int old_alignment;
@@ -4569,7 +4628,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       bfd *old_bfd;
       bfd_boolean matched;
 
-      override = FALSE;
+      override = NULL;
 
       flags = BSF_NO_FLAGS;
       sec = NULL;
@@ -4889,7 +4948,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
        }
 
       if (! (_bfd_generic_link_add_one_symbol
-            (info, abfd, name, flags, sec, value, NULL, FALSE, bed->collect,
+            (info, override ? override : abfd, name, flags, sec, value,
+             NULL, FALSE, bed->collect,
              (struct bfd_link_hash_entry **) sym_hash)))
        goto error_free_vers;
 
@@ -4960,11 +5020,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
             object and a shared object.  */
          bfd_boolean dynsym = FALSE;
 
-         /* Plugin symbols aren't normal.  Don't set def_regular or
-            ref_regular for them, or make them dynamic.  */
+         /* Plugin symbols aren't normal.  Don't set def/ref flags.  */
          if ((abfd->flags & BFD_PLUGIN) != 0)
            ;
-         else if (! dynamic)
+         else if (!dynamic)
            {
              if (! definition)
                {
@@ -4981,14 +5040,6 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                      h->ref_dynamic = 1;
                    }
                }
-
-             /* If the indirect symbol has been forced local, don't
-                make the real symbol dynamic.  */
-             if ((h == hi || !hi->forced_local)
-                 && (bfd_link_dll (info)
-                     || h->def_dynamic
-                     || h->ref_dynamic))
-               dynsym = TRUE;
            }
          else
            {
@@ -5002,21 +5053,34 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                  h->def_dynamic = 1;
                  hi->def_dynamic = 1;
                }
+           }
 
-             /* If the indirect symbol has been forced local, don't
-                make the real symbol dynamic.  */
-             if ((h == hi || !hi->forced_local)
-                 && (h->def_regular
-                     || h->ref_regular
-                     || (h->is_weakalias
-                         && weakdef (h)->dynindx != -1)))
+         /* If an indirect symbol has been forced local, don't
+            make the real symbol dynamic.  */
+         if (h != hi && hi->forced_local)
+           ;
+         else if (!dynamic)
+           {
+             if (bfd_link_dll (info)
+                 || h->def_dynamic
+                 || h->ref_dynamic)
+               dynsym = TRUE;
+           }
+         else
+           {
+             if (h->def_regular
+                 || h->ref_regular
+                 || (h->is_weakalias
+                     && weakdef (h)->dynindx != -1))
                dynsym = TRUE;
            }
 
          /* Check to see if we need to add an indirect symbol for
             the default name.  */
-         if (definition
-             || (!override && h->root.type == bfd_link_hash_common))
+         if ((definition
+              || (!override && h->root.type == bfd_link_hash_common))
+             && !(hi != h
+                  && hi->versioned == versioned_hidden))
            if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
                                              sec, value, &old_bfd, &dynsym))
              goto error_free_vers;
@@ -5137,7 +5201,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
            }
 
          /* Merge st_other field.  */
-         elf_merge_st_other (abfd, h, isym, sec, definition, dynamic);
+         elf_merge_st_other (abfd, h, isym->st_other, sec,
+                             definition, dynamic);
 
          /* We don't want to make debug symbol dynamic.  */
          if (definition
@@ -5199,15 +5264,14 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                break;
              }
 
-         /* Don't add DT_NEEDED for references from the dummy bfd nor
-            for unmatched symbol.  */
          if (!add_needed
              && matched
              && definition
              && ((dynsym
-                  && h->ref_regular_nonweak
-                  && (old_bfd == NULL
-                      || (old_bfd->flags & BFD_PLUGIN) == 0))
+                  && h->ref_regular_nonweak)
+                 || (old_bfd != NULL
+                     && (old_bfd->flags & BFD_PLUGIN) != 0
+                     && bind != STB_WEAK)
                  || (h->ref_dynamic_nonweak
                      && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
                      && !on_needed_list (elf_dt_name (abfd),
@@ -5332,49 +5396,31 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
        {
          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;
-
-             /* Preserve the maximum alignment and size for common
-                symbols even if this dynamic lib isn't on DT_NEEDED
-                since it can still be loaded at run time by another
-                dynamic lib.  */
-             if (h->root.type == bfd_link_hash_common)
-               {
-                 size = h->root.u.c.size;
-                 alignment_power = h->root.u.c.p->alignment_power;
-               }
-             else
-               {
-                 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.  */
+             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;
              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;
+             memcpy (h, old_ent, htab->root.table.entsize);
+             old_ent = (char *) old_ent + htab->root.table.entsize;
              if (h->root.type == bfd_link_hash_warning)
                {
-                 memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
-                 old_ent = (char *) old_ent + htab->root.table.entsize;
                  h = (struct elf_link_hash_entry *) h->root.u.i.link;
+                 memcpy (h, old_ent, htab->root.table.entsize);
+                 old_ent = (char *) old_ent + htab->root.table.entsize;
                }
              if (h->root.type == bfd_link_hash_common)
                {
-                 if (size > h->root.u.c.size)
-                   h->root.u.c.size = size;
-                 if (alignment_power > h->root.u.c.p->alignment_power)
-                   h->root.u.c.p->alignment_power = alignment_power;
+                 memcpy (h->root.u.c.p, old_ent, sizeof (*h->root.u.c.p));
+                 old_ent = (char *) old_ent + sizeof (*h->root.u.c.p);
                }
              h->root.non_ir_ref_dynamic = non_ir_ref_dynamic;
            }
@@ -5813,7 +5859,15 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
          if (h == NULL)
            continue;
 
-         if (h->root.type == bfd_link_hash_common)
+         if (h->root.type == bfd_link_hash_undefined)
+           {
+             /* If the archive element has already been loaded then one
+                of the symbols defined by that element might have been
+                made undefined due to being in a discarded section.  */
+             if (h->indx == -3)
+               continue;
+           }
+         else if (h->root.type == bfd_link_hash_common)
            {
              /* We currently have a common symbol.  The archive map contains
                 a reference to this symbol, so we may want to include it.  We
@@ -5830,7 +5884,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
              if (! elf_link_is_defined_archive_symbol (abfd, symdef))
                continue;
            }
-         else if (h->root.type != bfd_link_hash_undefined)
+         else
            {
              if (h->root.type != bfd_link_hash_undefweak)
                /* Symbol must be defined.  Don't check it again.  */
@@ -7124,7 +7178,10 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
              || !_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))
+                                             bed->s->sizeof_sym)
+             || (info->gnu_flags_1
+                 && !_bfd_elf_add_dynamic_entry (info, DT_GNU_FLAGS_1,
+                                                 info->gnu_flags_1)))
            return FALSE;
        }
     }
@@ -8171,7 +8228,7 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
       if (isymbuf1 == NULL)
        goto done;
 
-      if (!info->reduce_memory_overheads)
+      if (info != NULL && !info->reduce_memory_overheads)
        {
          ssymbuf1 = elf_create_symbuf (symcount1, isymbuf1);
          elf_tdata (bfd1)->symbuf = ssymbuf1;
@@ -8185,7 +8242,7 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
       if (isymbuf2 == NULL)
        goto done;
 
-      if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
+      if (ssymbuf1 != NULL && info != NULL && !info->reduce_memory_overheads)
        {
          ssymbuf2 = elf_create_symbuf (symcount2, isymbuf2);
          elf_tdata (bfd2)->symbuf = ssymbuf2;
@@ -8394,8 +8451,49 @@ struct elf_final_link_info
   Elf_External_Sym_Shndx *symshndxbuf;
   /* Number of STT_FILE syms seen.  */
   size_t filesym_count;
+  /* Local symbol hash table.  */
+  struct bfd_hash_table local_hash_table;
+};
+
+struct local_hash_entry
+{
+  /* Base hash table entry structure.  */
+  struct bfd_hash_entry root;
+  /* Size of the local symbol name.  */
+  size_t size;
+  /* Number of the duplicated local symbol names.  */
+  long count;
 };
 
+/* Create an entry in the local symbol hash table.  */
+
+static struct bfd_hash_entry *
+local_hash_newfunc (struct bfd_hash_entry *entry,
+                   struct bfd_hash_table *table,
+                   const char *string)
+{
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+                                sizeof (struct local_hash_entry));
+      if (entry == NULL)
+        return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      ((struct local_hash_entry *) entry)->count = 0;
+      ((struct local_hash_entry *) entry)->size = 0;
+    }
+
+  return entry;
+}
+
 /* This struct is used to pass information to elf_link_output_extsym.  */
 
 struct elf_outext_info
@@ -8413,12 +8511,12 @@ struct elf_outext_info
    implementation of them consists of two parts: complex symbols, and the
    relocations themselves.
 
-   The relocations are use a reserved elf-wide relocation type code (R_RELC
+   The relocations use a reserved elf-wide relocation type code (R_RELC
    external / BFD_RELOC_RELC internal) and an encoding of relocation field
    information (start bit, end bit, word width, etc) into the addend.  This
    information is extracted from CGEN-generated operand tables within gas.
 
-   Complex symbols are mangled symbols (BSF_RELC external / STT_RELC
+   Complex symbols are mangled symbols (STT_RELC external / BSF_RELC
    internal) representing prefix-notation expressions, including but not
    limited to those sorts of expressions normally encoded as addends in the
    addend field.  The symbol mangling format is:
@@ -8593,6 +8691,7 @@ undefined_reference (const char *reftype, const char *name)
   /* xgettext:c-format */
   _bfd_error_handler (_("undefined %s reference in complex symbol: %s"),
                      reftype, name);
+  bfd_set_error (bfd_error_bad_value);
 }
 
 static bfd_boolean
@@ -8701,7 +8800,7 @@ eval_symbol (bfd_vma *result,
       return TRUE;                                             \
     }
 
-#define BINARY_OP(op)                                          \
+#define BINARY_OP_HEAD(op)                                     \
   if (strncmp (sym, #op, strlen (#op)) == 0)                   \
     {                                                          \
       sym += strlen (#op);                                     \
@@ -8714,18 +8813,33 @@ eval_symbol (bfd_vma *result,
       ++*symp;                                                 \
       if (!eval_symbol (&b, symp, input_bfd, flinfo, dot,      \
                        isymbuf, locsymcount, signed_p))        \
-       return FALSE;                                           \
+       return FALSE;
+#define BINARY_OP_TAIL(op)                                     \
       if (signed_p)                                            \
        *result = ((bfd_signed_vma) a) op ((bfd_signed_vma) b); \
       else                                                     \
        *result = a op b;                                       \
       return TRUE;                                             \
     }
+#define BINARY_OP(op) BINARY_OP_HEAD(op) BINARY_OP_TAIL(op)
 
     default:
       UNARY_OP  (0-);
-      BINARY_OP (<<);
-      BINARY_OP (>>);
+      BINARY_OP_HEAD (<<);
+      if (b >= sizeof (a) * CHAR_BIT)
+       {
+         *result = 0;
+         return TRUE;
+       }
+      signed_p = 0;
+      BINARY_OP_TAIL (<<);
+      BINARY_OP_HEAD (>>);
+      if (b >= sizeof (a) * CHAR_BIT)
+       {
+         *result = signed_p && (bfd_signed_vma) a < 0 ? -1 : 0;
+         return TRUE;
+       }
+      BINARY_OP_TAIL (>>);
       BINARY_OP (==);
       BINARY_OP (!=);
       BINARY_OP (<=);
@@ -8735,8 +8849,22 @@ eval_symbol (bfd_vma *result,
       UNARY_OP  (~);
       UNARY_OP  (!);
       BINARY_OP (*);
-      BINARY_OP (/);
-      BINARY_OP (%);
+      BINARY_OP_HEAD (/);
+      if (b == 0)
+       {
+         _bfd_error_handler (_("division by zero"));
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
+      BINARY_OP_TAIL (/);
+      BINARY_OP_HEAD (%);
+      if (b == 0)
+       {
+         _bfd_error_handler (_("division by zero"));
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
+      BINARY_OP_TAIL (%);
       BINARY_OP (^);
       BINARY_OP (|);
       BINARY_OP (&);
@@ -9628,9 +9756,72 @@ elf_link_output_symstrtab (struct elf_final_link_info *flinfo,
     {
       /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
         to get the final offset for st_name.  */
+      char *versioned_name = (char *) name;
+      if (h != NULL)
+       {
+         if (h->versioned == versioned && h->def_dynamic)
+           {
+             /* Keep only one '@' for versioned symbols defined in
+                shared objects.  */
+             char *version = strrchr (name, ELF_VER_CHR);
+             char *base_end = strchr (name, ELF_VER_CHR);
+             if (version != base_end)
+               {
+                 size_t base_len;
+                 size_t len = strlen (name);
+                 versioned_name = bfd_alloc (flinfo->output_bfd, len);
+                 if (versioned_name == NULL)
+                   return 0;
+                 base_len = base_end - name;
+                 memcpy (versioned_name, name, base_len);
+                 memcpy (versioned_name + base_len, version,
+                         len - base_len);
+               }
+           }
+       }
+      else if (flinfo->info->unique_symbol
+              && ELF_ST_BIND (elfsym->st_info) == STB_LOCAL)
+       {
+         struct local_hash_entry *lh;
+         switch (ELF_ST_TYPE (elfsym->st_info))
+           {
+           case STT_FILE:
+           case STT_SECTION:
+             break;
+           default:
+             lh = (struct local_hash_entry *) bfd_hash_lookup
+                    (&flinfo->local_hash_table, name, TRUE, FALSE);
+             if (lh == NULL)
+               return 0;
+             if (lh->count)
+               {
+                 /* Append ".COUNT" to duplicated local symbols.  */
+                 size_t count_len;
+                 size_t base_len = lh->size;
+                 char buf[30];
+                 sprintf (buf, "%lx", lh->count);
+                 if (!base_len)
+                   {
+                     base_len = strlen (name);
+                     lh->size = base_len;
+                   }
+                 count_len = strlen (buf);
+                 versioned_name = bfd_alloc (flinfo->output_bfd,
+                                             base_len + count_len + 2);
+                 if (versioned_name == NULL)
+                   return 0;
+                 memcpy (versioned_name, name, base_len);
+                 versioned_name[base_len] = '.';
+                 memcpy (versioned_name + base_len + 1, buf,
+                         count_len + 1);
+               }
+             lh->count++;
+             break;
+           }
+       }
       elfsym->st_name
        = (unsigned long) _bfd_elf_strtab_add (flinfo->symstrtab,
-                                              name, FALSE);
+                                              versioned_name, FALSE);
       if (elfsym->st_name == (unsigned long) -1)
        return 0;
     }
@@ -9699,6 +9890,7 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
        }
     }
 
+  /* Now swap out the symbols.  */
   for (i = 0; i < hash_table->strtabcount; i++)
     {
       struct elf_sym_strtab *elfsym = &hash_table->strtab[i];
@@ -9708,6 +9900,13 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
        elfsym->sym.st_name
          = (unsigned long) _bfd_elf_strtab_offset (flinfo->symstrtab,
                                                    elfsym->sym.st_name);
+
+      /* Inform the linker of the addition of this symbol.  */
+
+      if (flinfo->info->callbacks->ctf_new_symbol)
+       flinfo->info->callbacks->ctf_new_symbol (elfsym->dest_index,
+                                                &elfsym->sym);
+
       bed->s->swap_symbol_out (flinfo->output_bfd, &elfsym->sym,
                               ((bfd_byte *) symbuf
                                + (elfsym->dest_index
@@ -9716,14 +9915,6 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
                                + elfsym->destshndx_index));
     }
 
-  /* Allow the linker to examine the strtab and symtab now they are
-     populated.  */
-
-  if (flinfo->info->callbacks->examine_strtab)
-    flinfo->info->callbacks->examine_strtab (hash_table->strtab,
-                                            hash_table->strtabcount,
-                                            flinfo->symstrtab);
-
   hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
   pos = hdr->sh_offset + hdr->sh_size;
   amt = hash_table->strtabcount * bed->s->sizeof_sym;
@@ -10331,6 +10522,12 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
          eoinfo->failed = TRUE;
          return FALSE;
        }
+
+      /* Inform the linker of the addition of this symbol.  */
+
+      if (flinfo->info->callbacks->ctf_new_dynsym)
+       flinfo->info->callbacks->ctf_new_dynsym (h->dynindx, &sym);
+
       bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0);
 
       if (flinfo->hash_sec != NULL)
@@ -10533,10 +10730,21 @@ _bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info)
     {
       if ((kept->flags & SEC_GROUP) != 0)
        kept = match_group_member (sec, kept, info);
-      if (kept != NULL
-         && ((sec->rawsize != 0 ? sec->rawsize : sec->size)
-             != (kept->rawsize != 0 ? kept->rawsize : kept->size)))
-       kept = NULL;
+      if (kept != NULL)
+       {
+         if ((sec->rawsize != 0 ? sec->rawsize : sec->size)
+             != (kept->rawsize != 0 ? kept->rawsize : kept->size))
+           kept = NULL;
+         else
+           {
+             /* Get the real kept section.  */
+             asection *next;
+             for (next = kept->kept_section;
+                  next != NULL;
+                  next = next->kept_section)
+               kept = next;
+           }
+       }
       sec->kept_section = kept;
     }
   return kept;
@@ -10592,6 +10800,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
       extsymoff = symtab_hdr->sh_info;
     }
 
+  /* Enable GNU OSABI features in the output BFD that are used in the input
+     BFD.  */
+  if (bed->elf_osabi == ELFOSABI_NONE
+      || bed->elf_osabi == ELFOSABI_GNU
+      || bed->elf_osabi == ELFOSABI_FREEBSD)
+    elf_tdata (output_bfd)->has_gnu_osabi
+      |= (elf_tdata (input_bfd)->has_gnu_osabi
+         & (bfd_link_relocatable (flinfo->info)
+            ? -1 : ~elf_gnu_osabi_retain));
+
   /* Read the local symbols.  */
   isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
   if (isymbuf == NULL && locsymcount != 0)
@@ -11939,6 +12157,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   const char *std_attrs_section;
   struct elf_link_hash_table *htab = elf_hash_table (info);
   bfd_boolean sections_removed;
+  bfd_boolean ret;
 
   if (!is_elf_hash_table (htab))
     return FALSE;
@@ -11952,6 +12171,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   emit_relocs = (bfd_link_relocatable (info)
                 || info->emitrelocations);
 
+  memset (&flinfo, 0, sizeof (flinfo));
   flinfo.info = info;
   flinfo.output_bfd = abfd;
   flinfo.symstrtab = _bfd_elf_strtab_init ();
@@ -11971,16 +12191,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       /* Note that it is OK if symver_sec is NULL.  */
     }
 
-  flinfo.contents = NULL;
-  flinfo.external_relocs = NULL;
-  flinfo.internal_relocs = NULL;
-  flinfo.external_syms = NULL;
-  flinfo.locsym_shndx = NULL;
-  flinfo.internal_syms = NULL;
-  flinfo.indices = NULL;
-  flinfo.sections = NULL;
-  flinfo.symshndxbuf = NULL;
-  flinfo.filesym_count = 0;
+  if (info->unique_symbol
+      && !bfd_hash_table_init (&flinfo.local_hash_table,
+                              local_hash_newfunc,
+                              sizeof (struct local_hash_entry)))
+    return FALSE;
 
   /* The object attributes have been merged.  Remove the input
      sections from the link, and set the contents of the output
@@ -12260,6 +12475,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   if (info->strip != strip_all || emit_relocs)
     {
+      bfd_boolean name_local_sections;
+      const char *name;
+
       file_ptr off = elf_next_file_pos (abfd);
 
       _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
@@ -12282,10 +12500,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
       /* Output a symbol for each section.  We output these even if we are
         discarding local symbols, since they are used for relocs.  These
-        symbols have no names.  We store the index of each one in the
-        index field of the section, so that we can find it again when
+        symbols usually have no names.  We store the index of each one in
+        the index field of the section, so that we can find it again when
         outputting relocs.  */
 
+      name_local_sections
+       = (bed->elf_backend_name_local_section_symbols
+          && bed->elf_backend_name_local_section_symbols (abfd));
+
+      name = NULL;
       elfsym.st_size = 0;
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
       elfsym.st_other = 0;
@@ -12300,13 +12523,22 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              elfsym.st_shndx = i;
              if (!bfd_link_relocatable (info))
                elfsym.st_value = o->vma;
-             if (elf_link_output_symstrtab (&flinfo, NULL, &elfsym, o,
+             if (name_local_sections)
+               name = o->name;
+             if (elf_link_output_symstrtab (&flinfo, name, &elfsym, o,
                                             NULL) != 1)
                goto error_return;
            }
        }
     }
 
+  /* On some targets like Irix 5 the symbol split between local and global
+     ones recorded in the sh_info field needs to be done between section
+     and all other symbols.  */
+  if (bed->elf_backend_elfsym_local_is_section
+      && bed->elf_backend_elfsym_local_is_section (abfd))
+    symtab_hdr->sh_info = bfd_get_symcount (abfd);
+
   /* Allocate some memory to hold information read in from the input
      files.  */
   if (max_contents_size != 0)
@@ -12498,6 +12730,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          }
     }
 
+  ret = TRUE;
+
   /* Output any global symbols that got converted to local in a
      version script or due to symbol visibility.  We do this in a
      separate step since ELF requires all local symbols to appear
@@ -12510,7 +12744,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   eoinfo.file_sym_done = FALSE;
   bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
-    return FALSE;
+    {
+      ret = FALSE;
+      goto return_local_hash_table;
+    }
 
   /* If backend needs to output some local symbols not present in the hash
      table, do it now.  */
@@ -12524,7 +12761,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       if (! ((*bed->elf_backend_output_arch_local_syms)
             (abfd, info, &flinfo,
              (out_sym_func) elf_link_output_symstrtab)))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
     }
 
   /* That wrote out all the local symbols.  Finish up the symbol table
@@ -12533,7 +12773,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
      converted to local in a version script.  */
 
   /* The sh_info field records the index of the first non local symbol.  */
-  symtab_hdr->sh_info = bfd_get_symcount (abfd);
+  if (!symtab_hdr->sh_info)
+    symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
   if (dynamic
       && htab->dynsym != NULL
@@ -12570,9 +12811,18 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              BFD_ASSERT (indx > 0);
              sym.st_shndx = indx;
              if (! check_dynsym (abfd, &sym))
-               return FALSE;
+               {
+                 ret = FALSE;
+                 goto return_local_hash_table;
+               }
              sym.st_value = s->vma;
              dest = dynsym + dynindx * bed->s->sizeof_sym;
+
+             /* Inform the linker of the addition of this symbol.  */
+
+             if (info->callbacks->ctf_new_dynsym)
+               info->callbacks->ctf_new_dynsym (dynindx, &sym);
+
              bed->s->swap_symbol_out (abfd, &sym, dest, 0);
            }
        }
@@ -12591,20 +12841,31 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                 the original st_name with the dynstr_index.  */
              sym = e->isym;
              sym.st_other &= ~ELF_ST_VISIBILITY (-1);
+             sym.st_shndx = SHN_UNDEF;
 
              s = bfd_section_from_elf_index (e->input_bfd,
                                              e->isym.st_shndx);
-             if (s != NULL)
+             if (s != NULL
+                 && s->output_section != NULL
+                 && elf_section_data (s->output_section) != NULL)
                {
                  sym.st_shndx =
                    elf_section_data (s->output_section)->this_idx;
                  if (! check_dynsym (abfd, &sym))
-                   return FALSE;
+                   {
+                     ret = FALSE;
+                     goto return_local_hash_table;
+                   }
                  sym.st_value = (s->output_section->vma
                                  + s->output_offset
                                  + e->isym.st_value);
                }
 
+             /* Inform the linker of the addition of this symbol.  */
+
+             if (info->callbacks->ctf_new_dynsym)
+               info->callbacks->ctf_new_dynsym (e->dynindx, &sym);
+
              dest = dynsym + e->dynindx * bed->s->sizeof_sym;
              bed->s->swap_symbol_out (abfd, &sym, dest, 0);
            }
@@ -12617,7 +12878,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   eoinfo.flinfo = &flinfo;
   bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
-    return FALSE;
+    {
+      ret = FALSE;
+      goto return_local_hash_table;
+    }
 
   /* If backend needs to output some symbols not present in the hash
      table, do it now.  */
@@ -12631,7 +12895,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       if (! ((*bed->elf_backend_output_arch_syms)
             (abfd, info, &flinfo,
              (out_sym_func) elf_link_output_symstrtab)))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
     }
 
   /* Finalize the .strtab section.  */
@@ -12639,7 +12906,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   /* Swap out the .strtab section. */
   if (!elf_link_swap_symbols_out (&flinfo))
-    return FALSE;
+    {
+      ret = FALSE;
+      goto return_local_hash_table;
+    }
 
   /* Now we know the size of the symtab section.  */
   if (bfd_get_symcount (abfd) > 0)
@@ -12666,7 +12936,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
                  || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
-               return FALSE;
+               {
+                 ret = FALSE;
+                 goto return_local_hash_table;
+               }
            }
        }
 
@@ -12688,14 +12961,18 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
       if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
          || ! _bfd_elf_strtab_emit (abfd, flinfo.symstrtab))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
     }
 
   if (info->out_implib_bfd && !elf_output_implib (abfd, info))
     {
       _bfd_error_handler (_("%pB: failed to generate import library"),
                          info->out_implib_bfd);
-      return FALSE;
+      ret = FALSE;
+      goto return_local_hash_table;
     }
 
   /* Adjust the relocs to have the correct symbol indices.  */
@@ -12710,10 +12987,16 @@ 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, o, &esdo->rel, sort, info))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
       if (esdo->rela.hdr != NULL
          && !elf_link_adjust_relocs (abfd, o, &esdo->rela, sort, info))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
@@ -13032,17 +13315,25 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     {
       bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size);
       if (contents == NULL)
-       return FALSE;   /* Bail out and fail.  */
+       {
+         /* Bail out and fail.  */
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
       bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
       bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
       free (contents);
     }
 
-  return TRUE;
+ return_local_hash_table:
+  if (info->unique_symbol)
+    bfd_hash_table_free (&flinfo.local_hash_table);
+  return ret;
 
  error_return:
   elf_final_link_free (abfd, &flinfo);
-  return FALSE;
+  ret = FALSE;
+  goto return_local_hash_table;
 }
 \f
 /* Initialize COOKIE for input bfd ABFD.  */
@@ -13771,8 +14062,7 @@ _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_und_section (h->root.u.def.section))
+         && !bfd_is_const_section (h->root.u.def.section))
        h->root.u.def.section->flags |= SEC_KEEP;
     }
 }
@@ -13900,7 +14190,10 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
                        || (elf_section_data (o)->this_hdr.sh_type
                            == SHT_FINI_ARRAY)))
                || (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
-                   && elf_next_in_group (o) == NULL )))
+                   && elf_next_in_group (o) == NULL
+                   && elf_linked_to_section (o) == NULL)
+               || ((elf_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain)
+                   && (elf_section_flags (o) & SHF_GNU_RETAIN))))
          {
            if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
              return FALSE;
@@ -14067,7 +14360,7 @@ typedef struct
   flagword flag_value;
 } elf_flags_to_name_table;
 
-static elf_flags_to_name_table elf_flags_to_names [] =
+static const elf_flags_to_name_table elf_flags_to_names [] =
 {
   { "SHF_WRITE", SHF_WRITE },
   { "SHF_ALLOC", SHF_ALLOC },
@@ -14526,7 +14819,8 @@ _bfd_elf_section_already_linked (bfd *abfd,
       if (((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
           && ((flags & SEC_GROUP) != 0
               || strcmp (name, l->sec->name) == 0))
-         || (l->sec->owner->flags & BFD_PLUGIN) != 0)
+         || (l->sec->owner->flags & BFD_PLUGIN) != 0
+         || (sec->owner->flags & BFD_PLUGIN) != 0)
        {
          /* The section has already been linked.  See if we should
             issue a warning.  */
@@ -14767,7 +15061,7 @@ _bfd_elf_copy_link_hash_symbol_type (bfd *abfd,
   ehdest->target_internal = ehsrc->target_internal;
 
   isym.st_other = ehsrc->other;
-  elf_merge_st_other (abfd, ehdest, &isym, NULL, TRUE, FALSE);
+  elf_merge_st_other (abfd, ehdest, isym.st_other, NULL, TRUE, FALSE);
 }
 
 /* Append a RELA relocation REL to section S in BFD.  */
@@ -14802,12 +15096,16 @@ bfd_elf_define_start_stop (struct bfd_link_info *info,
 
   h = elf_link_hash_lookup (elf_hash_table (info), symbol,
                            FALSE, FALSE, TRUE);
+  /* NB: Common symbols will be turned into definition later.  */
   if (h != NULL
       && (h->root.type == bfd_link_hash_undefined
          || h->root.type == bfd_link_hash_undefweak
-         || ((h->ref_regular || h->def_dynamic) && !h->def_regular)))
+         || ((h->ref_regular || h->def_dynamic)
+             && !h->def_regular
+             && h->root.type != bfd_link_hash_common)))
     {
       bfd_boolean was_dynamic = h->ref_dynamic || h->def_dynamic;
+      h->verinfo.verdef = NULL;
       h->root.type = bfd_link_hash_defined;
       h->root.u.def.section = sec;
       h->root.u.def.value = 0;
@@ -14825,7 +15123,8 @@ bfd_elf_define_start_stop (struct bfd_link_info *info,
       else
        {
          if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
-           h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_PROTECTED;
+           h->other = ((h->other & ~ELF_ST_VISIBILITY (-1))
+                       | info->start_stop_visibility);
          if (was_dynamic)
            bfd_elf_link_record_dynamic_symbol (info, h);
        }
@@ -14884,3 +15183,96 @@ _bfd_elf_maybe_set_textrel (struct elf_link_hash_entry *h, void *inf)
     }
   return TRUE;
 }
+
+/* Add dynamic tags.  */
+
+bfd_boolean
+_bfd_elf_add_dynamic_tags (bfd *output_bfd, struct bfd_link_info *info,
+                          bfd_boolean need_dynamic_reloc)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  if (htab->dynamic_sections_created)
+    {
+      /* Add some entries to the .dynamic section.  We fill in the
+        values later, in finish_dynamic_sections, but we must add
+        the entries now so that we get the correct size for the
+        .dynamic section.  The DT_DEBUG entry is filled in by the
+        dynamic linker and used by the debugger.  */
+#define add_dynamic_entry(TAG, VAL) \
+  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
+
+      const struct elf_backend_data *bed
+       = get_elf_backend_data (output_bfd);
+
+      if (bfd_link_executable (info))
+       {
+         if (!add_dynamic_entry (DT_DEBUG, 0))
+           return FALSE;
+       }
+
+      if (htab->dt_pltgot_required || htab->splt->size != 0)
+       {
+         /* DT_PLTGOT is used by prelink even if there is no PLT
+            relocation.  */
+         if (!add_dynamic_entry (DT_PLTGOT, 0))
+           return FALSE;
+       }
+
+      if (htab->dt_jmprel_required || htab->srelplt->size != 0)
+       {
+         if (!add_dynamic_entry (DT_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL,
+                                    (bed->rela_plts_and_copies_p
+                                     ? DT_RELA : DT_REL))
+             || !add_dynamic_entry (DT_JMPREL, 0))
+           return FALSE;
+       }
+
+      if (htab->tlsdesc_plt
+         && (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
+             || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
+       return FALSE;
+
+      if (need_dynamic_reloc)
+       {
+         if (bed->rela_plts_and_copies_p)
+           {
+             if (!add_dynamic_entry (DT_RELA, 0)
+                 || !add_dynamic_entry (DT_RELASZ, 0)
+                 || !add_dynamic_entry (DT_RELAENT,
+                                        bed->s->sizeof_rela))
+               return FALSE;
+           }
+         else
+           {
+             if (!add_dynamic_entry (DT_REL, 0)
+                 || !add_dynamic_entry (DT_RELSZ, 0)
+                 || !add_dynamic_entry (DT_RELENT,
+                                        bed->s->sizeof_rel))
+               return FALSE;
+           }
+
+         /* If any dynamic relocs apply to a read-only section,
+            then we need a DT_TEXTREL entry.  */
+         if ((info->flags & DF_TEXTREL) == 0)
+           elf_link_hash_traverse (htab, _bfd_elf_maybe_set_textrel,
+                                   info);
+
+         if ((info->flags & DF_TEXTREL) != 0)
+           {
+             if (htab->ifunc_resolvers)
+               info->callbacks->einfo
+                 (_("%P: warning: GNU indirect functions with DT_TEXTREL "
+                    "may result in a segfault at runtime; recompile with %s\n"),
+                  bfd_link_dll (info) ? "-fPIC" : "-fPIE");
+
+             if (!add_dynamic_entry (DT_TEXTREL, 0))
+               return FALSE;
+           }
+       }
+    }
+#undef add_dynamic_entry
+
+  return TRUE;
+}