]> 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 5217528a79b2c61a33fecc0d32e07375f33a359a..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,
@@ -747,7 +764,7 @@ bfd_elf_link_record_local_dynamic_symbol (struct bfd_link_info *info,
                                          bfd *input_bfd,
                                          long input_indx)
 {
-  bfd_size_type amt;
+  size_t amt;
   struct elf_link_local_dynamic_entry *entry;
   struct elf_link_hash_table *eht;
   struct elf_strtab_hash *dynstr;
@@ -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.  */
@@ -2039,7 +2060,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
   /* We also need to define an indirection from the nondefault version
      of the symbol.  */
 
-nondefault:
+ nondefault:
   len = strlen (name);
   shortname = (char *) bfd_hash_allocate (&info->hash->table, len);
   if (shortname == NULL)
@@ -2057,9 +2078,26 @@ nondefault:
     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 @@ nondefault:
          /* xgettext:c-format */
          (_("%pB: unexpected redefinition of indirect versioned symbol `%s'"),
           abfd, shortname);
+      return TRUE;
     }
   else
     {
@@ -2079,32 +2118,36 @@ nondefault:
              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;
            }
        }
     }
@@ -2155,7 +2198,7 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
   struct elf_find_verdep_info *rinfo = (struct elf_find_verdep_info *) data;
   Elf_Internal_Verneed *t;
   Elf_Internal_Vernaux *a;
-  bfd_size_type amt;
+  size_t amt;
 
   /* We only care about symbols defined in shared objects with version
      information.  */
@@ -2643,8 +2686,7 @@ _bfd_elf_link_read_relocs (bfd *abfd,
   if (keep_memory)
     esdo->relocs = internal_relocs;
 
-  if (alloc1 != NULL)
-    free (alloc1);
+  free (alloc1);
 
   /* Don't free alloc2, since if it was allocated we are passing it
      back (under the name of internal_relocs).  */
@@ -2652,8 +2694,7 @@ _bfd_elf_link_read_relocs (bfd *abfd,
   return internal_relocs;
 
  error_return:
-  if (alloc1 != NULL)
-    free (alloc1);
+  free (alloc1);
   if (alloc2 != NULL)
     {
       if (keep_memory)
@@ -3323,8 +3364,8 @@ _bfd_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
 
   elf_hash_table (info)->tls_sec = tls;
 
-  /* Ensure the alignment of the first section is the largest alignment,
-     so that the tls segment starts aligned.  */
+  /* Ensure the alignment of the first section (usually .tdata) is the largest
+     alignment, so that the tls segment starts aligned.  */
   if (tls != NULL)
     tls->alignment_power = align;
 
@@ -3501,23 +3542,119 @@ _bfd_elf_add_dynamic_entry (struct bfd_link_info *info,
   return TRUE;
 }
 
-/* Add a DT_NEEDED entry for this dynamic object if DO_IT is true,
-   otherwise just check whether one already exists.  Returns -1 on error,
+/* Strip zero-sized dynamic sections.  */
+
+bfd_boolean
+_bfd_elf_strip_zero_sized_dynamic_sections (struct bfd_link_info *info)
+{
+  struct elf_link_hash_table *hash_table;
+  const struct elf_backend_data *bed;
+  asection *s, *sdynamic, **pp;
+  asection *rela_dyn, *rel_dyn;
+  Elf_Internal_Dyn dyn;
+  bfd_byte *extdyn, *next;
+  void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
+  bfd_boolean strip_zero_sized;
+  bfd_boolean strip_zero_sized_plt;
+
+  if (bfd_link_relocatable (info))
+    return TRUE;
+
+  hash_table = elf_hash_table (info);
+  if (!is_elf_hash_table (hash_table))
+    return FALSE;
+
+  if (!hash_table->dynobj)
+    return TRUE;
+
+  sdynamic= bfd_get_linker_section (hash_table->dynobj, ".dynamic");
+  if (!sdynamic)
+    return TRUE;
+
+  bed = get_elf_backend_data (hash_table->dynobj);
+  swap_dyn_in = bed->s->swap_dyn_in;
+
+  strip_zero_sized = FALSE;
+  strip_zero_sized_plt = FALSE;
+
+  /* Strip zero-sized dynamic sections.  */
+  rela_dyn = bfd_get_section_by_name (info->output_bfd, ".rela.dyn");
+  rel_dyn = bfd_get_section_by_name (info->output_bfd, ".rel.dyn");
+  for (pp = &info->output_bfd->sections; (s = *pp) != NULL;)
+    if (s->size == 0
+       && (s == rela_dyn
+           || s == rel_dyn
+           || s == hash_table->srelplt->output_section
+           || s == hash_table->splt->output_section))
+      {
+       *pp = s->next;
+       info->output_bfd->section_count--;
+       strip_zero_sized = TRUE;
+       if (s == rela_dyn)
+         s = rela_dyn;
+       if (s == rel_dyn)
+         s = rel_dyn;
+       else if (s == hash_table->splt->output_section)
+         {
+           s = hash_table->splt;
+           strip_zero_sized_plt = TRUE;
+         }
+       else
+         s = hash_table->srelplt;
+       s->flags |= SEC_EXCLUDE;
+       s->output_section = bfd_abs_section_ptr;
+      }
+    else
+      pp = &s->next;
+
+  if (strip_zero_sized_plt)
+    for (extdyn = sdynamic->contents;
+        extdyn < sdynamic->contents + sdynamic->size;
+        extdyn = next)
+      {
+       next = extdyn + bed->s->sizeof_dyn;
+       swap_dyn_in (hash_table->dynobj, extdyn, &dyn);
+       switch (dyn.d_tag)
+         {
+         default:
+           break;
+         case DT_JMPREL:
+         case DT_PLTRELSZ:
+         case DT_PLTREL:
+           /* Strip DT_PLTRELSZ, DT_JMPREL and DT_PLTREL entries if
+              the procedure linkage table (the .plt section) has been
+              removed.  */
+           memmove (extdyn, next,
+                    sdynamic->size - (next - sdynamic->contents));
+           next = extdyn;
+         }
+      }
+
+  if (strip_zero_sized)
+    {
+      /* Regenerate program headers.  */
+      elf_seg_map (info->output_bfd) = NULL;
+      return _bfd_elf_map_sections_to_segments (info->output_bfd, info);
+    }
+
+  return TRUE;
+}
+
+/* Add a DT_NEEDED entry for this dynamic object.  Returns -1 on error,
    1 if a DT_NEEDED tag already exists, and 0 on success.  */
 
-static int
-elf_add_dt_needed_tag (bfd *abfd,
-                      struct bfd_link_info *info,
-                      const char *soname,
-                      bfd_boolean do_it)
+int
+bfd_elf_add_dt_needed_tag (bfd *abfd, struct bfd_link_info *info)
 {
   struct elf_link_hash_table *hash_table;
   size_t strindex;
+  const char *soname;
 
   if (!_bfd_elf_link_create_dynstrtab (abfd, info))
     return -1;
 
   hash_table = elf_hash_table (info);
+  soname = elf_dt_name (abfd);
   strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
   if (strindex == (size_t) -1)
     return -1;
@@ -3547,17 +3684,11 @@ elf_add_dt_needed_tag (bfd *abfd,
          }
     }
 
-  if (do_it)
-    {
-      if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
-       return -1;
+  if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
+    return -1;
 
-      if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
-       return -1;
-    }
-  else
-    /* We were just checking for existence of the tag.  */
-    _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+  if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+    return -1;
 
   return 0;
 }
@@ -3674,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);
@@ -3868,8 +4004,16 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
          Elf_Internal_Rela *internal_relocs;
          bfd_boolean ok;
 
-         /* Don't check relocations in excluded sections.  */
-         if ((o->flags & SEC_RELOC) == 0
+         /* Don't check relocations in excluded sections.  Don't do
+            anything special with non-loaded, non-alloced sections.
+            In particular, any relocs in such sections should not
+            affect GOT and PLT reference counting (ie.  we don't
+            allow them to create GOT or PLT entries), there's no
+            possibility or desire to optimize TLS relocs, and
+            there's not much point in propagating relocs to shared
+            libs that the dynamic linker won't relocate.  */
+         if ((o->flags & SEC_ALLOC) == 0
+             || (o->flags & SEC_RELOC) == 0
              || (o->flags & SEC_EXCLUDE) != 0
              || o->reloc_count == 0
              || ((info->strip == strip_all || info->strip == strip_debugger)
@@ -3919,7 +4063,6 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   const struct elf_backend_data *bed;
   bfd_boolean add_needed;
   struct elf_link_hash_table *htab;
-  bfd_size_type amt;
   void *alloc_mark = NULL;
   struct bfd_hash_entry **old_table = NULL;
   unsigned int old_size = 0;
@@ -4070,7 +4213,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       char *audit = NULL;
       struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
       const Elf_Internal_Phdr *phdr;
-      int ret;
+      struct elf_link_loaded_list *loaded_lib;
 
       /* ld --just-symbols and dynamic objects don't mix very well.
         ld shouldn't allow it.  */
@@ -4098,7 +4241,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 
          if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
            {
-error_free_dyn:
+           error_free_dyn:
              free (dynbuf);
              goto error_return;
            }
@@ -4127,8 +4270,8 @@ error_free_dyn:
                  struct bfd_link_needed_list *n, **pn;
                  char *fnm, *anm;
                  unsigned int tagv = dyn.d_un.d_val;
+                 size_t amt = sizeof (struct bfd_link_needed_list);
 
-                 amt = sizeof (struct bfd_link_needed_list);
                  n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
                  fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (n == NULL || fnm == NULL)
@@ -4150,8 +4293,8 @@ error_free_dyn:
                  struct bfd_link_needed_list *n, **pn;
                  char *fnm, *anm;
                  unsigned int tagv = dyn.d_un.d_val;
+                 size_t amt = sizeof (struct bfd_link_needed_list);
 
-                 amt = sizeof (struct bfd_link_needed_list);
                  n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
                  fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (n == NULL || fnm == NULL)
@@ -4176,8 +4319,8 @@ error_free_dyn:
                  struct bfd_link_needed_list *n, **pn;
                  char *fnm, *anm;
                  unsigned int tagv = dyn.d_un.d_val;
+                 size_t amt = sizeof (struct bfd_link_needed_list);
 
-                 amt = sizeof (struct bfd_link_needed_list);
                  n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
                  fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (n == NULL || fnm == NULL)
@@ -4227,10 +4370,14 @@ error_free_dyn:
        if (phdr->p_type == PT_GNU_RELRO)
          {
            for (s = abfd->sections; s != NULL; s = s->next)
-             if ((s->flags & SEC_ALLOC) != 0
-                 && s->vma >= phdr->p_vaddr
-                 && s->vma + s->size <= phdr->p_vaddr + phdr->p_memsz)
-               s->flags |= SEC_READONLY;
+             {
+               unsigned int opb = bfd_octets_per_byte (abfd, s);
+
+               if ((s->flags & SEC_ALLOC) != 0
+                   && s->vma * opb >= phdr->p_vaddr
+                   && s->vma * opb + s->size <= phdr->p_vaddr + phdr->p_memsz)
+                 s->flags |= SEC_READONLY;
+             }
            break;
          }
 
@@ -4259,15 +4406,22 @@ error_free_dyn:
         will need to know it.  */
       elf_dt_name (abfd) = soname;
 
-      ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
-      if (ret < 0)
-       goto error_return;
-
       /* If we have already included this dynamic object in the
         link, just ignore it.  There is no reason to include a
         particular dynamic object more than once.  */
-      if (ret > 0)
-       return TRUE;
+      for (loaded_lib = htab->dyn_loaded;
+          loaded_lib != NULL;
+          loaded_lib = loaded_lib->next)
+       {
+         if (strcmp (elf_dt_name (loaded_lib->abfd), soname) == 0)
+           return TRUE;
+       }
+
+      /* Create dynamic sections for backends that require that be done
+        before setup_gnu_properties.  */
+      if (add_needed
+         && !_bfd_elf_link_create_dynamic_sections (abfd, info))
+       return FALSE;
 
       /* Save the DT_AUDIT entry for the linker emulation code. */
       elf_dt_audit (abfd) = audit;
@@ -4311,8 +4465,7 @@ error_free_dyn:
        {
          /* We store a pointer to the hash table entry for each
             external symbol.  */
-         amt = extsymcount;
-         amt *= sizeof (struct elf_link_hash_entry *);
+         size_t amt = extsymcount * 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;
@@ -4331,17 +4484,16 @@ error_free_dyn:
         to internal format.  */
       if (elf_dynversym (abfd) != 0)
        {
-         Elf_Internal_Shdr *versymhdr;
+         Elf_Internal_Shdr *versymhdr = &elf_tdata (abfd)->dynversym_hdr;
+         bfd_size_type amt = versymhdr->sh_size;
 
-         versymhdr = &elf_tdata (abfd)->dynversym_hdr;
-         amt = versymhdr->sh_size;
-         extversym = (Elf_External_Versym *) bfd_malloc (amt);
+         if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0)
+           goto error_free_sym;
+         extversym = (Elf_External_Versym *)
+           _bfd_malloc_and_read (abfd, amt, amt);
          if (extversym == NULL)
            goto error_free_sym;
-         if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
-             || bfd_bread (extversym, amt, abfd) != amt)
-           goto error_free_vers;
-         extversym_end = extversym + (amt / sizeof (* extversym));
+         extversym_end = extversym + amt / sizeof (*extversym);
        }
     }
 
@@ -4363,7 +4515,12 @@ error_free_dyn:
              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);
            }
        }
 
@@ -4392,9 +4549,13 @@ error_free_dyn:
       old_table = htab->root.table.table;
       old_size = htab->root.table.size;
       old_count = htab->root.table.count;
-      old_strtab = _bfd_elf_strtab_save (htab->dynstr);
-      if (old_strtab == NULL)
-       goto error_free_vers;
+      old_strtab = NULL;
+      if (htab->dynstr != NULL)
+       {
+         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++)
        {
@@ -4403,14 +4564,20 @@ error_free_dyn:
 
          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);
+               }
            }
        }
     }
@@ -4453,7 +4620,7 @@ error_free_dyn:
       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;
@@ -4461,7 +4628,7 @@ error_free_dyn:
       bfd *old_bfd;
       bfd_boolean matched;
 
-      override = FALSE;
+      override = NULL;
 
       flags = BSF_NO_FLAGS;
       sec = NULL;
@@ -4781,7 +4948,8 @@ error_free_dyn:
        }
 
       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;
 
@@ -4852,11 +5020,10 @@ error_free_dyn:
             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)
                {
@@ -4873,14 +5040,6 @@ error_free_dyn:
                      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
            {
@@ -4894,21 +5053,34 @@ error_free_dyn:
                  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;
@@ -5029,7 +5201,8 @@ error_free_dyn:
            }
 
          /* 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
@@ -5056,8 +5229,8 @@ error_free_dyn:
                     aliases can be checked.  */
                  if (!nondeflt_vers)
                    {
-                     amt = ((isymend - isym + 1)
-                            * sizeof (struct elf_link_hash_entry *));
+                     size_t amt = ((isymend - isym + 1)
+                                   * sizeof (struct elf_link_hash_entry *));
                      nondeflt_vers
                        = (struct elf_link_hash_entry **) bfd_malloc (amt);
                      if (!nondeflt_vers)
@@ -5091,21 +5264,19 @@ error_free_dyn:
                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),
                                          htab->needed, NULL))))
            {
-             int ret;
              const char *soname = elf_dt_name (abfd);
 
              info->callbacks->minfo ("%!", soname, old_bfd,
@@ -5130,12 +5301,11 @@ error_free_dyn:
              elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
                (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);
 
+             /* Create dynamic sections for backends that require
+                that be done before setup_gnu_properties.  */
+             if (!_bfd_elf_link_create_dynamic_sections (abfd, info))
+               return FALSE;
              add_needed = TRUE;
-             ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
-             if (ret < 0)
-               goto error_free_vers;
-
-             BFD_ASSERT (ret == 0);
            }
        }
     }
@@ -5199,17 +5369,10 @@ error_free_dyn:
        }
     }
 
-  if (extversym != NULL)
-    {
-      free (extversym);
-      extversym = NULL;
-    }
-
-  if (isymbuf != NULL)
-    {
-      free (isymbuf);
-      isymbuf = NULL;
-    }
+  free (extversym);
+  extversym = NULL;
+  free (isymbuf);
+  isymbuf = NULL;
 
   if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)
     {
@@ -5225,56 +5388,39 @@ 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 (htab->dynstr, old_strtab);
+      if (htab->dynstr != NULL)
+       _bfd_elf_strtab_restore (htab->dynstr, old_strtab);
       free (old_strtab);
       old_strtab = NULL;
       for (i = 0; i < htab->root.table.size; i++)
        {
          struct bfd_hash_entry *p;
          struct elf_link_hash_entry *h;
-         bfd_size_type size;
-         unsigned int alignment_power;
          unsigned int non_ir_ref_dynamic;
 
          for (p = htab->root.table.table[i]; p != NULL; p = p->next)
            {
-             h = (struct elf_link_hash_entry *) p;
-             if (h->root.type == bfd_link_hash_warning)
-               h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-             /* 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;
            }
@@ -5288,8 +5434,7 @@ error_free_dyn:
       free (old_tab);
       objalloc_free_block ((struct objalloc *) htab->root.table.memory,
                           alloc_mark);
-      if (nondeflt_vers != NULL)
-       free (nondeflt_vers);
+      free (nondeflt_vers);
       return TRUE;
     }
 
@@ -5312,6 +5457,7 @@ error_free_dyn:
        {
          struct elf_link_hash_entry *h = nondeflt_vers[cnt], *hi;
          char *shortname, *p;
+         size_t amt;
 
          p = strchr (h->root.root.string, ELF_VER_CHR);
          if (p == NULL
@@ -5372,13 +5518,12 @@ error_free_dyn:
       struct elf_link_hash_entry **hppend;
       struct elf_link_hash_entry **sorted_sym_hash;
       struct elf_link_hash_entry *h;
-      size_t sym_count;
+      size_t sym_count, amt;
 
       /* 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;
-      amt *= sizeof (*sorted_sym_hash);
+      amt = extsymcount * sizeof (*sorted_sym_hash);
       sorted_sym_hash = bfd_malloc (amt);
       if (sorted_sym_hash == NULL)
        goto error_return;
@@ -5553,7 +5698,7 @@ error_free_dyn:
        }
     }
 
-  if (is_elf_hash_table (htab) && add_needed)
+  if (dynamic && add_needed)
     {
       /* Add this bfd to the loaded list.  */
       struct elf_link_loaded_list *n;
@@ -5562,24 +5707,22 @@ error_free_dyn:
       if (n == NULL)
        goto error_return;
       n->abfd = abfd;
-      n->next = htab->loaded;
-      htab->loaded = n;
+      n->next = htab->dyn_loaded;
+      htab->dyn_loaded = n;
     }
+  if (dynamic && !add_needed
+      && (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) != 0)
+    elf_dyn_lib_class (abfd) |= DYN_NO_NEEDED;
 
   return TRUE;
 
  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)
-    free (extversym);
+  free (old_tab);
+  free (old_strtab);
+  free (nondeflt_vers);
+  free (extversym);
  error_free_sym:
-  if (isymbuf != NULL)
-    free (isymbuf);
+  free (isymbuf);
  error_return:
   return FALSE;
 }
@@ -5653,7 +5796,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
   unsigned char *included = NULL;
   carsym *symdefs;
   bfd_boolean loop;
-  bfd_size_type amt;
+  size_t amt;
   const struct elf_backend_data *bed;
   struct elf_link_hash_entry * (*archive_symbol_lookup)
     (bfd *, struct bfd_link_info *, const char *);
@@ -5673,8 +5816,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
   c = bfd_ardata (abfd)->symdef_count;
   if (c == 0)
     return TRUE;
-  amt = c;
-  amt *= sizeof (*included);
+  amt = c * sizeof (*included);
   included = (unsigned char *) bfd_zmalloc (amt);
   if (included == NULL)
     return FALSE;
@@ -5717,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
@@ -5734,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.  */
@@ -5788,12 +5938,10 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
   while (loop);
 
   free (included);
-
   return TRUE;
 
  error_return:
-  if (included != NULL)
-    free (included);
+  free (included);
   return FALSE;
 }
 
@@ -5864,9 +6012,7 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
      later.  */
   h->u.elf_hash_value = ha;
 
-  if (alc != NULL)
-    free (alc);
-
+  free (alc);
   return TRUE;
 }
 
@@ -5940,9 +6086,7 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
   if (s->min_dynindx < 0 || s->min_dynindx > h->dynindx)
     s->min_dynindx = h->dynindx;
 
-  if (alc != NULL)
-    free (alc);
-
+  free (alc);
   return TRUE;
 }
 
@@ -6520,7 +6664,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            {
              size_t indx;
 
-             name = lbasename (output_bfd->filename);
+             name = lbasename (bfd_get_filename (output_bfd));
              def.vd_hash = bfd_elf_hash (name);
              indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                          name, FALSE);
@@ -6747,7 +6891,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
              indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
                                          elf_dt_name (vn->vn_bfd) != NULL
                                          ? elf_dt_name (vn->vn_bfd)
-                                         : lbasename (vn->vn_bfd->filename),
+                                         : lbasename (bfd_get_filename
+                                                      (vn->vn_bfd)),
                                          FALSE);
              if (indx == (size_t) -1)
                return FALSE;
@@ -7033,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;
        }
     }
@@ -7567,6 +7715,37 @@ _bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
 {
   struct elf_link_hash_table *htab;
 
+  if (ind->dyn_relocs != NULL)
+    {
+      if (dir->dyn_relocs != NULL)
+       {
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
+
+         /* Add reloc counts against the indirect sym to the direct sym
+            list.  Merge any entries against the same section.  */
+         for (pp = &ind->dyn_relocs; (p = *pp) != NULL; )
+           {
+             struct elf_dyn_relocs *q;
+
+             for (q = dir->dyn_relocs; q != NULL; q = q->next)
+               if (q->sec == p->sec)
+                 {
+                   q->pc_count += p->pc_count;
+                   q->count += p->count;
+                   *pp = p->next;
+                   break;
+                 }
+             if (q == NULL)
+               pp = &p->next;
+           }
+         *pp = dir->dyn_relocs;
+       }
+
+      dir->dyn_relocs = ind->dyn_relocs;
+      ind->dyn_relocs = NULL;
+    }
+
   /* Copy down any references that we may have already seen to the
      symbol which just became indirect.  */
 
@@ -7682,6 +7861,7 @@ _bfd_elf_link_hash_table_init
 
   table->root.type = bfd_link_elf_hash_table;
   table->hash_table_id = target_id;
+  table->target_os = get_elf_backend_data (abfd)->target_os;
 
   return ret;
 }
@@ -7692,7 +7872,7 @@ struct bfd_link_hash_table *
 _bfd_elf_link_hash_table_create (bfd *abfd)
 {
   struct elf_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct elf_link_hash_table);
+  size_t amt = sizeof (struct elf_link_hash_table);
 
   ret = (struct elf_link_hash_table *) bfd_zmalloc (amt);
   if (ret == NULL)
@@ -7846,7 +8026,7 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
          const char *string;
          struct bfd_link_needed_list *l;
          unsigned int tagv = dyn.d_un.d_val;
-         bfd_size_type amt;
+         size_t amt;
 
          string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
          if (string == NULL)
@@ -7869,8 +8049,7 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
   return TRUE;
 
  error_return:
-  if (dynbuf != NULL)
-    free (dynbuf);
+  free (dynbuf);
   return FALSE;
 }
 
@@ -7935,9 +8114,10 @@ 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;
-  size_t i, shndx_count, total_size;
+  size_t i, shndx_count, total_size, amt;
 
-  indbuf = (Elf_Internal_Sym **) bfd_malloc2 (symcount, sizeof (*indbuf));
+  amt = symcount * sizeof (*indbuf);
+  indbuf = (Elf_Internal_Sym **) bfd_malloc (amt);
   if (indbuf == NULL)
     return NULL;
 
@@ -8048,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;
@@ -8062,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;
@@ -8207,15 +8387,11 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
 
   result = TRUE;
 
-done:
-  if (symtable1)
-    free (symtable1);
-  if (symtable2)
-    free (symtable2);
-  if (isymbuf1)
-    free (isymbuf1);
-  if (isymbuf2)
-    free (isymbuf2);
+ done:
+  free (symtable1);
+  free (symtable2);
+  free (isymbuf1);
+  free (isymbuf2);
 
   return result;
 }
@@ -8275,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
@@ -8294,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:
@@ -8474,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
@@ -8582,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);                                     \
@@ -8595,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 (<=);
@@ -8616,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 (&);
@@ -9509,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;
     }
@@ -9548,7 +9858,7 @@ 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;
+  size_t amt;
   size_t i;
   const struct elf_backend_data *bed;
   bfd_byte *symbuf;
@@ -9580,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];
@@ -9589,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
@@ -9597,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;
@@ -9692,7 +10002,7 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
     }
   BFD_ASSERT (abfd != NULL);
 
-  for (loaded = elf_hash_table (info)->loaded;
+  for (loaded = elf_hash_table (info)->dyn_loaded;
        loaded != NULL;
        loaded = loaded->next)
     {
@@ -9712,7 +10022,6 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
 
       /* We check each DSO for a possible hidden versioned definition.  */
       if (input == abfd
-         || (input->flags & DYNAMIC) == 0
          || elf_dynversym (input) == 0)
        continue;
 
@@ -9740,16 +10049,11 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
 
       /* Read in any version definitions.  */
       versymhdr = &elf_tdata (input)->dynversym_hdr;
-      extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
-      if (extversym == NULL)
-       goto error_ret;
-
       if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0
-         || (bfd_bread (extversym, versymhdr->sh_size, input)
-             != versymhdr->sh_size))
+         || (extversym = (Elf_External_Versym *)
+             _bfd_malloc_and_read (input, versymhdr->sh_size,
+                                   versymhdr->sh_size)) == NULL)
        {
-         free (extversym);
-       error_ret:
          free (isymbuf);
          return FALSE;
        }
@@ -9886,11 +10190,13 @@ 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)
-       (*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);
+       {
+         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_DIAGNOSE
+            && !flinfo->info->warn_unresolved_syms);
+       }
 
       /* Strip a global symbol defined in a discarded section.  */
       if (h->indx == -3)
@@ -10216,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)
@@ -10418,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;
@@ -10477,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)
@@ -10567,6 +10900,18 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
       /* If this symbol is defined in a section which we are
         discarding, we don't need to keep it.  */
+      if (isym->st_shndx != SHN_UNDEF
+         && isym->st_shndx < SHN_LORESERVE
+         && isec->output_section == NULL
+         && flinfo->info->non_contiguous_regions
+         && flinfo->info->non_contiguous_regions_warnings)
+       {
+         _bfd_error_handler (_("warning: --enable-non-contiguous-regions "
+                               "discards section `%s' from '%s'\n"),
+                             isec->name, bfd_get_filename (isec->owner));
+         continue;
+       }
+
       if (isym->st_shndx != SHN_UNDEF
          && isym->st_shndx < SHN_LORESERVE
          && bfd_section_removed_from_list (output_bfd,
@@ -10614,7 +10959,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
          osym.st_shndx = SHN_ABS;
          if (!elf_link_output_symstrtab (flinfo,
                                          (input_bfd->lto_output ? NULL
-                                          : input_bfd->filename),
+                                          : bfd_get_filename (input_bfd)),
                                          &osym, bfd_abs_section_ptr,
                                          NULL))
            return FALSE;
@@ -10916,7 +11261,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 #ifdef DEBUG
                  printf ("Encountered a complex symbol!");
                  printf (" (input_bfd %s, section %s, reloc %ld\n",
-                         input_bfd->filename, o->name,
+                         bfd_get_filename (input_bfd), o->name,
                          (long) (rel - internal_relocs));
                  printf (" symbol: idx  %8.8lx, name %s\n",
                          r_symndx, sym_name);
@@ -11566,8 +11911,8 @@ elf_fixup_link_order (bfd *abfd, asection *o)
   struct bfd_link_order *p;
   bfd *sub;
   struct bfd_link_order **sections;
-  asection *s, *other_sec, *linkorder_sec;
-  bfd_vma offset;
+  asection *other_sec, *linkorder_sec;
+  bfd_vma offset;  /* Octets.  */
 
   other_sec = NULL;
   linkorder_sec = NULL;
@@ -11577,7 +11922,7 @@ elf_fixup_link_order (bfd *abfd, asection *o)
     {
       if (p->type == bfd_indirect_link_order)
        {
-         s = p->u.indirect.section;
+         asection *s = p->u.indirect.section;
          sub = s->owner;
          if ((s->flags & SEC_LINKER_CREATED) == 0
              && bfd_get_flavour (sub) == bfd_target_elf_flavour
@@ -11632,11 +11977,12 @@ elf_fixup_link_order (bfd *abfd, asection *o)
   for (n = 0; n < seen_linkorder; n++)
     {
       bfd_vma mask;
-      s = sections[n]->u.indirect.section;
-      mask = ~(bfd_vma) 0 << s->alignment_power;
+      asection *s = sections[n]->u.indirect.section;
+      unsigned int opb = bfd_octets_per_byte (abfd, s);
+
+      mask = ~(bfd_vma) 0 << s->alignment_power * opb;
       offset = (offset + ~mask) & mask;
-      s->output_offset = offset / bfd_octets_per_byte (abfd, s);
-      sections[n]->offset = offset;
+      sections[n]->offset = s->output_offset = offset / opb;
       offset += sections[n]->size;
     }
 
@@ -11661,6 +12007,7 @@ elf_output_implib (bfd *abfd, struct bfd_link_info *info)
   long symcount;
   long src_count;
   elf_symbol_type *osymbuf;
+  size_t amt;
 
   implib_bfd = info->out_implib_bfd;
   bed = get_elf_backend_data (abfd);
@@ -11718,8 +12065,8 @@ elf_output_implib (bfd *abfd, struct bfd_link_info *info)
 
 
   /* Make symbols absolute.  */
-  osymbuf = (elf_symbol_type *) bfd_alloc2 (implib_bfd, symcount,
-                                           sizeof (*osymbuf));
+  amt = symcount * sizeof (*osymbuf);
+  osymbuf = (elf_symbol_type *) bfd_alloc (implib_bfd, amt);
   if (osymbuf == NULL)
     goto free_sym_buf;
 
@@ -11748,7 +12095,7 @@ elf_output_implib (bfd *abfd, struct bfd_link_info *info)
 
   ret = TRUE;
 
-free_sym_buf:
+ free_sym_buf:
   free (sympp);
   return ret;
 }
@@ -11760,32 +12107,21 @@ elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo)
 
   if (flinfo->symstrtab != NULL)
     _bfd_elf_strtab_free (flinfo->symstrtab);
-  if (flinfo->contents != NULL)
-    free (flinfo->contents);
-  if (flinfo->external_relocs != NULL)
-    free (flinfo->external_relocs);
-  if (flinfo->internal_relocs != NULL)
-    free (flinfo->internal_relocs);
-  if (flinfo->external_syms != NULL)
-    free (flinfo->external_syms);
-  if (flinfo->locsym_shndx != NULL)
-    free (flinfo->locsym_shndx);
-  if (flinfo->internal_syms != NULL)
-    free (flinfo->internal_syms);
-  if (flinfo->indices != NULL)
-    free (flinfo->indices);
-  if (flinfo->sections != NULL)
-    free (flinfo->sections);
-  if (flinfo->symshndxbuf != NULL
-      && flinfo->symshndxbuf != (Elf_External_Sym_Shndx *) -1)
+  free (flinfo->contents);
+  free (flinfo->external_relocs);
+  free (flinfo->internal_relocs);
+  free (flinfo->external_syms);
+  free (flinfo->locsym_shndx);
+  free (flinfo->internal_syms);
+  free (flinfo->indices);
+  free (flinfo->sections);
+  if (flinfo->symshndxbuf != (Elf_External_Sym_Shndx *) -1)
     free (flinfo->symshndxbuf);
   for (o = obfd->sections; o != NULL; o = o->next)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
-      if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL)
-       free (esdo->rel.hashes);
-      if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL)
-       free (esdo->rela.hashes);
+      free (esdo->rel.hashes);
+      free (esdo->rela.hashes);
     }
 }
 
@@ -11821,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;
@@ -11834,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 ();
@@ -11853,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
@@ -12142,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);
@@ -12164,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;
@@ -12182,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)
@@ -12246,7 +12596,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   if (htab->tls_sec)
     {
-      bfd_vma base, end = 0;
+      bfd_vma base, end = 0;  /* Both bytes.  */
       asection *sec;
 
       for (sec = htab->tls_sec;
@@ -12254,6 +12604,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
           sec = sec->next)
        {
          bfd_size_type size = sec->size;
+         unsigned int opb = bfd_octets_per_byte (abfd, sec);
 
          if (size == 0
              && (sec->flags & SEC_HAS_CONTENTS) == 0)
@@ -12261,9 +12612,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              struct bfd_link_order *ord = sec->map_tail.link_order;
 
              if (ord != NULL)
-               size = ord->offset + ord->size;
+               size = ord->offset * opb + ord->size;
            }
-         end = sec->vma + size;
+         end = sec->vma + size / opb;
        }
       base = htab->tls_sec->vma;
       /* Only align end of TLS section if static TLS doesn't have special
@@ -12372,14 +12723,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (!info->reduce_memory_overheads)
     {
       for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
-       if (bfd_get_flavour (sub) == bfd_target_elf_flavour
-           && elf_tdata (sub)->symbuf)
+       if (bfd_get_flavour (sub) == bfd_target_elf_flavour)
          {
            free (elf_tdata (sub)->symbuf);
            elf_tdata (sub)->symbuf = NULL;
          }
     }
 
+  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
@@ -12392,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.  */
@@ -12406,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
@@ -12415,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
@@ -12452,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);
            }
        }
@@ -12473,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);
            }
@@ -12499,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.  */
@@ -12513,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.  */
@@ -12521,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)
@@ -12548,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;
+               }
            }
        }
 
@@ -12570,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.  */
@@ -12592,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.  */
@@ -12776,6 +13177,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              if (bed->dtrel_excludes_plt && htab->srelplt != NULL)
                {
+                 unsigned int opb = bfd_octets_per_byte (abfd, o);
+
                  /* Don't count procedure linkage table relocs in the
                     overall reloc count.  */
                  sh_size -= htab->srelplt->size;
@@ -12795,7 +13198,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                  /* If .rela.plt is the first .rela section, exclude
                     it from DT_RELA.  */
                  else if (sh_addr == (htab->srelplt->output_section->vma
-                                      + htab->srelplt->output_offset))
+                                      + htab->srelplt->output_offset) * opb)
                    sh_addr += htab->srelplt->size;
                }
 
@@ -12816,8 +13219,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        goto error_return;
 
       /* Check for DT_TEXTREL (late, in case the backend removes it).  */
-      if (((info->warn_shared_textrel && bfd_link_pic (info))
-          || info->error_textrel)
+      if (bfd_link_textrel_check (info)
          && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
        {
          bfd_byte *dyncon, *dynconend;
@@ -12832,12 +13234,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              if (dyn.d_tag == DT_TEXTREL)
                {
-                 if (info->error_textrel)
+                 if (info->textrel_check == textrel_check_error)
                    info->callbacks->einfo
                      (_("%P%X: read-only segment has dynamic relocations\n"));
+                 else if (bfd_link_dll (info))
+                   info->callbacks->einfo
+                     (_("%P: warning: creating DT_TEXTREL in a shared object\n"));
                  else
                    info->callbacks->einfo
-                     (_("%P: warning: creating a DT_TEXTREL in a shared object\n"));
+                     (_("%P: warning: creating DT_TEXTREL in a PIE\n"));
                  break;
                }
            }
@@ -12910,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.  */
@@ -12979,8 +13392,7 @@ fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd)
   Elf_Internal_Shdr *symtab_hdr;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  if (cookie->locsyms != NULL
-      && symtab_hdr->contents != (unsigned char *) cookie->locsyms)
+  if (symtab_hdr->contents != (unsigned char *) cookie->locsyms)
     free (cookie->locsyms);
 }
 
@@ -13017,7 +13429,7 @@ static void
 fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
                        asection *sec)
 {
-  if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels)
+  if (elf_section_data (sec)->relocs != cookie->rels)
     free (cookie->rels);
 }
 
@@ -13316,7 +13728,7 @@ _bfd_elf_gc_mark_debug_special_section_group (asection *grp)
 
 bfd_boolean
 _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
-                                elf_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED)
+                                elf_gc_mark_hook_fn mark_hook)
 {
   bfd *ibfd;
 
@@ -13345,11 +13757,33 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
                   && (isec->flags & SEC_ALLOC) != 0
                   && elf_section_type (isec) != SHT_NOTE)
            some_kept = TRUE;
+         else
+           {
+             /* Since all sections, except for backend specific ones,
+                have been garbage collected, call mark_hook on this
+                section if any of its linked-to sections is marked.  */
+             asection *linked_to_sec = elf_linked_to_section (isec);
+             for (; linked_to_sec != NULL;
+                  linked_to_sec = elf_linked_to_section (linked_to_sec))
+               if (linked_to_sec->gc_mark)
+                 {
+                   if (!_bfd_elf_gc_mark (info, isec, mark_hook))
+                     return FALSE;
+                   break;
+                 }
+           }
 
          if (!debug_frag_seen
              && (isec->flags & SEC_DEBUGGING)
              && CONST_STRNEQ (isec->name, ".debug_line."))
            debug_frag_seen = TRUE;
+         else if (strcmp (bfd_section_name (isec),
+                          "__patchable_function_entries") == 0
+                  && elf_linked_to_section (isec) == NULL)
+             info->callbacks->einfo (_("%F%P: %pB(%pA): error: "
+                                       "need linked-to section "
+                                       "for --gc-sections\n"),
+                                     isec->owner, isec);
        }
 
       /* If no non-note alloc section in this file will be kept, then
@@ -13359,14 +13793,16 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
 
       /* Keep debug and special sections like .comment when they are
         not part of a group.  Also keep section groups that contain
-        just debug sections or special sections.  */
+        just debug sections or special sections.  NB: Sections with
+        linked-to section has been handled above.  */
       for (isec = ibfd->sections; isec != NULL; isec = isec->next)
        {
          if ((isec->flags & SEC_GROUP) != 0)
            _bfd_elf_gc_mark_debug_special_section_group (isec);
          else if (((isec->flags & SEC_DEBUGGING) != 0
                    || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
-                  && elf_next_in_group (isec) == NULL)
+                  && elf_next_in_group (isec) == NULL
+                  && elf_linked_to_section (isec) == NULL)
            isec->gc_mark = 1;
          if (isec->gc_mark && (isec->flags & SEC_DEBUGGING) != 0)
            has_kept_debug_info = TRUE;
@@ -13626,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;
     }
 }
@@ -13755,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;
@@ -13922,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 },
@@ -14226,7 +14664,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
     {
       asection *i;
       int eh_changed = 0;
-      unsigned int eh_alignment;
+      unsigned int eh_alignment;  /* Octets.  */
 
       for (i = o->map_head.s; i != NULL; i = i->map_head.s)
        {
@@ -14253,7 +14691,8 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
          fini_reloc_cookie_for_section (&cookie, i);
        }
 
-      eh_alignment = 1 << o->alignment_power;
+      eh_alignment = ((1 << o->alignment_power)
+                     * bfd_octets_per_byte (output_bfd, o));
       /* Skip over zero terminator, and prevent empty sections from
         adding alignment padding at the end.  */
       for (i = o->map_tail.s; i != NULL; i = i->map_tail.s)
@@ -14380,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.  */
@@ -14621,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.  */
@@ -14656,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;
@@ -14679,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);
        }
@@ -14687,3 +15132,147 @@ bfd_elf_define_start_stop (struct bfd_link_info *info,
     }
   return NULL;
 }
+
+/* Find dynamic relocs for H that apply to read-only sections.  */
+
+asection *
+_bfd_elf_readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+  struct elf_dyn_relocs *p;
+
+  for (p = h->dyn_relocs; p != NULL; p = p->next)
+    {
+      asection *s = p->sec->output_section;
+
+      if (s != NULL && (s->flags & SEC_READONLY) != 0)
+       return p->sec;
+    }
+  return NULL;
+}
+
+/* Set DF_TEXTREL if we find any dynamic relocs that apply to
+   read-only sections.  */
+
+bfd_boolean
+_bfd_elf_maybe_set_textrel (struct elf_link_hash_entry *h, void *inf)
+{
+  asection *sec;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  sec = _bfd_elf_readonly_dynrelocs (h);
+  if (sec != NULL)
+    {
+      struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+      info->flags |= DF_TEXTREL;
+      /* xgettext:c-format */
+      info->callbacks->minfo (_("%pB: dynamic relocation against `%pT' "
+                               "in read-only section `%pA'\n"),
+                             sec->owner, h->root.root.string, sec);
+
+      if (bfd_link_textrel_check (info))
+       /* xgettext:c-format */
+       info->callbacks->einfo (_("%P: %pB: warning: relocation against `%s' "
+                                 "in read-only section `%pA'\n"),
+                               sec->owner, h->root.root.string, sec);
+
+      /* Not an error, just cut short the traversal.  */
+      return FALSE;
+    }
+  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;
+}