daily update
[deliverable/binutils-gdb.git] / bfd / elflink.c
index d76faae7e95b5f7981f935f78cba80dc6ad74228..6cfb8b96092d2a6b2857dab0cb8cdf49b8f7766f 100644 (file)
@@ -6,7 +6,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 
-#include "bfd.h"
 #include "sysdep.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #define ARCH_SIZE 0
 #include "bfdlink.h"
 #include "libbfd.h"
 #define ARCH_SIZE 0
@@ -467,8 +468,9 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
                                bfd_boolean provide,
                                bfd_boolean hidden)
 {
                                bfd_boolean provide,
                                bfd_boolean hidden)
 {
-  struct elf_link_hash_entry *h;
+  struct elf_link_hash_entry *h, *hv;
   struct elf_link_hash_table *htab;
   struct elf_link_hash_table *htab;
+  const struct elf_backend_data *bed;
 
   if (!is_elf_hash_table (info->hash))
     return TRUE;
 
   if (!is_elf_hash_table (info->hash))
     return TRUE;
@@ -478,21 +480,43 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
   if (h == NULL)
     return provide;
 
   if (h == NULL)
     return provide;
 
-  /* Since we're defining the symbol, don't let it seem to have not
-     been defined.  record_dynamic_symbol and size_dynamic_sections
-     may depend on this.  */
-  if (h->root.type == bfd_link_hash_undefweak
-      || h->root.type == bfd_link_hash_undefined)
+  switch (h->root.type)
     {
     {
+    case bfd_link_hash_defined:
+    case bfd_link_hash_defweak:
+    case bfd_link_hash_common:
+      break;
+    case bfd_link_hash_undefweak:
+    case bfd_link_hash_undefined:
+      /* Since we're defining the symbol, don't let it seem to have not
+        been defined.  record_dynamic_symbol and size_dynamic_sections
+        may depend on this.  */
       h->root.type = bfd_link_hash_new;
       if (h->root.u.undef.next != NULL || htab->root.undefs_tail == &h->root)
        bfd_link_repair_undef_list (&htab->root);
       h->root.type = bfd_link_hash_new;
       if (h->root.u.undef.next != NULL || htab->root.undefs_tail == &h->root)
        bfd_link_repair_undef_list (&htab->root);
-    }
-
-  if (h->root.type == bfd_link_hash_new)
-    {
+      break;
+    case bfd_link_hash_new:
       bfd_elf_link_mark_dynamic_symbol (info, h, NULL);
       h->non_elf = 0;
       bfd_elf_link_mark_dynamic_symbol (info, h, NULL);
       h->non_elf = 0;
+      break;
+    case bfd_link_hash_indirect:
+      /* We had a versioned symbol in a dynamic library.  We make the
+         the versioned symbol point to this one.  */
+      bed = get_elf_backend_data (output_bfd);
+      hv = h;
+      while (hv->root.type == bfd_link_hash_indirect
+            || hv->root.type == bfd_link_hash_warning)
+       hv = (struct elf_link_hash_entry *) hv->root.u.i.link;
+      /* We don't need to update h->root.u since linker will set them
+        later.  */
+      h->root.type = bfd_link_hash_undefined;
+      hv->root.type = bfd_link_hash_indirect;
+      hv->root.u.i.link = (struct bfd_link_hash_entry *) h;
+      (*bed->elf_backend_copy_indirect_symbol) (info, h, hv);
+      break;
+    case bfd_link_hash_warning:
+      abort ();
+      break;
     }
 
   /* If this symbol is being provided by the linker script, and it is
     }
 
   /* If this symbol is being provided by the linker script, and it is
@@ -947,6 +971,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
            && h->root.type != bfd_link_hash_undefweak
            && h->root.type != bfd_link_hash_common);
 
            && h->root.type != bfd_link_hash_undefweak
            && h->root.type != bfd_link_hash_common);
 
+  bed = get_elf_backend_data (abfd);
   /* When we try to create a default indirect symbol from the dynamic
      definition with the default version, we skip it if its type and
      the type of existing regular definition mismatch.  We only do it
   /* When we try to create a default indirect symbol from the dynamic
      definition with the default version, we skip it if its type and
      the type of existing regular definition mismatch.  We only do it
@@ -961,7 +986,9 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (olddef || h->root.type == bfd_link_hash_common)
       && ELF_ST_TYPE (sym->st_info) != h->type
       && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
       && (olddef || h->root.type == bfd_link_hash_common)
       && ELF_ST_TYPE (sym->st_info) != h->type
       && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
-      && h->type != STT_NOTYPE)
+      && h->type != STT_NOTYPE
+      && !(bed->is_function_type (ELF_ST_TYPE (sym->st_info))
+          && bed->is_function_type (h->type)))
     {
       *skip = TRUE;
       return TRUE;
     {
       *skip = TRUE;
       return TRUE;
@@ -1152,6 +1179,11 @@ _bfd_elf_merge_symbol (bfd *abfd,
   if (olddef && newdyn)
     oldweak = FALSE;
 
   if (olddef && newdyn)
     oldweak = FALSE;
 
+  /* Allow changes between different types of funciton symbol.  */
+  if (bed->is_function_type (ELF_ST_TYPE (sym->st_info))
+      && bed->is_function_type (h->type))
+    *type_change_ok = TRUE;
+
   /* It's OK to change the type if either the existing symbol or the
      new symbol is weak.  A type change is also OK if the old symbol
      is undefined and the new symbol is defined.  */
   /* It's OK to change the type if either the existing symbol or the
      new symbol is weak.  A type change is also OK if the old symbol
      is undefined and the new symbol is defined.  */
@@ -1198,7 +1230,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (sec->flags & SEC_ALLOC) != 0
       && (sec->flags & SEC_LOAD) == 0
       && sym->st_size > 0
       && (sec->flags & SEC_ALLOC) != 0
       && (sec->flags & SEC_LOAD) == 0
       && sym->st_size > 0
-      && ELF_ST_TYPE (sym->st_info) != STT_FUNC)
+      && !bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
     newdyncommon = TRUE;
   else
     newdyncommon = FALSE;
     newdyncommon = TRUE;
   else
     newdyncommon = FALSE;
@@ -1210,14 +1242,13 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (h->root.u.def.section->flags & SEC_ALLOC) != 0
       && (h->root.u.def.section->flags & SEC_LOAD) == 0
       && h->size > 0
       && (h->root.u.def.section->flags & SEC_ALLOC) != 0
       && (h->root.u.def.section->flags & SEC_LOAD) == 0
       && h->size > 0
-      && h->type != STT_FUNC)
+      && !bed->is_function_type (h->type))
     olddyncommon = TRUE;
   else
     olddyncommon = FALSE;
 
   /* We now know everything about the old and new symbols.  We ask the
      backend to check if we can merge them.  */
     olddyncommon = TRUE;
   else
     olddyncommon = FALSE;
 
   /* We now know everything about the old and new symbols.  We ask the
      backend to check if we can merge them.  */
-  bed = get_elf_backend_data (abfd);
   if (bed->merge_symbol
       && !bed->merge_symbol (info, sym_hash, h, sym, psec, pvalue,
                             pold_alignment, skip, override,
   if (bed->merge_symbol
       && !bed->merge_symbol (info, sym_hash, h, sym, psec, pvalue,
                             pold_alignment, skip, override,
@@ -1272,7 +1303,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (olddef
          || (h->root.type == bfd_link_hash_common
              && (newweak
       && (olddef
          || (h->root.type == bfd_link_hash_common
              && (newweak
-                 || ELF_ST_TYPE (sym->st_info) == STT_FUNC))))
+                 || bed->is_function_type (ELF_ST_TYPE (sym->st_info))))))
     {
       *override = TRUE;
       newdef = FALSE;
     {
       *override = TRUE;
       newdef = FALSE;
@@ -1327,7 +1358,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       && (newdef
          || (bfd_is_com_section (sec)
              && (oldweak
       && (newdef
          || (bfd_is_com_section (sec)
              && (oldweak
-                 || h->type == STT_FUNC)))
+                 || bed->is_function_type (h->type))))
       && olddyn
       && olddef
       && h->def_dynamic)
       && olddyn
       && olddef
       && h->def_dynamic)
@@ -1409,10 +1440,10 @@ _bfd_elf_merge_symbol (bfd *abfd,
         case, we make the versioned symbol point to the normal one.  */
       const struct elf_backend_data *bed = get_elf_backend_data (abfd);
       flip->root.type = h->root.type;
         case, we make the versioned symbol point to the normal one.  */
       const struct elf_backend_data *bed = get_elf_backend_data (abfd);
       flip->root.type = h->root.type;
+      flip->root.u.undef.abfd = h->root.u.undef.abfd;
       h->root.type = bfd_link_hash_indirect;
       h->root.u.i.link = (struct bfd_link_hash_entry *) flip;
       (*bed->elf_backend_copy_indirect_symbol) (info, flip, h);
       h->root.type = bfd_link_hash_indirect;
       h->root.u.i.link = (struct bfd_link_hash_entry *) flip;
       (*bed->elf_backend_copy_indirect_symbol) (info, flip, h);
-      flip->root.u.undef.abfd = h->root.u.undef.abfd;
       if (h->def_dynamic)
        {
          h->def_dynamic = 0;
       if (h->def_dynamic)
        {
          h->def_dynamic = 0;
@@ -1556,6 +1587,10 @@ _bfd_elf_add_default_symbol (bfd *abfd,
       hi = h;
     }
 
       hi = h;
     }
 
+  /* Check if HI is a warning symbol.  */
+  if (hi->root.type == bfd_link_hash_warning)
+    hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+
   /* If there is a duplicate definition somewhere, then HI may not
      point to an indirect symbol.  We will have reported an error to
      the user in that case.  */
   /* If there is a duplicate definition somewhere, then HI may not
      point to an indirect symbol.  We will have reported an error to
      the user in that case.  */
@@ -1936,7 +1971,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
          /* We could not find the version for a symbol when
             generating a shared archive.  Return an error.  */
          (*_bfd_error_handler)
          /* We could not find the version for a symbol when
             generating a shared archive.  Return an error.  */
          (*_bfd_error_handler)
-           (_("%B: undefined versioned symbol name %s"),
+           (_("%B: version node not found for symbol %s"),
             sinfo->output_bfd, h->root.root.string);
          bfd_set_error (bfd_error_bad_value);
          sinfo->failed = TRUE;
             sinfo->output_bfd, h->root.root.string);
          bfd_set_error (bfd_error_bad_value);
          sinfo->failed = TRUE;
@@ -2333,7 +2368,7 @@ bfd_boolean
 _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
                           struct elf_info_failed *eif)
 {
 _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
                           struct elf_info_failed *eif)
 {
-  const struct elf_backend_data *bed = NULL;
+  const struct elf_backend_data *bed;
 
   /* If this symbol was mentioned in a non-ELF file, try to set
      DEF_REGULAR and REF_REGULAR correctly.  This is the only way to
 
   /* If this symbol was mentioned in a non-ELF file, try to set
      DEF_REGULAR and REF_REGULAR correctly.  This is the only way to
@@ -2394,13 +2429,10 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
     }
 
   /* Backend specific symbol fixup.  */
     }
 
   /* Backend specific symbol fixup.  */
-  if (elf_hash_table (eif->info)->dynobj)
-    {
-      bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
-      if (bed->elf_backend_fixup_symbol
-         && !(*bed->elf_backend_fixup_symbol) (eif->info, h))
-       return FALSE;
-    }
+  bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
+  if (bed->elf_backend_fixup_symbol
+      && !(*bed->elf_backend_fixup_symbol) (eif->info, h))
+    return FALSE;
 
   /* If this is a final link, and the symbol was defined as a common
      symbol in a regular object file, and there was no definition in
 
   /* If this is a final link, and the symbol was defined as a common
      symbol in a regular object file, and there was no definition in
@@ -2438,11 +2470,7 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
      hide it from the dynamic linker.  */
   if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
       && h->root.type == bfd_link_hash_undefweak)
      hide it from the dynamic linker.  */
   if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
       && h->root.type == bfd_link_hash_undefweak)
-    {
-      const struct elf_backend_data *bed;
-      bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
-      (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
-    }
+    (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
 
   /* If this is a weak defined symbol in a dynamic object, and we know
      the real definition in the dynamic object, copy interesting flags
 
   /* If this is a weak defined symbol in a dynamic object, and we know
      the real definition in the dynamic object, copy interesting flags
@@ -2457,8 +2485,6 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
 
       BFD_ASSERT (h->root.type == bfd_link_hash_defined
                  || h->root.type == bfd_link_hash_defweak);
 
       BFD_ASSERT (h->root.type == bfd_link_hash_defined
                  || h->root.type == bfd_link_hash_defweak);
-      BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
-                 || weakdef->root.type == bfd_link_hash_defweak);
       BFD_ASSERT (weakdef->def_dynamic);
 
       /* If the real definition is defined by a regular object file,
       BFD_ASSERT (weakdef->def_dynamic);
 
       /* If the real definition is defined by a regular object file,
@@ -2467,8 +2493,11 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
       if (weakdef->def_regular)
        h->u.weakdef = NULL;
       else
       if (weakdef->def_regular)
        h->u.weakdef = NULL;
       else
-       (*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);
+       }
     }
 
   return TRUE;
     }
 
   return TRUE;
@@ -2598,6 +2627,52 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
   return TRUE;
 }
 
   return TRUE;
 }
 
+/* Adjust the dynamic symbol, H, for copy in the dynamic bss section,
+   DYNBSS.  */
+
+bfd_boolean
+_bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h,
+                             asection *dynbss)
+{
+  unsigned int power_of_two;
+  bfd_vma mask;
+  asection *sec = h->root.u.def.section;
+
+  /* The section aligment of definition is the maximum alignment
+     requirement of symbols defined in the section.  Since we don't
+     know the symbol alignment requirement, we start with the
+     maximum alignment and check low bits of the symbol address
+     for the minimum alignment.  */
+  power_of_two = bfd_get_section_alignment (sec->owner, sec);
+  mask = ((bfd_vma) 1 << power_of_two) - 1;
+  while ((h->root.u.def.value & mask) != 0)
+    {
+       mask >>= 1;
+       --power_of_two;
+    }
+
+  if (power_of_two > bfd_get_section_alignment (dynbss->owner,
+                                               dynbss))
+    {
+      /* Adjust the section alignment if needed.  */
+      if (! bfd_set_section_alignment (dynbss->owner, dynbss,
+                                      power_of_two))
+       return FALSE;
+    }
+
+  /* We make sure that the symbol will be aligned properly.  */
+  dynbss->size = BFD_ALIGN (dynbss->size, mask + 1);
+
+  /* Define the symbol as being at this point in DYNBSS.  */
+  h->root.u.def.section = dynbss;
+  h->root.u.def.value = dynbss->size;
+
+  /* Increment the size of DYNBSS to make room for the symbol.  */
+  dynbss->size += h->size;
+
+  return TRUE;
+}
+
 /* Adjust all external symbols pointing into SEC_MERGE sections
    to reflect the object merging within the sections.  */
 
 /* Adjust all external symbols pointing into SEC_MERGE sections
    to reflect the object merging within the sections.  */
 
@@ -2636,6 +2711,8 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
                           bfd_boolean ignore_protected)
 {
   bfd_boolean binding_stays_local_p;
                           bfd_boolean ignore_protected)
 {
   bfd_boolean binding_stays_local_p;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_table *hash_table;
 
   if (h == NULL)
     return FALSE;
 
   if (h == NULL)
     return FALSE;
@@ -2661,10 +2738,16 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
       return FALSE;
 
     case STV_PROTECTED:
       return FALSE;
 
     case STV_PROTECTED:
+      hash_table = elf_hash_table (info);
+      if (!is_elf_hash_table (hash_table))
+       return FALSE;
+
+      bed = get_elf_backend_data (hash_table->dynobj);
+
       /* Proper resolution for function pointer equality may require
         that these symbols perhaps be resolved dynamically, even though
         we should be resolving them to the current module.  */
       /* Proper resolution for function pointer equality may require
         that these symbols perhaps be resolved dynamically, even though
         we should be resolving them to the current module.  */
-      if (!ignore_protected || h->type != STT_FUNC)
+      if (!ignore_protected || !bed->is_function_type (h->type))
        binding_stays_local_p = TRUE;
       break;
 
        binding_stays_local_p = TRUE;
       break;
 
@@ -2691,6 +2774,9 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
                              struct bfd_link_info *info,
                              bfd_boolean local_protected)
 {
                              struct bfd_link_info *info,
                              bfd_boolean local_protected)
 {
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_table *hash_table;
+
   /* If it's a local sym, of course we resolve locally.  */
   if (h == NULL)
     return TRUE;
   /* If it's a local sym, of course we resolve locally.  */
   if (h == NULL)
     return TRUE;
@@ -2727,8 +2813,14 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
   if (ELF_ST_VISIBILITY (h->other) != STV_PROTECTED)
     return TRUE;
 
   if (ELF_ST_VISIBILITY (h->other) != STV_PROTECTED)
     return TRUE;
 
+  hash_table = elf_hash_table (info);
+  if (!is_elf_hash_table (hash_table))
+    return TRUE;
+
+  bed = get_elf_backend_data (hash_table->dynobj);
+
   /* STV_PROTECTED non-function symbols are local.  */
   /* STV_PROTECTED non-function symbols are local.  */
-  if (h->type != STT_FUNC)
+  if (!bed->is_function_type (h->type))
     return TRUE;
 
   /* Function pointer equality tests may require that STV_PROTECTED
     return TRUE;
 
   /* Function pointer equality tests may require that STV_PROTECTED
@@ -2777,8 +2869,9 @@ is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
       && ELF_ST_BIND (sym->st_info) < STB_LOOS)
     return FALSE;
 
       && ELF_ST_BIND (sym->st_info) < STB_LOOS)
     return FALSE;
 
+  bed = get_elf_backend_data (abfd);
   /* Function symbols do not count.  */
   /* Function symbols do not count.  */
-  if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
+  if (bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
     return FALSE;
 
   /* If the section is undefined, then so is the symbol.  */
     return FALSE;
 
   /* If the section is undefined, then so is the symbol.  */
@@ -2787,7 +2880,6 @@ is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
 
   /* If the symbol is defined in the common section, then
      it is a common definition and so does not count.  */
 
   /* If the symbol is defined in the common section, then
      it is a common definition and so does not count.  */
-  bed = get_elf_backend_data (abfd);
   if (bed->common_definition (sym))
     return FALSE;
 
   if (bed->common_definition (sym))
     return FALSE;
 
@@ -3599,8 +3691,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
         tell it that we are about to handle an as-needed lib.  */
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
                                       notice_as_needed))
         tell it that we are about to handle an as-needed lib.  */
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
                                       notice_as_needed))
-       return FALSE;
-
+       goto error_free_vers;
 
       /* Clone the symbol table and sym hashes.  Remember some
         pointers into the symbol table, and dynamic symbol count.  */
 
       /* Clone the symbol table and sym hashes.  Remember some
         pointers into the symbol table, and dynamic symbol count.  */
@@ -3795,8 +3886,9 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
             if it is not a function, because it might be the version
             symbol itself.  FIXME: What if it isn't?  */
          if ((iver.vs_vers & VERSYM_HIDDEN) != 0
             if it is not a function, because it might be the version
             symbol itself.  FIXME: What if it isn't?  */
          if ((iver.vs_vers & VERSYM_HIDDEN) != 0
-             || (vernum > 1 && (! bfd_is_abs_section (sec)
-                                || ELF_ST_TYPE (isym->st_info) == STT_FUNC)))
+             || (vernum > 1
+                 && (!bfd_is_abs_section (sec)
+                     || bed->is_function_type (ELF_ST_TYPE (isym->st_info)))))
            {
              const char *verstr;
              size_t namelen, verlen, newlen;
            {
              const char *verstr;
              size_t namelen, verlen, newlen;
@@ -3943,7 +4035,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       if (dynamic
          && definition
          && (flags & BSF_WEAK) != 0
       if (dynamic
          && definition
          && (flags & BSF_WEAK) != 0
-         && ELF_ST_TYPE (isym->st_info) != STT_FUNC
+         && !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
          && is_elf_hash_table (htab)
          && h->u.weakdef == NULL)
        {
          && is_elf_hash_table (htab)
          && h->u.weakdef == NULL)
        {
@@ -4068,7 +4160,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
             to be the size of the common symbol.  The code just above
             won't fix the size if a common symbol becomes larger.  We
             don't warn about a size change here, because that is
             to be the size of the common symbol.  The code just above
             won't fix the size if a common symbol becomes larger.  We
             don't warn about a size change here, because that is
-            covered by --warn-common.  */
+            covered by --warn-common.  Allow changed between different
+            function types.  */
          if (h->root.type == bfd_link_hash_common)
            h->size = h->root.u.c.size;
 
          if (h->root.type == bfd_link_hash_common)
            h->size = h->root.u.c.size;
 
@@ -4305,7 +4398,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
         tell it that symbols added for crefs may need to be removed.  */
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
                                       notice_not_needed))
         tell it that symbols added for crefs may need to be removed.  */
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
                                       notice_not_needed))
-       return FALSE;
+       goto error_free_vers;
 
       free (old_tab);
       objalloc_free_block ((struct objalloc *) htab->root.table.memory,
 
       free (old_tab);
       objalloc_free_block ((struct objalloc *) htab->root.table.memory,
@@ -4319,7 +4412,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
     {
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
                                       notice_needed))
     {
       if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
                                       notice_needed))
-       return FALSE;
+       goto error_free_vers;
       free (old_tab);
       old_tab = NULL;
     }
       free (old_tab);
       old_tab = NULL;
     }
@@ -4410,7 +4503,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          h = *hpp;
          if (h != NULL
              && h->root.type == bfd_link_hash_defined
          h = *hpp;
          if (h != NULL
              && h->root.type == bfd_link_hash_defined
-             && h->type != STT_FUNC)
+             && !bed->is_function_type (h->type))
            {
              *sym_hash = h;
              sym_hash++;
            {
              *sym_hash = h;
              sym_hash++;
@@ -5233,6 +5326,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
   if (!is_elf_hash_table (info->hash))
     return TRUE;
 
   if (!is_elf_hash_table (info->hash))
     return TRUE;
 
+  bed = get_elf_backend_data (output_bfd);
   elf_tdata (output_bfd)->relro = info->relro;
   if (info->execstack)
     elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
   elf_tdata (output_bfd)->relro = info->relro;
   if (info->execstack)
     elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
@@ -5259,7 +5353,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                exec = PF_X;
              notesec = s;
            }
                exec = PF_X;
              notesec = s;
            }
-         else
+         else if (bed->default_execstack)
            exec = PF_X;
        }
       if (notesec)
            exec = PF_X;
        }
       if (notesec)
@@ -5280,7 +5374,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* The backend may have to create some sections regardless of whether
      we're dynamic or not.  */
 
   /* The backend may have to create some sections regardless of whether
      we're dynamic or not.  */
-  bed = get_elf_backend_data (output_bfd);
   if (bed->elf_backend_always_size_sections
       && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
     return FALSE;
   if (bed->elf_backend_always_size_sections
       && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
     return FALSE;
@@ -5518,15 +5611,16 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
              for (sub = info->input_bfds; sub != NULL;
                   sub = sub->link_next)
 
              for (sub = info->input_bfds; sub != NULL;
                   sub = sub->link_next)
-               for (o = sub->sections; o != NULL; o = o->next)
-                 if (elf_section_data (o)->this_hdr.sh_type
-                     == SHT_PREINIT_ARRAY)
-                   {
-                     (*_bfd_error_handler)
-                       (_("%B: .preinit_array section is not allowed in DSO"),
-                        sub);
-                     break;
-                   }
+               if (bfd_get_flavour (sub) == bfd_target_elf_flavour)
+                 for (o = sub->sections; o != NULL; o = o->next)
+                   if (elf_section_data (o)->this_hdr.sh_type
+                       == SHT_PREINIT_ARRAY)
+                     {
+                       (*_bfd_error_handler)
+                         (_("%B: .preinit_array section is not allowed in DSO"),
+                          sub);
+                       break;
+                     }
 
              bfd_set_error (bfd_error_nonrepresentable_section);
              return FALSE;
 
              bfd_set_error (bfd_error_nonrepresentable_section);
              return FALSE;
@@ -6288,7 +6382,728 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
 
   return TRUE;
 }
 
   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)
+{
+  BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE);
+  sec->sec_info_type = ELF_INFO_TYPE_NONE;
+}
+
+/* Finish SHF_MERGE section merging.  */
+
+bfd_boolean
+_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
+{
+  bfd *ibfd;
+  asection *sec;
+
+  if (!is_elf_hash_table (info->hash))
+    return FALSE;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    if ((ibfd->flags & DYNAMIC) == 0)
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       if ((sec->flags & SEC_MERGE) != 0
+           && !bfd_is_abs_section (sec->output_section))
+         {
+           struct bfd_elf_section_data *secdata;
+
+           secdata = elf_section_data (sec);
+           if (! _bfd_add_merge_section (abfd,
+                                         &elf_hash_table (info)->merge_info,
+                                         sec, &secdata->sec_info))
+             return FALSE;
+           else if (secdata->sec_info)
+             sec->sec_info_type = ELF_INFO_TYPE_MERGE;
+         }
+
+  if (elf_hash_table (info)->merge_info != NULL)
+    _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
+                        merge_sections_remove_hook);
+  return TRUE;
+}
+
+/* Create an entry in an ELF linker hash table.  */
+
+struct bfd_hash_entry *
+_bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
+                           struct bfd_hash_table *table,
+                           const char *string)
+{
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
+      if (entry == NULL)
+       return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = _bfd_link_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry;
+      struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table;
+
+      /* Set local fields.  */
+      ret->indx = -1;
+      ret->dynindx = -1;
+      ret->got = htab->init_got_refcount;
+      ret->plt = htab->init_plt_refcount;
+      memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry)
+                             - offsetof (struct elf_link_hash_entry, size)));
+      /* Assume that we have been called by a non-ELF symbol reader.
+        This flag is then reset by the code which reads an ELF input
+        file.  This ensures that a symbol created by a non-ELF symbol
+        reader will have the flag set correctly.  */
+      ret->non_elf = 1;
+    }
+
+  return entry;
+}
+
+/* Copy data from an indirect symbol to its direct symbol, hiding the
+   old indirect symbol.  Also used for copying flags to a weakdef.  */
+
+void
+_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
+                                 struct elf_link_hash_entry *dir,
+                                 struct elf_link_hash_entry *ind)
+{
+  struct elf_link_hash_table *htab;
+
+  /* Copy down any references that we may have already seen to the
+     symbol which just became indirect.  */
+
+  dir->ref_dynamic |= ind->ref_dynamic;
+  dir->ref_regular |= ind->ref_regular;
+  dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
+  dir->non_got_ref |= ind->non_got_ref;
+  dir->needs_plt |= ind->needs_plt;
+  dir->pointer_equality_needed |= ind->pointer_equality_needed;
+
+  if (ind->root.type != bfd_link_hash_indirect)
+    return;
+
+  /* Copy over the global and procedure linkage table refcount entries.
+     These may have been already set up by a check_relocs routine.  */
+  htab = elf_hash_table (info);
+  if (ind->got.refcount > htab->init_got_refcount.refcount)
+    {
+      if (dir->got.refcount < 0)
+       dir->got.refcount = 0;
+      dir->got.refcount += ind->got.refcount;
+      ind->got.refcount = htab->init_got_refcount.refcount;
+    }
+
+  if (ind->plt.refcount > htab->init_plt_refcount.refcount)
+    {
+      if (dir->plt.refcount < 0)
+       dir->plt.refcount = 0;
+      dir->plt.refcount += ind->plt.refcount;
+      ind->plt.refcount = htab->init_plt_refcount.refcount;
+    }
+
+  if (ind->dynindx != -1)
+    {
+      if (dir->dynindx != -1)
+       _bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index);
+      dir->dynindx = ind->dynindx;
+      dir->dynstr_index = ind->dynstr_index;
+      ind->dynindx = -1;
+      ind->dynstr_index = 0;
+    }
+}
+
+void
+_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
+                               struct elf_link_hash_entry *h,
+                               bfd_boolean force_local)
+{
+  h->plt = elf_hash_table (info)->init_plt_offset;
+  h->needs_plt = 0;
+  if (force_local)
+    {
+      h->forced_local = 1;
+      if (h->dynindx != -1)
+       {
+         h->dynindx = -1;
+         _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                 h->dynstr_index);
+       }
+    }
+}
+
+/* Initialize an ELF linker hash table.  */
 
 
+bfd_boolean
+_bfd_elf_link_hash_table_init
+  (struct elf_link_hash_table *table,
+   bfd *abfd,
+   struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
+                                     struct bfd_hash_table *,
+                                     const char *),
+   unsigned int entsize)
+{
+  bfd_boolean ret;
+  int can_refcount = get_elf_backend_data (abfd)->can_refcount;
+
+  memset (table, 0, sizeof * table);
+  table->init_got_refcount.refcount = can_refcount - 1;
+  table->init_plt_refcount.refcount = can_refcount - 1;
+  table->init_got_offset.offset = -(bfd_vma) 1;
+  table->init_plt_offset.offset = -(bfd_vma) 1;
+  /* The first dynamic symbol is a dummy.  */
+  table->dynsymcount = 1;
+
+  ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
+  table->root.type = bfd_link_elf_hash_table;
+
+  return ret;
+}
+
+/* Create an ELF linker hash table.  */
+
+struct bfd_link_hash_table *
+_bfd_elf_link_hash_table_create (bfd *abfd)
+{
+  struct elf_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct elf_link_hash_table);
+
+  ret = bfd_malloc (amt);
+  if (ret == NULL)
+    return NULL;
+
+  if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc,
+                                      sizeof (struct elf_link_hash_entry)))
+    {
+      free (ret);
+      return NULL;
+    }
+
+  return &ret->root;
+}
+
+/* This is a hook for the ELF emulation code in the generic linker to
+   tell the backend linker what file name to use for the DT_NEEDED
+   entry for a dynamic object.  */
+
+void
+bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
+{
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    elf_dt_name (abfd) = name;
+}
+
+int
+bfd_elf_get_dyn_lib_class (bfd *abfd)
+{
+  int lib_class;
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    lib_class = elf_dyn_lib_class (abfd);
+  else
+    lib_class = 0;
+  return lib_class;
+}
+
+void
+bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class)
+{
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    elf_dyn_lib_class (abfd) = lib_class;
+}
+
+/* Get the list of DT_NEEDED entries for a link.  This is a hook for
+   the linker ELF emulation code.  */
+
+struct bfd_link_needed_list *
+bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
+                        struct bfd_link_info *info)
+{
+  if (! is_elf_hash_table (info->hash))
+    return NULL;
+  return elf_hash_table (info)->needed;
+}
+
+/* Get the list of DT_RPATH/DT_RUNPATH entries for a link.  This is a
+   hook for the linker ELF emulation code.  */
+
+struct bfd_link_needed_list *
+bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED,
+                         struct bfd_link_info *info)
+{
+  if (! is_elf_hash_table (info->hash))
+    return NULL;
+  return elf_hash_table (info)->runpath;
+}
+
+/* Get the name actually used for a dynamic object for a link.  This
+   is the SONAME entry if there is one.  Otherwise, it is the string
+   passed to bfd_elf_set_dt_needed_name, or it is the filename.  */
+
+const char *
+bfd_elf_get_dt_soname (bfd *abfd)
+{
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    return elf_dt_name (abfd);
+  return NULL;
+}
+
+/* Get the list of DT_NEEDED entries from a BFD.  This is a hook for
+   the ELF linker emulation code.  */
+
+bfd_boolean
+bfd_elf_get_bfd_needed_list (bfd *abfd,
+                            struct bfd_link_needed_list **pneeded)
+{
+  asection *s;
+  bfd_byte *dynbuf = NULL;
+  int elfsec;
+  unsigned long shlink;
+  bfd_byte *extdyn, *extdynend;
+  size_t extdynsize;
+  void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
+
+  *pneeded = NULL;
+
+  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour
+      || bfd_get_format (abfd) != bfd_object)
+    return TRUE;
+
+  s = bfd_get_section_by_name (abfd, ".dynamic");
+  if (s == NULL || s->size == 0)
+    return TRUE;
+
+  if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
+    goto error_return;
+
+  elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+  if (elfsec == -1)
+    goto error_return;
+
+  shlink = elf_elfsections (abfd)[elfsec]->sh_link;
+
+  extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
+  swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
+
+  extdyn = dynbuf;
+  extdynend = extdyn + s->size;
+  for (; extdyn < extdynend; extdyn += extdynsize)
+    {
+      Elf_Internal_Dyn dyn;
+
+      (*swap_dyn_in) (abfd, extdyn, &dyn);
+
+      if (dyn.d_tag == DT_NULL)
+       break;
+
+      if (dyn.d_tag == DT_NEEDED)
+       {
+         const char *string;
+         struct bfd_link_needed_list *l;
+         unsigned int tagv = dyn.d_un.d_val;
+         bfd_size_type amt;
+
+         string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+         if (string == NULL)
+           goto error_return;
+
+         amt = sizeof *l;
+         l = bfd_alloc (abfd, amt);
+         if (l == NULL)
+           goto error_return;
+
+         l->by = abfd;
+         l->name = string;
+         l->next = *pneeded;
+         *pneeded = l;
+       }
+    }
+
+  free (dynbuf);
+
+  return TRUE;
+
+ error_return:
+  if (dynbuf != NULL)
+    free (dynbuf);
+  return FALSE;
+}
+
+struct elf_symbuf_symbol
+{
+  unsigned long st_name;       /* Symbol name, index in string tbl */
+  unsigned char st_info;       /* Type and binding attributes */
+  unsigned char st_other;      /* Visibilty, and target specific */
+};
+
+struct elf_symbuf_head
+{
+  struct elf_symbuf_symbol *ssym;
+  bfd_size_type count;
+  unsigned int st_shndx;
+};
+
+struct elf_symbol
+{
+  union
+    {
+      Elf_Internal_Sym *isym;
+      struct elf_symbuf_symbol *ssym;
+    } u;
+  const char *name;
+};
+
+/* Sort references to symbols by ascending section number.  */
+
+static int
+elf_sort_elf_symbol (const void *arg1, const void *arg2)
+{
+  const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
+  const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
+
+  return s1->st_shndx - s2->st_shndx;
+}
+
+static int
+elf_sym_name_compare (const void *arg1, const void *arg2)
+{
+  const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
+  const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
+  return strcmp (s1->name, s2->name);
+}
+
+static struct elf_symbuf_head *
+elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
+{
+  Elf_Internal_Sym **ind, **indbufend, **indbuf
+    = bfd_malloc2 (symcount, sizeof (*indbuf));
+  struct elf_symbuf_symbol *ssym;
+  struct elf_symbuf_head *ssymbuf, *ssymhead;
+  bfd_size_type i, shndx_count;
+
+  if (indbuf == NULL)
+    return NULL;
+
+  for (ind = indbuf, i = 0; i < symcount; i++)
+    if (isymbuf[i].st_shndx != SHN_UNDEF)
+      *ind++ = &isymbuf[i];
+  indbufend = ind;
+
+  qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *),
+        elf_sort_elf_symbol);
+
+  shndx_count = 0;
+  if (indbufend > indbuf)
+    for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++)
+      if (ind[0]->st_shndx != ind[1]->st_shndx)
+       shndx_count++;
+
+  ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
+                       + (indbufend - indbuf) * sizeof (*ssymbuf));
+  if (ssymbuf == NULL)
+    {
+      free (indbuf);
+      return NULL;
+    }
+
+  ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
+  ssymbuf->ssym = NULL;
+  ssymbuf->count = shndx_count;
+  ssymbuf->st_shndx = 0;
+  for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++)
+    {
+      if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx)
+       {
+         ssymhead++;
+         ssymhead->ssym = ssym;
+         ssymhead->count = 0;
+         ssymhead->st_shndx = (*ind)->st_shndx;
+       }
+      ssym->st_name = (*ind)->st_name;
+      ssym->st_info = (*ind)->st_info;
+      ssym->st_other = (*ind)->st_other;
+      ssymhead->count++;
+    }
+  BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
+
+  free (indbuf);
+  return ssymbuf;
+}
+
+/* Check if 2 sections define the same set of local and global
+   symbols.  */
+
+bfd_boolean
+bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
+                                  struct bfd_link_info *info)
+{
+  bfd *bfd1, *bfd2;
+  const struct elf_backend_data *bed1, *bed2;
+  Elf_Internal_Shdr *hdr1, *hdr2;
+  bfd_size_type symcount1, symcount2;
+  Elf_Internal_Sym *isymbuf1, *isymbuf2;
+  struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
+  Elf_Internal_Sym *isym, *isymend;
+  struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
+  bfd_size_type count1, count2, i;
+  int shndx1, shndx2;
+  bfd_boolean result;
+
+  bfd1 = sec1->owner;
+  bfd2 = sec2->owner;
+
+  /* If both are .gnu.linkonce sections, they have to have the same
+     section name.  */
+  if (CONST_STRNEQ (sec1->name, ".gnu.linkonce")
+      && CONST_STRNEQ (sec2->name, ".gnu.linkonce"))
+    return strcmp (sec1->name + sizeof ".gnu.linkonce",
+                  sec2->name + sizeof ".gnu.linkonce") == 0;
+
+  /* Both sections have to be in ELF.  */
+  if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
+      || bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
+    return FALSE;
+
+  if (elf_section_type (sec1) != elf_section_type (sec2))
+    return FALSE;
+
+  if ((elf_section_flags (sec1) & SHF_GROUP) != 0
+      && (elf_section_flags (sec2) & SHF_GROUP) != 0)
+    {
+      /* If both are members of section groups, they have to have the
+        same group name.  */
+      if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
+       return FALSE;
+    }
+
+  shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
+  shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
+  if (shndx1 == -1 || shndx2 == -1)
+    return FALSE;
+
+  bed1 = get_elf_backend_data (bfd1);
+  bed2 = get_elf_backend_data (bfd2);
+  hdr1 = &elf_tdata (bfd1)->symtab_hdr;
+  symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
+  hdr2 = &elf_tdata (bfd2)->symtab_hdr;
+  symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
+
+  if (symcount1 == 0 || symcount2 == 0)
+    return FALSE;
+
+  result = FALSE;
+  isymbuf1 = NULL;
+  isymbuf2 = NULL;
+  ssymbuf1 = elf_tdata (bfd1)->symbuf;
+  ssymbuf2 = elf_tdata (bfd2)->symbuf;
+
+  if (ssymbuf1 == NULL)
+    {
+      isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
+                                      NULL, NULL, NULL);
+      if (isymbuf1 == NULL)
+       goto done;
+
+      if (!info->reduce_memory_overheads)
+       elf_tdata (bfd1)->symbuf = ssymbuf1
+         = elf_create_symbuf (symcount1, isymbuf1);
+    }
+
+  if (ssymbuf1 == NULL || ssymbuf2 == NULL)
+    {
+      isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
+                                      NULL, NULL, NULL);
+      if (isymbuf2 == NULL)
+       goto done;
+
+      if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
+       elf_tdata (bfd2)->symbuf = ssymbuf2
+         = elf_create_symbuf (symcount2, isymbuf2);
+    }
+
+  if (ssymbuf1 != NULL && ssymbuf2 != NULL)
+    {
+      /* Optimized faster version.  */
+      bfd_size_type lo, hi, mid;
+      struct elf_symbol *symp;
+      struct elf_symbuf_symbol *ssym, *ssymend;
+
+      lo = 0;
+      hi = ssymbuf1->count;
+      ssymbuf1++;
+      count1 = 0;
+      while (lo < hi)
+       {
+         mid = (lo + hi) / 2;
+         if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
+           hi = mid;
+         else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
+           lo = mid + 1;
+         else
+           {
+             count1 = ssymbuf1[mid].count;
+             ssymbuf1 += mid;
+             break;
+           }
+       }
+
+      lo = 0;
+      hi = ssymbuf2->count;
+      ssymbuf2++;
+      count2 = 0;
+      while (lo < hi)
+       {
+         mid = (lo + hi) / 2;
+         if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
+           hi = mid;
+         else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
+           lo = mid + 1;
+         else
+           {
+             count2 = ssymbuf2[mid].count;
+             ssymbuf2 += mid;
+             break;
+           }
+       }
+
+      if (count1 == 0 || count2 == 0 || count1 != count2)
+       goto done;
+
+      symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+      symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol));
+      if (symtable1 == NULL || symtable2 == NULL)
+       goto done;
+
+      symp = symtable1;
+      for (ssym = ssymbuf1->ssym, ssymend = ssym + count1;
+          ssym < ssymend; ssym++, symp++)
+       {
+         symp->u.ssym = ssym;
+         symp->name = bfd_elf_string_from_elf_section (bfd1,
+                                                       hdr1->sh_link,
+                                                       ssym->st_name);
+       }
+
+      symp = symtable2;
+      for (ssym = ssymbuf2->ssym, ssymend = ssym + count2;
+          ssym < ssymend; ssym++, symp++)
+       {
+         symp->u.ssym = ssym;
+         symp->name = bfd_elf_string_from_elf_section (bfd2,
+                                                       hdr2->sh_link,
+                                                       ssym->st_name);
+       }
+
+      /* Sort symbol by name.  */
+      qsort (symtable1, count1, sizeof (struct elf_symbol),
+            elf_sym_name_compare);
+      qsort (symtable2, count1, sizeof (struct elf_symbol),
+            elf_sym_name_compare);
+
+      for (i = 0; i < count1; i++)
+       /* Two symbols must have the same binding, type and name.  */
+       if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info
+           || symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other
+           || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
+         goto done;
+
+      result = TRUE;
+      goto done;
+    }
+
+  symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol));
+  symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol));
+  if (symtable1 == NULL || symtable2 == NULL)
+    goto done;
+
+  /* Count definitions in the section.  */
+  count1 = 0;
+  for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
+    if (isym->st_shndx == (unsigned int) shndx1)
+      symtable1[count1++].u.isym = isym;
+
+  count2 = 0;
+  for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
+    if (isym->st_shndx == (unsigned int) shndx2)
+      symtable2[count2++].u.isym = isym;
+
+  if (count1 == 0 || count2 == 0 || count1 != count2)
+    goto done;
+
+  for (i = 0; i < count1; i++)
+    symtable1[i].name
+      = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link,
+                                        symtable1[i].u.isym->st_name);
+
+  for (i = 0; i < count2; i++)
+    symtable2[i].name
+      = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link,
+                                        symtable2[i].u.isym->st_name);
+
+  /* Sort symbol by name.  */
+  qsort (symtable1, count1, sizeof (struct elf_symbol),
+        elf_sym_name_compare);
+  qsort (symtable2, count1, sizeof (struct elf_symbol),
+        elf_sym_name_compare);
+
+  for (i = 0; i < count1; i++)
+    /* Two symbols must have the same binding, type and name.  */
+    if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info
+       || symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other
+       || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
+      goto done;
+
+  result = TRUE;
+
+done:
+  if (symtable1)
+    free (symtable1);
+  if (symtable2)
+    free (symtable2);
+  if (isymbuf1)
+    free (isymbuf1);
+  if (isymbuf2)
+    free (isymbuf2);
+
+  return result;
+}
+
+/* Return TRUE if 2 section types are compatible.  */
+
+bfd_boolean
+_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec,
+                                bfd *bbfd, const asection *bsec)
+{
+  if (asec == NULL
+      || bsec == NULL
+      || abfd->xvec->flavour != bfd_target_elf_flavour
+      || bbfd->xvec->flavour != bfd_target_elf_flavour)
+    return TRUE;
+
+  return elf_section_type (asec) == elf_section_type (bsec);
+}
+\f
 /* Final phase of ELF linker.  */
 
 /* A structure we use to avoid passing large numbers of arguments.  */
 /* Final phase of ELF linker.  */
 
 /* A structure we use to avoid passing large numbers of arguments.  */
@@ -6754,7 +7569,7 @@ evaluate_complex_relocation_symbols (bfd * input_bfd,
        {
          Elf_Internal_Rela * rel;
          char * sym_name;
        {
          Elf_Internal_Rela * rel;
          char * sym_name;
-         unsigned long index;
+         bfd_vma index;
          Elf_Internal_Sym * sym;
          bfd_vma result;
          bfd_vma section_offset;
          Elf_Internal_Sym * sym;
          bfd_vma result;
          bfd_vma section_offset;
@@ -6945,7 +7760,7 @@ bfd_elf_perform_complex_relocation
   Elf_Internal_Shdr * symtab_hdr;
   asection * sec;
   bfd_vma relocation = 0, shift, x;
   Elf_Internal_Shdr * symtab_hdr;
   asection * sec;
   bfd_vma relocation = 0, shift, x;
-  unsigned long r_symndx;
+  bfd_vma r_symndx;
   bfd_vma mask;
   unsigned long start, oplen, len, wordsz, 
     chunksz, lsb0_p, signed_p, trunc_p;
   bfd_vma mask;
   unsigned long start, oplen, len, wordsz, 
     chunksz, lsb0_p, signed_p, trunc_p;
@@ -7189,7 +8004,9 @@ elf_link_sort_cmp2 (const void *A, const void *B)
 static size_t
 elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
 {
 static size_t
 elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
 {
-  asection *reldyn;
+  asection *dynamic_relocs;
+  asection *rela_dyn;
+  asection *rel_dyn;
   bfd_size_type count, size;
   size_t i, ret, sort_elt, ext_size;
   bfd_byte *sort, *s_non_relative, *p;
   bfd_size_type count, size;
   size_t i, ret, sort_elt, ext_size;
   bfd_byte *sort, *s_non_relative, *p;
@@ -7200,39 +8017,170 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
   struct bfd_link_order *lo;
   bfd_vma r_sym_mask;
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
   struct bfd_link_order *lo;
   bfd_vma r_sym_mask;
+  bfd_boolean use_rela;
 
 
-  reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
-  if (reldyn == NULL || reldyn->size == 0)
+  /* Find a dynamic reloc section.  */
+  rela_dyn = bfd_get_section_by_name (abfd, ".rela.dyn");
+  rel_dyn  = bfd_get_section_by_name (abfd, ".rel.dyn");
+  if (rela_dyn != NULL && rela_dyn->size > 0
+      && rel_dyn != NULL && rel_dyn->size > 0)
     {
     {
-      reldyn = bfd_get_section_by_name (abfd, ".rel.dyn");
-      if (reldyn == NULL || reldyn->size == 0)
-       return 0;
-      ext_size = bed->s->sizeof_rel;
-      swap_in = bed->s->swap_reloc_in;
-      swap_out = bed->s->swap_reloc_out;
+      bfd_boolean use_rela_initialised = FALSE;
+
+      /* This is just here to stop gcc from complaining.
+        It's initialization checking code is not perfect.  */
+      use_rela = TRUE;
+
+      /* Both sections are present.  Examine the sizes
+        of the indirect sections to help us choose.  */
+      for (lo = rela_dyn->map_head.link_order; lo != NULL; lo = lo->next)
+       if (lo->type == bfd_indirect_link_order)
+         {
+           asection *o = lo->u.indirect.section;
+
+           if ((o->size % bed->s->sizeof_rela) == 0)
+             {
+               if ((o->size % bed->s->sizeof_rel) == 0)
+                 /* Section size is divisible by both rel and rela sizes.
+                    It is of no help to us.  */
+                 ;
+               else
+                 {
+                   /* Section size is only divisible by rela.  */
+                   if (use_rela_initialised && (use_rela == FALSE))
+                     {
+                       _bfd_error_handler
+                         (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+                       bfd_set_error (bfd_error_invalid_operation);
+                       return 0;
+                     }
+                   else
+                     {
+                       use_rela = TRUE;
+                       use_rela_initialised = TRUE;
+                     }
+                 }
+             }
+           else if ((o->size % bed->s->sizeof_rel) == 0)
+             {
+               /* Section size is only divisible by rel.  */
+               if (use_rela_initialised && (use_rela == TRUE))
+                 {
+                   _bfd_error_handler
+                     (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+                   bfd_set_error (bfd_error_invalid_operation);
+                   return 0;
+                 }
+               else
+                 {
+                   use_rela = FALSE;
+                   use_rela_initialised = TRUE;
+                 }
+             }
+           else
+             {
+               /* The section size is not divisible by either - something is wrong.  */
+               _bfd_error_handler
+                 (_("%B: Unable to sort relocs - they are of an unknown size"), abfd);
+               bfd_set_error (bfd_error_invalid_operation);
+               return 0;
+             }
+         }
+
+      for (lo = rel_dyn->map_head.link_order; lo != NULL; lo = lo->next)
+       if (lo->type == bfd_indirect_link_order)
+         {
+           asection *o = lo->u.indirect.section;
+
+           if ((o->size % bed->s->sizeof_rela) == 0)
+             {
+               if ((o->size % bed->s->sizeof_rel) == 0)
+                 /* Section size is divisible by both rel and rela sizes.
+                    It is of no help to us.  */
+                 ;
+               else
+                 {
+                   /* Section size is only divisible by rela.  */
+                   if (use_rela_initialised && (use_rela == FALSE))
+                     {
+                       _bfd_error_handler
+                         (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+                       bfd_set_error (bfd_error_invalid_operation);
+                       return 0;
+                     }
+                   else
+                     {
+                       use_rela = TRUE;
+                       use_rela_initialised = TRUE;
+                     }
+                 }
+             }
+           else if ((o->size % bed->s->sizeof_rel) == 0)
+             {
+               /* Section size is only divisible by rel.  */
+               if (use_rela_initialised && (use_rela == TRUE))
+                 {
+                   _bfd_error_handler
+                     (_("%B: Unable to sort relocs - they are in more than one size"), abfd);
+                   bfd_set_error (bfd_error_invalid_operation);
+                   return 0;
+                 }
+               else
+                 {
+                   use_rela = FALSE;
+                   use_rela_initialised = TRUE;
+                 }
+             }
+           else
+             {
+               /* The section size is not divisible by either - something is wrong.  */
+               _bfd_error_handler
+                 (_("%B: Unable to sort relocs - they are of an unknown size"), abfd);
+               bfd_set_error (bfd_error_invalid_operation);
+               return 0;
+             }
+         }
+
+      if (! use_rela_initialised)
+       /* Make a guess.  */
+       use_rela = TRUE;
     }
     }
+  else if (rela_dyn != NULL && rela_dyn->size > 0)
+    use_rela = TRUE;
+  else if (rel_dyn != NULL && rel_dyn->size > 0)
+    use_rela = FALSE;
   else
   else
+    return 0;
+
+  if (use_rela)
     {
     {
+      dynamic_relocs = rela_dyn;
       ext_size = bed->s->sizeof_rela;
       swap_in = bed->s->swap_reloca_in;
       swap_out = bed->s->swap_reloca_out;
     }
       ext_size = bed->s->sizeof_rela;
       swap_in = bed->s->swap_reloca_in;
       swap_out = bed->s->swap_reloca_out;
     }
-  count = reldyn->size / ext_size;
+  else
+    {
+      dynamic_relocs = rel_dyn;
+      ext_size = bed->s->sizeof_rel;
+      swap_in = bed->s->swap_reloc_in;
+      swap_out = bed->s->swap_reloc_out;
+    }
 
   size = 0;
 
   size = 0;
-  for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
+  for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next)
     if (lo->type == bfd_indirect_link_order)
     if (lo->type == bfd_indirect_link_order)
-      {
-       asection *o = lo->u.indirect.section;
-       size += o->size;
-      }
+      size += lo->u.indirect.section->size;
 
 
-  if (size != reldyn->size)
+  if (size != dynamic_relocs->size)
     return 0;
 
   sort_elt = (sizeof (struct elf_link_sort_rela)
              + (i2e - 1) * sizeof (Elf_Internal_Rela));
     return 0;
 
   sort_elt = (sizeof (struct elf_link_sort_rela)
              + (i2e - 1) * sizeof (Elf_Internal_Rela));
+
+  count = dynamic_relocs->size / ext_size;
   sort = bfd_zmalloc (sort_elt * count);
   sort = bfd_zmalloc (sort_elt * count);
+
   if (sort == NULL)
     {
       (*info->callbacks->warning)
   if (sort == NULL)
     {
       (*info->callbacks->warning)
@@ -7245,7 +8193,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
   else
     r_sym_mask = ~(bfd_vma) 0xffffffff;
 
   else
     r_sym_mask = ~(bfd_vma) 0xffffffff;
 
-  for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
+  for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next)
     if (lo->type == bfd_indirect_link_order)
       {
        bfd_byte *erel, *erelend;
     if (lo->type == bfd_indirect_link_order)
       {
        bfd_byte *erel, *erelend;
@@ -7262,9 +8210,11 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
        erel = o->contents;
        erelend = o->contents + o->size;
        p = sort + o->output_offset / ext_size * sort_elt;
        erel = o->contents;
        erelend = o->contents + o->size;
        p = sort + o->output_offset / ext_size * sort_elt;
+
        while (erel < erelend)
          {
            struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
        while (erel < erelend)
          {
            struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
+
            (*swap_in) (abfd, erel, s->rela);
            s->type = (*bed->elf_backend_reloc_type_class) (s->rela);
            s->u.sym_mask = r_sym_mask;
            (*swap_in) (abfd, erel, s->rela);
            s->type = (*bed->elf_backend_reloc_type_class) (s->rela);
            s->u.sym_mask = r_sym_mask;
@@ -7295,7 +8245,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
 
   qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2);
 
 
   qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2);
 
-  for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next)
+  for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next)
     if (lo->type == bfd_indirect_link_order)
       {
        bfd_byte *erel, *erelend;
     if (lo->type == bfd_indirect_link_order)
       {
        bfd_byte *erel, *erelend;
@@ -7314,7 +8264,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
       }
 
   free (sort);
       }
 
   free (sort);
-  *psec = reldyn;
+  *psec = dynamic_relocs;
   return ret;
 }
 
   return ret;
 }
 
@@ -8032,7 +8982,7 @@ _bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info)
 static bfd_boolean
 elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 {
 static bfd_boolean
 elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 {
-  bfd_boolean (*relocate_section)
+  int (*relocate_section)
     (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
      Elf_Internal_Rela *, Elf_Internal_Sym *, asection **);
   bfd *output_bfd;
     (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
      Elf_Internal_Rela *, Elf_Internal_Sym *, asection **);
   bfd *output_bfd;
@@ -8046,7 +8996,6 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
   asection **ppsection;
   asection *o;
   const struct elf_backend_data *bed;
   asection **ppsection;
   asection *o;
   const struct elf_backend_data *bed;
-  bfd_boolean emit_relocs;
   struct elf_link_hash_entry **sym_hashes;
 
   output_bfd = finfo->output_bfd;
   struct elf_link_hash_entry **sym_hashes;
 
   output_bfd = finfo->output_bfd;
@@ -8059,9 +9008,6 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
   if ((input_bfd->flags & DYNAMIC) != 0)
     return TRUE;
 
   if ((input_bfd->flags & DYNAMIC) != 0)
     return TRUE;
 
-  emit_relocs = (finfo->info->relocatable
-                || finfo->info->emitrelocations);
-
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   if (elf_bad_symtab (input_bfd))
     {
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   if (elf_bad_symtab (input_bfd))
     {
@@ -8277,6 +9223,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
          Elf_Internal_Rela *internal_relocs;
          bfd_vma r_type_mask;
          int r_sym_shift;
          Elf_Internal_Rela *internal_relocs;
          bfd_vma r_type_mask;
          int r_sym_shift;
+         int ret;
 
          /* Get the swapped relocs.  */
          internal_relocs
 
          /* Get the swapped relocs.  */
          internal_relocs
@@ -8390,16 +9337,6 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                              continue;
                            }
                        }
                              continue;
                            }
                        }
-
-                     /* Remove the symbol reference from the reloc, but
-                        don't kill the reloc completely.  This is so that
-                        a zero value will be written into the section,
-                        which may have non-zero contents put there by the
-                        assembler.  Zero in things like an eh_frame fde
-                        pc_begin allows stack unwinders to recognize the
-                        fde as bogus.  */
-                     rel->r_info &= r_type_mask;
-                     rel->r_addend = 0;
                    }
                }
            }
                    }
                }
            }
@@ -8424,14 +9361,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.  */
 
-         if (! (*relocate_section) (output_bfd, finfo->info,
+         ret = (*relocate_section) (output_bfd, finfo->info,
                                     input_bfd, o, contents,
                                     internal_relocs,
                                     isymbuf,
                                     input_bfd, o, contents,
                                     internal_relocs,
                                     isymbuf,
-                                    finfo->sections))
+                                    finfo->sections);
+         if (!ret)
            return FALSE;
 
            return FALSE;
 
-         if (emit_relocs)
+         if (ret == 2
+             || finfo->info->relocatable
+             || finfo->info->emitrelocations)
            {
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend;
            {
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend;
@@ -8553,8 +9493,10 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
                          /* If we have discarded a section, the output
                             section will be the absolute section.  In
 
                          /* If we have discarded a section, the output
                             section will be the absolute section.  In
-                            case of discarded link-once and discarded
-                            SEC_MERGE sections, use the kept section.  */
+                            case of discarded SEC_MERGE sections, use
+                            the kept section.  relocate_section should
+                            have already handled discarded linkonce
+                            sections.  */
                          if (bfd_is_abs_section (osec)
                              && sec->kept_section != NULL
                              && sec->kept_section->output_section != NULL)
                          if (bfd_is_abs_section (osec)
                              && sec->kept_section != NULL
                              && sec->kept_section->output_section != NULL)
@@ -9062,6 +10004,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   size_t relativecount = 0;
   asection *reldyn = 0;
   bfd_size_type amt;
   size_t relativecount = 0;
   asection *reldyn = 0;
   bfd_size_type amt;
+  asection *attr_section = NULL;
+  bfd_vma attr_size = 0;
+  const char *std_attrs_section;
 
   if (! is_elf_hash_table (info->hash))
     return FALSE;
 
   if (! is_elf_hash_table (info->hash))
     return FALSE;
@@ -9109,6 +10054,40 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   finfo.symbuf_count = 0;
   finfo.shndxbuf_size = 0;
 
   finfo.symbuf_count = 0;
   finfo.shndxbuf_size = 0;
 
+  /* The object attributes have been merged.  Remove the input
+     sections from the link, and set the contents of the output
+     secton.  */
+  std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section;
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if ((std_attrs_section && strcmp (o->name, std_attrs_section) == 0)
+         || strcmp (o->name, ".gnu.attributes") == 0)
+       {
+         for (p = o->map_head.link_order; p != NULL; p = p->next)
+           {
+             asection *input_section;
+
+             if (p->type != bfd_indirect_link_order)
+               continue;
+             input_section = p->u.indirect.section;
+             /* Hack: reset the SEC_HAS_CONTENTS flag so that
+                elf_link_input_bfd ignores this section.  */
+             input_section->flags &= ~SEC_HAS_CONTENTS;
+           }
+           
+         attr_size = bfd_elf_obj_attr_size (abfd);
+         if (attr_size)
+           {
+             bfd_set_section_size (abfd, o, attr_size);
+             attr_section = o;
+             /* Skip this section later on.  */
+             o->map_head.link_order = NULL;
+           }
+         else
+           o->flags |= SEC_EXCLUDE;
+       }
+    }
+
   /* Count up the number of relocations we will output for each output
      section, so that we know the sizes of the reloc sections.  We
      also figure out some maximum sizes.  */
   /* Count up the number of relocations we will output for each output
      section, so that we know the sizes of the reloc sections.  We
      also figure out some maximum sizes.  */
@@ -9154,13 +10133,18 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                {
                  Elf_Internal_Rela * relocs;
 
                {
                  Elf_Internal_Rela * relocs;
 
-                 relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+                 relocs = _bfd_elf_link_read_relocs (sec->owner, sec,
+                                                     NULL, NULL,
                                                      info->keep_memory);
 
                                                      info->keep_memory);
 
-                 reloc_count = (*bed->elf_backend_count_relocs) (sec, relocs);
+                 if (relocs != NULL)
+                   {
+                     reloc_count
+                       = (*bed->elf_backend_count_relocs) (sec, relocs);
 
 
-                 if (elf_section_data (o)->relocs != relocs)
-                   free (relocs);
+                     if (elf_section_data (sec)->relocs != relocs)
+                       free (relocs);
+                   }
                }
 
              if (sec->rawsize > max_contents_size)
                }
 
              if (sec->rawsize > max_contents_size)
@@ -9537,7 +10521,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (!info->reduce_memory_overheads)
     {
       for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
   if (!info->reduce_memory_overheads)
     {
       for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
-       if (elf_tdata (sub)->symbuf)
+       if (bfd_get_flavour (sub) == bfd_target_elf_flavour
+           && elf_tdata (sub)->symbuf)
          {
            free (elf_tdata (sub)->symbuf);
            elf_tdata (sub)->symbuf = NULL;
          {
            free (elf_tdata (sub)->symbuf);
            elf_tdata (sub)->symbuf = NULL;
@@ -9948,8 +10933,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              if (dyn.d_tag == DT_TEXTREL)
                {
 
              if (dyn.d_tag == DT_TEXTREL)
                {
-                 _bfd_error_handler
-                   (_("warning: creating a DT_TEXTREL in a shared object."));
+                info->callbacks->einfo 
+                   (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
                  break;
                }
            }
                  break;
                }
            }
@@ -10047,6 +11032,16 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   elf_tdata (abfd)->linker = TRUE;
 
 
   elf_tdata (abfd)->linker = TRUE;
 
+  if (attr_section)
+    {
+      bfd_byte *contents = bfd_malloc (attr_size);
+      if (contents == NULL)
+       return FALSE;   /* Bail out and fail.  */
+      bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
+      bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
+      free (contents);
+    }
+
   return TRUE;
 
  error_return:
   return TRUE;
 
  error_return:
@@ -10084,10 +11079,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 \f
 /* Garbage collect unused sections.  */
 
 \f
 /* Garbage collect unused sections.  */
 
-typedef asection * (*gc_mark_hook_fn)
-  (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
-   struct elf_link_hash_entry *, Elf_Internal_Sym *);
-
 /* Default gc_mark_hook.  */
 
 asection *
 /* Default gc_mark_hook.  */
 
 asection *
@@ -10125,7 +11116,7 @@ _bfd_elf_gc_mark_hook (asection *sec,
 bfd_boolean
 _bfd_elf_gc_mark (struct bfd_link_info *info,
                  asection *sec,
 bfd_boolean
 _bfd_elf_gc_mark (struct bfd_link_info *info,
                  asection *sec,
-                 gc_mark_hook_fn gc_mark_hook)
+                 elf_gc_mark_hook_fn gc_mark_hook)
 {
   bfd_boolean ret;
   bfd_boolean is_eh;
 {
   bfd_boolean ret;
   bfd_boolean is_eh;
@@ -10310,7 +11301,7 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
             to remove a section from the output.  */
          o->flags |= SEC_EXCLUDE;
 
             to remove a section from the output.  */
          o->flags |= SEC_EXCLUDE;
 
-         if (info->print_gc_sections == TRUE)
+         if (info->print_gc_sections && o->size != 0)
            _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name);
 
          /* But we also have to update some of the relocation
            _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name);
 
          /* But we also have to update some of the relocation
@@ -10494,9 +11485,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
 {
   bfd_boolean ok = TRUE;
   bfd *sub;
 {
   bfd_boolean ok = TRUE;
   bfd *sub;
-  asection * (*gc_mark_hook)
-    (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
-     struct elf_link_hash_entry *h, Elf_Internal_Sym *);
+  elf_gc_mark_hook_fn gc_mark_hook;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (!bed->can_gc_sections
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (!bed->can_gc_sections
@@ -10543,6 +11532,10 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
            return FALSE;
     }
 
            return FALSE;
     }
 
+  /* Allow the backend to mark additional target specific sections.  */
+  if (bed->gc_mark_extra_sections)
+    bed->gc_mark_extra_sections(info, gc_mark_hook);
+
   /* ... again for sections marked from eh_frame.  */
   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
   /* ... again for sections marked from eh_frame.  */
   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
@@ -10990,7 +11983,10 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
                                                 cookie.locsymcount, 0,
                                                 NULL, NULL, NULL);
          if (cookie.locsyms == NULL)
                                                 cookie.locsymcount, 0,
                                                 NULL, NULL, NULL);
          if (cookie.locsyms == NULL)
-           return FALSE;
+           {
+             info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
+             return FALSE;
+           }
        }
 
       if (stab != NULL)
        }
 
       if (stab != NULL)
@@ -11239,7 +12235,8 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section *sec,
        }
 
   /* This is the first section with this name.  Record it.  */
        }
 
   /* This is the first section with this name.  Record it.  */
-  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"));
 }
 
 bfd_boolean
 }
 
 bfd_boolean
This page took 0.046384 seconds and 4 git commands to generate.