gdb/
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 98ea753579630ebaffefcac0abc0ba384164dc49..232c0b13c5aacfbd55074098634815f7a0385443 100644 (file)
@@ -1,6 +1,6 @@
 /* ELF linking support for BFD.
    Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
 /* ELF linking support for BFD.
    Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006, 2007, 2008, 2009, 2010
+   2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -36,7 +36,6 @@
 struct elf_info_failed
 {
   struct bfd_link_info *info;
 struct elf_info_failed
 {
   struct bfd_link_info *info;
-  struct bfd_elf_version_tree *verdefs;
   bfd_boolean failed;
 };
 
   bfd_boolean failed;
 };
 
@@ -86,6 +85,7 @@ _bfd_elf_define_linkage_sym (bfd *abfd,
     return NULL;
   h = (struct elf_link_hash_entry *) bh;
   h->def_regular = 1;
     return NULL;
   h = (struct elf_link_hash_entry *) bh;
   h->def_regular = 1;
+  h->non_elf = 0;
   h->type = STT_OBJECT;
   h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
 
   h->type = STT_OBJECT;
   h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
 
@@ -104,23 +104,23 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
   struct elf_link_hash_table *htab = elf_hash_table (info);
 
   /* This function may be called more than once.  */
   struct elf_link_hash_table *htab = elf_hash_table (info);
 
   /* This function may be called more than once.  */
-  s = bfd_get_section_by_name (abfd, ".got");
-  if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0)
+  s = bfd_get_linker_section (abfd, ".got");
+  if (s != NULL)
     return TRUE;
 
   flags = bed->dynamic_sec_flags;
 
     return TRUE;
 
   flags = bed->dynamic_sec_flags;
 
-  s = bfd_make_section_with_flags (abfd,
-                                  (bed->rela_plts_and_copies_p
-                                   ? ".rela.got" : ".rel.got"),
-                                  (bed->dynamic_sec_flags
-                                   | SEC_READONLY));
+  s = bfd_make_section_anyway_with_flags (abfd,
+                                         (bed->rela_plts_and_copies_p
+                                          ? ".rela.got" : ".rel.got"),
+                                         (bed->dynamic_sec_flags
+                                          | SEC_READONLY));
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
   htab->srelgot = s;
 
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
   htab->srelgot = s;
 
-  s = bfd_make_section_with_flags (abfd, ".got", flags);
+  s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
   if (s == NULL
       || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
   if (s == NULL
       || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
@@ -128,7 +128,7 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
 
   if (bed->want_got_plt)
     {
 
   if (bed->want_got_plt)
     {
-      s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
+      s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
       if (s == NULL
          || !bfd_set_section_alignment (abfd, s,
                                         bed->s->log_file_align))
       if (s == NULL
          || !bfd_set_section_alignment (abfd, s,
                                         bed->s->log_file_align))
@@ -187,6 +187,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   flagword flags;
   asection *s;
   const struct elf_backend_data *bed;
   flagword flags;
   asection *s;
   const struct elf_backend_data *bed;
+  struct elf_link_hash_entry *h;
 
   if (! is_elf_hash_table (info->hash))
     return FALSE;
 
   if (! is_elf_hash_table (info->hash))
     return FALSE;
@@ -206,44 +207,44 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
      shared library does not.  */
   if (info->executable)
     {
      shared library does not.  */
   if (info->executable)
     {
-      s = bfd_make_section_with_flags (abfd, ".interp",
-                                      flags | SEC_READONLY);
+      s = bfd_make_section_anyway_with_flags (abfd, ".interp",
+                                             flags | SEC_READONLY);
       if (s == NULL)
        return FALSE;
     }
 
   /* Create sections to hold version informations.  These are removed
      if they are not needed.  */
       if (s == NULL)
        return FALSE;
     }
 
   /* Create sections to hold version informations.  These are removed
      if they are not needed.  */
-  s = bfd_make_section_with_flags (abfd, ".gnu.version_d",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_d",
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".gnu.version",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version",
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, 1))
     return FALSE;
 
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, 1))
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".gnu.version_r",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_r",
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".dynsym",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".dynsym",
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".dynstr",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".dynstr",
+                                         flags | SEC_READONLY);
   if (s == NULL)
     return FALSE;
 
   if (s == NULL)
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".dynamic", flags);
+  s = bfd_make_section_anyway_with_flags (abfd, ".dynamic", flags);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
@@ -254,12 +255,15 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
      section.  We don't want to define it if there is no .dynamic
      section, since on some ELF platforms the start up code examines it
      to decide how to initialize the process.  */
      section.  We don't want to define it if there is no .dynamic
      section, since on some ELF platforms the start up code examines it
      to decide how to initialize the process.  */
-  if (!_bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC"))
+  h = _bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC");
+  elf_hash_table (info)->hdynamic = h;
+  if (h == NULL)
     return FALSE;
 
   if (info->emit_hash)
     {
     return FALSE;
 
   if (info->emit_hash)
     {
-      s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY);
+      s = bfd_make_section_anyway_with_flags (abfd, ".hash",
+                                             flags | SEC_READONLY);
       if (s == NULL
          || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
        return FALSE;
       if (s == NULL
          || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
        return FALSE;
@@ -268,8 +272,8 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   if (info->emit_gnu_hash)
     {
 
   if (info->emit_gnu_hash)
     {
-      s = bfd_make_section_with_flags (abfd, ".gnu.hash",
-                                      flags | SEC_READONLY);
+      s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash",
+                                             flags | SEC_READONLY);
       if (s == NULL
          || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
        return FALSE;
       if (s == NULL
          || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
        return FALSE;
@@ -285,7 +289,8 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   /* Let the backend create the rest of the sections.  This lets the
      backend set the right flags.  The backend will normally create
      the .got and .plt sections.  */
   /* Let the backend create the rest of the sections.  This lets the
      backend set the right flags.  The backend will normally create
      the .got and .plt sections.  */
-  if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
+  if (bed->elf_backend_create_dynamic_sections == NULL
+      || ! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
     return FALSE;
 
   elf_hash_table (info)->dynamic_sections_created = TRUE;
     return FALSE;
 
   elf_hash_table (info)->dynamic_sections_created = TRUE;
@@ -319,7 +324,7 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (bed->plt_readonly)
     pltflags |= SEC_READONLY;
 
   if (bed->plt_readonly)
     pltflags |= SEC_READONLY;
 
-  s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
+  s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
     return FALSE;
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
     return FALSE;
@@ -336,10 +341,10 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
        return FALSE;
     }
 
        return FALSE;
     }
 
-  s = bfd_make_section_with_flags (abfd,
-                                  (bed->rela_plts_and_copies_p
-                                   ? ".rela.plt" : ".rel.plt"),
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd,
+                                         (bed->rela_plts_and_copies_p
+                                          ? ".rela.plt" : ".rel.plt"),
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
@@ -356,9 +361,8 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         image and use a R_*_COPY reloc to tell the dynamic linker to
         initialize them at run time.  The linker script puts the .dynbss
         section into the .bss section of the final image.  */
         image and use a R_*_COPY reloc to tell the dynamic linker to
         initialize them at run time.  The linker script puts the .dynbss
         section into the .bss section of the final image.  */
-      s = bfd_make_section_with_flags (abfd, ".dynbss",
-                                      (SEC_ALLOC
-                                       | SEC_LINKER_CREATED));
+      s = bfd_make_section_anyway_with_flags (abfd, ".dynbss",
+                                             (SEC_ALLOC | SEC_LINKER_CREATED));
       if (s == NULL)
        return FALSE;
 
       if (s == NULL)
        return FALSE;
 
@@ -375,10 +379,10 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         copy relocs.  */
       if (! info->shared)
        {
         copy relocs.  */
       if (! info->shared)
        {
-         s = bfd_make_section_with_flags (abfd,
-                                          (bed->rela_plts_and_copies_p
-                                           ? ".rela.bss" : ".rel.bss"),
-                                          flags | SEC_READONLY);
+         s = bfd_make_section_anyway_with_flags (abfd,
+                                                 (bed->rela_plts_and_copies_p
+                                                  ? ".rela.bss" : ".rel.bss"),
+                                                 flags | SEC_READONLY);
          if (s == NULL
              || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
            return FALSE;
          if (s == NULL
              || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
            return FALSE;
@@ -568,7 +572,7 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
 
   h->def_regular = 1;
 
 
   h->def_regular = 1;
 
-  if (provide && hidden)
+  if (hidden)
     {
       bed = get_elf_backend_data (output_bfd);
       h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
     {
       bed = get_elf_backend_data (output_bfd);
       h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
@@ -720,9 +724,6 @@ elf_link_renumber_hash_table_dynsyms (struct elf_link_hash_entry *h,
 {
   size_t *count = (size_t *) data;
 
 {
   size_t *count = (size_t *) data;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if (h->forced_local)
     return TRUE;
 
   if (h->forced_local)
     return TRUE;
 
@@ -742,9 +743,6 @@ elf_link_renumber_local_hash_table_dynsyms (struct elf_link_hash_entry *h,
 {
   size_t *count = (size_t *) data;
 
 {
   size_t *count = (size_t *) data;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if (!h->forced_local)
     return TRUE;
 
   if (!h->forced_local)
     return TRUE;
 
@@ -784,8 +782,7 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
          asection *ip;
 
          if (htab->dynobj != NULL
          asection *ip;
 
          if (htab->dynobj != NULL
-             && (ip = bfd_get_section_by_name (htab->dynobj, p->name)) != NULL
-             && (ip->flags & SEC_LINKER_CREATED)
+             && (ip = bfd_get_linker_section (htab->dynobj, p->name)) != NULL
              && ip->output_section == p)
            return TRUE;
        }
              && ip->output_section == p)
            return TRUE;
        }
@@ -898,6 +895,33 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
     }
 }
 
     }
 }
 
+/* Mark if a symbol has a definition in a dynamic object or is
+   weak in all dynamic objects.  */
+
+static void
+_bfd_elf_mark_dynamic_def_weak (struct elf_link_hash_entry *h,
+                               asection *sec, int bind)
+{
+  if (!h->dynamic_def)
+    {
+      if (!bfd_is_und_section (sec))
+       h->dynamic_def = 1;
+      else
+       {
+         /* Check if this symbol is weak in all dynamic objects. If it
+            is the first time we see it in a dynamic object, we mark
+            if it is weak. Otherwise, we clear it.  */
+         if (!h->ref_dynamic)
+           {
+             if (bind == STB_WEAK)
+               h->dynamic_weak = 1;
+           }
+         else if (bind != STB_WEAK)
+           h->dynamic_weak = 0;
+       }
+    }
+}
+
 /* This function is called when we want to define a new symbol.  It
    handles the various cases which arise when we find a definition in
    a dynamic object, or when there is already a definition in a
 /* This function is called when we want to define a new symbol.  It
    handles the various cases which arise when we find a definition in
    a dynamic object, or when there is already a definition in a
@@ -917,6 +941,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
                       Elf_Internal_Sym *sym,
                       asection **psec,
                       bfd_vma *pvalue,
                       Elf_Internal_Sym *sym,
                       asection **psec,
                       bfd_vma *pvalue,
+                      bfd_boolean *pold_weak,
                       unsigned int *pold_alignment,
                       struct elf_link_hash_entry **sym_hash,
                       bfd_boolean *skip,
                       unsigned int *pold_alignment,
                       struct elf_link_hash_entry **sym_hash,
                       bfd_boolean *skip,
@@ -926,6 +951,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
 {
   asection *sec, *oldsec;
   struct elf_link_hash_entry *h;
 {
   asection *sec, *oldsec;
   struct elf_link_hash_entry *h;
+  struct elf_link_hash_entry *hi;
   struct elf_link_hash_entry *flip;
   int bind;
   bfd *oldbfd;
   struct elf_link_hash_entry *flip;
   int bind;
   bfd *oldbfd;
@@ -942,7 +968,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   /* Silently discard TLS symbols from --just-syms.  There's no way to
      combine a static TLS block with a new TLS block for this executable.  */
   if (ELF_ST_TYPE (sym->st_info) == STT_TLS
   /* Silently discard TLS symbols from --just-syms.  There's no way to
      combine a static TLS block with a new TLS block for this executable.  */
   if (ELF_ST_TYPE (sym->st_info) == STT_TLS
-      && sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+      && sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
     {
       *skip = TRUE;
       return TRUE;
     {
       *skip = TRUE;
       return TRUE;
@@ -964,8 +990,9 @@ _bfd_elf_merge_symbol (bfd *abfd,
   if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
     return TRUE;
 
   if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
     return TRUE;
 
-  /* For merging, we only care about real symbols.  */
-
+  /* For merging, we only care about real symbols.  But we need to make
+     sure that indirect symbol dynamic flags are updated.  */
+  hi = h;
   while (h->root.type == bfd_link_hash_indirect
         || h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
   while (h->root.type == bfd_link_hash_indirect
         || h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
@@ -1013,6 +1040,13 @@ _bfd_elf_merge_symbol (bfd *abfd,
       break;
     }
 
       break;
     }
 
+  /* Differentiate strong and weak symbols.  */
+  newweak = bind == STB_WEAK;
+  oldweak = (h->root.type == bfd_link_hash_defweak
+            || h->root.type == bfd_link_hash_undefweak);
+  if (pold_weak)
+    *pold_weak = oldweak;
+
   /* In cases involving weak versioned symbols, we may wind up trying
      to merge a symbol with itself.  Catch that here, to avoid the
      confusion that results if we try to override a symbol with
   /* In cases involving weak versioned symbols, we may wind up trying
      to merge a symbol with itself.  Catch that here, to avoid the
      confusion that results if we try to override a symbol with
@@ -1020,6 +1054,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
      _GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a
      dynamic object, which we do want to handle here.  */
   if (abfd == oldbfd
      _GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a
      dynamic object, which we do want to handle here.  */
   if (abfd == oldbfd
+      && (newweak || oldweak)
       && ((abfd->flags & DYNAMIC) == 0
          || !h->def_regular))
     return TRUE;
       && ((abfd->flags & DYNAMIC) == 0
          || !h->def_regular))
     return TRUE;
@@ -1078,11 +1113,15 @@ _bfd_elf_merge_symbol (bfd *abfd,
       return TRUE;
     }
 
       return TRUE;
     }
 
+  /* Plugin symbol type isn't currently set.  Stop bogus errors.  */
+  if (oldbfd != NULL && (oldbfd->flags & BFD_PLUGIN) != 0)
+    *type_change_ok = TRUE;
+
   /* Check TLS symbol.  We don't check undefined symbol introduced by
      "ld -u".  */
   /* Check TLS symbol.  We don't check undefined symbol introduced by
      "ld -u".  */
-  if ((ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)
-      && ELF_ST_TYPE (sym->st_info) != h->type
-      && oldbfd != NULL)
+  else if (oldbfd != NULL
+          && ELF_ST_TYPE (sym->st_info) != h->type
+          && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS))
     {
       bfd *ntbfd, *tbfd;
       bfd_boolean ntdef, tdef;
     {
       bfd *ntbfd, *tbfd;
       bfd_boolean ntdef, tdef;
@@ -1131,23 +1170,11 @@ _bfd_elf_merge_symbol (bfd *abfd,
   /* We need to remember if a symbol has a definition in a dynamic
      object or is weak in all dynamic objects. Internal and hidden
      visibility will make it unavailable to dynamic objects.  */
   /* We need to remember if a symbol has a definition in a dynamic
      object or is weak in all dynamic objects. Internal and hidden
      visibility will make it unavailable to dynamic objects.  */
-  if (newdyn && !h->dynamic_def)
+  if (newdyn)
     {
     {
-      if (!bfd_is_und_section (sec))
-       h->dynamic_def = 1;
-      else
-       {
-         /* Check if this symbol is weak in all dynamic objects. If it
-            is the first time we see it in a dynamic object, we mark
-            if it is weak. Otherwise, we clear it.  */
-         if (!h->ref_dynamic)
-           {
-             if (bind == STB_WEAK)
-               h->dynamic_weak = 1;
-           }
-         else if (bind != STB_WEAK)
-           h->dynamic_weak = 0;
-       }
+      _bfd_elf_mark_dynamic_def_weak (h, sec, bind);
+      if (h != hi)
+       _bfd_elf_mark_dynamic_def_weak (hi, sec, bind);
     }
 
   /* If the old symbol has non-default visibility, we ignore the new
     }
 
   /* If the old symbol has non-default visibility, we ignore the new
@@ -1159,6 +1186,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       *skip = TRUE;
       /* Make sure this symbol is dynamic.  */
       h->ref_dynamic = 1;
       *skip = TRUE;
       /* Make sure this symbol is dynamic.  */
       h->ref_dynamic = 1;
+      hi->ref_dynamic = 1;
       /* A protected symbol has external availability. Make sure it is
         recorded as dynamic.
 
       /* A protected symbol has external availability. Make sure it is
         recorded as dynamic.
 
@@ -1188,38 +1216,40 @@ _bfd_elf_merge_symbol (bfd *abfd,
              vh->root.type = h->root.type;
              h->root.type = bfd_link_hash_indirect;
              (*bed->elf_backend_copy_indirect_symbol) (info, vh, h);
              vh->root.type = h->root.type;
              h->root.type = bfd_link_hash_indirect;
              (*bed->elf_backend_copy_indirect_symbol) (info, vh, h);
-             /* Protected symbols will override the dynamic definition
-                with default version.  */
-             if (ELF_ST_VISIBILITY (sym->st_other) == STV_PROTECTED)
+
+             h->root.u.i.link = (struct bfd_link_hash_entry *) vh;
+             if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED)
                {
                {
-                 h->root.u.i.link = (struct bfd_link_hash_entry *) vh;
-                 vh->dynamic_def = 1;
-                 vh->ref_dynamic = 1;
+                 /* If the new symbol is hidden or internal, completely undo
+                    any dynamic link state.  */
+                 (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+                 h->forced_local = 0;
+                 h->ref_dynamic = 0;
                }
              else
                }
              else
-               {
-                 h->root.type = vh->root.type;
-                 vh->ref_dynamic = 0;
-                 /* We have to hide it here since it was made dynamic
-                    global with extra bits when the symbol info was
-                    copied from the old dynamic definition.  */
-                 (*bed->elf_backend_hide_symbol) (info, vh, TRUE);
-               }
+               h->ref_dynamic = 1;
+
+             h->def_dynamic = 0;
+             h->dynamic_def = 0;
+             /* FIXME: Should we check type and size for protected symbol?  */
+             h->size = 0;
+             h->type = 0;
+
              h = vh;
            }
          else
            h = *sym_hash;
        }
 
              h = vh;
            }
          else
            h = *sym_hash;
        }
 
-      if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root)
-         && bfd_is_und_section (sec))
+      /* If the old symbol was undefined before, then it will still be
+        on the undefs list.  If the new symbol is undefined or
+        common, we can't make it bfd_link_hash_new here, because new
+        undefined or common symbols will be added to the undefs list
+        by _bfd_generic_link_add_one_symbol.  Symbols may not be
+        added twice to the undefs list.  Also, if the new symbol is
+        undefweak then we don't want to lose the strong undef.  */
+      if (h->root.u.undef.next || info->hash->undefs_tail == &h->root)
        {
        {
-         /* If the new symbol is undefined and the old symbol was
-            also undefined before, we need to make sure
-            _bfd_generic_link_add_one_symbol doesn't mess
-            up the linker hash table undefs list.  Since the old
-            definition came from a dynamic object, it is still on the
-            undefs list.  */
          h->root.type = bfd_link_hash_undefined;
          h->root.u.undef.abfd = abfd;
        }
          h->root.type = bfd_link_hash_undefined;
          h->root.u.undef.abfd = abfd;
        }
@@ -1229,23 +1259,24 @@ _bfd_elf_merge_symbol (bfd *abfd,
          h->root.u.undef.abfd = NULL;
        }
 
          h->root.u.undef.abfd = NULL;
        }
 
-      if (h->def_dynamic)
+      if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED)
        {
        {
-         h->def_dynamic = 0;
-         h->ref_dynamic = 1;
-         h->dynamic_def = 1;
+         /* If the new symbol is hidden or internal, completely undo
+            any dynamic link state.  */
+         (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+         h->forced_local = 0;
+         h->ref_dynamic = 0;
        }
        }
+      else
+       h->ref_dynamic = 1;
+      h->def_dynamic = 0;
+      h->dynamic_def = 0;
       /* FIXME: Should we check type and size for protected symbol?  */
       h->size = 0;
       h->type = 0;
       return TRUE;
     }
 
       /* FIXME: Should we check type and size for protected symbol?  */
       h->size = 0;
       h->type = 0;
       return TRUE;
     }
 
-  /* Differentiate strong and weak symbols.  */
-  newweak = bind == STB_WEAK;
-  oldweak = (h->root.type == bfd_link_hash_defweak
-            || h->root.type == bfd_link_hash_undefweak);
-
   if (bind == STB_GNU_UNIQUE)
     h->unique_global = 1;
 
   if (bind == STB_GNU_UNIQUE)
     h->unique_global = 1;
 
@@ -1359,8 +1390,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
         symbols defined in dynamic objects.  */
 
       if (! ((*info->callbacks->multiple_common)
         symbols defined in dynamic objects.  */
 
       if (! ((*info->callbacks->multiple_common)
-            (info, h->root.root.string, oldbfd, bfd_link_hash_common,
-             h->size, abfd, bfd_link_hash_common, sym->st_size)))
+            (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
        return FALSE;
 
       if (sym->st_size > h->size)
        return FALSE;
 
       if (sym->st_size > h->size)
@@ -1426,7 +1456,11 @@ _bfd_elf_merge_symbol (bfd *abfd,
   /* Skip weak definitions of symbols that are already defined.  */
   if (newdef && olddef && newweak)
     {
   /* Skip weak definitions of symbols that are already defined.  */
   if (newdef && olddef && newweak)
     {
-      *skip = TRUE;
+      /* Don't skip new non-IR weak syms.  */
+      if (!(oldbfd != NULL
+           && (oldbfd->flags & BFD_PLUGIN) != 0
+           && (abfd->flags & BFD_PLUGIN) == 0))
+       *skip = TRUE;
 
       /* Merge st_other.  If the symbol already has a dynamic index,
         but visibility says it should not be visible, turn it into a
 
       /* Merge st_other.  If the symbol already has a dynamic index,
         but visibility says it should not be visible, turn it into a
@@ -1511,8 +1545,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
         common symbol, but we don't know what to use for the section
         or the alignment.  */
       if (! ((*info->callbacks->multiple_common)
         common symbol, but we don't know what to use for the section
         or the alignment.  */
       if (! ((*info->callbacks->multiple_common)
-            (info, h->root.root.string, oldbfd, bfd_link_hash_common,
-             h->size, abfd, bfd_link_hash_common, sym->st_size)))
+            (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
        return FALSE;
 
       /* If the presumed common symbol in the dynamic object is
        return FALSE;
 
       /* If the presumed common symbol in the dynamic object is
@@ -1635,7 +1668,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
   size_change_ok = FALSE;
   sec = *psec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
   size_change_ok = FALSE;
   sec = *psec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
-                             NULL, &hi, &skip, &override,
+                             NULL, NULL, &hi, &skip, &override,
                              &type_change_ok, &size_change_ok))
     return FALSE;
 
                              &type_change_ok, &size_change_ok))
     return FALSE;
 
@@ -1716,6 +1749,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
          if (! dynamic)
            {
              if (! info->executable
          if (! dynamic)
            {
              if (! info->executable
+                 || hi->def_dynamic
                  || hi->ref_dynamic)
                *dynsym = TRUE;
            }
                  || hi->ref_dynamic)
                *dynsym = TRUE;
            }
@@ -1743,7 +1777,7 @@ nondefault:
   size_change_ok = FALSE;
   sec = *psec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
   size_change_ok = FALSE;
   sec = *psec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
-                             NULL, &hi, &skip, &override,
+                             NULL, NULL, &hi, &skip, &override,
                              &type_change_ok, &size_change_ok))
     return FALSE;
 
                              &type_change_ok, &size_change_ok))
     return FALSE;
 
@@ -1808,32 +1842,23 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
 {
   struct elf_info_failed *eif = (struct elf_info_failed *) data;
 
 {
   struct elf_info_failed *eif = (struct elf_info_failed *) data;
 
-  /* Ignore this if we won't export it.  */
-  if (!eif->info->export_dynamic && !h->dynamic)
-    return TRUE;
-
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+  /* Ignore this if we won't export it.  */
+  if (!eif->info->export_dynamic && !h->dynamic)
+    return TRUE;
 
   if (h->dynindx == -1
 
   if (h->dynindx == -1
-      && (h->def_regular
-         || h->ref_regular))
+      && (h->def_regular || h->ref_regular)
+      && ! bfd_hide_sym_by_version (eif->info->version_info,
+                                   h->root.root.string))
     {
     {
-      bfd_boolean hide;
-
-      if (eif->verdefs == NULL
-         || (bfd_find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
-             && !hide))
+      if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
        {
        {
-         if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
-           {
-             eif->failed = TRUE;
-             return FALSE;
-           }
+         eif->failed = TRUE;
+         return FALSE;
        }
     }
 
        }
     }
 
@@ -1854,9 +1879,6 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
   Elf_Internal_Vernaux *a;
   bfd_size_type amt;
 
   Elf_Internal_Vernaux *a;
   bfd_size_type amt;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* We only care about symbols defined in shared objects with version
      information.  */
   if (!h->def_dynamic
   /* We only care about symbols defined in shared objects with version
      information.  */
   if (!h->def_dynamic
@@ -1942,9 +1964,6 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
   sinfo = (struct elf_info_failed *) data;
   info = sinfo->info;
 
   sinfo = (struct elf_info_failed *) data;
   info = sinfo->info;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Fix the symbol flags.  */
   eif.failed = FALSE;
   eif.info = info;
   /* Fix the symbol flags.  */
   eif.failed = FALSE;
   eif.info = info;
@@ -1987,7 +2006,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
        }
 
       /* Look for the version.  If we find it, it is no longer weak.  */
        }
 
       /* Look for the version.  If we find it, it is no longer weak.  */
-      for (t = sinfo->verdefs; t != NULL; t = t->next)
+      for (t = sinfo->info->version_info; t != NULL; t = t->next)
        {
          if (strcmp (t->name, p) == 0)
            {
        {
          if (strcmp (t->name, p) == 0)
            {
@@ -2056,9 +2075,12 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
 
          version_index = 1;
          /* Don't count anonymous version tag.  */
 
          version_index = 1;
          /* Don't count anonymous version tag.  */
-         if (sinfo->verdefs != NULL && sinfo->verdefs->vernum == 0)
+         if (sinfo->info->version_info != NULL
+             && sinfo->info->version_info->vernum == 0)
            version_index = 0;
            version_index = 0;
-         for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
+         for (pp = &sinfo->info->version_info;
+              *pp != NULL;
+              pp = &(*pp)->next)
            ++version_index;
          t->vernum = version_index;
 
            ++version_index;
          t->vernum = version_index;
 
@@ -2084,12 +2106,13 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
 
   /* If we don't have a version for this symbol, see if we can find
      something.  */
 
   /* If we don't have a version for this symbol, see if we can find
      something.  */
-  if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
+  if (h->verinfo.vertree == NULL && sinfo->info->version_info != NULL)
     {
       bfd_boolean hide;
 
     {
       bfd_boolean hide;
 
-      h->verinfo.vertree = bfd_find_version_for_sym (sinfo->verdefs,
-                                                h->root.root.string, &hide);
+      h->verinfo.vertree
+       = bfd_find_version_for_sym (sinfo->info->version_info,
+                                   h->root.root.string, &hide);
       if (h->verinfo.vertree != NULL && hide)
        (*bed->elf_backend_hide_symbol) (info, h, TRUE);
     }
       if (h->verinfo.vertree != NULL && hide)
        (*bed->elf_backend_hide_symbol) (info, h, TRUE);
     }
@@ -2169,7 +2192,7 @@ elf_link_read_relocs_from_section (bfd *abfd,
              return FALSE;
            }
        }
              return FALSE;
            }
        }
-      else if (r_symndx != 0)
+      else if (r_symndx != STN_UNDEF)
        {
          (*_bfd_error_handler)
            (_("%B: non-zero symbol index (0x%lx) for offset 0x%lx in section `%A'"
        {
          (*_bfd_error_handler)
            (_("%B: non-zero symbol index (0x%lx) for offset 0x%lx in section `%A'"
@@ -2194,7 +2217,7 @@ elf_link_read_relocs_from_section (bfd *abfd,
    according to the KEEP_MEMORY argument.  If O has two relocation
    sections (both REL and RELA relocations), then the REL_HDR
    relocations will appear first in INTERNAL_RELOCS, followed by the
    according to the KEEP_MEMORY argument.  If O has two relocation
    sections (both REL and RELA relocations), then the REL_HDR
    relocations will appear first in INTERNAL_RELOCS, followed by the
-   REL_HDR2 relocations.  */
+   RELA_HDR relocations.  */
 
 Elf_Internal_Rela *
 _bfd_elf_link_read_relocs (bfd *abfd,
 
 Elf_Internal_Rela *
 _bfd_elf_link_read_relocs (bfd *abfd,
@@ -2203,19 +2226,18 @@ _bfd_elf_link_read_relocs (bfd *abfd,
                           Elf_Internal_Rela *internal_relocs,
                           bfd_boolean keep_memory)
 {
                           Elf_Internal_Rela *internal_relocs,
                           bfd_boolean keep_memory)
 {
-  Elf_Internal_Shdr *rel_hdr;
   void *alloc1 = NULL;
   Elf_Internal_Rela *alloc2 = NULL;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   void *alloc1 = NULL;
   Elf_Internal_Rela *alloc2 = NULL;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct bfd_elf_section_data *esdo = elf_section_data (o);
+  Elf_Internal_Rela *internal_rela_relocs;
 
 
-  if (elf_section_data (o)->relocs != NULL)
-    return elf_section_data (o)->relocs;
+  if (esdo->relocs != NULL)
+    return esdo->relocs;
 
   if (o->reloc_count == 0)
     return NULL;
 
 
   if (o->reloc_count == 0)
     return NULL;
 
-  rel_hdr = &elf_section_data (o)->rel_hdr;
-
   if (internal_relocs == NULL)
     {
       bfd_size_type size;
   if (internal_relocs == NULL)
     {
       bfd_size_type size;
@@ -2232,32 +2254,41 @@ _bfd_elf_link_read_relocs (bfd *abfd,
 
   if (external_relocs == NULL)
     {
 
   if (external_relocs == NULL)
     {
-      bfd_size_type size = rel_hdr->sh_size;
+      bfd_size_type size = 0;
+
+      if (esdo->rel.hdr)
+       size += esdo->rel.hdr->sh_size;
+      if (esdo->rela.hdr)
+       size += esdo->rela.hdr->sh_size;
 
 
-      if (elf_section_data (o)->rel_hdr2)
-       size += elf_section_data (o)->rel_hdr2->sh_size;
       alloc1 = bfd_malloc (size);
       if (alloc1 == NULL)
        goto error_return;
       external_relocs = alloc1;
     }
 
       alloc1 = bfd_malloc (size);
       if (alloc1 == NULL)
        goto error_return;
       external_relocs = alloc1;
     }
 
-  if (!elf_link_read_relocs_from_section (abfd, o, rel_hdr,
-                                         external_relocs,
-                                         internal_relocs))
-    goto error_return;
-  if (elf_section_data (o)->rel_hdr2
-      && (!elf_link_read_relocs_from_section
-         (abfd, o,
-          elf_section_data (o)->rel_hdr2,
-          ((bfd_byte *) external_relocs) + rel_hdr->sh_size,
-          internal_relocs + (NUM_SHDR_ENTRIES (rel_hdr)
-                             * bed->s->int_rels_per_ext_rel))))
+  internal_rela_relocs = internal_relocs;
+  if (esdo->rel.hdr)
+    {
+      if (!elf_link_read_relocs_from_section (abfd, o, esdo->rel.hdr,
+                                             external_relocs,
+                                             internal_relocs))
+       goto error_return;
+      external_relocs = (((bfd_byte *) external_relocs)
+                        + esdo->rel.hdr->sh_size);
+      internal_rela_relocs += (NUM_SHDR_ENTRIES (esdo->rel.hdr)
+                              * bed->s->int_rels_per_ext_rel);
+    }
+
+  if (esdo->rela.hdr
+      && (!elf_link_read_relocs_from_section (abfd, o, esdo->rela.hdr,
+                                             external_relocs,
+                                             internal_rela_relocs)))
     goto error_return;
 
   /* Cache the results for next time, if we can.  */
   if (keep_memory)
     goto error_return;
 
   /* Cache the results for next time, if we can.  */
   if (keep_memory)
-    elf_section_data (o)->relocs = internal_relocs;
+    esdo->relocs = internal_relocs;
 
   if (alloc1 != NULL)
     free (alloc1);
 
   if (alloc1 != NULL)
     free (alloc1);
@@ -2285,24 +2316,12 @@ _bfd_elf_link_read_relocs (bfd *abfd,
 
 static bfd_boolean
 _bfd_elf_link_size_reloc_section (bfd *abfd,
 
 static bfd_boolean
 _bfd_elf_link_size_reloc_section (bfd *abfd,
-                                 Elf_Internal_Shdr *rel_hdr,
-                                 asection *o)
+                                 struct bfd_elf_section_reloc_data *reldata)
 {
 {
-  bfd_size_type reloc_count;
-  bfd_size_type num_rel_hashes;
-
-  /* Figure out how many relocations there will be.  */
-  if (rel_hdr == &elf_section_data (o)->rel_hdr)
-    reloc_count = elf_section_data (o)->rel_count;
-  else
-    reloc_count = elf_section_data (o)->rel_count2;
-
-  num_rel_hashes = o->reloc_count;
-  if (num_rel_hashes < reloc_count)
-    num_rel_hashes = reloc_count;
+  Elf_Internal_Shdr *rel_hdr = reldata->hdr;
 
   /* That allows us to calculate the size of the section.  */
 
   /* That allows us to calculate the size of the section.  */
-  rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count;
+  rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
 
   /* The contents field must last into write_object_contents, so we
      allocate it with bfd_alloc rather than malloc.  Also since we
 
   /* The contents field must last into write_object_contents, so we
      allocate it with bfd_alloc rather than malloc.  Also since we
@@ -2312,19 +2331,16 @@ _bfd_elf_link_size_reloc_section (bfd *abfd,
   if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
     return FALSE;
 
   if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
     return FALSE;
 
-  /* We only allocate one set of hash entries, so we only do it the
-     first time we are called.  */
-  if (elf_section_data (o)->rel_hashes == NULL
-      && num_rel_hashes)
+  if (reldata->hashes == NULL && reldata->count)
     {
       struct elf_link_hash_entry **p;
 
       p = (struct elf_link_hash_entry **)
     {
       struct elf_link_hash_entry **p;
 
       p = (struct elf_link_hash_entry **)
-          bfd_zmalloc (num_rel_hashes * sizeof (struct elf_link_hash_entry *));
+          bfd_zmalloc (reldata->count * sizeof (struct elf_link_hash_entry *));
       if (p == NULL)
        return FALSE;
 
       if (p == NULL)
        return FALSE;
 
-      elf_section_data (o)->rel_hashes = p;
+      reldata->hashes = p;
     }
 
   return TRUE;
     }
 
   return TRUE;
@@ -2345,27 +2361,26 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
   Elf_Internal_Rela *irela;
   Elf_Internal_Rela *irelaend;
   bfd_byte *erel;
   Elf_Internal_Rela *irela;
   Elf_Internal_Rela *irelaend;
   bfd_byte *erel;
-  Elf_Internal_Shdr *output_rel_hdr;
+  struct bfd_elf_section_reloc_data *output_reldata;
   asection *output_section;
   asection *output_section;
-  unsigned int *rel_countp = NULL;
   const struct elf_backend_data *bed;
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
   const struct elf_backend_data *bed;
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+  struct bfd_elf_section_data *esdo;
 
   output_section = input_section->output_section;
 
   output_section = input_section->output_section;
-  output_rel_hdr = NULL;
 
 
-  if (elf_section_data (output_section)->rel_hdr.sh_entsize
-      == input_rel_hdr->sh_entsize)
+  bed = get_elf_backend_data (output_bfd);
+  esdo = elf_section_data (output_section);
+  if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
     {
     {
-      output_rel_hdr = &elf_section_data (output_section)->rel_hdr;
-      rel_countp = &elf_section_data (output_section)->rel_count;
+      output_reldata = &esdo->rel;
+      swap_out = bed->s->swap_reloc_out;
     }
     }
-  else if (elf_section_data (output_section)->rel_hdr2
-          && (elf_section_data (output_section)->rel_hdr2->sh_entsize
-              == input_rel_hdr->sh_entsize))
+  else if (esdo->rela.hdr
+          && esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
     {
     {
-      output_rel_hdr = elf_section_data (output_section)->rel_hdr2;
-      rel_countp = &elf_section_data (output_section)->rel_count2;
+      output_reldata = &esdo->rela;
+      swap_out = bed->s->swap_reloca_out;
     }
   else
     {
     }
   else
     {
@@ -2376,16 +2391,8 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
       return FALSE;
     }
 
       return FALSE;
     }
 
-  bed = get_elf_backend_data (output_bfd);
-  if (input_rel_hdr->sh_entsize == bed->s->sizeof_rel)
-    swap_out = bed->s->swap_reloc_out;
-  else if (input_rel_hdr->sh_entsize == bed->s->sizeof_rela)
-    swap_out = bed->s->swap_reloca_out;
-  else
-    abort ();
-
-  erel = output_rel_hdr->contents;
-  erel += *rel_countp * input_rel_hdr->sh_entsize;
+  erel = output_reldata->hdr->contents;
+  erel += output_reldata->count * input_rel_hdr->sh_entsize;
   irela = internal_relocs;
   irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
                      * bed->s->int_rels_per_ext_rel);
   irela = internal_relocs;
   irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
                      * bed->s->int_rels_per_ext_rel);
@@ -2398,7 +2405,7 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
 
   /* Bump the counter, so that we know where to add the next set of
      relocations.  */
 
   /* Bump the counter, so that we know where to add the next set of
      relocations.  */
-  *rel_countp += NUM_SHDR_ENTRIES (input_rel_hdr);
+  output_reldata->count += NUM_SHDR_ENTRIES (input_rel_hdr);
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -2536,23 +2543,21 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
      over to the real definition.  */
   if (h->u.weakdef != NULL)
     {
      over to the real definition.  */
   if (h->u.weakdef != NULL)
     {
-      struct elf_link_hash_entry *weakdef;
-
-      weakdef = h->u.weakdef;
-      if (h->root.type == bfd_link_hash_indirect)
-       h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-      BFD_ASSERT (h->root.type == bfd_link_hash_defined
-                 || h->root.type == bfd_link_hash_defweak);
-      BFD_ASSERT (weakdef->def_dynamic);
-
       /* If the real definition is defined by a regular object file,
         don't do anything special.  See the longer description in
         _bfd_elf_adjust_dynamic_symbol, below.  */
       /* If the real definition is defined by a regular object file,
         don't do anything special.  See the longer description in
         _bfd_elf_adjust_dynamic_symbol, below.  */
-      if (weakdef->def_regular)
+      if (h->u.weakdef->def_regular)
        h->u.weakdef = NULL;
       else
        {
        h->u.weakdef = NULL;
       else
        {
+         struct elf_link_hash_entry *weakdef = h->u.weakdef;
+
+         while (h->root.type == bfd_link_hash_indirect)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+         BFD_ASSERT (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak);
+         BFD_ASSERT (weakdef->def_dynamic);
          BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
                      || weakdef->root.type == bfd_link_hash_defweak);
          (*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef, h);
          BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
                      || weakdef->root.type == bfd_link_hash_defweak);
          (*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef, h);
@@ -2576,17 +2581,6 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
   if (! is_elf_hash_table (eif->info->hash))
     return FALSE;
 
   if (! is_elf_hash_table (eif->info->hash))
     return FALSE;
 
-  if (h->root.type == bfd_link_hash_warning)
-    {
-      h->got = elf_hash_table (eif->info)->init_got_offset;
-      h->plt = elf_hash_table (eif->info)->init_plt_offset;
-
-      /* When warning symbols are created, they **replace** the "real"
-        entry in the hash table, thus we never get to see the real
-        symbol in a hash traversal.  So look at it now.  */
-      h = (struct elf_link_hash_entry *) h->root.u.i.link;
-    }
-
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -2654,12 +2648,12 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
 
   if (h->u.weakdef != NULL)
     {
 
   if (h->u.weakdef != NULL)
     {
-      /* If we get to this point, we know there is an implicit
-        reference by a regular object file via the weak symbol H.
-        FIXME: Is this really true?  What if the traversal finds
-        H->U.WEAKDEF before it finds H?  */
+      /* If we get to this point, there is an implicit reference to
+        H->U.WEAKDEF by a regular object file via the weak symbol H.  */
       h->u.weakdef->ref_regular = 1;
 
       h->u.weakdef->ref_regular = 1;
 
+      /* Ensure that the backend adjust_dynamic_symbol function sees
+        H->U.WEAKDEF before H by recursively calling ourselves.  */
       if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, eif))
        return FALSE;
     }
       if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, eif))
        return FALSE;
     }
@@ -2742,13 +2736,10 @@ _bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *data)
 {
   asection *sec;
 
 {
   asection *sec;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
       && ((sec = h->root.u.def.section)->flags & SEC_MERGE)
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
       && ((sec = h->root.u.def.section)->flags & SEC_MERGE)
-      && sec->sec_info_type == ELF_INFO_TYPE_MERGE)
+      && sec->sec_info_type == SEC_INFO_TYPE_MERGE)
     {
       bfd *output_bfd = (bfd *) data;
 
     {
       bfd *output_bfd = (bfd *) data;
 
@@ -2769,7 +2760,7 @@ _bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *data)
 bfd_boolean
 _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
                           struct bfd_link_info *info,
 bfd_boolean
 _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
                           struct bfd_link_info *info,
-                          bfd_boolean ignore_protected)
+                          bfd_boolean not_local_protected)
 {
   bfd_boolean binding_stays_local_p;
   const struct elf_backend_data *bed;
 {
   bfd_boolean binding_stays_local_p;
   const struct elf_backend_data *bed;
@@ -2808,7 +2799,7 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
       /* Proper resolution for function pointer equality may require
         that these symbols perhaps be resolved dynamically, even though
         we should be resolving them to the current module.  */
       /* Proper resolution for function pointer equality may require
         that these symbols perhaps be resolved dynamically, even though
         we should be resolving them to the current module.  */
-      if (!ignore_protected || !bed->is_function_type (h->type))
+      if (!not_local_protected || !bed->is_function_type (h->type))
        binding_stays_local_p = TRUE;
       break;
 
        binding_stays_local_p = TRUE;
       break;
 
@@ -2817,7 +2808,7 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
     }
 
   /* If it isn't defined locally, then clearly it's dynamic.  */
     }
 
   /* If it isn't defined locally, then clearly it's dynamic.  */
-  if (!h->def_regular)
+  if (!h->def_regular && !ELF_COMMON_DEF_P (h))
     return TRUE;
 
   /* Otherwise, the symbol is dynamic if binding rules don't tell
     return TRUE;
 
   /* Otherwise, the symbol is dynamic if binding rules don't tell
@@ -2828,7 +2819,15 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
 /* Return true if the symbol referred to by H should be considered
    to resolve local to the current module, and false otherwise.  Differs
    from (the inverse of) _bfd_elf_dynamic_symbol_p in the treatment of
 /* Return true if the symbol referred to by H should be considered
    to resolve local to the current module, and false otherwise.  Differs
    from (the inverse of) _bfd_elf_dynamic_symbol_p in the treatment of
-   undefined symbols and weak symbols.  */
+   undefined symbols.  The two functions are virtually identical except
+   for the place where forced_local and dynindx == -1 are tested.  If
+   either of those tests are true, _bfd_elf_dynamic_symbol_p will say
+   the symbol is local, while _bfd_elf_symbol_refs_local_p will say
+   the symbol is local only for defined symbols.
+   It might seem that _bfd_elf_dynamic_symbol_p could be rewritten as
+   !_bfd_elf_symbol_refs_local_p, except that targets differ in their
+   treatment of undefined weak symbols.  For those that do not make
+   undefined weak symbols dynamic, both functions may return false.  */
 
 bfd_boolean
 _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
 
 bfd_boolean
 _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
@@ -2886,8 +2885,10 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
     return TRUE;
 
   /* Function pointer equality tests may require that STV_PROTECTED
     return TRUE;
 
   /* Function pointer equality tests may require that STV_PROTECTED
-     symbols be treated as dynamic symbols, even when we know that the
-     dynamic linker will resolve them locally.  */
+     symbols be treated as dynamic symbols.  If the address of a
+     function not defined in an executable is set to that function's
+     plt entry in the executable, then the address of the function in
+     a shared library must also be the plt entry in the executable.  */
   return local_protected;
 }
 
   return local_protected;
 }
 
@@ -3061,7 +3062,7 @@ _bfd_elf_add_dynamic_entry (struct bfd_link_info *info,
     return FALSE;
 
   bed = get_elf_backend_data (hash_table->dynobj);
     return FALSE;
 
   bed = get_elf_backend_data (hash_table->dynobj);
-  s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
+  s = bfd_get_linker_section (hash_table->dynobj, ".dynamic");
   BFD_ASSERT (s != NULL);
 
   newsize = s->size + bed->s->sizeof_dyn;
   BFD_ASSERT (s != NULL);
 
   newsize = s->size + bed->s->sizeof_dyn;
@@ -3109,7 +3110,7 @@ elf_add_dt_needed_tag (bfd *abfd,
       bfd_byte *extdyn;
 
       bed = get_elf_backend_data (hash_table->dynobj);
       bfd_byte *extdyn;
 
       bed = get_elf_backend_data (hash_table->dynobj);
-      sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
+      sdyn = bfd_get_linker_section (hash_table->dynobj, ".dynamic");
       if (sdyn != NULL)
        for (extdyn = sdyn->contents;
             extdyn < sdyn->contents + sdyn->size;
       if (sdyn != NULL)
        for (extdyn = sdyn->contents;
             extdyn < sdyn->contents + sdyn->size;
@@ -3152,7 +3153,7 @@ on_needed_list (const char *soname, struct bfd_link_needed_list *needed)
   return FALSE;
 }
 
   return FALSE;
 }
 
-/* Sort symbol by value and section.  */
+/* Sort symbol by value, section, and size.  */
 static int
 elf_sort_symbol (const void *arg1, const void *arg2)
 {
 static int
 elf_sort_symbol (const void *arg1, const void *arg2)
 {
@@ -3171,7 +3172,8 @@ elf_sort_symbol (const void *arg1, const void *arg2)
       if (sdiff != 0)
        return sdiff > 0 ? 1 : -1;
     }
       if (sdiff != 0)
        return sdiff > 0 ? 1 : -1;
     }
-  return 0;
+  vdiff = h1->size - h2->size;
+  return vdiff == 0 ? 0 : vdiff > 0 ? 1 : -1;
 }
 
 /* This function is used to adjust offsets into .dynstr for
 }
 
 /* This function is used to adjust offsets into .dynstr for
@@ -3182,9 +3184,6 @@ elf_adjust_dynstr_offsets (struct elf_link_hash_entry *h, void *data)
 {
   struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
 
 {
   struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if (h->dynindx != -1)
     h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index);
   return TRUE;
   if (h->dynindx != -1)
     h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index);
   return TRUE;
@@ -3209,7 +3208,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
   size = _bfd_elf_strtab_size (dynstr);
 
   bed = get_elf_backend_data (dynobj);
   size = _bfd_elf_strtab_size (dynstr);
 
   bed = get_elf_backend_data (dynobj);
-  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  sdyn = bfd_get_linker_section (dynobj, ".dynamic");
   BFD_ASSERT (sdyn != NULL);
 
   /* Update all .dynamic entries referencing .dynstr strings.  */
   BFD_ASSERT (sdyn != NULL);
 
   /* Update all .dynamic entries referencing .dynstr strings.  */
@@ -3258,7 +3257,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
       Elf_Internal_Verdef def;
       Elf_Internal_Verdaux defaux;
 
       Elf_Internal_Verdef def;
       Elf_Internal_Verdaux defaux;
 
-      s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
+      s = bfd_get_linker_section (dynobj, ".gnu.version_d");
       p = s->contents;
       do
        {
       p = s->contents;
       do
        {
@@ -3290,7 +3289,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
       Elf_Internal_Verneed need;
       Elf_Internal_Vernaux needaux;
 
       Elf_Internal_Verneed need;
       Elf_Internal_Vernaux needaux;
 
-      s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
+      s = bfd_get_linker_section (dynobj, ".gnu.version_r");
       p = s->contents;
       do
        {
       p = s->contents;
       do
        {
@@ -3428,7 +3427,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
      .gnu.warning.SYMBOL are treated as warning symbols for the given
      symbol.  This differs from .gnu.warning sections, which generate
      warnings when they are included in an output file.  */
      .gnu.warning.SYMBOL are treated as warning symbols for the given
      symbol.  This differs from .gnu.warning sections, which generate
      warnings when they are included in an output file.  */
-  if (info->executable)
+  /* PR 12761: Also generate this warning when building shared libraries.  */
+  if (info->executable || info->shared)
     {
       asection *s;
 
     {
       asection *s;
 
@@ -3531,7 +3531,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       /* ld --just-symbols and dynamic objects don't mix very well.
         ld shouldn't allow it.  */
       if ((s = abfd->sections) != NULL
       /* ld --just-symbols and dynamic objects don't mix very well.
         ld shouldn't allow it.  */
       if ((s = abfd->sections) != NULL
-         && s->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+         && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
        abort ();
 
       /* If this dynamic lib was specified on the command line with
        abort ();
 
       /* If this dynamic lib was specified on the command line with
@@ -3819,7 +3819,7 @@ error_free_dyn:
       /* Make a special call to the linker "notice" function to
         tell it that we are about to handle an as-needed lib.  */
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
       /* Make a special call to the linker "notice" function to
         tell it that we are about to handle an as-needed lib.  */
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
-                                      notice_as_needed))
+                                      notice_as_needed, 0, NULL))
        goto error_free_vers;
 
       /* Clone the symbol table and sym hashes.  Remember some
        goto error_free_vers;
 
       /* Clone the symbol table and sym hashes.  Remember some
@@ -3866,10 +3866,13 @@ error_free_dyn:
       flagword flags;
       const char *name;
       struct elf_link_hash_entry *h;
       flagword flags;
       const char *name;
       struct elf_link_hash_entry *h;
+      struct elf_link_hash_entry *hi;
       bfd_boolean definition;
       bfd_boolean size_change_ok;
       bfd_boolean type_change_ok;
       bfd_boolean new_weakdef;
       bfd_boolean definition;
       bfd_boolean size_change_ok;
       bfd_boolean type_change_ok;
       bfd_boolean new_weakdef;
+      bfd_boolean new_weak;
+      bfd_boolean old_weak;
       bfd_boolean override;
       bfd_boolean common;
       unsigned int old_alignment;
       bfd_boolean override;
       bfd_boolean common;
       unsigned int old_alignment;
@@ -3928,7 +3931,7 @@ error_free_dyn:
          sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
          if (sec == NULL)
            sec = bfd_abs_section_ptr;
          sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
          if (sec == NULL)
            sec = bfd_abs_section_ptr;
-         else if (sec->kept_section)
+         else if (discarded_section (sec))
            {
              /* Symbols from discarded section are undefined.  We keep
                 its visibility.  */
            {
              /* Symbols from discarded section are undefined.  We keep
                 its visibility.  */
@@ -3945,18 +3948,31 @@ error_free_dyn:
        goto error_free_vers;
 
       if (isym->st_shndx == SHN_COMMON
        goto error_free_vers;
 
       if (isym->st_shndx == SHN_COMMON
-         && ELF_ST_TYPE (isym->st_info) == STT_TLS
-         && !info->relocatable)
+         && (abfd->flags & BFD_PLUGIN) != 0)
+       {
+         asection *xc = bfd_get_section_by_name (abfd, "COMMON");
+
+         if (xc == NULL)
+           {
+             flagword sflags = (SEC_ALLOC | SEC_IS_COMMON | SEC_KEEP
+                                | SEC_EXCLUDE);
+             xc = bfd_make_section_with_flags (abfd, "COMMON", sflags);
+             if (xc == NULL)
+               goto error_free_vers;
+           }
+         sec = xc;
+       }
+      else if (isym->st_shndx == SHN_COMMON
+              && ELF_ST_TYPE (isym->st_info) == STT_TLS
+              && !info->relocatable)
        {
          asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
 
          if (tcomm == NULL)
            {
        {
          asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
 
          if (tcomm == NULL)
            {
-             tcomm = bfd_make_section_with_flags (abfd, ".tcommon",
-                                                  (SEC_ALLOC
-                                                   | SEC_IS_COMMON
-                                                   | SEC_LINKER_CREATED
-                                                   | SEC_THREAD_LOCAL));
+             flagword sflags = (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_IS_COMMON
+                                | SEC_LINKER_CREATED);
+             tcomm = bfd_make_section_with_flags (abfd, ".tcommon", sflags);
              if (tcomm == NULL)
                goto error_free_vers;
            }
              if (tcomm == NULL)
                goto error_free_vers;
            }
@@ -3989,6 +4005,7 @@ error_free_dyn:
 
       size_change_ok = FALSE;
       type_change_ok = bed->type_change_ok;
 
       size_change_ok = FALSE;
       type_change_ok = bed->type_change_ok;
+      old_weak = FALSE;
       old_alignment = 0;
       old_bfd = NULL;
       new_sec = sec;
       old_alignment = 0;
       old_bfd = NULL;
       new_sec = sec;
@@ -4134,7 +4151,7 @@ error_free_dyn:
            }
 
          if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec,
            }
 
          if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec,
-                                     &value, &old_alignment,
+                                     &value, &old_weak, &old_alignment,
                                      sym_hash, &skip, &override,
                                      &type_change_ok, &size_change_ok))
            goto error_free_vers;
                                      sym_hash, &skip, &override,
                                      &type_change_ok, &size_change_ok))
            goto error_free_vers;
@@ -4185,17 +4202,22 @@ error_free_dyn:
        goto error_free_vers;
 
       h = *sym_hash;
        goto error_free_vers;
 
       h = *sym_hash;
+      /* We need to make sure that indirect symbol dynamic flags are
+        updated.  */
+      hi = h;
       while (h->root.type == bfd_link_hash_indirect
             || h->root.type == bfd_link_hash_warning)
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
       *sym_hash = h;
       while (h->root.type == bfd_link_hash_indirect
             || h->root.type == bfd_link_hash_warning)
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
       *sym_hash = h;
-      h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
+      if (is_elf_hash_table (htab))
+       h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
 
 
+      new_weak = (flags & BSF_WEAK) != 0;
       new_weakdef = FALSE;
       if (dynamic
          && definition
       new_weakdef = FALSE;
       if (dynamic
          && definition
-         && (flags & BSF_WEAK) != 0
+         && new_weak
          && !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
          && is_elf_hash_table (htab)
          && h->u.weakdef == NULL)
          && !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
          && is_elf_hash_table (htab)
          && h->u.weakdef == NULL)
@@ -4231,10 +4253,7 @@ error_free_dyn:
                 We need to get the alignment from the section.  */
              align = new_sec->alignment_power;
            }
                 We need to get the alignment from the section.  */
              align = new_sec->alignment_power;
            }
-         if (align > old_alignment
-             /* Permit an alignment power of zero if an alignment of one
-                is specified and no other alignments have been specified.  */
-             || (isym->st_value == 1 && old_alignment == 0))
+         if (align > old_alignment)
            h->root.u.c.p->alignment_power = align;
          else
            h->root.u.c.p->alignment_power = old_alignment;
            h->root.u.c.p->alignment_power = align;
          else
            h->root.u.c.p->alignment_power = old_alignment;
@@ -4327,7 +4346,9 @@ error_free_dyn:
            h->size = h->root.u.c.size;
 
          if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
            h->size = h->root.u.c.size;
 
          if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
-             && (definition || h->type == STT_NOTYPE))
+             && ((definition && !new_weak)
+                 || (old_weak && h->root.type == bfd_link_hash_common)
+                 || h->type == STT_NOTYPE))
            {
              unsigned int type = ELF_ST_TYPE (isym->st_info);
 
            {
              unsigned int type = ELF_ST_TYPE (isym->st_info);
 
@@ -4373,33 +4394,53 @@ error_free_dyn:
                    {
                      h->def_dynamic = 0;
                      h->ref_dynamic = 1;
                    {
                      h->def_dynamic = 0;
                      h->ref_dynamic = 1;
-                     h->dynamic_def = 1;
                    }
                }
                    }
                }
-             if (! info->executable
-                 || h->def_dynamic
-                 || h->ref_dynamic)
+
+             /* If the indirect symbol has been forced local, don't
+                make the real symbol dynamic.  */
+             if ((h == hi || !hi->forced_local)
+                 && (! info->executable
+                     || h->def_dynamic
+                     || h->ref_dynamic))
                dynsym = TRUE;
            }
          else
            {
              if (! definition)
                dynsym = TRUE;
            }
          else
            {
              if (! definition)
-               h->ref_dynamic = 1;
+               {
+                 h->ref_dynamic = 1;
+                 hi->ref_dynamic = 1;
+               }
              else
              else
-               h->def_dynamic = 1;
-             if (h->def_regular
-                 || h->ref_regular
-                 || (h->u.weakdef != NULL
-                     && ! new_weakdef
-                     && h->u.weakdef->dynindx != -1))
+               {
+                 h->def_dynamic = 1;
+                 h->dynamic_def = 1;
+                 hi->def_dynamic = 1;
+                 hi->dynamic_def = 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->u.weakdef != NULL
+                         && ! new_weakdef
+                         && h->u.weakdef->dynindx != -1)))
                dynsym = TRUE;
            }
 
                dynsym = TRUE;
            }
 
+         /* We don't want to make debug symbol dynamic.  */
          if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
          if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
-           {
-             /* We don't want to make debug symbol dynamic.  */
-             dynsym = FALSE;
-           }
+           dynsym = FALSE;
+
+         /* Nor should we make plugin symbols dynamic.  */
+         if ((abfd->flags & BFD_PLUGIN) != 0)
+           dynsym = FALSE;
+
+         if (definition)
+           h->target_internal = isym->st_target_internal;
 
          /* Check to see if we need to add an indirect symbol for
             the default name.  */
 
          /* Check to see if we need to add an indirect symbol for
             the default name.  */
@@ -4529,6 +4570,8 @@ error_free_dyn:
        {
          struct bfd_hash_entry *p;
          struct elf_link_hash_entry *h;
        {
          struct bfd_hash_entry *p;
          struct elf_link_hash_entry *h;
+         bfd_size_type size;
+         unsigned int alignment_power;
 
          for (p = htab->root.table.table[i]; p != NULL; p = p->next)
            {
 
          for (p = htab->root.table.table[i]; p != NULL; p = p->next)
            {
@@ -4538,6 +4581,20 @@ error_free_dyn:
              if (h->dynindx >= old_dynsymcount)
                _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index);
 
              if (h->dynindx >= old_dynsymcount)
                _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index);
 
+             /* Preserve the maximum alignment and size for common
+                symbols even if this dynamic lib isn't on DT_NEEDED
+                since it can still be loaded at the 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;
+               }
              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 (p, old_ent, htab->root.table.entsize);
              old_ent = (char *) old_ent + htab->root.table.entsize;
              h = (struct elf_link_hash_entry *) p;
@@ -4546,13 +4603,20 @@ error_free_dyn:
                  memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
                  old_ent = (char *) old_ent + htab->root.table.entsize;
                }
                  memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
                  old_ent = (char *) old_ent + htab->root.table.entsize;
                }
+             else 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;
+               }
            }
        }
 
       /* Make a special call to the linker "notice" function to
         tell it that symbols added for crefs may need to be removed.  */
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
            }
        }
 
       /* Make a special call to the linker "notice" function to
         tell it that symbols added for crefs may need to be removed.  */
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
-                                      notice_not_needed))
+                                      notice_not_needed, 0, NULL))
        goto error_free_vers;
 
       free (old_tab);
        goto error_free_vers;
 
       free (old_tab);
@@ -4566,7 +4630,7 @@ error_free_dyn:
   if (old_tab != NULL)
     {
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
   if (old_tab != NULL)
     {
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
-                                      notice_needed))
+                                      notice_needed, 0, NULL))
        goto error_free_vers;
       free (old_tab);
       old_tab = NULL;
        goto error_free_vers;
       free (old_tab);
       old_tab = NULL;
@@ -4677,7 +4741,6 @@ error_free_dyn:
          struct elf_link_hash_entry *hlook;
          asection *slook;
          bfd_vma vlook;
          struct elf_link_hash_entry *hlook;
          asection *slook;
          bfd_vma vlook;
-         long ilook;
          size_t i, j, idx;
 
          hlook = weaks;
          size_t i, j, idx;
 
          hlook = weaks;
@@ -4691,14 +4754,13 @@ error_free_dyn:
          slook = hlook->root.u.def.section;
          vlook = hlook->root.u.def.value;
 
          slook = hlook->root.u.def.section;
          vlook = hlook->root.u.def.value;
 
-         ilook = -1;
          i = 0;
          j = sym_count;
          i = 0;
          j = sym_count;
-         while (i < j)
+         while (i != j)
            {
              bfd_signed_vma vdiff;
              idx = (i + j) / 2;
            {
              bfd_signed_vma vdiff;
              idx = (i + j) / 2;
-             h = sorted_sym_hash [idx];
+             h = sorted_sym_hash[idx];
              vdiff = vlook - h->root.u.def.value;
              if (vdiff < 0)
                j = idx;
              vdiff = vlook - h->root.u.def.value;
              if (vdiff < 0)
                j = idx;
@@ -4712,24 +4774,36 @@ error_free_dyn:
                  else if (sdiff > 0)
                    i = idx + 1;
                  else
                  else if (sdiff > 0)
                    i = idx + 1;
                  else
-                   {
-                     ilook = idx;
-                     break;
-                   }
+                   break;
                }
            }
 
          /* We didn't find a value/section match.  */
                }
            }
 
          /* We didn't find a value/section match.  */
-         if (ilook == -1)
+         if (i == j)
            continue;
 
            continue;
 
-         for (i = ilook; i < sym_count; i++)
+         /* With multiple aliases, or when the weak symbol is already
+            strongly defined, we have multiple matching symbols and
+            the binary search above may land on any of them.  Step
+            one past the matching symbol(s).  */
+         while (++idx != j)
            {
            {
-             h = sorted_sym_hash [i];
+             h = sorted_sym_hash[idx];
+             if (h->root.u.def.section != slook
+                 || h->root.u.def.value != vlook)
+               break;
+           }
+
+         /* Now look back over the aliases.  Since we sorted by size
+            as well as value and section, we'll choose the one with
+            the largest size.  */
+         while (idx-- != i)
+           {
+             h = sorted_sym_hash[idx];
 
              /* Stop if value or section doesn't match.  */
 
              /* Stop if value or section doesn't match.  */
-             if (h->root.u.def.value != vlook
-                 || h->root.u.def.section != slook)
+             if (h->root.u.def.section != slook
+                 || h->root.u.def.value != vlook)
                break;
              else if (h != hlook)
                {
                break;
              else if (h != hlook)
                {
@@ -4790,6 +4864,7 @@ error_free_dyn:
   if (! dynamic
       && is_elf_hash_table (htab)
       && bed->check_relocs != NULL
   if (! dynamic
       && is_elf_hash_table (htab)
       && bed->check_relocs != NULL
+      && elf_object_id (abfd) == elf_hash_table_id (htab)
       && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
     {
       asection *o;
       && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
     {
       asection *o;
@@ -4851,7 +4926,7 @@ error_free_dyn:
                                               &string_offset))
                  goto error_return;
                if (secdata->sec_info)
                                               &string_offset))
                  goto error_return;
                if (secdata->sec_info)
-                 stab->sec_info_type = ELF_INFO_TYPE_STABS;
+                 stab->sec_info_type = SEC_INFO_TYPE_STABS;
            }
        }
     }
            }
        }
     }
@@ -4898,7 +4973,7 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd,
   char *p, *copy;
   size_t len, first;
 
   char *p, *copy;
   size_t len, first;
 
-  h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
+  h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, TRUE);
   if (h != NULL)
     return h;
 
   if (h != NULL)
     return h;
 
@@ -4921,14 +4996,14 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd,
   memcpy (copy, name, first);
   memcpy (copy + first, name + first + 1, len - first);
 
   memcpy (copy, name, first);
   memcpy (copy + first, name + first + 1, len - first);
 
-  h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, FALSE);
+  h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, TRUE);
   if (h == NULL)
     {
       /* We also need to check references to the symbol without the
         version.  */
       copy[first - 1] = '\0';
       h = elf_link_hash_lookup (elf_hash_table (info), copy,
   if (h == NULL)
     {
       /* We also need to check references to the symbol without the
         version.  */
       copy[first - 1] = '\0';
       h = elf_link_hash_lookup (elf_hash_table (info), copy,
-                               FALSE, FALSE, FALSE);
+                               FALSE, FALSE, TRUE);
     }
 
   bfd_release (abfd, copy);
     }
 
   bfd_release (abfd, copy);
@@ -5077,10 +5152,10 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
 
          undefs_tail = info->hash->undefs_tail;
 
 
          undefs_tail = info->hash->undefs_tail;
 
-         if (! (*info->callbacks->add_archive_element) (info, element,
-                                                        symdef->name))
+         if (!(*info->callbacks
+               ->add_archive_element) (info, element, symdef->name, &element))
            goto error_return;
            goto error_return;
-         if (! bfd_link_add_symbols (element, info))
+         if (!bfd_link_add_symbols (element, info))
            goto error_return;
 
          /* If there are any new undefined symbols, we need to make
            goto error_return;
 
          /* If there are any new undefined symbols, we need to make
@@ -5161,9 +5236,6 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
   unsigned long ha;
   char *alc = NULL;
 
   unsigned long ha;
   char *alc = NULL;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->dynindx == -1)
     return TRUE;
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->dynindx == -1)
     return TRUE;
@@ -5232,9 +5304,6 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
   unsigned long ha;
   char *alc = NULL;
 
   unsigned long ha;
   char *alc = NULL;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->dynindx == -1)
     return TRUE;
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->dynindx == -1)
     return TRUE;
@@ -5285,9 +5354,6 @@ elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
   unsigned long int bucket;
   unsigned long int val;
 
   unsigned long int bucket;
   unsigned long int val;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Ignore indirect symbols.  */
   if (h->dynindx == -1)
     return TRUE;
   /* Ignore indirect symbols.  */
   if (h->dynindx == -1)
     return TRUE;
@@ -5351,7 +5417,7 @@ static const size_t elf_buckets[] =
    Therefore the result is always a good payoff between few collisions
    (= short chain lengths) and table size.  */
 static size_t
    Therefore the result is always a good payoff between few collisions
    (= short chain lengths) and table size.  */
 static size_t
-compute_bucket_count (struct bfd_link_info *info,
+compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
                      unsigned long int *hashcodes ATTRIBUTE_UNUSED,
                      unsigned long int nsyms,
                      int gnu_hash)
                      unsigned long int *hashcodes ATTRIBUTE_UNUSED,
                      unsigned long int nsyms,
                      int gnu_hash)
@@ -5373,6 +5439,7 @@ compute_bucket_count (struct bfd_link_info *info,
       const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
       unsigned long int *counts;
       bfd_size_type amt;
       const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
       unsigned long int *counts;
       bfd_size_type amt;
+      unsigned int no_improvement_count = 0;
 
       /* Possible optimization parameters: if we have NSYMS symbols we say
         that the hashing table must at least have NSYMS/4 and at most
 
       /* Possible optimization parameters: if we have NSYMS symbols we say
         that the hashing table must at least have NSYMS/4 and at most
@@ -5457,7 +5524,12 @@ compute_bucket_count (struct bfd_link_info *info,
            {
              best_chlen = max;
              best_size = i;
            {
              best_chlen = max;
              best_size = i;
+              no_improvement_count = 0;
            }
            }
+         /* PR 11843: Avoid futile long searches for the best bucket size
+            when there are a large number of symbols.  */
+         else if (++no_improvement_count == 100)
+           break;
        }
 
       free (counts);
        }
 
       free (counts);
@@ -5509,8 +5581,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                               const char *depaudit,
                               const char * const *auxiliary_filters,
                               struct bfd_link_info *info,
                               const char *depaudit,
                               const char * const *auxiliary_filters,
                               struct bfd_link_info *info,
-                              asection **sinterpptr,
-                              struct bfd_elf_version_tree *verdefs)
+                              asection **sinterpptr)
 {
   bfd_size_type soname_indx;
   bfd *dynobj;
 {
   bfd_size_type soname_indx;
   bfd *dynobj;
@@ -5541,7 +5612,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        {
          asection *s;
 
        {
          asection *s;
 
-         if (inputobj->flags & (DYNAMIC | EXEC_P | BFD_LINKER_CREATED))
+         if (inputobj->flags
+             & (DYNAMIC | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED))
            continue;
          s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
          if (s)
            continue;
          s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
          if (s)
@@ -5579,17 +5651,9 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
     return FALSE;
 
       && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
     return FALSE;
 
-  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
-    return FALSE;
-
   dynobj = elf_hash_table (info)->dynobj;
 
   dynobj = elf_hash_table (info)->dynobj;
 
-  /* If there were no dynamic objects in the link, there is nothing to
-     do here.  */
-  if (dynobj == NULL)
-    return TRUE;
-
-  if (elf_hash_table (info)->dynamic_sections_created)
+  if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
     {
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
@@ -5599,7 +5663,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       asection *s;
       bfd_boolean all_defined;
 
       asection *s;
       bfd_boolean all_defined;
 
-      *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
+      *sinterpptr = bfd_get_linker_section (dynobj, ".interp");
       BFD_ASSERT (*sinterpptr != NULL || !info->executable);
 
       if (soname != NULL)
       BFD_ASSERT (*sinterpptr != NULL || !info->executable);
 
       if (soname != NULL)
@@ -5686,7 +5750,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        }
 
       eif.info = info;
        }
 
       eif.info = info;
-      eif.verdefs = verdefs;
       eif.failed = FALSE;
 
       /* If we are supposed to export all symbols into the dynamic symbol
       eif.failed = FALSE;
 
       /* If we are supposed to export all symbols into the dynamic symbol
@@ -5702,17 +5765,18 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        }
 
       /* Make all global versions with definition.  */
        }
 
       /* Make all global versions with definition.  */
-      for (t = verdefs; t != NULL; t = t->next)
+      for (t = info->version_info; t != NULL; t = t->next)
        for (d = t->globals.list; d != NULL; d = d->next)
          if (!d->symver && d->literal)
            {
              const char *verstr, *name;
              size_t namelen, verlen, newlen;
        for (d = t->globals.list; d != NULL; d = d->next)
          if (!d->symver && d->literal)
            {
              const char *verstr, *name;
              size_t namelen, verlen, newlen;
-             char *newname, *p;
+             char *newname, *p, leading_char;
              struct elf_link_hash_entry *newh;
 
              struct elf_link_hash_entry *newh;
 
+             leading_char = bfd_get_symbol_leading_char (output_bfd);
              name = d->pattern;
              name = d->pattern;
-             namelen = strlen (name);
+             namelen = strlen (name) + (leading_char != '\0');
              verstr = t->name;
              verlen = strlen (verstr);
              newlen = namelen + verlen + 3;
              verstr = t->name;
              verlen = strlen (verstr);
              newlen = namelen + verlen + 3;
@@ -5720,7 +5784,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
              newname = (char *) bfd_malloc (newlen);
              if (newname == NULL)
                return FALSE;
              newname = (char *) bfd_malloc (newlen);
              if (newname == NULL)
                return FALSE;
-             memcpy (newname, name, namelen);
+             newname[0] = leading_char;
+             memcpy (newname + (leading_char != '\0'), name, namelen);
 
              /* Check the hidden versioned definition.  */
              p = newname + namelen;
 
              /* Check the hidden versioned definition.  */
              p = newname + namelen;
@@ -5753,7 +5818,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       /* Attach all the symbols to their version information.  */
       asvinfo.info = info;
 
       /* Attach all the symbols to their version information.  */
       asvinfo.info = info;
-      asvinfo.verdefs = verdefs;
       asvinfo.failed = FALSE;
 
       elf_link_hash_traverse (elf_hash_table (info),
       asvinfo.failed = FALSE;
 
       elf_link_hash_traverse (elf_hash_table (info),
@@ -5766,7 +5830,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        {
          /* Check if all global versions have a definition.  */
          all_defined = TRUE;
        {
          /* Check if all global versions have a definition.  */
          all_defined = TRUE;
-         for (t = verdefs; t != NULL; t = t->next)
+         for (t = info->version_info; t != NULL; t = t->next)
            for (d = t->globals.list; d != NULL; d = d->next)
              if (d->literal && !d->symver && !d->script)
                {
            for (d = t->globals.list; d != NULL; d = d->next)
              if (d->literal && !d->symver && !d->script)
                {
@@ -5867,7 +5931,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
            return FALSE;
        }
 
            return FALSE;
        }
 
-      dynstr = bfd_get_section_by_name (dynobj, ".dynstr");
+      dynstr = bfd_get_linker_section (dynobj, ".dynstr");
       /* If .dynstr is excluded from the link, we don't want any of
         these tags.  Strictly, we should be checking each section
         individually;  This quick check covers for the case where
       /* If .dynstr is excluded from the link, we don't want any of
         these tags.  Strictly, we should be checking each section
         individually;  This quick check covers for the case where
@@ -5892,22 +5956,27 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* The backend must work out the sizes of all the other dynamic
      sections.  */
 
   /* The backend must work out the sizes of all the other dynamic
      sections.  */
-  if (bed->elf_backend_size_dynamic_sections
+  if (dynobj != NULL
+      && bed->elf_backend_size_dynamic_sections != NULL
       && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
     return FALSE;
 
       && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
     return FALSE;
 
-  if (elf_hash_table (info)->dynamic_sections_created)
+  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
+    return FALSE;
+
+  if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
       unsigned long section_sym_count;
     {
       unsigned long section_sym_count;
+      struct bfd_elf_version_tree *verdefs;
       asection *s;
 
       /* Set up the version definition section.  */
       asection *s;
 
       /* Set up the version definition section.  */
-      s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
+      s = bfd_get_linker_section (dynobj, ".gnu.version_d");
       BFD_ASSERT (s != NULL);
 
       /* We may have created additional version definitions if we are
         just linking a regular application.  */
       BFD_ASSERT (s != NULL);
 
       /* We may have created additional version definitions if we are
         just linking a regular application.  */
-      verdefs = asvinfo.verdefs;
+      verdefs = info->version_info;
 
       /* Skip anonymous version tag.  */
       if (verdefs != NULL && verdefs->vernum == 0)
 
       /* Skip anonymous version tag.  */
       if (verdefs != NULL && verdefs->vernum == 0)
@@ -6165,7 +6234,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       /* Work out the size of the version reference section.  */
 
 
       /* Work out the size of the version reference section.  */
 
-      s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
+      s = bfd_get_linker_section (dynobj, ".gnu.version_r");
       BFD_ASSERT (s != NULL);
       {
        struct elf_find_verdep_info sinfo;
       BFD_ASSERT (s != NULL);
       {
        struct elf_find_verdep_info sinfo;
@@ -6277,7 +6346,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
          || _bfd_elf_link_renumber_dynsyms (output_bfd, info,
                                             &section_sym_count) == 0)
        {
          || _bfd_elf_link_renumber_dynsyms (output_bfd, info,
                                             &section_sym_count) == 0)
        {
-         s = bfd_get_section_by_name (dynobj, ".gnu.version");
+         s = bfd_get_linker_section (dynobj, ".gnu.version");
          s->flags |= SEC_EXCLUDE;
        }
     }
          s->flags |= SEC_EXCLUDE;
        }
     }
@@ -6361,7 +6430,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
                                                    &section_sym_count);
 
       /* Work out the size of the symbol version section.  */
                                                    &section_sym_count);
 
       /* Work out the size of the symbol version section.  */
-      s = bfd_get_section_by_name (dynobj, ".gnu.version");
+      s = bfd_get_linker_section (dynobj, ".gnu.version");
       BFD_ASSERT (s != NULL);
       if (dynsymcount != 0
          && (s->flags & SEC_EXCLUDE) == 0)
       BFD_ASSERT (s != NULL);
       if (dynsymcount != 0
          && (s->flags & SEC_EXCLUDE) == 0)
@@ -6381,7 +6450,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
         the final symbol table, because until then we do not know the
         correct value to give the symbols.  We built the .dynstr
         section as we went along in elf_link_add_object_symbols.  */
         the final symbol table, because until then we do not know the
         correct value to give the symbols.  We built the .dynstr
         section as we went along in elf_link_add_object_symbols.  */
-      s = bfd_get_section_by_name (dynobj, ".dynsym");
+      s = bfd_get_linker_section (dynobj, ".dynsym");
       BFD_ASSERT (s != NULL);
       s->size = dynsymcount * bed->s->sizeof_sym;
 
       BFD_ASSERT (s != NULL);
       s->size = dynsymcount * bed->s->sizeof_sym;
 
@@ -6439,7 +6508,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
 
          elf_hash_table (info)->bucketcount = bucketcount;
 
 
          elf_hash_table (info)->bucketcount = bucketcount;
 
-         s = bfd_get_section_by_name (dynobj, ".hash");
+         s = bfd_get_linker_section (dynobj, ".hash");
          BFD_ASSERT (s != NULL);
          hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
          s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
          BFD_ASSERT (s != NULL);
          hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
          s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
@@ -6493,7 +6562,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
              return FALSE;
            }
 
              return FALSE;
            }
 
-         s = bfd_get_section_by_name (dynobj, ".gnu.hash");
+         s = bfd_get_linker_section (dynobj, ".gnu.hash");
          BFD_ASSERT (s != NULL);
 
          if (cinfo.nsyms == 0)
          BFD_ASSERT (s != NULL);
 
          if (cinfo.nsyms == 0)
@@ -6522,10 +6591,13 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
            }
          else
            {
            }
          else
            {
-             unsigned long int maskwords, maskbitslog2;
+             unsigned long int maskwords, maskbitslog2, x;
              BFD_ASSERT (cinfo.min_dynindx != -1);
 
              BFD_ASSERT (cinfo.min_dynindx != -1);
 
-             maskbitslog2 = bfd_log2 (cinfo.nsyms) + 1;
+             x = cinfo.nsyms;
+             maskbitslog2 = 1;
+             while ((x >>= 1) != 0)
+               ++maskbitslog2;
              if (maskbitslog2 < 3)
                maskbitslog2 = 5;
              else if ((1 << (maskbitslog2 - 2)) & cinfo.nsyms)
              if (maskbitslog2 < 3)
                maskbitslog2 = 5;
              else if ((1 << (maskbitslog2 - 2)) & cinfo.nsyms)
@@ -6618,7 +6690,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
            }
        }
 
            }
        }
 
-      s = bfd_get_section_by_name (dynobj, ".dynstr");
+      s = bfd_get_linker_section (dynobj, ".dynstr");
       BFD_ASSERT (s != NULL);
 
       elf_finalize_dynstr (output_bfd, info);
       BFD_ASSERT (s != NULL);
 
       elf_finalize_dynstr (output_bfd, info);
@@ -6633,25 +6705,14 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
   return TRUE;
 }
 \f
   return TRUE;
 }
 \f
-/* Indicate that we are only retrieving symbol values from this
-   section.  */
-
-void
-_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
-{
-  if (is_elf_hash_table (info->hash))
-    sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
-  _bfd_generic_link_just_syms (sec, info);
-}
-
 /* Make sure sec_info_type is cleared if sec_info is cleared too.  */
 
 static void
 merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
                            asection *sec)
 {
 /* Make sure sec_info_type is cleared if sec_info is cleared too.  */
 
 static void
 merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
                            asection *sec)
 {
-  BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE);
-  sec->sec_info_type = ELF_INFO_TYPE_NONE;
+  BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_MERGE);
+  sec->sec_info_type = SEC_INFO_TYPE_NONE;
 }
 
 /* Finish SHF_MERGE section merging.  */
 }
 
 /* Finish SHF_MERGE section merging.  */
@@ -6679,7 +6740,7 @@ _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
                                          sec, &secdata->sec_info))
              return FALSE;
            else if (secdata->sec_info)
                                          sec, &secdata->sec_info))
              return FALSE;
            else if (secdata->sec_info)
-             sec->sec_info_type = ELF_INFO_TYPE_MERGE;
+             sec->sec_info_type = SEC_INFO_TYPE_MERGE;
          }
 
   if (elf_hash_table (info)->merge_info != NULL)
          }
 
   if (elf_hash_table (info)->merge_info != NULL)
@@ -7402,6 +7463,8 @@ struct elf_final_link_info
   size_t symbuf_size;
   /* And same for symshndxbuf.  */
   size_t shndxbuf_size;
   size_t symbuf_size;
   /* And same for symshndxbuf.  */
   size_t shndxbuf_size;
+  /* Number of STT_FILE syms seen.  */
+  size_t filesym_count;
 };
 
 /* This struct is used to pass information to elf_link_output_extsym.  */
 };
 
 /* This struct is used to pass information to elf_link_output_extsym.  */
@@ -7410,7 +7473,9 @@ struct elf_outext_info
 {
   bfd_boolean failed;
   bfd_boolean localsyms;
 {
   bfd_boolean failed;
   bfd_boolean localsyms;
-  struct elf_final_link_info *finfo;
+  bfd_boolean need_second_pass;
+  bfd_boolean second_pass;
+  struct elf_final_link_info *flinfo;
 };
 
 
 };
 
 
@@ -7487,7 +7552,7 @@ set_symbol_value (bfd *bfd_with_globals,
 static bfd_boolean
 resolve_symbol (const char *name,
                bfd *input_bfd,
 static bfd_boolean
 resolve_symbol (const char *name,
                bfd *input_bfd,
-               struct elf_final_link_info *finfo,
+               struct elf_final_link_info *flinfo,
                bfd_vma *result,
                Elf_Internal_Sym *isymbuf,
                size_t locsymcount)
                bfd_vma *result,
                Elf_Internal_Sym *isymbuf,
                size_t locsymcount)
@@ -7516,7 +7581,7 @@ resolve_symbol (const char *name,
 #endif
       if (candidate && strcmp (candidate, name) == 0)
        {
 #endif
       if (candidate && strcmp (candidate, name) == 0)
        {
-         asection *sec = finfo->sections [i];
+         asection *sec = flinfo->sections [i];
 
          *result = _bfd_elf_rel_local_sym (input_bfd, sym, &sec, 0);
          *result += sec->output_offset + sec->output_section->vma;
 
          *result = _bfd_elf_rel_local_sym (input_bfd, sym, &sec, 0);
          *result += sec->output_offset + sec->output_section->vma;
@@ -7529,7 +7594,7 @@ resolve_symbol (const char *name,
     }
 
   /* Hmm, haven't found it yet. perhaps it is a global.  */
     }
 
   /* Hmm, haven't found it yet. perhaps it is a global.  */
-  global_entry = bfd_link_hash_lookup (finfo->info->hash, name,
+  global_entry = bfd_link_hash_lookup (flinfo->info->hash, name,
                                       FALSE, FALSE, TRUE);
   if (!global_entry)
     return FALSE;
                                       FALSE, FALSE, TRUE);
   if (!global_entry)
     return FALSE;
@@ -7598,7 +7663,7 @@ static bfd_boolean
 eval_symbol (bfd_vma *result,
             const char **symp,
             bfd *input_bfd,
 eval_symbol (bfd_vma *result,
             const char **symp,
             bfd *input_bfd,
-            struct elf_final_link_info *finfo,
+            struct elf_final_link_info *flinfo,
             bfd_vma dot,
             Elf_Internal_Sym *isymbuf,
             size_t locsymcount,
             bfd_vma dot,
             Elf_Internal_Sym *isymbuf,
             size_t locsymcount,
@@ -7658,8 +7723,8 @@ eval_symbol (bfd_vma *result,
 
       if (symbol_is_section)
        {
 
       if (symbol_is_section)
        {
-         if (!resolve_section (symbuf, finfo->output_bfd->sections, result)
-             && !resolve_symbol (symbuf, input_bfd, finfo, result,
+         if (!resolve_section (symbuf, flinfo->output_bfd->sections, result)
+             && !resolve_symbol (symbuf, input_bfd, flinfo, result,
                                  isymbuf, locsymcount))
            {
              undefined_reference ("section", symbuf);
                                  isymbuf, locsymcount))
            {
              undefined_reference ("section", symbuf);
@@ -7668,9 +7733,9 @@ eval_symbol (bfd_vma *result,
        }
       else
        {
        }
       else
        {
-         if (!resolve_symbol (symbuf, input_bfd, finfo, result,
+         if (!resolve_symbol (symbuf, input_bfd, flinfo, result,
                               isymbuf, locsymcount)
                               isymbuf, locsymcount)
-             && !resolve_section (symbuf, finfo->output_bfd->sections,
+             && !resolve_section (symbuf, flinfo->output_bfd->sections,
                                   result))
            {
              undefined_reference ("symbol", symbuf);
                                   result))
            {
              undefined_reference ("symbol", symbuf);
@@ -7689,7 +7754,7 @@ eval_symbol (bfd_vma *result,
       if (*sym == ':')                                         \
        ++sym;                                                  \
       *symp = sym;                                             \
       if (*sym == ':')                                         \
        ++sym;                                                  \
       *symp = sym;                                             \
-      if (!eval_symbol (&a, symp, input_bfd, finfo, dot,       \
+      if (!eval_symbol (&a, symp, input_bfd, flinfo, dot,      \
                        isymbuf, locsymcount, signed_p))        \
        return FALSE;                                           \
       if (signed_p)                                            \
                        isymbuf, locsymcount, signed_p))        \
        return FALSE;                                           \
       if (signed_p)                                            \
@@ -7706,11 +7771,11 @@ eval_symbol (bfd_vma *result,
       if (*sym == ':')                                         \
        ++sym;                                                  \
       *symp = sym;                                             \
       if (*sym == ':')                                         \
        ++sym;                                                  \
       *symp = sym;                                             \
-      if (!eval_symbol (&a, symp, input_bfd, finfo, dot,       \
+      if (!eval_symbol (&a, symp, input_bfd, flinfo, dot,      \
                        isymbuf, locsymcount, signed_p))        \
        return FALSE;                                           \
       ++*symp;                                                 \
                        isymbuf, locsymcount, signed_p))        \
        return FALSE;                                           \
       ++*symp;                                                 \
-      if (!eval_symbol (&b, symp, input_bfd, finfo, dot,       \
+      if (!eval_symbol (&b, symp, input_bfd, flinfo, dot,      \
                        isymbuf, locsymcount, signed_p))        \
        return FALSE;                                           \
       if (signed_p)                                            \
                        isymbuf, locsymcount, signed_p))        \
        return FALSE;                                           \
       if (signed_p)                                            \
@@ -7880,7 +7945,8 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd,
          "chunksz %ld, start %ld, len %ld, oplen %ld\n"
          "    dest: %8.8lx, mask: %8.8lx, reloc: %8.8lx\n",
          lsb0_p, signed_p, trunc_p, wordsz, chunksz, start, len,
          "chunksz %ld, start %ld, len %ld, oplen %ld\n"
          "    dest: %8.8lx, mask: %8.8lx, reloc: %8.8lx\n",
          lsb0_p, signed_p, trunc_p, wordsz, chunksz, start, len,
-         oplen, x, mask,  relocation);
+         oplen, (unsigned long) x, (unsigned long) mask,
+         (unsigned long) relocation);
 #endif
 
   r = bfd_reloc_ok;
 #endif
 
   r = bfd_reloc_ok;
@@ -7900,8 +7966,8 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd,
          "         shifted mask: %8.8lx\n"
          " shifted/masked reloc: %8.8lx\n"
          "               result: %8.8lx\n",
          "         shifted mask: %8.8lx\n"
          " shifted/masked reloc: %8.8lx\n"
          "               result: %8.8lx\n",
-         relocation, (mask << shift),
-         ((relocation & mask) << shift), x);
+         (unsigned long) relocation, (unsigned long) (mask << shift),
+         (unsigned long) ((relocation & mask) << shift), (unsigned long) x);
 #endif
   /* FIXME: octets_per_byte.  */
   put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
 #endif
   /* FIXME: octets_per_byte.  */
   put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
@@ -7910,14 +7976,12 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd,
 
 /* When performing a relocatable link, the input relocations are
    preserved.  But, if they reference global symbols, the indices
 
 /* When performing a relocatable link, the input relocations are
    preserved.  But, if they reference global symbols, the indices
-   referenced must be updated.  Update all the relocations in
-   REL_HDR (there are COUNT of them), using the data in REL_HASH.  */
+   referenced must be updated.  Update all the relocations found in
+   RELDATA.  */
 
 static void
 elf_link_adjust_relocs (bfd *abfd,
 
 static void
 elf_link_adjust_relocs (bfd *abfd,
-                       Elf_Internal_Shdr *rel_hdr,
-                       unsigned int count,
-                       struct elf_link_hash_entry **rel_hash)
+                       struct bfd_elf_section_reloc_data *reldata)
 {
   unsigned int i;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 {
   unsigned int i;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
@@ -7926,13 +7990,15 @@ elf_link_adjust_relocs (bfd *abfd,
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
   bfd_vma r_type_mask;
   int r_sym_shift;
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
   bfd_vma r_type_mask;
   int r_sym_shift;
+  unsigned int count = reldata->count;
+  struct elf_link_hash_entry **rel_hash = reldata->hashes;
 
 
-  if (rel_hdr->sh_entsize == bed->s->sizeof_rel)
+  if (reldata->hdr->sh_entsize == bed->s->sizeof_rel)
     {
       swap_in = bed->s->swap_reloc_in;
       swap_out = bed->s->swap_reloc_out;
     }
     {
       swap_in = bed->s->swap_reloc_in;
       swap_out = bed->s->swap_reloc_out;
     }
-  else if (rel_hdr->sh_entsize == bed->s->sizeof_rela)
+  else if (reldata->hdr->sh_entsize == bed->s->sizeof_rela)
     {
       swap_in = bed->s->swap_reloca_in;
       swap_out = bed->s->swap_reloca_out;
     {
       swap_in = bed->s->swap_reloca_in;
       swap_out = bed->s->swap_reloca_out;
@@ -7954,8 +8020,8 @@ elf_link_adjust_relocs (bfd *abfd,
       r_sym_shift = 32;
     }
 
       r_sym_shift = 32;
     }
 
-  erela = rel_hdr->contents;
-  for (i = 0; i < count; i++, rel_hash++, erela += rel_hdr->sh_entsize)
+  erela = reldata->hdr->contents;
+  for (i = 0; i < count; i++, rel_hash++, erela += reldata->hdr->sh_entsize)
     {
       Elf_Internal_Rela irela[MAX_INT_RELS_PER_EXT_REL];
       unsigned int j;
     {
       Elf_Internal_Rela irela[MAX_INT_RELS_PER_EXT_REL];
       unsigned int j;
@@ -8307,24 +8373,24 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
 /* Flush the output symbols to the file.  */
 
 static bfd_boolean
 /* Flush the output symbols to the file.  */
 
 static bfd_boolean
-elf_link_flush_output_syms (struct elf_final_link_info *finfo,
+elf_link_flush_output_syms (struct elf_final_link_info *flinfo,
                            const struct elf_backend_data *bed)
 {
                            const struct elf_backend_data *bed)
 {
-  if (finfo->symbuf_count > 0)
+  if (flinfo->symbuf_count > 0)
     {
       Elf_Internal_Shdr *hdr;
       file_ptr pos;
       bfd_size_type amt;
 
     {
       Elf_Internal_Shdr *hdr;
       file_ptr pos;
       bfd_size_type amt;
 
-      hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr;
+      hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
       pos = hdr->sh_offset + hdr->sh_size;
       pos = hdr->sh_offset + hdr->sh_size;
-      amt = finfo->symbuf_count * bed->s->sizeof_sym;
-      if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
-         || bfd_bwrite (finfo->symbuf, amt, finfo->output_bfd) != amt)
+      amt = flinfo->symbuf_count * bed->s->sizeof_sym;
+      if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) != 0
+         || bfd_bwrite (flinfo->symbuf, amt, flinfo->output_bfd) != amt)
        return FALSE;
 
       hdr->sh_size += amt;
        return FALSE;
 
       hdr->sh_size += amt;
-      finfo->symbuf_count = 0;
+      flinfo->symbuf_count = 0;
     }
 
   return TRUE;
     }
 
   return TRUE;
@@ -8333,7 +8399,7 @@ elf_link_flush_output_syms (struct elf_final_link_info *finfo,
 /* Add a symbol to the output symbol table.  */
 
 static int
 /* Add a symbol to the output symbol table.  */
 
 static int
-elf_link_output_sym (struct elf_final_link_info *finfo,
+elf_link_output_sym (struct elf_final_link_info *flinfo,
                     const char *name,
                     Elf_Internal_Sym *elfsym,
                     asection *input_sec,
                     const char *name,
                     Elf_Internal_Sym *elfsym,
                     asection *input_sec,
@@ -8346,11 +8412,11 @@ elf_link_output_sym (struct elf_final_link_info *finfo,
      struct elf_link_hash_entry *);
   const struct elf_backend_data *bed;
 
      struct elf_link_hash_entry *);
   const struct elf_backend_data *bed;
 
-  bed = get_elf_backend_data (finfo->output_bfd);
+  bed = get_elf_backend_data (flinfo->output_bfd);
   output_symbol_hook = bed->elf_backend_link_output_symbol_hook;
   if (output_symbol_hook != NULL)
     {
   output_symbol_hook = bed->elf_backend_link_output_symbol_hook;
   if (output_symbol_hook != NULL)
     {
-      int ret = (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h);
+      int ret = (*output_symbol_hook) (flinfo->info, name, elfsym, input_sec, h);
       if (ret != 1)
        return ret;
     }
       if (ret != 1)
        return ret;
     }
@@ -8361,41 +8427,41 @@ elf_link_output_sym (struct elf_final_link_info *finfo,
     elfsym->st_name = 0;
   else
     {
     elfsym->st_name = 0;
   else
     {
-      elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab,
+      elfsym->st_name = (unsigned long) _bfd_stringtab_add (flinfo->symstrtab,
                                                            name, TRUE, FALSE);
       if (elfsym->st_name == (unsigned long) -1)
        return 0;
     }
 
                                                            name, TRUE, FALSE);
       if (elfsym->st_name == (unsigned long) -1)
        return 0;
     }
 
-  if (finfo->symbuf_count >= finfo->symbuf_size)
+  if (flinfo->symbuf_count >= flinfo->symbuf_size)
     {
     {
-      if (! elf_link_flush_output_syms (finfo, bed))
+      if (! elf_link_flush_output_syms (flinfo, bed))
        return 0;
     }
 
        return 0;
     }
 
-  dest = finfo->symbuf + finfo->symbuf_count * bed->s->sizeof_sym;
-  destshndx = finfo->symshndxbuf;
+  dest = flinfo->symbuf + flinfo->symbuf_count * bed->s->sizeof_sym;
+  destshndx = flinfo->symshndxbuf;
   if (destshndx != NULL)
     {
   if (destshndx != NULL)
     {
-      if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size)
+      if (bfd_get_symcount (flinfo->output_bfd) >= flinfo->shndxbuf_size)
        {
          bfd_size_type amt;
 
        {
          bfd_size_type amt;
 
-         amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
+         amt = flinfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
          destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx,
                                                               amt * 2);
          if (destshndx == NULL)
            return 0;
          destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx,
                                                               amt * 2);
          if (destshndx == NULL)
            return 0;
-         finfo->symshndxbuf = destshndx;
+         flinfo->symshndxbuf = destshndx;
          memset ((char *) destshndx + amt, 0, amt);
          memset ((char *) destshndx + amt, 0, amt);
-         finfo->shndxbuf_size *= 2;
+         flinfo->shndxbuf_size *= 2;
        }
        }
-      destshndx += bfd_get_symcount (finfo->output_bfd);
+      destshndx += bfd_get_symcount (flinfo->output_bfd);
     }
 
     }
 
-  bed->s->swap_symbol_out (finfo->output_bfd, elfsym, dest, destshndx);
-  finfo->symbuf_count += 1;
-  bfd_get_symcount (finfo->output_bfd) += 1;
+  bed->s->swap_symbol_out (flinfo->output_bfd, elfsym, dest, destshndx);
+  flinfo->symbuf_count += 1;
+  bfd_get_symcount (flinfo->output_bfd) += 1;
 
   return 1;
 }
 
   return 1;
 }
@@ -8436,6 +8502,10 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
   if (!is_elf_hash_table (info->hash))
     return FALSE;
 
   if (!is_elf_hash_table (info->hash))
     return FALSE;
 
+  /* Check indirect symbol.  */
+  while (h->root.type == bfd_link_hash_indirect)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
   switch (h->root.type)
     {
     default:
   switch (h->root.type)
     {
     default:
@@ -8579,10 +8649,11 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
    global symbols.  */
 
 static bfd_boolean
    global symbols.  */
 
 static bfd_boolean
-elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
+elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 {
 {
+  struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh;
   struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
   struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
-  struct elf_final_link_info *finfo = eoinfo->finfo;
+  struct elf_final_link_info *flinfo = eoinfo->flinfo;
   bfd_boolean strip;
   Elf_Internal_Sym sym;
   asection *input_sec;
   bfd_boolean strip;
   Elf_Internal_Sym sym;
   asection *input_sec;
@@ -8602,6 +8673,11 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
     {
       if (!h->forced_local)
        return TRUE;
     {
       if (!h->forced_local)
        return TRUE;
+      if (eoinfo->second_pass
+         && !((h->root.type == bfd_link_hash_defined
+               || h->root.type == bfd_link_hash_defweak)
+              && h->root.u.def.section->output_section != NULL))
+       return TRUE;
     }
   else
     {
     }
   else
     {
@@ -8609,7 +8685,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
        return TRUE;
     }
 
        return TRUE;
     }
 
-  bed = get_elf_backend_data (finfo->output_bfd);
+  bed = get_elf_backend_data (flinfo->output_bfd);
 
   if (h->root.type == bfd_link_hash_undefined)
     {
 
   if (h->root.type == bfd_link_hash_undefined)
     {
@@ -8626,17 +8702,20 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
        ignore_undef = bed->elf_backend_ignore_undef_symbol (h);
 
       /* If we are reporting errors for this situation then do so now.  */
        ignore_undef = bed->elf_backend_ignore_undef_symbol (h);
 
       /* If we are reporting errors for this situation then do so now.  */
-      if (ignore_undef == FALSE
+      if (!ignore_undef
          && h->ref_dynamic
          && h->ref_dynamic
-         && (!h->ref_regular || finfo->info->gc_sections)
-         && ! elf_link_check_versioned_symbol (finfo->info, bed, h)
-         && finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
-       {
-         if (! (finfo->info->callbacks->undefined_symbol
-                (finfo->info, h->root.root.string,
-                 h->ref_regular ? NULL : h->root.u.undef.abfd,
-                 NULL, 0, finfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR)))
+         && (!h->ref_regular || flinfo->info->gc_sections)
+         && !elf_link_check_versioned_symbol (flinfo->info, bed, h)
+         && flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
+       {
+         if (!(flinfo->info->callbacks->undefined_symbol
+               (flinfo->info, h->root.root.string,
+                h->ref_regular ? NULL : h->root.u.undef.abfd,
+                NULL, 0,
+                (flinfo->info->unresolved_syms_in_shared_libs
+                 == RM_GENERATE_ERROR))))
            {
            {
+             bfd_set_error (bfd_error_bad_value);
              eoinfo->failed = TRUE;
              return FALSE;
            }
              eoinfo->failed = TRUE;
              return FALSE;
            }
@@ -8645,24 +8724,35 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
 
   /* We should also warn if a forced local symbol is referenced from
      shared libraries.  */
 
   /* We should also warn if a forced local symbol is referenced from
      shared libraries.  */
-  if (! finfo->info->relocatable
-      && (! finfo->info->shared)
+  if (!flinfo->info->relocatable
+      && flinfo->info->executable
       && h->forced_local
       && h->ref_dynamic
       && h->forced_local
       && h->ref_dynamic
+      && h->def_regular
       && !h->dynamic_def
       && !h->dynamic_weak
       && !h->dynamic_def
       && !h->dynamic_weak
-      && ! elf_link_check_versioned_symbol (finfo->info, bed, h))
+      && !elf_link_check_versioned_symbol (flinfo->info, bed, h))
     {
     {
-      (*_bfd_error_handler)
-       (_("%B: %s symbol `%s' in %B is referenced by DSO"),
-        finfo->output_bfd,
-        h->root.u.def.section == bfd_abs_section_ptr
-        ? finfo->output_bfd : h->root.u.def.section->owner,
-        ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-        ? "internal"
-        : ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
-        ? "hidden" : "local",
-        h->root.root.string);
+      bfd *def_bfd;
+      const char *msg;
+      struct elf_link_hash_entry *hi = h;
+
+      /* Check indirect symbol.  */
+      while (hi->root.type == bfd_link_hash_indirect)
+       hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+
+      if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
+       msg = _("%B: internal symbol `%s' in %B is referenced by DSO");
+      else if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+       msg = _("%B: hidden symbol `%s' in %B is referenced by DSO");
+      else
+       msg = _("%B: local symbol `%s' in %B is referenced by DSO");
+      def_bfd = flinfo->output_bfd;
+      if (hi->root.u.def.section != bfd_abs_section_ptr)
+       def_bfd = hi->root.u.def.section->owner;
+      (*_bfd_error_handler) (msg, flinfo->output_bfd, def_bfd,
+                            h->root.root.string);
+      bfd_set_error (bfd_error_bad_value);
       eoinfo->failed = TRUE;
       return FALSE;
     }
       eoinfo->failed = TRUE;
       return FALSE;
     }
@@ -8679,16 +8769,23 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
           && !h->def_regular
           && !h->ref_regular)
     strip = TRUE;
           && !h->def_regular
           && !h->ref_regular)
     strip = TRUE;
-  else if (finfo->info->strip == strip_all)
+  else if (flinfo->info->strip == strip_all)
     strip = TRUE;
     strip = TRUE;
-  else if (finfo->info->strip == strip_some
-          && bfd_hash_lookup (finfo->info->keep_hash,
+  else if (flinfo->info->strip == strip_some
+          && bfd_hash_lookup (flinfo->info->keep_hash,
                               h->root.root.string, FALSE, FALSE) == NULL)
     strip = TRUE;
                               h->root.root.string, FALSE, FALSE) == NULL)
     strip = TRUE;
-  else if (finfo->info->strip_discarded
-          && (h->root.type == bfd_link_hash_defined
-              || h->root.type == bfd_link_hash_defweak)
-          && elf_discarded_section (h->root.u.def.section))
+  else if ((h->root.type == bfd_link_hash_defined
+           || h->root.type == bfd_link_hash_defweak)
+          && ((flinfo->info->strip_discarded
+               && discarded_section (h->root.u.def.section))
+              || (h->root.u.def.section->owner != NULL
+                  && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)))
+    strip = TRUE;
+  else if ((h->root.type == bfd_link_hash_undefined
+           || h->root.type == bfd_link_hash_undefweak)
+          && h->root.u.undef.abfd != NULL
+          && (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0)
     strip = TRUE;
   else
     strip = FALSE;
     strip = TRUE;
   else
     strip = FALSE;
@@ -8718,6 +8815,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
     sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
   else
     sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
     sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
   else
     sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
+  sym.st_target_internal = h->target_internal;
 
   switch (h->root.type)
     {
 
   switch (h->root.type)
     {
@@ -8739,14 +8837,28 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
        input_sec = h->root.u.def.section;
        if (input_sec->output_section != NULL)
          {
        input_sec = h->root.u.def.section;
        if (input_sec->output_section != NULL)
          {
+           if (eoinfo->localsyms && flinfo->filesym_count == 1)
+             {
+               bfd_boolean second_pass_sym
+                 = (input_sec->owner == flinfo->output_bfd
+                    || input_sec->owner == NULL
+                    || (input_sec->flags & SEC_LINKER_CREATED) != 0
+                    || (input_sec->owner->flags & BFD_LINKER_CREATED) != 0);
+
+               eoinfo->need_second_pass |= second_pass_sym;
+               if (eoinfo->second_pass != second_pass_sym)
+                 return TRUE;
+             }
+
            sym.st_shndx =
            sym.st_shndx =
-             _bfd_elf_section_from_bfd_section (finfo->output_bfd,
+             _bfd_elf_section_from_bfd_section (flinfo->output_bfd,
                                                 input_sec->output_section);
            if (sym.st_shndx == SHN_BAD)
              {
                (*_bfd_error_handler)
                  (_("%B: could not find output section %A for input section %A"),
                                                 input_sec->output_section);
            if (sym.st_shndx == SHN_BAD)
              {
                (*_bfd_error_handler)
                  (_("%B: could not find output section %A for input section %A"),
-                  finfo->output_bfd, input_sec->output_section, input_sec);
+                  flinfo->output_bfd, input_sec->output_section, input_sec);
+               bfd_set_error (bfd_error_nonrepresentable_section);
                eoinfo->failed = TRUE;
                return FALSE;
              }
                eoinfo->failed = TRUE;
                return FALSE;
              }
@@ -8755,18 +8867,18 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
               but in nonrelocatable files they are virtual
               addresses.  */
            sym.st_value = h->root.u.def.value + input_sec->output_offset;
               but in nonrelocatable files they are virtual
               addresses.  */
            sym.st_value = h->root.u.def.value + input_sec->output_offset;
-           if (! finfo->info->relocatable)
+           if (!flinfo->info->relocatable)
              {
                sym.st_value += input_sec->output_section->vma;
                if (h->type == STT_TLS)
                  {
              {
                sym.st_value += input_sec->output_section->vma;
                if (h->type == STT_TLS)
                  {
-                   asection *tls_sec = elf_hash_table (finfo->info)->tls_sec;
+                   asection *tls_sec = elf_hash_table (flinfo->info)->tls_sec;
                    if (tls_sec != NULL)
                      sym.st_value -= tls_sec->vma;
                    else
                      {
                        /* The TLS section may have been garbage collected.  */
                    if (tls_sec != NULL)
                      sym.st_value -= tls_sec->vma;
                    else
                      {
                        /* The TLS section may have been garbage collected.  */
-                       BFD_ASSERT (finfo->info->gc_sections
+                       BFD_ASSERT (flinfo->info->gc_sections
                                    && !input_sec->gc_mark);
                      }
                  }
                                    && !input_sec->gc_mark);
                      }
                  }
@@ -8805,17 +8917,17 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
      STT_GNU_IFUNC symbol must go through PLT.  */
   if ((h->type == STT_GNU_IFUNC
        && h->def_regular
      STT_GNU_IFUNC symbol must go through PLT.  */
   if ((h->type == STT_GNU_IFUNC
        && h->def_regular
-       && !finfo->info->relocatable)
+       && !flinfo->info->relocatable)
       || ((h->dynindx != -1
           || h->forced_local)
       || ((h->dynindx != -1
           || h->forced_local)
-         && ((finfo->info->shared
+         && ((flinfo->info->shared
               && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak))
              || !h->forced_local)
               && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak))
              || !h->forced_local)
-         && elf_hash_table (finfo->info)->dynamic_sections_created))
+         && elf_hash_table (flinfo->info)->dynamic_sections_created))
     {
       if (! ((*bed->elf_backend_finish_dynamic_symbol)
     {
       if (! ((*bed->elf_backend_finish_dynamic_symbol)
-            (finfo->output_bfd, finfo->info, h, &sym)))
+            (flinfo->output_bfd, flinfo->info, h, &sym)))
        {
          eoinfo->failed = TRUE;
          return FALSE;
        {
          eoinfo->failed = TRUE;
          return FALSE;
@@ -8858,20 +8970,22 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
 
   /* If a non-weak symbol with non-default visibility is not defined
      locally, it is a fatal error.  */
 
   /* If a non-weak symbol with non-default visibility is not defined
      locally, it is a fatal error.  */
-  if (! finfo->info->relocatable
+  if (!flinfo->info->relocatable
       && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
       && ELF_ST_BIND (sym.st_info) != STB_WEAK
       && h->root.type == bfd_link_hash_undefined
       && !h->def_regular)
     {
       && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
       && ELF_ST_BIND (sym.st_info) != STB_WEAK
       && h->root.type == bfd_link_hash_undefined
       && !h->def_regular)
     {
-      (*_bfd_error_handler)
-       (_("%B: %s symbol `%s' isn't defined"),
-        finfo->output_bfd,
-        ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED
-        ? "protected"
-        : ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL
-        ? "internal" : "hidden",
-        h->root.root.string);
+      const char *msg;
+
+      if (ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED)
+       msg = _("%B: protected symbol `%s' isn't defined");
+      else if (ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL)
+       msg = _("%B: internal symbol `%s' isn't defined");
+      else
+       msg = _("%B: hidden symbol `%s' isn't defined");
+      (*_bfd_error_handler) (msg, flinfo->output_bfd, h->root.root.string);
+      bfd_set_error (bfd_error_bad_value);
       eoinfo->failed = TRUE;
       return FALSE;
     }
       eoinfo->failed = TRUE;
       return FALSE;
     }
@@ -8879,21 +8993,39 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We already know the symbol index.  We also fill in
      the entry in the .hash section.  */
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We already know the symbol index.  We also fill in
      the entry in the .hash section.  */
-  if (h->dynindx != -1
-      && elf_hash_table (finfo->info)->dynamic_sections_created)
+  if (flinfo->dynsym_sec != NULL
+      && h->dynindx != -1
+      && elf_hash_table (flinfo->info)->dynamic_sections_created)
     {
       bfd_byte *esym;
 
     {
       bfd_byte *esym;
 
+      /* Since there is no version information in the dynamic string,
+        if there is no version info in symbol version section, we will
+        have a run-time problem.  */
+      if (h->verinfo.verdef == NULL)
+       {
+         char *p = strrchr (h->root.root.string, ELF_VER_CHR);
+
+         if (p && p [1] != '\0')
+           {
+             (*_bfd_error_handler)
+               (_("%B: No symbol version section for versioned symbol `%s'"),
+                flinfo->output_bfd, h->root.root.string);
+             eoinfo->failed = TRUE;
+             return FALSE;
+           }
+       }
+
       sym.st_name = h->dynstr_index;
       sym.st_name = h->dynstr_index;
-      esym = finfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
-      if (! check_dynsym (finfo->output_bfd, &sym))
+      esym = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
+      if (!check_dynsym (flinfo->output_bfd, &sym))
        {
          eoinfo->failed = TRUE;
          return FALSE;
        }
        {
          eoinfo->failed = TRUE;
          return FALSE;
        }
-      bed->s->swap_symbol_out (finfo->output_bfd, &sym, esym, 0);
+      bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0);
 
 
-      if (finfo->hash_sec != NULL)
+      if (flinfo->hash_sec != NULL)
        {
          size_t hash_entry_size;
          bfd_byte *bucketpos;
        {
          size_t hash_entry_size;
          bfd_byte *bucketpos;
@@ -8901,21 +9033,22 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
          size_t bucketcount;
          size_t bucket;
 
          size_t bucketcount;
          size_t bucket;
 
-         bucketcount = elf_hash_table (finfo->info)->bucketcount;
+         bucketcount = elf_hash_table (flinfo->info)->bucketcount;
          bucket = h->u.elf_hash_value % bucketcount;
 
          hash_entry_size
          bucket = h->u.elf_hash_value % bucketcount;
 
          hash_entry_size
-           = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
-         bucketpos = ((bfd_byte *) finfo->hash_sec->contents
+           = elf_section_data (flinfo->hash_sec)->this_hdr.sh_entsize;
+         bucketpos = ((bfd_byte *) flinfo->hash_sec->contents
                       + (bucket + 2) * hash_entry_size);
                       + (bucket + 2) * hash_entry_size);
-         chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos);
-         bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos);
-         bfd_put (8 * hash_entry_size, finfo->output_bfd, chain,
-                  ((bfd_byte *) finfo->hash_sec->contents
+         chain = bfd_get (8 * hash_entry_size, flinfo->output_bfd, bucketpos);
+         bfd_put (8 * hash_entry_size, flinfo->output_bfd, h->dynindx,
+                  bucketpos);
+         bfd_put (8 * hash_entry_size, flinfo->output_bfd, chain,
+                  ((bfd_byte *) flinfo->hash_sec->contents
                    + (bucketcount + 2 + h->dynindx) * hash_entry_size));
        }
 
                    + (bucketcount + 2 + h->dynindx) * hash_entry_size));
        }
 
-      if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL)
+      if (flinfo->symver_sec != NULL && flinfo->symver_sec->contents != NULL)
        {
          Elf_Internal_Versym iversym;
          Elf_External_Versym *eversym;
        {
          Elf_Internal_Versym iversym;
          Elf_External_Versym *eversym;
@@ -8933,16 +9066,16 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
                iversym.vs_vers = 1;
              else
                iversym.vs_vers = h->verinfo.vertree->vernum + 1;
                iversym.vs_vers = 1;
              else
                iversym.vs_vers = h->verinfo.vertree->vernum + 1;
-             if (finfo->info->create_default_symver)
+             if (flinfo->info->create_default_symver)
                iversym.vs_vers++;
            }
 
          if (h->hidden)
            iversym.vs_vers |= VERSYM_HIDDEN;
 
                iversym.vs_vers++;
            }
 
          if (h->hidden)
            iversym.vs_vers |= VERSYM_HIDDEN;
 
-         eversym = (Elf_External_Versym *) finfo->symver_sec->contents;
+         eversym = (Elf_External_Versym *) flinfo->symver_sec->contents;
          eversym += h->dynindx;
          eversym += h->dynindx;
-         _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym);
+         _bfd_elf_swap_versym_out (flinfo->output_bfd, &iversym, eversym);
        }
     }
 
        }
     }
 
@@ -8951,8 +9084,8 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
   if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
     return TRUE;
 
   if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
     return TRUE;
 
-  indx = bfd_get_symcount (finfo->output_bfd);
-  ret = elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h);
+  indx = bfd_get_symcount (flinfo->output_bfd);
+  ret = elf_link_output_sym (flinfo, h->root.root.string, &sym, input_sec, h);
   if (ret == 0)
     {
       eoinfo->failed = TRUE;
   if (ret == 0)
     {
       eoinfo->failed = TRUE;
@@ -8976,8 +9109,8 @@ elf_section_ignore_discarded_relocs (asection *sec)
 
   switch (sec->sec_info_type)
     {
 
   switch (sec->sec_info_type)
     {
-    case ELF_INFO_TYPE_STABS:
-    case ELF_INFO_TYPE_EH_FRAME:
+    case SEC_INFO_TYPE_STABS:
+    case SEC_INFO_TYPE_EH_FRAME:
       return TRUE;
     default:
       break;
       return TRUE;
     default:
       break;
@@ -9066,7 +9199,7 @@ _bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info)
    don't have to keep them in memory.  */
 
 static bfd_boolean
    don't have to keep them in memory.  */
 
 static bfd_boolean
-elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
+elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 {
   int (*relocate_section)
     (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
 {
   int (*relocate_section)
     (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
@@ -9083,8 +9216,12 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
   asection *o;
   const struct elf_backend_data *bed;
   struct elf_link_hash_entry **sym_hashes;
   asection *o;
   const struct elf_backend_data *bed;
   struct elf_link_hash_entry **sym_hashes;
+  bfd_size_type address_size;
+  bfd_vma r_type_mask;
+  int r_sym_shift;
+  bfd_boolean have_file_sym = FALSE;
 
 
-  output_bfd = finfo->output_bfd;
+  output_bfd = flinfo->output_bfd;
   bed = get_elf_backend_data (output_bfd);
   relocate_section = bed->elf_backend_relocate_section;
 
   bed = get_elf_backend_data (output_bfd);
   relocate_section = bed->elf_backend_relocate_section;
 
@@ -9111,9 +9248,9 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
   if (isymbuf == NULL && locsymcount != 0)
     {
       isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
   if (isymbuf == NULL && locsymcount != 0)
     {
       isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
-                                     finfo->internal_syms,
-                                     finfo->external_syms,
-                                     finfo->locsym_shndx);
+                                     flinfo->internal_syms,
+                                     flinfo->external_syms,
+                                     flinfo->locsym_shndx);
       if (isymbuf == NULL)
        return FALSE;
     }
       if (isymbuf == NULL)
        return FALSE;
     }
@@ -9122,7 +9259,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
      SEC_MERGE sections.  Write out those local symbols we know are
      going into the output file.  */
   isymend = isymbuf + locsymcount;
      SEC_MERGE sections.  Write out those local symbols we know are
      going into the output file.  */
   isymend = isymbuf + locsymcount;
-  for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections;
+  for (isym = isymbuf, pindex = flinfo->indices, ppsection = flinfo->sections;
        isym < isymend;
        isym++, pindex++, ppsection++)
     {
        isym < isymend;
        isym++, pindex++, ppsection++)
     {
@@ -9159,7 +9296,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
              *ppsection = NULL;
              continue;
            }
              *ppsection = NULL;
              continue;
            }
-         else if (isec->sec_info_type == ELF_INFO_TYPE_MERGE
+         else if (isec->sec_info_type == SEC_INFO_TYPE_MERGE
                   && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
            isym->st_value =
              _bfd_merged_section_offset (output_bfd, &isec,
                   && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
            isym->st_value =
              _bfd_merged_section_offset (output_bfd, &isec,
@@ -9170,7 +9307,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
       *ppsection = isec;
 
       /* Don't output the first, undefined, symbol.  */
       *ppsection = isec;
 
       /* Don't output the first, undefined, symbol.  */
-      if (ppsection == finfo->sections)
+      if (ppsection == flinfo->sections)
        continue;
 
       if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
        continue;
 
       if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
@@ -9183,7 +9320,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
       /* If we are stripping all symbols, we don't want to output this
         one.  */
 
       /* If we are stripping all symbols, we don't want to output this
         one.  */
-      if (finfo->info->strip == strip_all)
+      if (flinfo->info->strip == strip_all)
        continue;
 
       /* If we are discarding all local symbols, we don't want to
        continue;
 
       /* If we are discarding all local symbols, we don't want to
@@ -9191,7 +9328,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
         file, then some of the local symbols may be required by
         relocs; we output them below as we discover that they are
         needed.  */
         file, then some of the local symbols may be required by
         relocs; we output them below as we discover that they are
         needed.  */
-      if (finfo->info->discard == discard_all)
+      if (flinfo->info->discard == discard_all)
        continue;
 
       /* If this symbol is defined in a section which we are
        continue;
 
       /* If this symbol is defined in a section which we are
@@ -9209,15 +9346,38 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
        return FALSE;
 
       /* See if we are discarding symbols with this name.  */
        return FALSE;
 
       /* See if we are discarding symbols with this name.  */
-      if ((finfo->info->strip == strip_some
-          && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE, FALSE)
+      if ((flinfo->info->strip == strip_some
+          && (bfd_hash_lookup (flinfo->info->keep_hash, name, FALSE, FALSE)
               == NULL))
               == NULL))
-         || (((finfo->info->discard == discard_sec_merge
-               && (isec->flags & SEC_MERGE) && ! finfo->info->relocatable)
-              || finfo->info->discard == discard_l)
+         || (((flinfo->info->discard == discard_sec_merge
+               && (isec->flags & SEC_MERGE) && !flinfo->info->relocatable)
+              || flinfo->info->discard == discard_l)
              && bfd_is_local_label_name (input_bfd, name)))
        continue;
 
              && bfd_is_local_label_name (input_bfd, name)))
        continue;
 
+      if (ELF_ST_TYPE (isym->st_info) == STT_FILE)
+       {
+         have_file_sym = TRUE;
+         flinfo->filesym_count += 1;
+       }
+      if (!have_file_sym)
+       {
+         /* In the absence of debug info, bfd_find_nearest_line uses
+            FILE symbols to determine the source file for local
+            function symbols.  Provide a FILE symbol here if input
+            files lack such, so that their symbols won't be
+            associated with a previous input file.  It's not the
+            source file, but the best we can do.  */
+         have_file_sym = TRUE;
+         flinfo->filesym_count += 1;
+         memset (&osym, 0, sizeof (osym));
+         osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+         osym.st_shndx = SHN_ABS;
+         if (!elf_link_output_sym (flinfo, input_bfd->filename, &osym,
+                                   bfd_abs_section_ptr, NULL))
+           return FALSE;
+       }
+
       osym = *isym;
 
       /* Adjust the section index for the output file.  */
       osym = *isym;
 
       /* Adjust the section index for the output file.  */
@@ -9234,25 +9394,38 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
         output_section.  Any special sections must be set up to meet
         these requirements.  */
       osym.st_value += isec->output_offset;
         output_section.  Any special sections must be set up to meet
         these requirements.  */
       osym.st_value += isec->output_offset;
-      if (! finfo->info->relocatable)
+      if (!flinfo->info->relocatable)
        {
          osym.st_value += isec->output_section->vma;
          if (ELF_ST_TYPE (osym.st_info) == STT_TLS)
            {
              /* STT_TLS symbols are relative to PT_TLS segment base.  */
        {
          osym.st_value += isec->output_section->vma;
          if (ELF_ST_TYPE (osym.st_info) == STT_TLS)
            {
              /* STT_TLS symbols are relative to PT_TLS segment base.  */
-             BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
-             osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
+             BFD_ASSERT (elf_hash_table (flinfo->info)->tls_sec != NULL);
+             osym.st_value -= elf_hash_table (flinfo->info)->tls_sec->vma;
            }
        }
 
       indx = bfd_get_symcount (output_bfd);
            }
        }
 
       indx = bfd_get_symcount (output_bfd);
-      ret = elf_link_output_sym (finfo, name, &osym, isec, NULL);
+      ret = elf_link_output_sym (flinfo, name, &osym, isec, NULL);
       if (ret == 0)
        return FALSE;
       else if (ret == 1)
        *pindex = indx;
     }
 
       if (ret == 0)
        return FALSE;
       else if (ret == 1)
        *pindex = indx;
     }
 
+  if (bed->s->arch_size == 32)
+    {
+      r_type_mask = 0xff;
+      r_sym_shift = 8;
+      address_size = 4;
+    }
+  else
+    {
+      r_type_mask = 0xffffffff;
+      r_sym_shift = 32;
+      address_size = 8;
+    }
+
   /* Relocate the contents of each section.  */
   sym_hashes = elf_sym_hashes (input_bfd);
   for (o = input_bfd->sections; o != NULL; o = o->next)
   /* Relocate the contents of each section.  */
   sym_hashes = elf_sym_hashes (input_bfd);
   for (o = input_bfd->sections; o != NULL; o = o->next)
@@ -9265,7 +9438,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
          continue;
        }
 
          continue;
        }
 
-      if (finfo->info->relocatable
+      if (flinfo->info->relocatable
          && (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP)
        {
          /* Deal with the group signature symbol.  */
          && (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP)
        {
          /* Deal with the group signature symbol.  */
@@ -9275,7 +9448,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
          if (symndx >= locsymcount
              || (elf_bad_symtab (input_bfd)
 
          if (symndx >= locsymcount
              || (elf_bad_symtab (input_bfd)
-                 && finfo->sections[symndx] == NULL))
+                 && flinfo->sections[symndx] == NULL))
            {
              struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff];
              while (h->root.type == bfd_link_hash_indirect
            {
              struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff];
              while (h->root.type == bfd_link_hash_indirect
@@ -9288,16 +9461,16 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
          else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION)
            {
              /* We'll use the output section target_index.  */
          else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION)
            {
              /* We'll use the output section target_index.  */
-             asection *sec = finfo->sections[symndx]->output_section;
+             asection *sec = flinfo->sections[symndx]->output_section;
              elf_section_data (osec)->this_hdr.sh_info = sec->target_index;
            }
          else
            {
              elf_section_data (osec)->this_hdr.sh_info = sec->target_index;
            }
          else
            {
-             if (finfo->indices[symndx] == -1)
+             if (flinfo->indices[symndx] == -1)
                {
                  /* Otherwise output the local symbol now.  */
                  Elf_Internal_Sym sym = isymbuf[symndx];
                {
                  /* Otherwise output the local symbol now.  */
                  Elf_Internal_Sym sym = isymbuf[symndx];
-                 asection *sec = finfo->sections[symndx]->output_section;
+                 asection *sec = flinfo->sections[symndx]->output_section;
                  const char *name;
                  long indx;
                  int ret;
                  const char *name;
                  long indx;
                  int ret;
@@ -9316,16 +9489,16 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                  sym.st_value += o->output_offset;
 
                  indx = bfd_get_symcount (output_bfd);
                  sym.st_value += o->output_offset;
 
                  indx = bfd_get_symcount (output_bfd);
-                 ret = elf_link_output_sym (finfo, name, &sym, o, NULL);
+                 ret = elf_link_output_sym (flinfo, name, &sym, o, NULL);
                  if (ret == 0)
                    return FALSE;
                  else if (ret == 1)
                  if (ret == 0)
                    return FALSE;
                  else if (ret == 1)
-                   finfo->indices[symndx] = indx;
+                   flinfo->indices[symndx] = indx;
                  else
                    abort ();
                }
              elf_section_data (osec)->this_hdr.sh_info
                  else
                    abort ();
                }
              elf_section_data (osec)->this_hdr.sh_info
-               = finfo->indices[symndx];
+               = flinfo->indices[symndx];
            }
        }
 
            }
        }
 
@@ -9348,10 +9521,8 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
        contents = elf_section_data (o)->this_hdr.contents;
       else
        {
        contents = elf_section_data (o)->this_hdr.contents;
       else
        {
-         bfd_size_type amt = o->rawsize ? o->rawsize : o->size;
-
-         contents = finfo->contents;
-         if (! bfd_get_section_contents (input_bfd, o, contents, 0, amt))
+         contents = flinfo->contents;
+         if (! bfd_get_full_section_contents (input_bfd, o, &contents))
            return FALSE;
        }
 
            return FALSE;
        }
 
@@ -9359,28 +9530,38 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
        {
          Elf_Internal_Rela *internal_relocs;
          Elf_Internal_Rela *rel, *relend;
        {
          Elf_Internal_Rela *internal_relocs;
          Elf_Internal_Rela *rel, *relend;
-         bfd_vma r_type_mask;
-         int r_sym_shift;
          int action_discarded;
          int ret;
 
          /* Get the swapped relocs.  */
          internal_relocs
          int action_discarded;
          int ret;
 
          /* Get the swapped relocs.  */
          internal_relocs
-           = _bfd_elf_link_read_relocs (input_bfd, o, finfo->external_relocs,
-                                        finfo->internal_relocs, FALSE);
+           = _bfd_elf_link_read_relocs (input_bfd, o, flinfo->external_relocs,
+                                        flinfo->internal_relocs, FALSE);
          if (internal_relocs == NULL
              && o->reloc_count > 0)
            return FALSE;
 
          if (internal_relocs == NULL
              && o->reloc_count > 0)
            return FALSE;
 
-         if (bed->s->arch_size == 32)
-           {
-             r_type_mask = 0xff;
-             r_sym_shift = 8;
-           }
-         else
+         /* We need to reverse-copy input .ctors/.dtors sections if
+            they are placed in .init_array/.finit_array for output.  */
+         if (o->size > address_size
+             && ((strncmp (o->name, ".ctors", 6) == 0
+                  && strcmp (o->output_section->name,
+                             ".init_array") == 0)
+                 || (strncmp (o->name, ".dtors", 6) == 0
+                     && strcmp (o->output_section->name,
+                                ".fini_array") == 0))
+             && (o->name[6] == 0 || o->name[6] == '.'))
            {
            {
-             r_type_mask = 0xffffffff;
-             r_sym_shift = 32;
+             if (o->size != o->reloc_count * address_size)
+               {
+                 (*_bfd_error_handler)
+                   (_("error: %B: size of section %A is not "
+                      "multiple of address size"),
+                    input_bfd, o);
+                 bfd_set_error (bfd_error_on_input);
+                 return FALSE;
+               }
+             o->flags |= SEC_ELF_REVERSE_COPY;
            }
 
          action_discarded = -1;
            }
 
          action_discarded = -1;
@@ -9408,7 +9589,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
              if (r_symndx >= locsymcount
                  || (elf_bad_symtab (input_bfd)
 
              if (r_symndx >= locsymcount
                  || (elf_bad_symtab (input_bfd)
-                     && finfo->sections[r_symndx] == NULL))
+                     && flinfo->sections[r_symndx] == NULL))
                {
                  h = sym_hashes[r_symndx - extsymoff];
 
                {
                  h = sym_hashes[r_symndx - extsymoff];
 
@@ -9446,13 +9627,13 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                  Elf_Internal_Sym *sym = isymbuf + r_symndx;
 
                  s_type = ELF_ST_TYPE (sym->st_info);
                  Elf_Internal_Sym *sym = isymbuf + r_symndx;
 
                  s_type = ELF_ST_TYPE (sym->st_info);
-                 ps = &finfo->sections[r_symndx];
+                 ps = &flinfo->sections[r_symndx];
                  sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr,
                                               sym, *ps);
                }
 
              if ((s_type == STT_RELC || s_type == STT_SRELC)
                  sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr,
                                               sym, *ps);
                }
 
              if ((s_type == STT_RELC || s_type == STT_SRELC)
-                 && !finfo->info->relocatable)
+                 && !flinfo->info->relocatable)
                {
                  bfd_vma val;
                  bfd_vma dot = (rel->r_offset
                {
                  bfd_vma val;
                  bfd_vma dot = (rel->r_offset
@@ -9460,14 +9641,15 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 #ifdef DEBUG
                  printf ("Encountered a complex symbol!");
                  printf (" (input_bfd %s, section %s, reloc %ld\n",
 #ifdef DEBUG
                  printf ("Encountered a complex symbol!");
                  printf (" (input_bfd %s, section %s, reloc %ld\n",
-                         input_bfd->filename, o->name, rel - internal_relocs);
+                         input_bfd->filename, o->name,
+                         (long) (rel - internal_relocs));
                  printf (" symbol: idx  %8.8lx, name %s\n",
                          r_symndx, sym_name);
                  printf (" reloc : info %8.8lx, addr %8.8lx\n",
                          (unsigned long) rel->r_info,
                          (unsigned long) rel->r_offset);
 #endif
                  printf (" symbol: idx  %8.8lx, name %s\n",
                          r_symndx, sym_name);
                  printf (" reloc : info %8.8lx, addr %8.8lx\n",
                          (unsigned long) rel->r_info,
                          (unsigned long) rel->r_offset);
 #endif
-                 if (!eval_symbol (&val, &sym_name, input_bfd, finfo, dot,
+                 if (!eval_symbol (&val, &sym_name, input_bfd, flinfo, dot,
                                    isymbuf, locsymcount, s_type == STT_SRELC))
                    return FALSE;
 
                                    isymbuf, locsymcount, s_type == STT_SRELC))
                    return FALSE;
 
@@ -9481,11 +9663,11 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                {
                  /* Complain if the definition comes from a
                     discarded section.  */
                {
                  /* Complain if the definition comes from a
                     discarded section.  */
-                 if ((sec = *ps) != NULL && elf_discarded_section (sec))
+                 if ((sec = *ps) != NULL && discarded_section (sec))
                    {
                    {
-                     BFD_ASSERT (r_symndx != 0);
+                     BFD_ASSERT (r_symndx != STN_UNDEF);
                      if (action_discarded & COMPLAIN)
                      if (action_discarded & COMPLAIN)
-                       (*finfo->info->callbacks->einfo)
+                       (*flinfo->info->callbacks->einfo)
                          (_("%X`%s' referenced in section `%A' of %B: "
                             "defined in discarded section `%A' of %B\n"),
                           sym_name, o, input_bfd, sec, sec->owner);
                          (_("%X`%s' referenced in section `%A' of %B: "
                             "defined in discarded section `%A' of %B\n"),
                           sym_name, o, input_bfd, sec, sec->owner);
@@ -9501,7 +9683,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                          asection *kept;
 
                          kept = _bfd_elf_check_kept_section (sec,
                          asection *kept;
 
                          kept = _bfd_elf_check_kept_section (sec,
-                                                             finfo->info);
+                                                             flinfo->info);
                          if (kept != NULL)
                            {
                              *ps = kept;
                          if (kept != NULL)
                            {
                              *ps = kept;
@@ -9532,42 +9714,47 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
             corresponding to the output section, which will require
             the addend to be adjusted.  */
 
             corresponding to the output section, which will require
             the addend to be adjusted.  */
 
-         ret = (*relocate_section) (output_bfd, finfo->info,
+         ret = (*relocate_section) (output_bfd, flinfo->info,
                                     input_bfd, o, contents,
                                     internal_relocs,
                                     isymbuf,
                                     input_bfd, o, contents,
                                     internal_relocs,
                                     isymbuf,
-                                    finfo->sections);
+                                    flinfo->sections);
          if (!ret)
            return FALSE;
 
          if (ret == 2
          if (!ret)
            return FALSE;
 
          if (ret == 2
-             || finfo->info->relocatable
-             || finfo->info->emitrelocations)
+             || flinfo->info->relocatable
+             || flinfo->info->emitrelocations)
            {
              Elf_Internal_Rela *irela;
            {
              Elf_Internal_Rela *irela;
-             Elf_Internal_Rela *irelaend;
+             Elf_Internal_Rela *irelaend, *irelamid;
              bfd_vma last_offset;
              struct elf_link_hash_entry **rel_hash;
              bfd_vma last_offset;
              struct elf_link_hash_entry **rel_hash;
-             struct elf_link_hash_entry **rel_hash_list;
-             Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2;
+             struct elf_link_hash_entry **rel_hash_list, **rela_hash_list;
+             Elf_Internal_Shdr *input_rel_hdr, *input_rela_hdr;
              unsigned int next_erel;
              bfd_boolean rela_normal;
              unsigned int next_erel;
              bfd_boolean rela_normal;
+             struct bfd_elf_section_data *esdi, *esdo;
 
 
-             input_rel_hdr = &elf_section_data (o)->rel_hdr;
-             rela_normal = (bed->rela_normal
-                            && (input_rel_hdr->sh_entsize
-                                == bed->s->sizeof_rela));
+             esdi = elf_section_data (o);
+             esdo = elf_section_data (o->output_section);
+             rela_normal = FALSE;
 
              /* Adjust the reloc addresses and symbol indices.  */
 
              irela = internal_relocs;
              irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
 
              /* Adjust the reloc addresses and symbol indices.  */
 
              irela = internal_relocs;
              irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
-             rel_hash = (elf_section_data (o->output_section)->rel_hashes
-                         + elf_section_data (o->output_section)->rel_count
-                         + elf_section_data (o->output_section)->rel_count2);
+             rel_hash = esdo->rel.hashes + esdo->rel.count;
+             /* We start processing the REL relocs, if any.  When we reach
+                IRELAMID in the loop, we switch to the RELA relocs.  */
+             irelamid = irela;
+             if (esdi->rel.hdr != NULL)
+               irelamid += (NUM_SHDR_ENTRIES (esdi->rel.hdr)
+                            * bed->s->int_rels_per_ext_rel);
              rel_hash_list = rel_hash;
              rel_hash_list = rel_hash;
+             rela_hash_list = NULL;
              last_offset = o->output_offset;
              last_offset = o->output_offset;
-             if (!finfo->info->relocatable)
+             if (!flinfo->info->relocatable)
                last_offset += o->output_section->vma;
              for (next_erel = 0; irela < irelaend; irela++, next_erel++)
                {
                last_offset += o->output_section->vma;
              for (next_erel = 0; irela < irelaend; irela++, next_erel++)
                {
@@ -9581,8 +9768,15 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                      next_erel = 0;
                    }
 
                      next_erel = 0;
                    }
 
+                 if (irela == irelamid)
+                   {
+                     rel_hash = esdo->rela.hashes + esdo->rela.count;
+                     rela_hash_list = rel_hash;
+                     rela_normal = bed->rela_normal;
+                   }
+
                  irela->r_offset = _bfd_elf_section_offset (output_bfd,
                  irela->r_offset = _bfd_elf_section_offset (output_bfd,
-                                                            finfo->info, o,
+                                                            flinfo->info, o,
                                                             irela->r_offset);
                  if (irela->r_offset >= (bfd_vma) -2)
                    {
                                                             irela->r_offset);
                  if (irela->r_offset >= (bfd_vma) -2)
                    {
@@ -9600,7 +9794,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                  irela->r_offset += o->output_offset;
 
                  /* Relocs in an executable have to be virtual addresses.  */
                  irela->r_offset += o->output_offset;
 
                  /* Relocs in an executable have to be virtual addresses.  */
-                 if (!finfo->info->relocatable)
+                 if (!flinfo->info->relocatable)
                    irela->r_offset += o->output_section->vma;
 
                  last_offset = irela->r_offset;
                    irela->r_offset += o->output_section->vma;
 
                  last_offset = irela->r_offset;
@@ -9611,7 +9805,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
                  if (r_symndx >= locsymcount
                      || (elf_bad_symtab (input_bfd)
 
                  if (r_symndx >= locsymcount
                      || (elf_bad_symtab (input_bfd)
-                         && finfo->sections[r_symndx] == NULL))
+                         && flinfo->sections[r_symndx] == NULL))
                    {
                      struct elf_link_hash_entry *rh;
                      unsigned long indx;
                    {
                      struct elf_link_hash_entry *rh;
                      unsigned long indx;
@@ -9644,13 +9838,13 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
                  *rel_hash = NULL;
                  sym = isymbuf[r_symndx];
 
                  *rel_hash = NULL;
                  sym = isymbuf[r_symndx];
-                 sec = finfo->sections[r_symndx];
+                 sec = flinfo->sections[r_symndx];
                  if (ELF_ST_TYPE (sym.st_info) == STT_SECTION)
                    {
                      /* I suppose the backend ought to fill in the
                         section of any STT_SECTION symbol against a
                         processor specific section.  */
                  if (ELF_ST_TYPE (sym.st_info) == STT_SECTION)
                    {
                      /* I suppose the backend ought to fill in the
                         section of any STT_SECTION symbol against a
                         processor specific section.  */
-                     r_symndx = 0;
+                     r_symndx = STN_UNDEF;
                      if (bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                      if (bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
@@ -9679,25 +9873,14 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                          if (!bfd_is_abs_section (osec))
                            {
                              r_symndx = osec->target_index;
                          if (!bfd_is_abs_section (osec))
                            {
                              r_symndx = osec->target_index;
-                             if (r_symndx == 0)
+                             if (r_symndx == STN_UNDEF)
                                {
                                {
-                                 struct elf_link_hash_table *htab;
-                                 asection *oi;
-
-                                 htab = elf_hash_table (finfo->info);
-                                 oi = htab->text_index_section;
-                                 if ((osec->flags & SEC_READONLY) == 0
-                                     && htab->data_index_section != NULL)
-                                   oi = htab->data_index_section;
-
-                                 if (oi != NULL)
-                                   {
-                                     irela->r_addend += osec->vma - oi->vma;
-                                     r_symndx = oi->target_index;
-                                   }
+                                 irela->r_addend += osec->vma;
+                                 osec = _bfd_nearby_section (output_bfd, osec,
+                                                             osec->vma);
+                                 irela->r_addend -= osec->vma;
+                                 r_symndx = osec->target_index;
                                }
                                }
-
-                             BFD_ASSERT (r_symndx != 0);
                            }
                        }
 
                            }
                        }
 
@@ -9708,14 +9891,14 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                    }
                  else
                    {
                    }
                  else
                    {
-                     if (finfo->indices[r_symndx] == -1)
+                     if (flinfo->indices[r_symndx] == -1)
                        {
                          unsigned long shlink;
                          const char *name;
                          asection *osec;
                          long indx;
 
                        {
                          unsigned long shlink;
                          const char *name;
                          asection *osec;
                          long indx;
 
-                         if (finfo->info->strip == strip_all)
+                         if (flinfo->info->strip == strip_all)
                            {
                              /* You can't do ld -r -s.  */
                              bfd_set_error (bfd_error_invalid_operation);
                            {
                              /* You can't do ld -r -s.  */
                              bfd_set_error (bfd_error_invalid_operation);
@@ -9739,32 +9922,32 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                            return FALSE;
 
                          sym.st_value += sec->output_offset;
                            return FALSE;
 
                          sym.st_value += sec->output_offset;
-                         if (! finfo->info->relocatable)
+                         if (!flinfo->info->relocatable)
                            {
                              sym.st_value += osec->vma;
                              if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
                                {
                                  /* STT_TLS symbols are relative to PT_TLS
                                     segment base.  */
                            {
                              sym.st_value += osec->vma;
                              if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
                                {
                                  /* STT_TLS symbols are relative to PT_TLS
                                     segment base.  */
-                                 BFD_ASSERT (elf_hash_table (finfo->info)
+                                 BFD_ASSERT (elf_hash_table (flinfo->info)
                                              ->tls_sec != NULL);
                                              ->tls_sec != NULL);
-                                 sym.st_value -= (elf_hash_table (finfo->info)
+                                 sym.st_value -= (elf_hash_table (flinfo->info)
                                                   ->tls_sec->vma);
                                }
                            }
 
                          indx = bfd_get_symcount (output_bfd);
                                                   ->tls_sec->vma);
                                }
                            }
 
                          indx = bfd_get_symcount (output_bfd);
-                         ret = elf_link_output_sym (finfo, name, &sym, sec,
+                         ret = elf_link_output_sym (flinfo, name, &sym, sec,
                                                     NULL);
                          if (ret == 0)
                            return FALSE;
                          else if (ret == 1)
                                                     NULL);
                          if (ret == 0)
                            return FALSE;
                          else if (ret == 1)
-                           finfo->indices[r_symndx] = indx;
+                           flinfo->indices[r_symndx] = indx;
                          else
                            abort ();
                        }
 
                          else
                            abort ();
                        }
 
-                     r_symndx = finfo->indices[r_symndx];
+                     r_symndx = flinfo->indices[r_symndx];
                    }
 
                  irela->r_info = ((bfd_vma) r_symndx << r_sym_shift
                    }
 
                  irela->r_info = ((bfd_vma) r_symndx << r_sym_shift
@@ -9772,23 +9955,26 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                }
 
              /* Swap out the relocs.  */
                }
 
              /* Swap out the relocs.  */
-             if (input_rel_hdr->sh_size != 0
-                 && !bed->elf_backend_emit_relocs (output_bfd, o,
-                                                   input_rel_hdr,
-                                                   internal_relocs,
-                                                   rel_hash_list))
-               return FALSE;
-
-             input_rel_hdr2 = elf_section_data (o)->rel_hdr2;
-             if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0)
+             input_rel_hdr = esdi->rel.hdr;
+             if (input_rel_hdr && input_rel_hdr->sh_size != 0)
                {
                {
+                 if (!bed->elf_backend_emit_relocs (output_bfd, o,
+                                                    input_rel_hdr,
+                                                    internal_relocs,
+                                                    rel_hash_list))
+                   return FALSE;
                  internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
                                      * bed->s->int_rels_per_ext_rel);
                  rel_hash_list += NUM_SHDR_ENTRIES (input_rel_hdr);
                  internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
                                      * bed->s->int_rels_per_ext_rel);
                  rel_hash_list += NUM_SHDR_ENTRIES (input_rel_hdr);
+               }
+
+             input_rela_hdr = esdi->rela.hdr;
+             if (input_rela_hdr && input_rela_hdr->sh_size != 0)
+               {
                  if (!bed->elf_backend_emit_relocs (output_bfd, o,
                  if (!bed->elf_backend_emit_relocs (output_bfd, o,
-                                                    input_rel_hdr2,
+                                                    input_rela_hdr,
                                                     internal_relocs,
                                                     internal_relocs,
-                                                    rel_hash_list))
+                                                    rela_hash_list))
                    return FALSE;
                }
            }
                    return FALSE;
                }
            }
@@ -9796,28 +9982,28 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
       /* Write out the modified section contents.  */
       if (bed->elf_backend_write_section
 
       /* Write out the modified section contents.  */
       if (bed->elf_backend_write_section
-         && (*bed->elf_backend_write_section) (output_bfd, finfo->info, o,
+         && (*bed->elf_backend_write_section) (output_bfd, flinfo->info, o,
                                                contents))
        {
          /* Section written out.  */
        }
       else switch (o->sec_info_type)
        {
                                                contents))
        {
          /* Section written out.  */
        }
       else switch (o->sec_info_type)
        {
-       case ELF_INFO_TYPE_STABS:
+       case SEC_INFO_TYPE_STABS:
          if (! (_bfd_write_section_stabs
                 (output_bfd,
          if (! (_bfd_write_section_stabs
                 (output_bfd,
-                 &elf_hash_table (finfo->info)->stab_info,
+                 &elf_hash_table (flinfo->info)->stab_info,
                  o, &elf_section_data (o)->sec_info, contents)))
            return FALSE;
          break;
                  o, &elf_section_data (o)->sec_info, contents)))
            return FALSE;
          break;
-       case ELF_INFO_TYPE_MERGE:
+       case SEC_INFO_TYPE_MERGE:
          if (! _bfd_write_merged_section (output_bfd, o,
                                           elf_section_data (o)->sec_info))
            return FALSE;
          break;
          if (! _bfd_write_merged_section (output_bfd, o,
                                           elf_section_data (o)->sec_info))
            return FALSE;
          break;
-       case ELF_INFO_TYPE_EH_FRAME:
+       case SEC_INFO_TYPE_EH_FRAME:
          {
          {
-           if (! _bfd_elf_write_section_eh_frame (output_bfd, finfo->info,
+           if (! _bfd_elf_write_section_eh_frame (output_bfd, flinfo->info,
                                                   o, contents))
              return FALSE;
          }
                                                   o, contents))
              return FALSE;
          }
@@ -9825,13 +10011,34 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
        default:
          {
            /* FIXME: octets_per_byte.  */
        default:
          {
            /* FIXME: octets_per_byte.  */
-           if (! (o->flags & SEC_EXCLUDE)
-               && ! (o->output_section->flags & SEC_NEVER_LOAD)
-               && ! bfd_set_section_contents (output_bfd, o->output_section,
-                                              contents,
-                                              (file_ptr) o->output_offset,
-                                              o->size))
-             return FALSE;
+           if (! (o->flags & SEC_EXCLUDE))
+             {
+               file_ptr offset = (file_ptr) o->output_offset;
+               bfd_size_type todo = o->size;
+               if ((o->flags & SEC_ELF_REVERSE_COPY))
+                 {
+                   /* Reverse-copy input section to output.  */
+                   do
+                     {
+                       todo -= address_size;
+                       if (! bfd_set_section_contents (output_bfd,
+                                                       o->output_section,
+                                                       contents + todo,
+                                                       offset,
+                                                       address_size))
+                         return FALSE;
+                       if (todo == 0)
+                         break;
+                       offset += address_size;
+                     }
+                   while (1);
+                 }
+               else if (! bfd_set_section_contents (output_bfd,
+                                                    o->output_section,
+                                                    contents,
+                                                    offset, todo))
+                 return FALSE;
+             }
          }
          break;
        }
          }
          break;
        }
@@ -9855,12 +10062,14 @@ elf_reloc_link_order (bfd *output_bfd,
   long indx;
   bfd_vma offset;
   bfd_vma addend;
   long indx;
   bfd_vma offset;
   bfd_vma addend;
+  struct bfd_elf_section_reloc_data *reldata;
   struct elf_link_hash_entry **rel_hash_ptr;
   Elf_Internal_Shdr *rel_hdr;
   const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
   Elf_Internal_Rela irel[MAX_INT_RELS_PER_EXT_REL];
   bfd_byte *erel;
   unsigned int i;
   struct elf_link_hash_entry **rel_hash_ptr;
   Elf_Internal_Shdr *rel_hdr;
   const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
   Elf_Internal_Rela irel[MAX_INT_RELS_PER_EXT_REL];
   bfd_byte *erel;
   unsigned int i;
+  struct bfd_elf_section_data *esdo = elf_section_data (output_section);
 
   howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
   if (howto == NULL)
 
   howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
   if (howto == NULL)
@@ -9871,10 +10080,18 @@ elf_reloc_link_order (bfd *output_bfd,
 
   addend = link_order->u.reloc.p->addend;
 
 
   addend = link_order->u.reloc.p->addend;
 
+  if (esdo->rel.hdr)
+    reldata = &esdo->rel;
+  else if (esdo->rela.hdr)
+    reldata = &esdo->rela;
+  else
+    {
+      reldata = NULL;
+      BFD_ASSERT (0);
+    }
+
   /* Figure out the symbol index.  */
   /* Figure out the symbol index.  */
-  rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
-                 + elf_section_data (output_section)->rel_count
-                 + elf_section_data (output_section)->rel_count2);
+  rel_hash_ptr = reldata->hashes + reldata->count;
   if (link_order->type == bfd_section_reloc_link_order)
     {
       indx = link_order->u.reloc.p->u.section->target_index;
   if (link_order->type == bfd_section_reloc_link_order)
     {
       indx = link_order->u.reloc.p->u.section->target_index;
@@ -9986,23 +10203,21 @@ elf_reloc_link_order (bfd *output_bfd,
   else
     irel[0].r_info = ELF64_R_INFO (indx, howto->type);
 
   else
     irel[0].r_info = ELF64_R_INFO (indx, howto->type);
 
-  rel_hdr = &elf_section_data (output_section)->rel_hdr;
+  rel_hdr = reldata->hdr;
   erel = rel_hdr->contents;
   if (rel_hdr->sh_type == SHT_REL)
     {
   erel = rel_hdr->contents;
   if (rel_hdr->sh_type == SHT_REL)
     {
-      erel += (elf_section_data (output_section)->rel_count
-              * bed->s->sizeof_rel);
+      erel += reldata->count * bed->s->sizeof_rel;
       (*bed->s->swap_reloc_out) (output_bfd, irel, erel);
     }
   else
     {
       irel[0].r_addend = addend;
       (*bed->s->swap_reloc_out) (output_bfd, irel, erel);
     }
   else
     {
       irel[0].r_addend = addend;
-      erel += (elf_section_data (output_section)->rel_count
-              * bed->s->sizeof_rela);
+      erel += reldata->count * bed->s->sizeof_rela;
       (*bed->s->swap_reloca_out) (output_bfd, irel, erel);
     }
 
       (*bed->s->swap_reloca_out) (output_bfd, irel, erel);
     }
 
-  ++elf_section_data (output_section)->rel_count;
+  ++reldata->count;
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -10165,7 +10380,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   bfd_boolean dynamic;
   bfd_boolean emit_relocs;
   bfd *dynobj;
   bfd_boolean dynamic;
   bfd_boolean emit_relocs;
   bfd *dynobj;
-  struct elf_final_link_info finfo;
+  struct elf_final_link_info flinfo;
   asection *o;
   struct bfd_link_order *p;
   bfd *sub;
   asection *o;
   struct bfd_link_order *p;
   bfd *sub;
@@ -10202,39 +10417,40 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   emit_relocs = (info->relocatable
                 || info->emitrelocations);
 
   emit_relocs = (info->relocatable
                 || info->emitrelocations);
 
-  finfo.info = info;
-  finfo.output_bfd = abfd;
-  finfo.symstrtab = _bfd_elf_stringtab_init ();
-  if (finfo.symstrtab == NULL)
+  flinfo.info = info;
+  flinfo.output_bfd = abfd;
+  flinfo.symstrtab = _bfd_elf_stringtab_init ();
+  if (flinfo.symstrtab == NULL)
     return FALSE;
 
   if (! dynamic)
     {
     return FALSE;
 
   if (! dynamic)
     {
-      finfo.dynsym_sec = NULL;
-      finfo.hash_sec = NULL;
-      finfo.symver_sec = NULL;
+      flinfo.dynsym_sec = NULL;
+      flinfo.hash_sec = NULL;
+      flinfo.symver_sec = NULL;
     }
   else
     {
     }
   else
     {
-      finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym");
-      finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash");
-      BFD_ASSERT (finfo.dynsym_sec != NULL);
-      finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version");
+      flinfo.dynsym_sec = bfd_get_linker_section (dynobj, ".dynsym");
+      flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash");
+      /* Note that dynsym_sec can be NULL (on VMS).  */
+      flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version");
       /* Note that it is OK if symver_sec is NULL.  */
     }
 
       /* Note that it is OK if symver_sec is NULL.  */
     }
 
-  finfo.contents = NULL;
-  finfo.external_relocs = NULL;
-  finfo.internal_relocs = NULL;
-  finfo.external_syms = NULL;
-  finfo.locsym_shndx = NULL;
-  finfo.internal_syms = NULL;
-  finfo.indices = NULL;
-  finfo.sections = NULL;
-  finfo.symbuf = NULL;
-  finfo.symshndxbuf = NULL;
-  finfo.symbuf_count = 0;
-  finfo.shndxbuf_size = 0;
+  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.symbuf = NULL;
+  flinfo.symshndxbuf = NULL;
+  flinfo.symbuf_count = 0;
+  flinfo.shndxbuf_size = 0;
+  flinfo.filesym_count = 0;
 
   /* The object attributes have been merged.  Remove the input
      sections from the link, and set the contents of the output
 
   /* The object attributes have been merged.  Remove the input
      sections from the link, and set the contents of the output
@@ -10288,7 +10504,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        {
          unsigned int reloc_count = 0;
          struct bfd_elf_section_data *esdi = NULL;
        {
          unsigned int reloc_count = 0;
          struct bfd_elf_section_data *esdi = NULL;
-         unsigned int *rel_count1;
 
          if (p->type == bfd_section_reloc_link_order
              || p->type == bfd_symbol_reloc_link_order)
 
          if (p->type == bfd_section_reloc_link_order
              || p->type == bfd_symbol_reloc_link_order)
@@ -10309,7 +10524,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              if (sec->flags & SEC_MERGE)
                merged = TRUE;
 
              if (sec->flags & SEC_MERGE)
                merged = TRUE;
 
-             if (info->relocatable || info->emitrelocations)
+             if (esdo->this_hdr.sh_type == SHT_REL
+                 || esdo->this_hdr.sh_type == SHT_RELA)
+               /* Some backends use reloc_count in relocation sections
+                  to count particular types of relocs.  Of course,
+                  reloc sections themselves can't have relocations.  */
+               reloc_count = 0;
+             else if (info->relocatable || info->emitrelocations)
                reloc_count = sec->reloc_count;
              else if (bed->elf_backend_count_relocs)
                reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
                reloc_count = sec->reloc_count;
              else if (bed->elf_backend_count_relocs)
                reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
@@ -10341,9 +10562,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
                  if ((sec->flags & SEC_RELOC) != 0)
                    {
 
                  if ((sec->flags & SEC_RELOC) != 0)
                    {
-                     size_t ext_size;
+                     size_t ext_size = 0;
+
+                     if (esdi->rel.hdr != NULL)
+                       ext_size = esdi->rel.hdr->sh_size;
+                     if (esdi->rela.hdr != NULL)
+                       ext_size += esdi->rela.hdr->sh_size;
 
 
-                     ext_size = elf_section_data (sec)->rel_hdr.sh_size;
                      if (ext_size > max_external_reloc_size)
                        max_external_reloc_size = ext_size;
                      if (sec->reloc_count > max_internal_reloc_count)
                      if (ext_size > max_external_reloc_size)
                        max_external_reloc_size = ext_size;
                      if (sec->reloc_count > max_internal_reloc_count)
@@ -10357,54 +10582,21 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
          o->reloc_count += reloc_count;
 
 
          o->reloc_count += reloc_count;
 
-         /* MIPS may have a mix of REL and RELA relocs on sections.
-            To support this curious ABI we keep reloc counts in
-            elf_section_data too.  We must be careful to add the
-            relocations from the input section to the right output
-            count.  FIXME: Get rid of one count.  We have
-            o->reloc_count == esdo->rel_count + esdo->rel_count2.  */
-         rel_count1 = &esdo->rel_count;
-         if (esdi != NULL)
+         if (p->type == bfd_indirect_link_order
+             && (info->relocatable || info->emitrelocations))
+           {
+             if (esdi->rel.hdr)
+               esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
+             if (esdi->rela.hdr)
+               esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
+           }
+         else
            {
            {
-             bfd_boolean same_size;
-             bfd_size_type entsize1;
-
-             entsize1 = esdi->rel_hdr.sh_entsize;
-             /* PR 9827: If the header size has not been set yet then
-                assume that it will match the output section's reloc type.  */
-             if (entsize1 == 0)
-               entsize1 = o->use_rela_p ? bed->s->sizeof_rela : bed->s->sizeof_rel;
+             if (o->use_rela_p)
+               esdo->rela.count += reloc_count;
              else
              else
-               BFD_ASSERT (entsize1 == bed->s->sizeof_rel
-                           || entsize1 == bed->s->sizeof_rela);
-             same_size = !o->use_rela_p == (entsize1 == bed->s->sizeof_rel);
-
-             if (!same_size)
-               rel_count1 = &esdo->rel_count2;
-
-             if (esdi->rel_hdr2 != NULL)
-               {
-                 bfd_size_type entsize2 = esdi->rel_hdr2->sh_entsize;
-                 unsigned int alt_count;
-                 unsigned int *rel_count2;
-
-                 BFD_ASSERT (entsize2 != entsize1
-                             && (entsize2 == bed->s->sizeof_rel
-                                 || entsize2 == bed->s->sizeof_rela));
-
-                 rel_count2 = &esdo->rel_count2;
-                 if (!same_size)
-                   rel_count2 = &esdo->rel_count;
-
-                 /* The following is probably too simplistic if the
-                    backend counts output relocs unusually.  */
-                 BFD_ASSERT (bed->elf_backend_count_relocs == NULL);
-                 alt_count = NUM_SHDR_ENTRIES (esdi->rel_hdr2);
-                 *rel_count2 += alt_count;
-                 reloc_count -= alt_count;
-               }
+               esdo->rel.count += reloc_count;
            }
            }
-         *rel_count1 += reloc_count;
        }
 
       if (o->reloc_count > 0)
        }
 
       if (o->reloc_count > 0)
@@ -10441,22 +10633,22 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   /* Set sizes, and assign file positions for reloc sections.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
   /* Set sizes, and assign file positions for reloc sections.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
+      struct bfd_elf_section_data *esdo = elf_section_data (o);
       if ((o->flags & SEC_RELOC) != 0)
        {
       if ((o->flags & SEC_RELOC) != 0)
        {
-         if (!(_bfd_elf_link_size_reloc_section
-               (abfd, &elf_section_data (o)->rel_hdr, o)))
+         if (esdo->rel.hdr
+             && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
            goto error_return;
 
            goto error_return;
 
-         if (elf_section_data (o)->rel_hdr2
-             && !(_bfd_elf_link_size_reloc_section
-                  (abfd, elf_section_data (o)->rel_hdr2, o)))
+         if (esdo->rela.hdr
+             && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
            goto error_return;
        }
 
       /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
         to count upwards while actually outputting the relocations.  */
            goto error_return;
        }
 
       /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
         to count upwards while actually outputting the relocations.  */
-      elf_section_data (o)->rel_count = 0;
-      elf_section_data (o)->rel_count2 = 0;
+      esdo->rel.count = 0;
+      esdo->rela.count = 0;
     }
 
   _bfd_elf_assign_file_positions_for_relocs (abfd);
     }
 
   _bfd_elf_assign_file_positions_for_relocs (abfd);
@@ -10486,22 +10678,22 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   /* Allocate a buffer to hold swapped out symbols.  This is to avoid
      continuously seeking to the right position in the file.  */
   if (! info->keep_memory || max_sym_count < 20)
   /* Allocate a buffer to hold swapped out symbols.  This is to avoid
      continuously seeking to the right position in the file.  */
   if (! info->keep_memory || max_sym_count < 20)
-    finfo.symbuf_size = 20;
+    flinfo.symbuf_size = 20;
   else
   else
-    finfo.symbuf_size = max_sym_count;
-  amt = finfo.symbuf_size;
+    flinfo.symbuf_size = max_sym_count;
+  amt = flinfo.symbuf_size;
   amt *= bed->s->sizeof_sym;
   amt *= bed->s->sizeof_sym;
-  finfo.symbuf = (bfd_byte *) bfd_malloc (amt);
-  if (finfo.symbuf == NULL)
+  flinfo.symbuf = (bfd_byte *) bfd_malloc (amt);
+  if (flinfo.symbuf == NULL)
     goto error_return;
   if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
     {
       /* Wild guess at number of output symbols.  realloc'd as needed.  */
       amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
     goto error_return;
   if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
     {
       /* Wild guess at number of output symbols.  realloc'd as needed.  */
       amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
-      finfo.shndxbuf_size = amt;
+      flinfo.shndxbuf_size = amt;
       amt *= sizeof (Elf_External_Sym_Shndx);
       amt *= sizeof (Elf_External_Sym_Shndx);
-      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
-      if (finfo.symshndxbuf == NULL)
+      flinfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
+      if (flinfo.symshndxbuf == NULL)
        goto error_return;
     }
 
        goto error_return;
     }
 
@@ -10515,7 +10707,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       elfsym.st_info = 0;
       elfsym.st_other = 0;
       elfsym.st_shndx = SHN_UNDEF;
       elfsym.st_info = 0;
       elfsym.st_other = 0;
       elfsym.st_shndx = SHN_UNDEF;
-      if (elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
+      elfsym.st_target_internal = 0;
+      if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr,
                               NULL) != 1)
        goto error_return;
     }
                               NULL) != 1)
        goto error_return;
     }
@@ -10532,6 +10725,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
       elfsym.st_other = 0;
       elfsym.st_value = 0;
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
       elfsym.st_other = 0;
       elfsym.st_value = 0;
+      elfsym.st_target_internal = 0;
       for (i = 1; i < elf_numsections (abfd); i++)
        {
          o = bfd_section_from_elf_index (abfd, i);
       for (i = 1; i < elf_numsections (abfd); i++)
        {
          o = bfd_section_from_elf_index (abfd, i);
@@ -10541,7 +10735,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              elfsym.st_shndx = i;
              if (!info->relocatable)
                elfsym.st_value = o->vma;
              elfsym.st_shndx = i;
              if (!info->relocatable)
                elfsym.st_value = o->vma;
-             if (elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL) != 1)
+             if (elf_link_output_sym (&flinfo, NULL, &elfsym, o, NULL) != 1)
                goto error_return;
            }
        }
                goto error_return;
            }
        }
@@ -10551,15 +10745,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
      files.  */
   if (max_contents_size != 0)
     {
      files.  */
   if (max_contents_size != 0)
     {
-      finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
-      if (finfo.contents == NULL)
+      flinfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+      if (flinfo.contents == NULL)
        goto error_return;
     }
 
   if (max_external_reloc_size != 0)
     {
        goto error_return;
     }
 
   if (max_external_reloc_size != 0)
     {
-      finfo.external_relocs = bfd_malloc (max_external_reloc_size);
-      if (finfo.external_relocs == NULL)
+      flinfo.external_relocs = bfd_malloc (max_external_reloc_size);
+      if (flinfo.external_relocs == NULL)
        goto error_return;
     }
 
        goto error_return;
     }
 
@@ -10567,39 +10761,39 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     {
       amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
       amt *= sizeof (Elf_Internal_Rela);
     {
       amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
       amt *= sizeof (Elf_Internal_Rela);
-      finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
-      if (finfo.internal_relocs == NULL)
+      flinfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
+      if (flinfo.internal_relocs == NULL)
        goto error_return;
     }
 
   if (max_sym_count != 0)
     {
       amt = max_sym_count * bed->s->sizeof_sym;
        goto error_return;
     }
 
   if (max_sym_count != 0)
     {
       amt = max_sym_count * bed->s->sizeof_sym;
-      finfo.external_syms = (bfd_byte *) bfd_malloc (amt);
-      if (finfo.external_syms == NULL)
+      flinfo.external_syms = (bfd_byte *) bfd_malloc (amt);
+      if (flinfo.external_syms == NULL)
        goto error_return;
 
       amt = max_sym_count * sizeof (Elf_Internal_Sym);
        goto error_return;
 
       amt = max_sym_count * sizeof (Elf_Internal_Sym);
-      finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
-      if (finfo.internal_syms == NULL)
+      flinfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
+      if (flinfo.internal_syms == NULL)
        goto error_return;
 
       amt = max_sym_count * sizeof (long);
        goto error_return;
 
       amt = max_sym_count * sizeof (long);
-      finfo.indices = (long int *) bfd_malloc (amt);
-      if (finfo.indices == NULL)
+      flinfo.indices = (long int *) bfd_malloc (amt);
+      if (flinfo.indices == NULL)
        goto error_return;
 
       amt = max_sym_count * sizeof (asection *);
        goto error_return;
 
       amt = max_sym_count * sizeof (asection *);
-      finfo.sections = (asection **) bfd_malloc (amt);
-      if (finfo.sections == NULL)
+      flinfo.sections = (asection **) bfd_malloc (amt);
+      if (flinfo.sections == NULL)
        goto error_return;
     }
 
   if (max_sym_shndx_count != 0)
     {
       amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
        goto error_return;
     }
 
   if (max_sym_shndx_count != 0)
     {
       amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
-      finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
-      if (finfo.locsym_shndx == NULL)
+      flinfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (flinfo.locsym_shndx == NULL)
        goto error_return;
     }
 
        goto error_return;
     }
 
@@ -10625,7 +10819,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          end = sec->vma + size;
        }
       base = elf_hash_table (info)->tls_sec->vma;
          end = sec->vma + size;
        }
       base = elf_hash_table (info)->tls_sec->vma;
-      end = align_power (end, elf_hash_table (info)->tls_sec->alignment_power);
+      /* Only align end of TLS section if static TLS doesn't have special
+        alignment requirements.  */
+      if (bed->static_tls_alignment == 1)
+       end = align_power (end,
+                          elf_hash_table (info)->tls_sec->alignment_power);
       elf_hash_table (info)->tls_size = end - base;
     }
 
       elf_hash_table (info)->tls_size = end - base;
     }
 
@@ -10669,7 +10867,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            {
              if (! sub->output_has_begun)
                {
            {
              if (! sub->output_has_begun)
                {
-                 if (! elf_link_input_bfd (&finfo, sub))
+                 if (! elf_link_input_bfd (&flinfo, sub))
                    goto error_return;
                  sub->output_has_begun = TRUE;
                }
                    goto error_return;
                  sub->output_has_begun = TRUE;
                }
@@ -10683,7 +10881,34 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          else
            {
              if (! _bfd_default_link_order (abfd, info, o, p))
          else
            {
              if (! _bfd_default_link_order (abfd, info, o, p))
-               goto error_return;
+               {
+                 if (p->type == bfd_indirect_link_order
+                     && (bfd_get_flavour (sub)
+                         == bfd_target_elf_flavour)
+                     && (elf_elfheader (sub)->e_ident[EI_CLASS]
+                         != bed->s->elfclass))
+                   {
+                     const char *iclass, *oclass;
+
+                     if (bed->s->elfclass == ELFCLASS64)
+                       {
+                         iclass = "ELFCLASS32";
+                         oclass = "ELFCLASS64";
+                       }
+                     else
+                       {
+                         iclass = "ELFCLASS64";
+                         oclass = "ELFCLASS32";
+                       }
+
+                     bfd_set_error (bfd_error_wrong_format);
+                     (*_bfd_error_handler)
+                       (_("%B: file class %s incompatible with %s"),
+                        sub, iclass, oclass);
+                   }
+
+                 goto error_return;
+               }
            }
        }
     }
            }
        }
     }
@@ -10700,6 +10925,17 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          }
     }
 
          }
     }
 
+  /* Output a FILE symbol so that following locals are not associated
+     with the wrong input file.  */
+  memset (&elfsym, 0, sizeof (elfsym));
+  elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+  elfsym.st_shndx = SHN_ABS;
+
+  if (flinfo.filesym_count > 1
+      && !elf_link_output_sym (&flinfo, NULL, &elfsym,
+                              bfd_und_section_ptr, NULL))
+    return FALSE;
+
   /* 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
   /* 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
@@ -10707,13 +10943,27 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
      some global symbols were, in fact, converted to become local.
      FIXME: Will this work correctly with the Irix 5 linker?  */
   eoinfo.failed = FALSE;
      some global symbols were, in fact, converted to become local.
      FIXME: Will this work correctly with the Irix 5 linker?  */
   eoinfo.failed = FALSE;
-  eoinfo.finfo = &finfo;
+  eoinfo.flinfo = &flinfo;
   eoinfo.localsyms = TRUE;
   eoinfo.localsyms = TRUE;
-  elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
-                         &eoinfo);
+  eoinfo.need_second_pass = FALSE;
+  eoinfo.second_pass = FALSE;
+  bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
     return FALSE;
 
   if (eoinfo.failed)
     return FALSE;
 
+  if (flinfo.filesym_count == 1
+      && !elf_link_output_sym (&flinfo, NULL, &elfsym,
+                              bfd_und_section_ptr, NULL))
+    return FALSE;
+
+  if (eoinfo.need_second_pass)
+    {
+      eoinfo.second_pass = TRUE;
+      bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
+      if (eoinfo.failed)
+       return FALSE;
+    }
+
   /* If backend needs to output some local symbols not present in the hash
      table, do it now.  */
   if (bed->elf_backend_output_arch_local_syms)
   /* If backend needs to output some local symbols not present in the hash
      table, do it now.  */
   if (bed->elf_backend_output_arch_local_syms)
@@ -10723,7 +10973,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
         struct elf_link_hash_entry *);
 
       if (! ((*bed->elf_backend_output_arch_local_syms)
         struct elf_link_hash_entry *);
 
       if (! ((*bed->elf_backend_output_arch_local_syms)
-            (abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
+            (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym)))
        return FALSE;
     }
 
        return FALSE;
     }
 
@@ -10736,10 +10986,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
   if (dynamic
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
   if (dynamic
-      && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
+      && flinfo.dynsym_sec != NULL
+      && flinfo.dynsym_sec->output_section != bfd_abs_section_ptr)
     {
       Elf_Internal_Sym sym;
     {
       Elf_Internal_Sym sym;
-      bfd_byte *dynsym = finfo.dynsym_sec->contents;
+      bfd_byte *dynsym = flinfo.dynsym_sec->contents;
       long last_local = 0;
 
       /* Write out the section symbols for the output sections.  */
       long last_local = 0;
 
       /* Write out the section symbols for the output sections.  */
@@ -10751,6 +11002,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          sym.st_name = 0;
          sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
          sym.st_other = 0;
          sym.st_name = 0;
          sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
          sym.st_other = 0;
+         sym.st_target_internal = 0;
 
          for (s = abfd->sections; s != NULL; s = s->next)
            {
 
          for (s = abfd->sections; s != NULL; s = s->next)
            {
@@ -10810,16 +11062,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            }
        }
 
            }
        }
 
-      elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+      elf_section_data (flinfo.dynsym_sec->output_section)->this_hdr.sh_info =
        last_local + 1;
     }
 
   /* We get the global symbols from the hash table.  */
   eoinfo.failed = FALSE;
   eoinfo.localsyms = FALSE;
        last_local + 1;
     }
 
   /* We get the global symbols from the hash table.  */
   eoinfo.failed = FALSE;
   eoinfo.localsyms = FALSE;
-  eoinfo.finfo = &finfo;
-  elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
-                         &eoinfo);
+  eoinfo.flinfo = &flinfo;
+  bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
     return FALSE;
 
   if (eoinfo.failed)
     return FALSE;
 
@@ -10832,12 +11083,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
         struct elf_link_hash_entry *);
 
       if (! ((*bed->elf_backend_output_arch_syms)
         struct elf_link_hash_entry *);
 
       if (! ((*bed->elf_backend_output_arch_syms)
-            (abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
+            (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym)))
        return FALSE;
     }
 
   /* Flush all symbols to the file.  */
        return FALSE;
     }
 
   /* Flush all symbols to the file.  */
-  if (! elf_link_flush_output_syms (&finfo, bed))
+  if (! elf_link_flush_output_syms (&flinfo, bed))
     return FALSE;
 
   /* Now we know the size of the symtab section.  */
     return FALSE;
 
   /* Now we know the size of the symtab section.  */
@@ -10856,7 +11107,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                                                       off, TRUE);
 
       if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
                                                       off, TRUE);
 
       if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
-         || (bfd_bwrite (finfo.symshndxbuf, amt, abfd) != amt))
+         || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
        return FALSE;
     }
 
        return FALSE;
     }
 
@@ -10868,7 +11119,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   symstrtab_hdr->sh_type = SHT_STRTAB;
   symstrtab_hdr->sh_flags = 0;
   symstrtab_hdr->sh_addr = 0;
   symstrtab_hdr->sh_type = SHT_STRTAB;
   symstrtab_hdr->sh_flags = 0;
   symstrtab_hdr->sh_addr = 0;
-  symstrtab_hdr->sh_size = _bfd_stringtab_size (finfo.symstrtab);
+  symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab);
   symstrtab_hdr->sh_entsize = 0;
   symstrtab_hdr->sh_link = 0;
   symstrtab_hdr->sh_info = 0;
   symstrtab_hdr->sh_entsize = 0;
   symstrtab_hdr->sh_link = 0;
   symstrtab_hdr->sh_info = 0;
@@ -10881,24 +11132,21 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (bfd_get_symcount (abfd) > 0)
     {
       if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
   if (bfd_get_symcount (abfd) > 0)
     {
       if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
-         || ! _bfd_stringtab_emit (abfd, finfo.symstrtab))
+         || ! _bfd_stringtab_emit (abfd, flinfo.symstrtab))
        return FALSE;
     }
 
   /* Adjust the relocs to have the correct symbol indices.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
        return FALSE;
     }
 
   /* Adjust the relocs to have the correct symbol indices.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
+      struct bfd_elf_section_data *esdo = elf_section_data (o);
       if ((o->flags & SEC_RELOC) == 0)
        continue;
 
       if ((o->flags & SEC_RELOC) == 0)
        continue;
 
-      elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr,
-                             elf_section_data (o)->rel_count,
-                             elf_section_data (o)->rel_hashes);
-      if (elf_section_data (o)->rel_hdr2 != NULL)
-       elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
-                               elf_section_data (o)->rel_count2,
-                               (elf_section_data (o)->rel_hashes
-                                + elf_section_data (o)->rel_count));
+      if (esdo->rel.hdr != NULL)
+       elf_link_adjust_relocs (abfd, &esdo->rel);
+      if (esdo->rela.hdr != NULL)
+       elf_link_adjust_relocs (abfd, &esdo->rela);
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
@@ -10915,7 +11163,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       bfd_byte *dyncon, *dynconend;
 
       /* Fix up .dynamic entries.  */
       bfd_byte *dyncon, *dynconend;
 
       /* Fix up .dynamic entries.  */
-      o = bfd_get_section_by_name (dynobj, ".dynamic");
+      o = bfd_get_linker_section (dynobj, ".dynamic");
       BFD_ASSERT (o != NULL);
 
       dyncon = o->contents;
       BFD_ASSERT (o != NULL);
 
       dyncon = o->contents;
@@ -11038,6 +11286,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                    (_("%B: could not find output section %s"), abfd, name);
                  goto error_return;
                }
                    (_("%B: could not find output section %s"), abfd, name);
                  goto error_return;
                }
+             if (elf_section_data (o->output_section)->this_hdr.sh_type == SHT_NOTE)
+               {
+                 (*_bfd_error_handler)
+                   (_("warning: section '%s' is being made into a note"), name);
+                 bfd_set_error (bfd_error_nonrepresentable_section);
+                 goto error_return;
+               }
              dyn.d_un.d_ptr = o->vma;
              break;
 
              dyn.d_un.d_ptr = o->vma;
              break;
 
@@ -11082,14 +11337,12 @@ 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).  */
        goto error_return;
 
       /* Check for DT_TEXTREL (late, in case the backend removes it).  */
-      if (info->warn_shared_textrel && info->shared)
+      if (((info->warn_shared_textrel && info->shared)
+          || info->error_textrel)
+         && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
        {
          bfd_byte *dyncon, *dynconend;
 
        {
          bfd_byte *dyncon, *dynconend;
 
-         /* Fix up .dynamic entries.  */
-         o = bfd_get_section_by_name (dynobj, ".dynamic");
-         BFD_ASSERT (o != NULL);
-
          dyncon = o->contents;
          dynconend = o->contents + o->size;
          for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
          dyncon = o->contents;
          dynconend = o->contents + o->size;
          for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
@@ -11100,8 +11353,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              if (dyn.d_tag == DT_TEXTREL)
                {
 
              if (dyn.d_tag == DT_TEXTREL)
                {
-                info->callbacks->einfo
-                   (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
+                 if (info->error_textrel)
+                   info->callbacks->einfo
+                     (_("%P%X: read-only segment has dynamic relocations.\n"));
+                 else
+                   info->callbacks->einfo
+                     (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
                  break;
                }
            }
                  break;
                }
            }
@@ -11123,9 +11380,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            continue;
          if (elf_hash_table (info)->eh_info.hdr_sec == o)
            continue;
            continue;
          if (elf_hash_table (info)->eh_info.hdr_sec == o)
            continue;
-         if ((elf_section_data (o->output_section)->this_hdr.sh_type
-              != SHT_STRTAB)
-             || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
+         if (strcmp (o->name, ".dynstr") != 0)
            {
              /* FIXME: octets_per_byte.  */
              if (! bfd_set_section_contents (abfd, o->output_section,
            {
              /* FIXME: octets_per_byte.  */
              if (! bfd_set_section_contents (abfd, o->output_section,
@@ -11169,33 +11424,35 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        goto error_return;
     }
 
        goto error_return;
     }
 
-  if (finfo.symstrtab != NULL)
-    _bfd_stringtab_free (finfo.symstrtab);
-  if (finfo.contents != NULL)
-    free (finfo.contents);
-  if (finfo.external_relocs != NULL)
-    free (finfo.external_relocs);
-  if (finfo.internal_relocs != NULL)
-    free (finfo.internal_relocs);
-  if (finfo.external_syms != NULL)
-    free (finfo.external_syms);
-  if (finfo.locsym_shndx != NULL)
-    free (finfo.locsym_shndx);
-  if (finfo.internal_syms != NULL)
-    free (finfo.internal_syms);
-  if (finfo.indices != NULL)
-    free (finfo.indices);
-  if (finfo.sections != NULL)
-    free (finfo.sections);
-  if (finfo.symbuf != NULL)
-    free (finfo.symbuf);
-  if (finfo.symshndxbuf != NULL)
-    free (finfo.symshndxbuf);
+  if (flinfo.symstrtab != NULL)
+    _bfd_stringtab_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.symbuf != NULL)
+    free (flinfo.symbuf);
+  if (flinfo.symshndxbuf != NULL)
+    free (flinfo.symshndxbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
   for (o = abfd->sections; o != NULL; o = o->next)
     {
-      if ((o->flags & SEC_RELOC) != 0
-         && elf_section_data (o)->rel_hashes != NULL)
-       free (elf_section_data (o)->rel_hashes);
+      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);
     }
 
   elf_tdata (abfd)->linker = TRUE;
     }
 
   elf_tdata (abfd)->linker = TRUE;
@@ -11213,33 +11470,35 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 
  error_return:
   return TRUE;
 
  error_return:
-  if (finfo.symstrtab != NULL)
-    _bfd_stringtab_free (finfo.symstrtab);
-  if (finfo.contents != NULL)
-    free (finfo.contents);
-  if (finfo.external_relocs != NULL)
-    free (finfo.external_relocs);
-  if (finfo.internal_relocs != NULL)
-    free (finfo.internal_relocs);
-  if (finfo.external_syms != NULL)
-    free (finfo.external_syms);
-  if (finfo.locsym_shndx != NULL)
-    free (finfo.locsym_shndx);
-  if (finfo.internal_syms != NULL)
-    free (finfo.internal_syms);
-  if (finfo.indices != NULL)
-    free (finfo.indices);
-  if (finfo.sections != NULL)
-    free (finfo.sections);
-  if (finfo.symbuf != NULL)
-    free (finfo.symbuf);
-  if (finfo.symshndxbuf != NULL)
-    free (finfo.symshndxbuf);
+  if (flinfo.symstrtab != NULL)
+    _bfd_stringtab_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.symbuf != NULL)
+    free (flinfo.symbuf);
+  if (flinfo.symshndxbuf != NULL)
+    free (flinfo.symshndxbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
   for (o = abfd->sections; o != NULL; o = o->next)
     {
-      if ((o->flags & SEC_RELOC) != 0
-         && elf_section_data (o)->rel_hashes != NULL)
-       free (elf_section_data (o)->rel_hashes);
+      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);
     }
 
   return FALSE;
     }
 
   return FALSE;
@@ -11452,7 +11711,7 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
   struct elf_link_hash_entry *h;
 
   r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
   struct elf_link_hash_entry *h;
 
   r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
-  if (r_symndx == 0)
+  if (r_symndx == STN_UNDEF)
     return NULL;
 
   if (r_symndx >= cookie->locsymcount
     return NULL;
 
   if (r_symndx >= cookie->locsymcount
@@ -11462,6 +11721,13 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
       while (h->root.type == bfd_link_hash_indirect
             || h->root.type == bfd_link_hash_warning)
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
       while (h->root.type == bfd_link_hash_indirect
             || h->root.type == bfd_link_hash_warning)
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      h->mark = 1;
+      /* If this symbol is weak and there is a non-weak definition, we
+        keep the non-weak definition because many backends put
+        dynamic reloc info on the non-weak definition for code
+        handling copy relocs.  */
+      if (h->u.weakdef != NULL)
+       h->u.weakdef->mark = 1;
       return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
     }
 
       return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
     }
 
@@ -11484,7 +11750,8 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
   rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
   if (rsec && !rsec->gc_mark)
     {
   rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
   if (rsec && !rsec->gc_mark)
     {
-      if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
+      if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
+         || (rsec->owner->flags & DYNAMIC) != 0)
        rsec->gc_mark = 1;
       else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
        return FALSE;
        rsec->gc_mark = 1;
       else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
        return FALSE;
@@ -11553,6 +11820,50 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
   return ret;
 }
 
   return ret;
 }
 
+/* Keep debug and special sections.  */
+
+bfd_boolean
+_bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
+                                elf_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED)
+{
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      asection *isec;
+      bfd_boolean some_kept;
+
+      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+       continue;
+
+      /* Ensure all linker created sections are kept, and see whether
+        any other section is already marked.  */
+      some_kept = FALSE;
+      for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+       {
+         if ((isec->flags & SEC_LINKER_CREATED) != 0)
+           isec->gc_mark = 1;
+         else if (isec->gc_mark)
+           some_kept = TRUE;
+       }
+
+      /* If no section in this file will be kept, then we can
+        toss out debug sections.  */
+      if (!some_kept)
+       continue;
+
+      /* Keep debug and special sections like .comment when they are
+        not part of a group, or when we have single-member groups.  */
+      for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+       if ((elf_next_in_group (isec) == NULL
+            || elf_next_in_group (isec) == isec)
+           && ((isec->flags & SEC_DEBUGGING) != 0
+               || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0))
+         isec->gc_mark = 1;
+    }
+  return TRUE;
+}
+
 /* Sweep symbols in swept sections.  Called via elf_link_hash_traverse.  */
 
 struct elf_gc_sweep_symbol_info
 /* Sweep symbols in swept sections.  Called via elf_link_hash_traverse.  */
 
 struct elf_gc_sweep_symbol_info
@@ -11565,17 +11876,21 @@ struct elf_gc_sweep_symbol_info
 static bfd_boolean
 elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
 {
 static bfd_boolean
 elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
 {
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  if ((h->root.type == bfd_link_hash_defined
-       || h->root.type == bfd_link_hash_defweak)
-      && !h->root.u.def.section->gc_mark
-      && !(h->root.u.def.section->owner->flags & DYNAMIC))
+  if (!h->mark
+      && (((h->root.type == bfd_link_hash_defined
+           || h->root.type == bfd_link_hash_defweak)
+          && !(h->def_regular
+               && h->root.u.def.section->gc_mark))
+         || h->root.type == bfd_link_hash_undefined
+         || h->root.type == bfd_link_hash_undefweak))
     {
     {
-      struct elf_gc_sweep_symbol_info *inf =
-          (struct elf_gc_sweep_symbol_info *) data;
+      struct elf_gc_sweep_symbol_info *inf;
+
+      inf = (struct elf_gc_sweep_symbol_info *) data;
       (*inf->hide_symbol) (inf->info, h, TRUE);
       (*inf->hide_symbol) (inf->info, h, TRUE);
+      h->def_regular = 0;
+      h->ref_regular = 0;
+      h->ref_regular_nonweak = 0;
     }
 
   return TRUE;
     }
 
   return TRUE;
@@ -11613,13 +11928,6 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
              asection *first = elf_next_in_group (o);
              o->gc_mark = first->gc_mark;
            }
              asection *first = elf_next_in_group (o);
              o->gc_mark = first->gc_mark;
            }
-         else if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
-                  || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0
-                  || elf_section_data (o)->this_hdr.sh_type == SHT_NOTE)
-           {
-             /* Keep debug, special and SHT_NOTE sections.  */
-             o->gc_mark = 1;
-           }
 
          if (o->gc_mark)
            continue;
 
          if (o->gc_mark)
            continue;
@@ -11680,9 +11988,6 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
 static bfd_boolean
 elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
 {
 static bfd_boolean
 elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
 {
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Those that are not vtables.  */
   if (h->vtable == NULL || h->vtable->parent == NULL)
     return TRUE;
   /* Those that are not vtables.  */
   if (h->vtable == NULL || h->vtable->parent == NULL)
     return TRUE;
@@ -11744,9 +12049,6 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
   const struct elf_backend_data *bed;
   unsigned int log_file_align;
 
   const struct elf_backend_data *bed;
   unsigned int log_file_align;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Take care of both those symbols that do not describe vtables as
      well as those that are not loaded.  */
   if (h->vtable == NULL || h->vtable->parent == NULL)
   /* Take care of both those symbols that do not describe vtables as
      well as those that are not loaded.  */
   if (h->vtable == NULL || h->vtable->parent == NULL)
@@ -11794,16 +12096,16 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info = (struct bfd_link_info *) inf;
 
 {
   struct bfd_link_info *info = (struct bfd_link_info *) inf;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
       && (h->ref_dynamic
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
       && (h->ref_dynamic
-         || (!info->executable
+         || ((!info->executable || info->export_dynamic)
              && h->def_regular
              && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
              && h->def_regular
              && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
-             && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN)))
+             && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
+             && (strchr (h->root.root.string, ELF_VER_CHR) != NULL
+                 || !bfd_hide_sym_by_version (info->version_info,
+                                              h->root.root.string)))))
     h->root.u.def.section->flags |= SEC_KEEP;
 
   return TRUE;
     h->root.u.def.section->flags |= SEC_KEEP;
 
   return TRUE;
@@ -11860,12 +12162,14 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
       struct elf_reloc_cookie cookie;
 
       sec = bfd_get_section_by_name (sub, ".eh_frame");
       struct elf_reloc_cookie cookie;
 
       sec = bfd_get_section_by_name (sub, ".eh_frame");
-      if (sec && init_reloc_cookie_for_section (&cookie, info, sec))
+      while (sec && init_reloc_cookie_for_section (&cookie, info, sec))
        {
          _bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
        {
          _bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
-         if (elf_section_data (sec)->sec_info)
+         if (elf_section_data (sec)->sec_info
+             && (sec->flags & SEC_LINKER_CREATED) == 0)
            elf_eh_frame_section (sub) = sec;
          fini_reloc_cookie_for_section (&cookie, sec);
            elf_eh_frame_section (sub) = sec;
          fini_reloc_cookie_for_section (&cookie, sec);
+         sec = bfd_get_next_section_by_name (sec);
        }
     }
   _bfd_elf_end_eh_frame_parsing (info);
        }
     }
   _bfd_elf_end_eh_frame_parsing (info);
@@ -11899,15 +12203,23 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
       if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
        continue;
 
       if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
        continue;
 
+      /* Start at sections marked with SEC_KEEP (ref _bfd_elf_gc_keep).
+        Also treat note sections as a root, if the section is not part
+        of a group.  */
       for (o = sub->sections; o != NULL; o = o->next)
       for (o = sub->sections; o != NULL; o = o->next)
-       if ((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP && !o->gc_mark)
-         if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
-           return FALSE;
+       if (!o->gc_mark
+           && (o->flags & SEC_EXCLUDE) == 0
+           && ((o->flags & SEC_KEEP) != 0
+               || (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
+                   && elf_next_in_group (o) == NULL )))
+         {
+           if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
+             return FALSE;
+         }
     }
 
   /* Allow the backend to mark additional target specific sections.  */
     }
 
   /* Allow the backend to mark additional target specific sections.  */
-  if (bed->gc_mark_extra_sections)
-    bed->gc_mark_extra_sections (info, gc_mark_hook);
+  bed->gc_mark_extra_sections (info, gc_mark_hook);
 
   /* ... and mark SEC_EXCLUDE for those that go.  */
   return elf_gc_sweep (abfd, info);
 
   /* ... and mark SEC_EXCLUDE for those that go.  */
   return elf_gc_sweep (abfd, info);
@@ -12050,6 +12362,98 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
   return TRUE;
 }
 
+/* Map an ELF section header flag to its corresponding string.  */
+typedef struct
+{
+  char *flag_name;
+  flagword flag_value;
+} elf_flags_to_name_table;
+
+static elf_flags_to_name_table elf_flags_to_names [] =
+{
+  { "SHF_WRITE", SHF_WRITE },
+  { "SHF_ALLOC", SHF_ALLOC },
+  { "SHF_EXECINSTR", SHF_EXECINSTR },
+  { "SHF_MERGE", SHF_MERGE },
+  { "SHF_STRINGS", SHF_STRINGS },
+  { "SHF_INFO_LINK", SHF_INFO_LINK},
+  { "SHF_LINK_ORDER", SHF_LINK_ORDER},
+  { "SHF_OS_NONCONFORMING", SHF_OS_NONCONFORMING},
+  { "SHF_GROUP", SHF_GROUP },
+  { "SHF_TLS", SHF_TLS },
+  { "SHF_MASKOS", SHF_MASKOS },
+  { "SHF_EXCLUDE", SHF_EXCLUDE },
+};
+
+/* Returns TRUE if the section is to be included, otherwise FALSE.  */
+bfd_boolean
+bfd_elf_lookup_section_flags (struct bfd_link_info *info,
+                             struct flag_info *flaginfo,
+                             asection *section)
+{
+  const bfd_vma sh_flags = elf_section_flags (section);
+
+  if (!flaginfo->flags_initialized)
+    {
+      bfd *obfd = info->output_bfd;
+      const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+      struct flag_info_list *tf = flaginfo->flag_list;
+      int with_hex = 0;
+      int without_hex = 0;
+
+      for (tf = flaginfo->flag_list; tf != NULL; tf = tf->next)
+       {
+         unsigned i;
+         flagword (*lookup) (char *);
+
+         lookup = bed->elf_backend_lookup_section_flags_hook;
+         if (lookup != NULL)
+           {
+             flagword hexval = (*lookup) ((char *) tf->name);
+
+             if (hexval != 0)
+               {
+                 if (tf->with == with_flags)
+                   with_hex |= hexval;
+                 else if (tf->with == without_flags)
+                   without_hex |= hexval;
+                 tf->valid = TRUE;
+                 continue;
+               }
+           }
+         for (i = 0; i < ARRAY_SIZE (elf_flags_to_names); ++i)
+           {
+             if (strcmp (tf->name, elf_flags_to_names[i].flag_name) == 0)
+               {
+                 if (tf->with == with_flags)
+                   with_hex |= elf_flags_to_names[i].flag_value;
+                 else if (tf->with == without_flags)
+                   without_hex |= elf_flags_to_names[i].flag_value;
+                 tf->valid = TRUE;
+                 break;
+               }
+           }
+         if (!tf->valid)
+           {
+             info->callbacks->einfo 
+               (_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name);
+             return FALSE;
+           }
+       }
+      flaginfo->flags_initialized = TRUE;
+      flaginfo->only_with_flags |= with_hex;
+      flaginfo->not_with_flags |= without_hex;
+    }
+
+  if ((flaginfo->only_with_flags & sh_flags) != flaginfo->only_with_flags)
+    return FALSE;
+
+  if ((flaginfo->not_with_flags & sh_flags) != 0)
+    return FALSE;
+
+  return TRUE;
+}
+
 struct alloc_got_off_arg {
   bfd_vma gotoff;
   struct bfd_link_info *info;
 struct alloc_got_off_arg {
   bfd_vma gotoff;
   struct bfd_link_info *info;
@@ -12065,9 +12469,6 @@ elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
   bfd *obfd = gofarg->info->output_bfd;
   const struct elf_backend_data *bed = get_elf_backend_data (obfd);
 
   bfd *obfd = gofarg->info->output_bfd;
   const struct elf_backend_data *bed = get_elf_backend_data (obfd);
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if (h->got.refcount > 0)
     {
       h->got.offset = gofarg->gotoff;
   if (h->got.refcount > 0)
     {
       h->got.offset = gofarg->gotoff;
@@ -12177,7 +12578,7 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
        continue;
 
       r_symndx = rcookie->rel->r_info >> rcookie->r_sym_shift;
        continue;
 
       r_symndx = rcookie->rel->r_info >> rcookie->r_sym_shift;
-      if (r_symndx == SHN_UNDEF)
+      if (r_symndx == STN_UNDEF)
        return TRUE;
 
       if (r_symndx >= rcookie->locsymcount
        return TRUE;
 
       if (r_symndx >= rcookie->locsymcount
@@ -12193,7 +12594,7 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
 
          if ((h->root.type == bfd_link_hash_defined
               || h->root.type == bfd_link_hash_defweak)
 
          if ((h->root.type == bfd_link_hash_defined
               || h->root.type == bfd_link_hash_defweak)
-             && elf_discarded_section (h->root.u.def.section))
+             && discarded_section (h->root.u.def.section))
            return TRUE;
          else
            return FALSE;
            return TRUE;
          else
            return FALSE;
@@ -12209,7 +12610,7 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
          /* Need to: get the symbol; get the section.  */
          isym = &rcookie->locsyms[r_symndx];
          isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
          /* Need to: get the symbol; get the section.  */
          isym = &rcookie->locsyms[r_symndx];
          isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
-         if (isec != NULL && elf_discarded_section (isec))
+         if (isec != NULL && discarded_section (isec))
            return TRUE;
        }
       return FALSE;
            return TRUE;
        }
       return FALSE;
@@ -12243,24 +12644,21 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 
       bed = get_elf_backend_data (abfd);
 
 
       bed = get_elf_backend_data (abfd);
 
-      if ((abfd->flags & DYNAMIC) != 0)
-       continue;
-
       eh = NULL;
       if (!info->relocatable)
        {
          eh = bfd_get_section_by_name (abfd, ".eh_frame");
       eh = NULL;
       if (!info->relocatable)
        {
          eh = bfd_get_section_by_name (abfd, ".eh_frame");
-         if (eh != NULL
-             && (eh->size == 0
-                 || bfd_is_abs_section (eh->output_section)))
-           eh = NULL;
+         while (eh != NULL
+                && (eh->size == 0
+                    || bfd_is_abs_section (eh->output_section)))
+           eh = bfd_get_next_section_by_name (eh);
        }
 
       stab = bfd_get_section_by_name (abfd, ".stab");
       if (stab != NULL
          && (stab->size == 0
              || bfd_is_abs_section (stab->output_section)
        }
 
       stab = bfd_get_section_by_name (abfd, ".stab");
       if (stab != NULL
          && (stab->size == 0
              || bfd_is_abs_section (stab->output_section)
-             || stab->sec_info_type != ELF_INFO_TYPE_STABS))
+             || stab->sec_info_type != SEC_INFO_TYPE_STABS))
        stab = NULL;
 
       if (stab == NULL
        stab = NULL;
 
       if (stab == NULL
@@ -12283,8 +12681,8 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
          fini_reloc_cookie_rels (&cookie, stab);
        }
 
          fini_reloc_cookie_rels (&cookie, stab);
        }
 
-      if (eh != NULL
-         && init_reloc_cookie_rels (&cookie, info, abfd, eh))
+      while (eh != NULL
+            && init_reloc_cookie_rels (&cookie, info, abfd, eh))
        {
          _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
          if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
        {
          _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
          if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
@@ -12292,6 +12690,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
                                                 &cookie))
            ret = TRUE;
          fini_reloc_cookie_rels (&cookie, eh);
                                                 &cookie))
            ret = TRUE;
          fini_reloc_cookie_rels (&cookie, eh);
+         eh = bfd_get_next_section_by_name (eh);
        }
 
       if (bed->elf_backend_discard_info != NULL
        }
 
       if (bed->elf_backend_discard_info != NULL
@@ -12310,139 +12709,69 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
   return ret;
 }
 
   return ret;
 }
 
-/* For a SHT_GROUP section, return the group signature.  For other
-   sections, return the normal section name.  */
-
-static const char *
-section_signature (asection *sec)
-{
-  if ((sec->flags & SEC_GROUP) != 0
-      && elf_next_in_group (sec) != NULL
-      && elf_group_name (elf_next_in_group (sec)) != NULL)
-    return elf_group_name (elf_next_in_group (sec));
-  return sec->name;
-}
-
-void
-_bfd_elf_section_already_linked (bfd *abfd, asection *sec,
+bfd_boolean
+_bfd_elf_section_already_linked (bfd *abfd,
+                                asection *sec,
                                 struct bfd_link_info *info)
 {
   flagword flags;
                                 struct bfd_link_info *info)
 {
   flagword flags;
-  const char *name, *p;
+  const char *name, *key;
   struct bfd_section_already_linked *l;
   struct bfd_section_already_linked_hash_entry *already_linked_list;
 
   if (sec->output_section == bfd_abs_section_ptr)
   struct bfd_section_already_linked *l;
   struct bfd_section_already_linked_hash_entry *already_linked_list;
 
   if (sec->output_section == bfd_abs_section_ptr)
-    return;
+    return FALSE;
 
   flags = sec->flags;
 
   /* Return if it isn't a linkonce section.  A comdat group section
      also has SEC_LINK_ONCE set.  */
   if ((flags & SEC_LINK_ONCE) == 0)
 
   flags = sec->flags;
 
   /* Return if it isn't a linkonce section.  A comdat group section
      also has SEC_LINK_ONCE set.  */
   if ((flags & SEC_LINK_ONCE) == 0)
-    return;
+    return FALSE;
 
   /* Don't put group member sections on our list of already linked
      sections.  They are handled as a group via their group section.  */
   if (elf_sec_group (sec) != NULL)
 
   /* Don't put group member sections on our list of already linked
      sections.  They are handled as a group via their group section.  */
   if (elf_sec_group (sec) != NULL)
-    return;
-
-  /* FIXME: When doing a relocatable link, we may have trouble
-     copying relocations in other sections that refer to local symbols
-     in the section being discarded.  Those relocations will have to
-     be converted somehow; as of this writing I'm not sure that any of
-     the backends handle that correctly.
-
-     It is tempting to instead not discard link once sections when
-     doing a relocatable link (technically, they should be discarded
-     whenever we are building constructors).  However, that fails,
-     because the linker winds up combining all the link once sections
-     into a single large link once section, which defeats the purpose
-     of having link once sections in the first place.
-
-     Also, not merging link once sections in a relocatable link
-     causes trouble for MIPS ELF, which relies on link once semantics
-     to handle the .reginfo section correctly.  */
-
-  name = section_signature (sec);
+    return FALSE;
 
 
-  if (CONST_STRNEQ (name, ".gnu.linkonce.")
-      && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
-    p++;
+  /* For a SHT_GROUP section, use the group signature as the key.  */
+  name = sec->name;
+  if ((flags & SEC_GROUP) != 0
+      && elf_next_in_group (sec) != NULL
+      && elf_group_name (elf_next_in_group (sec)) != NULL)
+    key = elf_group_name (elf_next_in_group (sec));
   else
   else
-    p = name;
+    {
+      /* Otherwise we should have a .gnu.linkonce.<type>.<key> section.  */
+      if (CONST_STRNEQ (name, ".gnu.linkonce.")
+         && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
+       key++;
+      else
+       /* Must be a user linkonce section that doesn't follow gcc's
+          naming convention.  In this case we won't be matching
+          single member groups.  */
+       key = name;
+    }
 
 
-  already_linked_list = bfd_section_already_linked_table_lookup (p);
+  already_linked_list = bfd_section_already_linked_table_lookup (key);
 
   for (l = already_linked_list->entry; l != NULL; l = l->next)
     {
       /* We may have 2 different types of sections on the list: group
 
   for (l = already_linked_list->entry; l != NULL; l = l->next)
     {
       /* We may have 2 different types of sections on the list: group
-        sections and linkonce sections.  Match like sections.  */
-      if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
-         && strcmp (name, section_signature (l->sec)) == 0
-         && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
+        sections with a signature of <key> (<key> is some string),
+        and linkonce sections named .gnu.linkonce.<type>.<key>.
+        Match like sections.  LTO plugin sections are an exception.
+        They are always named .gnu.linkonce.t.<key> and match either
+        type of section.  */
+      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)
        {
          /* The section has already been linked.  See if we should
             issue a warning.  */
        {
          /* The section has already been linked.  See if we should
             issue a warning.  */
-         switch (flags & SEC_LINK_DUPLICATES)
-           {
-           default:
-             abort ();
-
-           case SEC_LINK_DUPLICATES_DISCARD:
-             break;
-
-           case SEC_LINK_DUPLICATES_ONE_ONLY:
-             (*_bfd_error_handler)
-               (_("%B: ignoring duplicate section `%A'"),
-                abfd, sec);
-             break;
-
-           case SEC_LINK_DUPLICATES_SAME_SIZE:
-             if (sec->size != l->sec->size)
-               (*_bfd_error_handler)
-                 (_("%B: duplicate section `%A' has different size"),
-                  abfd, sec);
-             break;
-
-           case SEC_LINK_DUPLICATES_SAME_CONTENTS:
-             if (sec->size != l->sec->size)
-               (*_bfd_error_handler)
-                 (_("%B: duplicate section `%A' has different size"),
-                  abfd, sec);
-             else if (sec->size != 0)
-               {
-                 bfd_byte *sec_contents, *l_sec_contents;
-
-                 if (!bfd_malloc_and_get_section (abfd, sec, &sec_contents))
-                   (*_bfd_error_handler)
-                     (_("%B: warning: could not read contents of section `%A'"),
-                      abfd, sec);
-                 else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
-                                                       &l_sec_contents))
-                   (*_bfd_error_handler)
-                     (_("%B: warning: could not read contents of section `%A'"),
-                      l->sec->owner, l->sec);
-                 else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
-                   (*_bfd_error_handler)
-                     (_("%B: warning: duplicate section `%A' has different contents"),
-                      abfd, sec);
-
-                 if (sec_contents)
-                   free (sec_contents);
-                 if (l_sec_contents)
-                   free (l_sec_contents);
-               }
-             break;
-           }
-
-         /* Set the output_section field so that lang_add_section
-            does not create a lang_input_section structure for this
-            section.  Since there might be a symbol in the section
-            being discarded, we must retain a pointer to the section
-            which we are really going to use.  */
-         sec->output_section = bfd_abs_section_ptr;
-         sec->kept_section = l->sec;
+         if (!_bfd_handle_already_linked (sec, l, info))
+           return FALSE;
 
          if (flags & SEC_GROUP)
            {
 
          if (flags & SEC_GROUP)
            {
@@ -12461,13 +12790,12 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
                }
            }
 
                }
            }
 
-         return;
+         return TRUE;
        }
     }
 
   /* A single member comdat group section may be discarded by a
      linkonce section and vice versa.  */
        }
     }
 
   /* A single member comdat group section may be discarded by a
      linkonce section and vice versa.  */
-
   if ((flags & SEC_GROUP) != 0)
     {
       asection *first = elf_next_in_group (sec);
   if ((flags & SEC_GROUP) != 0)
     {
       asection *first = elf_next_in_group (sec);
@@ -12476,7 +12804,6 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
        /* Check this single member group against linkonce sections.  */
        for (l = already_linked_list->entry; l != NULL; l = l->next)
          if ((l->sec->flags & SEC_GROUP) == 0
        /* Check this single member group against linkonce sections.  */
        for (l = already_linked_list->entry; l != NULL; l = l->next)
          if ((l->sec->flags & SEC_GROUP) == 0
-             && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL
              && bfd_elf_match_symbols_in_sections (l->sec, first, info))
            {
              first->output_section = bfd_abs_section_ptr;
              && bfd_elf_match_symbols_in_sections (l->sec, first, info))
            {
              first->output_section = bfd_abs_section_ptr;
@@ -12525,8 +12852,9 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
        }
 
   /* This is the first section with this name.  Record it.  */
        }
 
   /* This is the first section with this name.  Record it.  */
-  if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
+  if (!bfd_section_already_linked_table_insert (already_linked_list, sec))
     info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
     info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
+  return sec->output_section == bfd_abs_section_ptr;
 }
 
 bfd_boolean
 }
 
 bfd_boolean
@@ -12560,20 +12888,6 @@ _bfd_elf_default_got_elt_size (bfd *abfd,
 
 /* Routines to support the creation of dynamic relocs.  */
 
 
 /* Routines to support the creation of dynamic relocs.  */
 
-/* Return true if NAME is a name of a relocation
-   section associated with section S.  */
-
-static bfd_boolean
-is_reloc_section (bfd_boolean rela, const char * name, asection * s)
-{
-  if (rela)
-    return CONST_STRNEQ (name, ".rela")
-      && strcmp (bfd_get_section_name (NULL, s), name + 5) == 0;
-
-  return CONST_STRNEQ (name, ".rel")
-    && strcmp (bfd_get_section_name (NULL, s), name + 4) == 0;
-}
-
 /* Returns the name of the dynamic reloc section associated with SEC.  */
 
 static const char *
 /* Returns the name of the dynamic reloc section associated with SEC.  */
 
 static const char *
@@ -12581,26 +12895,15 @@ get_dynamic_reloc_section_name (bfd *       abfd,
                                asection *  sec,
                                bfd_boolean is_rela)
 {
                                asection *  sec,
                                bfd_boolean is_rela)
 {
-  const char * name;
-  unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
-  unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
+  char *name;
+  const char *old_name = bfd_get_section_name (NULL, sec);
+  const char *prefix = is_rela ? ".rela" : ".rel";
 
 
-  name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
-  if (name == NULL)
+  if (old_name == NULL)
     return NULL;
 
     return NULL;
 
-  if (! is_reloc_section (is_rela, name, sec))
-    {
-      static bfd_boolean complained = FALSE;
-
-      if (! complained)
-       {
-         (*_bfd_error_handler)
-           (_("%B: bad relocation section name `%s\'"),  abfd, name);
-         complained = TRUE;
-       }
-      name = NULL;
-    }
+  name = bfd_alloc (abfd, strlen (prefix) + strlen (old_name) + 1);
+  sprintf (name, "%s%s", prefix, old_name); 
 
   return name;
 }
 
   return name;
 }
@@ -12623,7 +12926,7 @@ _bfd_elf_get_dynamic_reloc_section (bfd *       abfd,
 
       if (name != NULL)
        {
 
       if (name != NULL)
        {
-         reloc_sec = bfd_get_section_by_name (abfd, name);
+         reloc_sec = bfd_get_linker_section (abfd, name);
 
          if (reloc_sec != NULL)
            elf_section_data (sec)->sreloc = reloc_sec;
 
          if (reloc_sec != NULL)
            elf_section_data (sec)->sreloc = reloc_sec;
@@ -12659,17 +12962,16 @@ _bfd_elf_make_dynamic_reloc_section (asection *         sec,
       if (name == NULL)
        return NULL;
 
       if (name == NULL)
        return NULL;
 
-      reloc_sec = bfd_get_section_by_name (dynobj, name);
+      reloc_sec = bfd_get_linker_section (dynobj, name);
 
       if (reloc_sec == NULL)
        {
 
       if (reloc_sec == NULL)
        {
-         flagword flags;
-
-         flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+         flagword flags = (SEC_HAS_CONTENTS | SEC_READONLY
+                           | SEC_IN_MEMORY | SEC_LINKER_CREATED);
          if ((sec->flags & SEC_ALLOC) != 0)
            flags |= SEC_ALLOC | SEC_LOAD;
 
          if ((sec->flags & SEC_ALLOC) != 0)
            flags |= SEC_ALLOC | SEC_LOAD;
 
-         reloc_sec = bfd_make_section_with_flags (dynobj, name, flags);
+         reloc_sec = bfd_make_section_anyway_with_flags (dynobj, name, flags);
          if (reloc_sec != NULL)
            {
              if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment))
          if (reloc_sec != NULL)
            {
              if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment))
@@ -12693,4 +12995,27 @@ _bfd_elf_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED,
   struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc;
 
   ehdest->type = ehsrc->type;
   struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc;
 
   ehdest->type = ehsrc->type;
+  ehdest->target_internal = ehsrc->target_internal;
+}
+
+/* Append a RELA relocation REL to section S in BFD.  */
+
+void
+elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela);
+  BFD_ASSERT (loc + bed->s->sizeof_rela <= s->contents + s->size);
+  bed->s->swap_reloca_out (abfd, rel, loc);
+}
+
+/* Append a REL relocation REL to section S in BFD.  */
+
+void
+elf_append_rel (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rel);
+  BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size);
+  bed->s->swap_reloca_out (abfd, rel, loc);
 }
 }
This page took 1.096022 seconds and 4 git commands to generate.