* elf-bfd.h (struct elf_link_hash_entry): Delete dynamic_weak.
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 639c3e7edf3286827e2efdee2c5bdda7e56a3621..6985786e21d0055acb50b03ba999eb4873151f79 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, 2011
+   2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
    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;
 };
 
@@ -105,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;
@@ -129,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))
@@ -188,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;
@@ -207,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;
@@ -255,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;
@@ -269,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;
@@ -286,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;
@@ -320,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;
@@ -337,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;
@@ -357,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;
 
@@ -376,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;
@@ -569,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;
@@ -721,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;
 
@@ -743,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;
 
@@ -785,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;
        }
@@ -918,6 +914,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,
@@ -927,6 +924,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;
@@ -943,7 +941,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;
@@ -965,17 +963,47 @@ _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;
 
   /* We have to check it for every instance since the first few may be
   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;
 
   /* We have to check it for every instance since the first few may be
-     refereences and not all compilers emit symbol type for undefined
+     references and not all compilers emit symbol type for undefined
      symbols.  */
   bfd_elf_link_mark_dynamic_symbol (info, h, sym);
 
      symbols.  */
   bfd_elf_link_mark_dynamic_symbol (info, h, sym);
 
+  /* NEWDYN and OLDDYN indicate whether the new or old symbol,
+     respectively, is from a dynamic object.  */
+
+  newdyn = (abfd->flags & DYNAMIC) != 0;
+
+  /* ref_dynamic_nonweak and dynamic_def flags track actual undefined
+     syms and defined syms in dynamic libraries respectively.
+     ref_dynamic on the other hand can be set for a symbol defined in
+     a dynamic library, and def_dynamic may not be set;  When the
+     definition in a dynamic lib is overridden by a definition in the
+     executable use of the symbol in the dynamic lib becomes a
+     reference to the executable symbol.  */
+  if (newdyn)
+    {
+      if (bfd_is_und_section (sec))
+       {
+         if (bind != STB_WEAK)
+           {
+             h->ref_dynamic_nonweak = 1;
+             hi->ref_dynamic_nonweak = 1;
+           }
+       }
+      else
+       {
+         h->dynamic_def = 1;
+         hi->dynamic_def = 1;
+       }
+    }
+
   /* If we just created the symbol, mark it as being an ELF symbol.
      Other than that, there is nothing to do--there is no merge issue
      with a newly defined symbol--so we just return.  */
   /* If we just created the symbol, mark it as being an ELF symbol.
      Other than that, there is nothing to do--there is no merge issue
      with a newly defined symbol--so we just return.  */
@@ -1018,6 +1046,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
   newweak = bind == STB_WEAK;
   oldweak = (h->root.type == bfd_link_hash_defweak
             || h->root.type == bfd_link_hash_undefweak);
   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
 
   /* In cases involving weak versioned symbols, we may wind up trying
      to merge a symbol with itself.  Catch that here, to avoid the
@@ -1031,11 +1061,6 @@ _bfd_elf_merge_symbol (bfd *abfd,
          || !h->def_regular))
     return TRUE;
 
          || !h->def_regular))
     return TRUE;
 
-  /* NEWDYN and OLDDYN indicate whether the new or old symbol,
-     respectively, is from a dynamic object.  */
-
-  newdyn = (abfd->flags & DYNAMIC) != 0;
-
   olddyn = FALSE;
   if (oldbfd != NULL)
     olddyn = (oldbfd->flags & DYNAMIC) != 0;
   olddyn = FALSE;
   if (oldbfd != NULL)
     olddyn = (oldbfd->flags & DYNAMIC) != 0;
@@ -1085,11 +1110,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;
@@ -1135,28 +1164,6 @@ _bfd_elf_merge_symbol (bfd *abfd,
       return FALSE;
     }
 
       return FALSE;
     }
 
-  /* 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 (!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;
-       }
-    }
-
   /* If the old symbol has non-default visibility, we ignore the new
      definition from a dynamic object.  */
   if (newdyn
   /* If the old symbol has non-default visibility, we ignore the new
      definition from a dynamic object.  */
   if (newdyn
@@ -1166,6 +1173,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.
 
@@ -1195,38 +1203,39 @@ _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;
+             /* 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;
        }
@@ -1236,12 +1245,17 @@ _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;
       /* FIXME: Should we check type and size for protected symbol?  */
       h->size = 0;
       h->type = 0;
       /* FIXME: Should we check type and size for protected symbol?  */
       h->size = 0;
       h->type = 0;
@@ -1428,7 +1442,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
   if (newdef && olddef && newweak)
     {
       /* Don't skip new non-IR weak syms.  */
   if (newdef && olddef && newweak)
     {
       /* Don't skip new non-IR weak syms.  */
-      if (!((oldbfd->flags & BFD_PLUGIN) != 0
+      if (!(oldbfd != NULL
+           && (oldbfd->flags & BFD_PLUGIN) != 0
            && (abfd->flags & BFD_PLUGIN) == 0))
        *skip = TRUE;
 
            && (abfd->flags & BFD_PLUGIN) == 0))
        *skip = TRUE;
 
@@ -1638,7 +1653,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;
 
@@ -1719,6 +1734,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;
            }
@@ -1746,7 +1762,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;
 
@@ -1811,32 +1827,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;
        }
     }
 
        }
     }
 
@@ -1857,9 +1864,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
@@ -1945,9 +1949,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;
@@ -1990,7 +1991,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)
            {
@@ -2059,9 +2060,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;
 
@@ -2087,12 +2091,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);
     }
@@ -2523,23 +2528,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);
@@ -2563,17 +2566,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;
@@ -2641,12 +2633,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;
     }
@@ -2729,13 +2721,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;
 
@@ -3058,7 +3047,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;
@@ -3087,26 +3076,24 @@ elf_add_dt_needed_tag (bfd *abfd,
                       bfd_boolean do_it)
 {
   struct elf_link_hash_table *hash_table;
                       bfd_boolean do_it)
 {
   struct elf_link_hash_table *hash_table;
-  bfd_size_type oldsize;
   bfd_size_type strindex;
 
   if (!_bfd_elf_link_create_dynstrtab (abfd, info))
     return -1;
 
   hash_table = elf_hash_table (info);
   bfd_size_type strindex;
 
   if (!_bfd_elf_link_create_dynstrtab (abfd, info))
     return -1;
 
   hash_table = elf_hash_table (info);
-  oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
   strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
   if (strindex == (bfd_size_type) -1)
     return -1;
 
   strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
   if (strindex == (bfd_size_type) -1)
     return -1;
 
-  if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
+  if (_bfd_elf_strtab_refcount (hash_table->dynstr, strindex) != 1)
     {
       asection *sdyn;
       const struct elf_backend_data *bed;
       bfd_byte *extdyn;
 
       bed = get_elf_backend_data (hash_table->dynobj);
     {
       asection *sdyn;
       const struct elf_backend_data *bed;
       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;
@@ -3149,7 +3136,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)
 {
@@ -3168,7 +3155,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
@@ -3179,9 +3167,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;
@@ -3206,7 +3191,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.  */
@@ -3255,7 +3240,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
        {
@@ -3287,7 +3272,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
        {
@@ -3383,6 +3368,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   struct bfd_link_hash_entry *old_undefs = NULL;
   struct bfd_link_hash_entry *old_undefs_tail = NULL;
   long old_dynsymcount = 0;
   struct bfd_link_hash_entry *old_undefs = NULL;
   struct bfd_link_hash_entry *old_undefs_tail = NULL;
   long old_dynsymcount = 0;
+  bfd_size_type old_dynstr_size = 0;
   size_t tabsize = 0;
   size_t hashsize = 0;
 
   size_t tabsize = 0;
   size_t hashsize = 0;
 
@@ -3529,7 +3515,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
@@ -3710,7 +3696,7 @@ error_free_dyn:
        return TRUE;
 
       /* Save the DT_AUDIT entry for the linker emulation code. */
        return TRUE;
 
       /* Save the DT_AUDIT entry for the linker emulation code. */
-      elf_dt_audit (abfd) = audit; 
+      elf_dt_audit (abfd) = audit;
     }
 
   /* If this is a dynamic object, we always link against the .dynsym
     }
 
   /* If this is a dynamic object, we always link against the .dynsym
@@ -3832,6 +3818,7 @@ error_free_dyn:
       old_size = htab->root.table.size;
       old_count = htab->root.table.count;
       old_dynsymcount = htab->dynsymcount;
       old_size = htab->root.table.size;
       old_count = htab->root.table.count;
       old_dynsymcount = htab->dynsymcount;
+      old_dynstr_size = _bfd_elf_strtab_size (htab->dynstr);
 
       for (i = 0; i < htab->root.table.size; i++)
        {
 
       for (i = 0; i < htab->root.table.size; i++)
        {
@@ -3864,10 +3851,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;
@@ -3926,7 +3916,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.  */
@@ -4000,6 +3990,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;
@@ -4023,7 +4014,7 @@ error_free_dyn:
                  && h->root.u.undef.abfd)
                undef_bfd = h->root.u.undef.abfd;
            }
                  && h->root.u.undef.abfd)
                undef_bfd = h->root.u.undef.abfd;
            }
-         
+
          if (ever == NULL)
            {
              if (info->default_imported_symver)
          if (ever == NULL)
            {
              if (info->default_imported_symver)
@@ -4145,7 +4136,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;
@@ -4184,7 +4175,6 @@ error_free_dyn:
            }
 
          if (elf_tdata (abfd)->verdef != NULL
            }
 
          if (elf_tdata (abfd)->verdef != NULL
-             && ! override
              && vernum > 1
              && definition)
            h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
              && vernum > 1
              && definition)
            h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
@@ -4196,6 +4186,9 @@ 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;
       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;
@@ -4204,10 +4197,11 @@ error_free_dyn:
       if (is_elf_hash_table (htab))
        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)
@@ -4336,7 +4330,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);
 
@@ -4382,33 +4378,48 @@ 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;
+                 hi->def_dynamic = 1;
+               }
+
+             /* If the indirect symbol has been forced local, don't
+                make the real symbol dynamic.  */
+             if ((h == hi || !hi->forced_local)
+                 && (h->def_regular
+                     || h->ref_regular
+                     || (h->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;
 
          if (definition)
            h->target_internal = isym->st_target_internal;
@@ -4537,19 +4548,37 @@ error_free_dyn:
       memcpy (sym_hash, old_hash, hashsize);
       htab->root.undefs = old_undefs;
       htab->root.undefs_tail = old_undefs_tail;
       memcpy (sym_hash, old_hash, hashsize);
       htab->root.undefs = old_undefs;
       htab->root.undefs_tail = old_undefs_tail;
+      _bfd_elf_strtab_clear_refs (htab->dynstr, old_dynstr_size);
       for (i = 0; i < htab->root.table.size; i++)
        {
          struct bfd_hash_entry *p;
          struct elf_link_hash_entry *h;
       for (i = 0; i < htab->root.table.size; i++)
        {
          struct bfd_hash_entry *p;
          struct elf_link_hash_entry *h;
+         bfd_size_type size;
+         unsigned int alignment_power;
 
          for (p = htab->root.table.table[i]; p != NULL; p = p->next)
            {
              h = (struct elf_link_hash_entry *) p;
              if (h->root.type == bfd_link_hash_warning)
                h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
          for (p = htab->root.table.table[i]; p != NULL; p = p->next)
            {
              h = (struct elf_link_hash_entry *) p;
              if (h->root.type == bfd_link_hash_warning)
                h = (struct elf_link_hash_entry *) h->root.u.i.link;
-             if (h->dynindx >= old_dynsymcount)
+             if (h->dynindx >= old_dynsymcount
+                 && h->dynstr_index < old_dynstr_size)
                _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index);
 
                _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 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;
@@ -4557,6 +4586,14 @@ 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;
+                 h = (struct elf_link_hash_entry *) h->root.u.i.link;
+               }
+             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;
                }
            }
        }
                }
            }
        }
@@ -4689,7 +4726,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;
@@ -4703,14 +4739,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;
@@ -4724,24 +4759,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[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 [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)
                {
@@ -4864,7 +4911,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;
            }
        }
     }
            }
        }
     }
@@ -5174,9 +5221,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;
@@ -5245,9 +5289,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;
@@ -5298,9 +5339,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;
@@ -5514,6 +5552,65 @@ _bfd_elf_size_group_sections (struct bfd_link_info *info)
   return TRUE;
 }
 
   return TRUE;
 }
 
+/* Set a default stack segment size.  The value in INFO wins.  If it
+   is unset, LEGACY_SYMBOL's value is used, and if that symbol is
+   undefined it is initialized.  */
+
+bfd_boolean
+bfd_elf_stack_segment_size (bfd *output_bfd,
+                           struct bfd_link_info *info,
+                           const char *legacy_symbol,
+                           bfd_vma default_size)
+{
+  struct elf_link_hash_entry *h = NULL;
+
+  /* Look for legacy symbol.  */
+  if (legacy_symbol)
+    h = elf_link_hash_lookup (elf_hash_table (info), legacy_symbol,
+                             FALSE, FALSE, FALSE);
+  if (h && (h->root.type == bfd_link_hash_defined
+           || h->root.type == bfd_link_hash_defweak)
+      && h->def_regular
+      && (h->type == STT_NOTYPE || h->type == STT_OBJECT))
+    {
+      /* The symbol has no type if specified on the command line.  */
+      h->type = STT_OBJECT;
+      if (info->stacksize)
+       (*_bfd_error_handler) (_("%B: stack size specified and %s set"),
+                              output_bfd, legacy_symbol);
+      else if (h->root.u.def.section != bfd_abs_section_ptr)
+       (*_bfd_error_handler) (_("%B: %s not absolute"),
+                              output_bfd, legacy_symbol);
+      else
+       info->stacksize = h->root.u.def.value;
+    }
+
+  if (!info->stacksize)
+    /* If the user didn't set a size, or explicitly inhibit the
+       size, set it now.  */
+    info->stacksize = default_size;
+
+  /* Provide the legacy symbol, if it is referenced.  */
+  if (h && (h->root.type == bfd_link_hash_undefined
+           || h->root.type == bfd_link_hash_undefweak))
+    {
+      struct bfd_link_hash_entry *bh = NULL;
+
+      if (!(_bfd_generic_link_add_one_symbol
+           (info, output_bfd, legacy_symbol,
+            BSF_GLOBAL, bfd_abs_section_ptr,
+            info->stacksize >= 0 ? info->stacksize : 0,
+            NULL, FALSE, get_elf_backend_data (output_bfd)->collect, &bh)))
+       return FALSE;
+
+      h = (struct elf_link_hash_entry *) bh;
+      h->def_regular = 1;
+      h->type = STT_OBJECT;
+    }
+
+  return TRUE;
+}
+
 /* Set up the sizes and contents of the ELF dynamic sections.  This is
    called by the ELF linker emulation before_allocation routine.  We
    must set the sizes of the sections before the linker sets the
 /* Set up the sizes and contents of the ELF dynamic sections.  This is
    called by the ELF linker emulation before_allocation routine.  We
    must set the sizes of the sections before the linker sets the
@@ -5528,8 +5625,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;
@@ -5544,6 +5640,26 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
     return TRUE;
 
   bed = get_elf_backend_data (output_bfd);
     return TRUE;
 
   bed = get_elf_backend_data (output_bfd);
+
+  /* Any syms created from now on start with -1 in
+     got.refcount/offset and plt.refcount/offset.  */
+  elf_hash_table (info)->init_got_refcount
+    = elf_hash_table (info)->init_got_offset;
+  elf_hash_table (info)->init_plt_refcount
+    = elf_hash_table (info)->init_plt_offset;
+
+  if (info->relocatable
+      && !_bfd_elf_size_group_sections (info))
+    return FALSE;
+
+  /* The backend may have to create some sections regardless of whether
+     we're dynamic or not.  */
+  if (bed->elf_backend_always_size_sections
+      && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
+    return FALSE;
+
+  /* Determine any GNU_STACK segment requirements, after the backend
+     has had a chance to set a default segment size.  */
   if (info->execstack)
     elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
   else if (info->noexecstack)
   if (info->execstack)
     elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
   else if (info->noexecstack)
@@ -5560,7 +5676,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)
@@ -5572,43 +5689,16 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
          else if (bed->default_execstack)
            exec = PF_X;
        }
          else if (bed->default_execstack)
            exec = PF_X;
        }
-      if (notesec)
-       {
-         elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec;
-         if (exec && info->relocatable
-             && notesec->output_section != bfd_abs_section_ptr)
-           notesec->output_section->flags |= SEC_CODE;
-       }
+      if (notesec || info->stacksize > 0)
+       elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec;
+      if (notesec && exec && info->relocatable
+         && notesec->output_section != bfd_abs_section_ptr)
+       notesec->output_section->flags |= SEC_CODE;
     }
 
     }
 
-  /* Any syms created from now on start with -1 in
-     got.refcount/offset and plt.refcount/offset.  */
-  elf_hash_table (info)->init_got_refcount
-    = elf_hash_table (info)->init_got_offset;
-  elf_hash_table (info)->init_plt_refcount
-    = elf_hash_table (info)->init_plt_offset;
-
-  if (info->relocatable
-      && !_bfd_elf_size_group_sections (info))
-    return FALSE;
-
-  /* The backend may have to create some sections regardless of whether
-     we're dynamic or not.  */
-  if (bed->elf_backend_always_size_sections
-      && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
-    return FALSE;
-
-  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;
@@ -5618,7 +5708,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)
@@ -5705,7 +5795,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
@@ -5721,7 +5810,7 @@ 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)
            {
        for (d = t->globals.list; d != NULL; d = d->next)
          if (!d->symver && d->literal)
            {
@@ -5774,7 +5863,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),
@@ -5787,7 +5875,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)
                {
@@ -5888,7 +5976,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
@@ -5913,22 +6001,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)
@@ -6186,7 +6279,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;
@@ -6298,7 +6391,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;
        }
     }
@@ -6382,7 +6475,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)
@@ -6402,7 +6495,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;
 
@@ -6460,7 +6553,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);
@@ -6514,7 +6607,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)
@@ -6642,7 +6735,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);
@@ -6657,25 +6750,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.  */
@@ -6703,7 +6785,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)
@@ -7426,6 +7508,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.  */
@@ -7434,7 +7518,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;
 };
 
 
 };
 
 
@@ -7511,7 +7597,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)
@@ -7540,7 +7626,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;
@@ -7553,7 +7639,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;
@@ -7622,7 +7708,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,
@@ -7682,8 +7768,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);
@@ -7692,9 +7778,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);
@@ -7713,7 +7799,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)                                            \
@@ -7730,11 +7816,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)                                            \
@@ -7816,31 +7902,49 @@ get_value (bfd_vma size,
           bfd *input_bfd,
           bfd_byte *location)
 {
           bfd *input_bfd,
           bfd_byte *location)
 {
+  int shift;
   bfd_vma x = 0;
 
   bfd_vma x = 0;
 
+  /* Sanity checks.  */
+  BFD_ASSERT (chunksz <= sizeof (x)
+             && size >= chunksz
+             && chunksz != 0
+             && (size % chunksz) == 0
+             && input_bfd != NULL
+             && location != NULL);
+
+  if (chunksz == sizeof (x))
+    {
+      BFD_ASSERT (size == chunksz);
+
+      /* Make sure that we do not perform an undefined shift operation.
+        We know that size == chunksz so there will only be one iteration
+        of the loop below.  */
+      shift = 0;
+    }
+  else
+    shift = 8 * chunksz;
+
   for (; size; size -= chunksz, location += chunksz)
     {
       switch (chunksz)
        {
   for (; size; size -= chunksz, location += chunksz)
     {
       switch (chunksz)
        {
-       default:
-       case 0:
-         abort ();
        case 1:
        case 1:
-         x = (x << (8 * chunksz)) | bfd_get_8 (input_bfd, location);
+         x = (x << shift) | bfd_get_8 (input_bfd, location);
          break;
        case 2:
          break;
        case 2:
-         x = (x << (8 * chunksz)) | bfd_get_16 (input_bfd, location);
+         x = (x << shift) | bfd_get_16 (input_bfd, location);
          break;
        case 4:
          break;
        case 4:
-         x = (x << (8 * chunksz)) | bfd_get_32 (input_bfd, location);
+         x = (x << shift) | bfd_get_32 (input_bfd, location);
          break;
          break;
-       case 8:
 #ifdef BFD64
 #ifdef BFD64
-         x = (x << (8 * chunksz)) | bfd_get_64 (input_bfd, location);
-#else
-         abort ();
-#endif
+       case 8:
+         x = (x << shift) | bfd_get_64 (input_bfd, location);
          break;
          break;
+#endif
+       default:
+         abort ();
        }
     }
   return x;
        }
     }
   return x;
@@ -8332,24 +8436,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;
@@ -8358,7 +8462,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,
@@ -8371,11 +8475,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;
     }
@@ -8386,41 +8490,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;
 }
@@ -8461,6 +8565,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:
@@ -8604,10 +8712,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;
@@ -8627,6 +8736,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
     {
@@ -8634,7 +8748,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)
     {
@@ -8653,14 +8767,16 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
       /* If we are reporting errors for this situation then do so now.  */
       if (!ignore_undef
          && h->ref_dynamic
       /* If we are reporting errors for this situation then do so now.  */
       if (!ignore_undef
          && 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;
            {
              bfd_set_error (bfd_error_bad_value);
              eoinfo->failed = TRUE;
@@ -8671,16 +8787,22 @@ 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_def
-      && !h->dynamic_weak
-      && ! elf_link_check_versioned_symbol (finfo->info, bed, h))
+      && h->ref_dynamic_nonweak
+      && !elf_link_check_versioned_symbol (flinfo->info, bed, h))
     {
       bfd *def_bfd;
       const char *msg;
     {
       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");
 
       if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
        msg = _("%B: internal symbol `%s' in %B is referenced by DSO");
@@ -8688,10 +8810,10 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
        msg = _("%B: hidden symbol `%s' in %B is referenced by DSO");
       else
        msg = _("%B: local symbol `%s' in %B is referenced by DSO");
        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 = finfo->output_bfd;
-      if (h->root.u.def.section != bfd_abs_section_ptr)
-       def_bfd = h->root.u.def.section->owner;
-      (*_bfd_error_handler) (msg, finfo->output_bfd, def_bfd,
+      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;
                             h->root.root.string);
       bfd_set_error (bfd_error_bad_value);
       eoinfo->failed = TRUE;
@@ -8710,16 +8832,18 @@ 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)
     strip = TRUE;
   else if ((h->root.type == bfd_link_hash_undefined
            || h->root.type == bfd_link_hash_undefweak)
@@ -8776,14 +8900,27 @@ 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;
                bfd_set_error (bfd_error_nonrepresentable_section);
                eoinfo->failed = TRUE;
                return FALSE;
@@ -8793,18 +8930,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);
                      }
                  }
@@ -8843,17 +8980,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;
@@ -8896,7 +9033,7 @@ 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
       && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
       && ELF_ST_BIND (sym.st_info) != STB_WEAK
       && h->root.type == bfd_link_hash_undefined
@@ -8910,7 +9047,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
        msg = _("%B: internal symbol `%s' isn't defined");
       else
        msg = _("%B: hidden symbol `%s' isn't defined");
        msg = _("%B: internal symbol `%s' isn't defined");
       else
        msg = _("%B: hidden symbol `%s' isn't defined");
-      (*_bfd_error_handler) (msg, finfo->output_bfd, h->root.root.string);
+      (*_bfd_error_handler) (msg, flinfo->output_bfd, h->root.root.string);
       bfd_set_error (bfd_error_bad_value);
       eoinfo->failed = TRUE;
       return FALSE;
       bfd_set_error (bfd_error_bad_value);
       eoinfo->failed = TRUE;
       return FALSE;
@@ -8919,21 +9056,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;
@@ -8941,21 +9096,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;
@@ -8973,16 +9129,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);
        }
     }
 
        }
     }
 
@@ -8991,8 +9147,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;
@@ -9016,8 +9172,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;
@@ -9106,7 +9262,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 *,
@@ -9126,8 +9282,9 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
   bfd_size_type address_size;
   bfd_vma r_type_mask;
   int r_sym_shift;
   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;
 
@@ -9154,9 +9311,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;
     }
@@ -9165,7 +9322,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++)
     {
@@ -9202,7 +9359,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,
@@ -9213,7 +9370,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)
@@ -9226,7 +9383,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
@@ -9234,7 +9391,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
@@ -9252,15 +9409,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.  */
@@ -9277,19 +9457,19 @@ 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)
       if (ret == 0)
        return FALSE;
       else if (ret == 1)
@@ -9321,7 +9501,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.  */
@@ -9331,7 +9511,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
@@ -9344,16 +9524,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;
@@ -9372,16 +9552,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];
            }
        }
 
            }
        }
 
@@ -9404,7 +9584,7 @@ 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
        {
-         contents = finfo->contents;
+         contents = flinfo->contents;
          if (! bfd_get_full_section_contents (input_bfd, o, &contents))
            return FALSE;
        }
          if (! bfd_get_full_section_contents (input_bfd, o, &contents))
            return FALSE;
        }
@@ -9418,8 +9598,8 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
          /* Get the swapped relocs.  */
          internal_relocs
 
          /* 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;
@@ -9472,7 +9652,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];
 
@@ -9510,13 +9690,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
@@ -9532,7 +9712,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                          (unsigned long) rel->r_info,
                          (unsigned long) rel->r_offset);
 #endif
                          (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;
 
@@ -9546,11 +9726,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 != STN_UNDEF);
                      if (action_discarded & COMPLAIN)
                    {
                      BFD_ASSERT (r_symndx != STN_UNDEF);
                      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);
@@ -9566,7 +9746,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;
@@ -9597,17 +9777,17 @@ 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 *irelaend, *irelamid;
            {
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend, *irelamid;
@@ -9637,7 +9817,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
              rel_hash_list = rel_hash;
              rela_hash_list = NULL;
              last_offset = o->output_offset;
              rel_hash_list = rel_hash;
              rela_hash_list = NULL;
              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++)
                {
@@ -9659,7 +9839,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                    }
 
                  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)
                    {
@@ -9677,7 +9857,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;
@@ -9688,7 +9868,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;
@@ -9721,7 +9901,7 @@ 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
                  if (ELF_ST_TYPE (sym.st_info) == STT_SECTION)
                    {
                      /* I suppose the backend ought to fill in the
@@ -9758,23 +9938,12 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                              r_symndx = osec->target_index;
                              if (r_symndx == STN_UNDEF)
                                {
                              r_symndx = osec->target_index;
                              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 != STN_UNDEF);
                            }
                        }
 
                            }
                        }
 
@@ -9785,14 +9954,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);
@@ -9816,32 +9985,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
@@ -9876,28 +10045,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;
          }
@@ -10274,7 +10443,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;
@@ -10311,39 +10480,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
@@ -10417,7 +10587,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);
@@ -10565,22 +10741,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;
     }
 
@@ -10595,7 +10771,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       elfsym.st_other = 0;
       elfsym.st_shndx = SHN_UNDEF;
       elfsym.st_target_internal = 0;
       elfsym.st_other = 0;
       elfsym.st_shndx = SHN_UNDEF;
       elfsym.st_target_internal = 0;
-      if (elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
+      if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr,
                               NULL) != 1)
        goto error_return;
     }
                               NULL) != 1)
        goto error_return;
     }
@@ -10622,7 +10798,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;
            }
        }
@@ -10632,15 +10808,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;
     }
 
@@ -10648,39 +10824,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;
     }
 
@@ -10754,7 +10930,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;
                }
@@ -10812,6 +10988,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
@@ -10819,13 +11006,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)
@@ -10835,7 +11036,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;
     }
 
@@ -10848,10 +11049,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.  */
@@ -10923,16 +11125,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;
 
@@ -10945,12 +11146,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.  */
@@ -10969,7 +11170,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;
     }
 
@@ -10981,7 +11182,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;
@@ -10994,7 +11195,7 @@ 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;
     }
 
        return FALSE;
     }
 
@@ -11025,7 +11226,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;
@@ -11148,6 +11349,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;
 
@@ -11192,14 +11400,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)
@@ -11210,8 +11416,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;
                }
            }
@@ -11233,9 +11443,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,
@@ -11279,28 +11487,28 @@ 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)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
@@ -11325,28 +11533,28 @@ 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)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
@@ -11533,7 +11741,7 @@ _bfd_elf_gc_mark_hook (asection *sec,
          if (sec_name && *sec_name != '\0')
            {
              bfd *i;
          if (sec_name && *sec_name != '\0')
            {
              bfd *i;
-             
+
              for (i = info->input_bfds; i; i = i->link_next)
                {
                  sec = bfd_get_section_by_name (i, sec_name);
              for (i = info->input_bfds; i; i = i->link_next)
                {
                  sec = bfd_get_section_by_name (i, sec_name);
@@ -11576,6 +11784,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);
     }
 
@@ -11598,7 +11813,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;
@@ -11667,6 +11883,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
@@ -11679,17 +11939,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;
@@ -11727,12 +11991,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)
-           {
-             /* Keep debug and special sections.  */
-             o->gc_mark = 1;
-           }
 
          if (o->gc_mark)
            continue;
 
          if (o->gc_mark)
            continue;
@@ -11793,9 +12051,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;
@@ -11857,9 +12112,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)
@@ -11907,16 +12159,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;
@@ -11973,12 +12225,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);
@@ -12012,19 +12266,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;
 
-      /* Also keep SHT_NOTE sections.  */
+      /* 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) == 0
+       if (!o->gc_mark
+           && (o->flags & SEC_EXCLUDE) == 0
            && ((o->flags & SEC_KEEP) != 0
            && ((o->flags & SEC_KEEP) != 0
-               || elf_section_data (o)->this_hdr.sh_type == SHT_NOTE)
-           && !o->gc_mark)
-         if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
-           return FALSE;
+               || (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);
@@ -12167,6 +12425,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;
@@ -12182,9 +12532,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;
@@ -12310,7 +12657,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;
@@ -12326,7 +12673,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;
@@ -12360,24 +12707,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
@@ -12400,8 +12744,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,
@@ -12409,6 +12753,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
@@ -12427,139 +12772,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)
            {
@@ -12578,13 +12853,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);
@@ -12593,7 +12867,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;
@@ -12642,8 +12915,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
@@ -12692,7 +12966,7 @@ get_dynamic_reloc_section_name (bfd *       abfd,
     return NULL;
 
   name = bfd_alloc (abfd, strlen (prefix) + strlen (old_name) + 1);
     return NULL;
 
   name = bfd_alloc (abfd, strlen (prefix) + strlen (old_name) + 1);
-  sprintf (name, "%s%s", prefix, old_name); 
+  sprintf (name, "%s%s", prefix, old_name);
 
   return name;
 }
 
   return name;
 }
@@ -12715,7 +12989,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;
@@ -12751,17 +13025,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))
@@ -12807,5 +13080,5 @@ 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);
   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);
+  bed->s->swap_reloc_out (abfd, rel, loc);
 }
 }
This page took 0.079293 seconds and 4 git commands to generate.