Automatic date update in version.in
[platform/upstream/binutils.git] / bfd / elflink.c
index 47e4802..c8068c0 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linking support for BFD.
-   Copyright 1995-2013 Free Software Foundation, Inc.
+   Copyright (C) 1995-2014 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -851,47 +851,26 @@ _bfd_elf_link_renumber_dynsyms (bfd *output_bfd,
 
 static void
 elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
-                   Elf_Internal_Sym *isym, bfd_boolean definition,
-                   bfd_boolean dynamic)
+                   const Elf_Internal_Sym *isym,
+                   bfd_boolean definition, bfd_boolean dynamic)
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   /* If st_other has a processor-specific meaning, specific
-     code might be needed here. We never merge the visibility
-     attribute with the one from a dynamic object.  */
+     code might be needed here.  */
   if (bed->elf_backend_merge_symbol_attribute)
     (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
                                                dynamic);
 
-  /* If this symbol has default visibility and the user has requested
-     we not re-export it, then mark it as hidden.  */
-  if (definition
-      && !dynamic
-      && (abfd->no_export
-         || (abfd->my_archive && abfd->my_archive->no_export))
-      && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
-    isym->st_other = (STV_HIDDEN
-                     | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
-
-  if (!dynamic && ELF_ST_VISIBILITY (isym->st_other) != 0)
-    {
-      unsigned char hvis, symvis, other, nvis;
-
-      /* Only merge the visibility. Leave the remainder of the
-        st_other field to elf_backend_merge_symbol_attribute.  */
-      other = h->other & ~ELF_ST_VISIBILITY (-1);
-
-      /* Combine visibilities, using the most constraining one.  */
-      hvis = ELF_ST_VISIBILITY (h->other);
-      symvis = ELF_ST_VISIBILITY (isym->st_other);
-      if (! hvis)
-       nvis = symvis;
-      else if (! symvis)
-       nvis = hvis;
-      else
-       nvis = hvis < symvis ? hvis : symvis;
+  if (!dynamic)
+    {
+      unsigned symvis = ELF_ST_VISIBILITY (isym->st_other);
+      unsigned hvis = ELF_ST_VISIBILITY (h->other);
 
-      h->other = other | nvis;
+      /* Keep the most constraining visibility.  Leave the remainder
+        of the st_other field to elf_backend_merge_symbol_attribute.  */
+      if (symvis - 1 < hvis - 1)
+       h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1));
     }
 }
 
@@ -1105,15 +1084,14 @@ _bfd_elf_merge_symbol (bfd *abfd,
       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".  */
-  else if (oldbfd != NULL
-          && ELF_ST_TYPE (sym->st_info) != h->type
-          && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS))
+  /* Check TLS symbols.  We don't check undefined symbols introduced
+     by "ld -u" which have no type (and oldbfd NULL), and we don't
+     check symbols from plugins because they also have no type.  */
+  if (oldbfd != NULL
+      && (oldbfd->flags & BFD_PLUGIN) == 0
+      && (abfd->flags & BFD_PLUGIN) == 0
+      && 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;
@@ -1745,7 +1723,7 @@ nondefault:
   size_change_ok = FALSE;
   tmp_sec = sec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
-                             &hi, NULL, NULL, NULL, &skip, &override,
+                             &hi, poldbfd, NULL, NULL, &skip, &override,
                              &type_change_ok, &size_change_ok))
     return FALSE;
 
@@ -2953,13 +2931,6 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
   if (! bfd_check_format (abfd, bfd_object))
     return FALSE;
 
-  /* If we have already included the element containing this symbol in the
-     link then we do not need to include it again.  Just claim that any symbol
-     it contains is not a definition, so that our caller will not decide to
-     (re)include this element.  */
-  if (abfd->archive_pass)
-    return FALSE;
-
   /* Select the appropriate symbol table.  */
   if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
     hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -3115,7 +3086,8 @@ static bfd_boolean
 on_needed_list (const char *soname, struct bfd_link_needed_list *needed)
 {
   for (; needed != NULL; needed = needed->next)
-    if (strcmp (soname, needed->name) == 0)
+    if ((elf_dyn_lib_class (needed->by) & DYN_AS_NEEDED) == 0
+       && strcmp (soname, needed->name) == 0)
       return TRUE;
 
   return FALSE;
@@ -3328,7 +3300,7 @@ _bfd_elf_notice_as_needed (bfd *ibfd,
                           struct bfd_link_info *info,
                           enum notice_asneeded_action act)
 {
-  return (*info->callbacks->notice) (info, NULL, ibfd, NULL, act, 0, NULL);
+  return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
 }
 
 /* Add symbols from an ELF object file to the linker hash table.  */
@@ -3367,6 +3339,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   bfd_size_type old_dynstr_size = 0;
   size_t tabsize = 0;
   asection *s;
+  bfd_boolean just_syms;
 
   htab = elf_hash_table (info);
   bed = get_elf_backend_data (abfd);
@@ -3470,15 +3443,20 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
        }
     }
 
+  just_syms = ((s = abfd->sections) != NULL
+              && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS);
+
   add_needed = TRUE;
   if (! dynamic)
     {
       /* If we are creating a shared library, create all the dynamic
         sections immediately.  We need to attach them to something,
         so we attach them to this BFD, provided it is the right
-        format.  FIXME: If there are no input BFD's of the same
-        format as the output, we can't make a shared library.  */
-      if (info->shared
+        format and is not from ld --just-symbols.  FIXME: If there
+        are no input BFD's of the same format as the output, we can't
+        make a shared library.  */
+      if (!just_syms
+         && info->shared
          && is_elf_hash_table (htab)
          && info->output_bfd->xvec == abfd->xvec
          && !htab->dynamic_sections_created)
@@ -3498,8 +3476,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
-         && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+      if (just_syms)
        abort ();
 
       /* If this dynamic lib was specified on the command line with
@@ -4096,6 +4073,16 @@ error_free_dyn:
              name = newname;
            }
 
+         /* If this symbol has default visibility and the user has
+            requested we not re-export it, then mark it as hidden.  */
+         if (definition
+             && !dynamic
+             && (abfd->no_export
+                 || (abfd->my_archive && abfd->my_archive->no_export))
+             && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
+           isym->st_other = (STV_HIDDEN
+                             | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
+
          if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
                                      sym_hash, &old_bfd, &old_weak,
                                      &old_alignment, &skip, &override,
@@ -4940,20 +4927,8 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd,
 }
 
 /* Add symbols from an ELF archive file to the linker hash table.  We
-   don't use _bfd_generic_link_add_archive_symbols because of a
-   problem which arises on UnixWare.  The UnixWare libc.so is an
-   archive which includes an entry libc.so.1 which defines a bunch of
-   symbols.  The libc.so archive also includes a number of other
-   object files, which also define symbols, some of which are the same
-   as those defined in libc.so.1.  Correct linking requires that we
-   consider each object file in turn, and include it if it defines any
-   symbols we need.  _bfd_generic_link_add_archive_symbols does not do
-   this; it looks through the list of undefined symbols, and includes
-   any object file which defines them.  When this algorithm is used on
-   UnixWare, it winds up pulling in libc.so.1 early and defining a
-   bunch of symbols.  This means that some of the other objects in the
-   archive are not included in the link, which is incorrect since they
-   precede libc.so.1 in the archive.
+   don't use _bfd_generic_link_add_archive_symbols because we need to
+   handle versioned symbols.
 
    Fortunately, ELF archive handling is simpler than that done by
    _bfd_generic_link_add_archive_symbols, which has to allow for a.out
@@ -4968,8 +4943,7 @@ static bfd_boolean
 elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
 {
   symindex c;
-  bfd_boolean *defined = NULL;
-  bfd_boolean *included = NULL;
+  unsigned char *included = NULL;
   carsym *symdefs;
   bfd_boolean loop;
   bfd_size_type amt;
@@ -4993,11 +4967,10 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
   if (c == 0)
     return TRUE;
   amt = c;
-  amt *= sizeof (bfd_boolean);
-  defined = (bfd_boolean *) bfd_zmalloc (amt);
-  included = (bfd_boolean *) bfd_zmalloc (amt);
-  if (defined == NULL || included == NULL)
-    goto error_return;
+  amt *= sizeof (*included);
+  included = (unsigned char *) bfd_zmalloc (amt);
+  if (included == NULL)
+    return FALSE;
 
   symdefs = bfd_ardata (abfd)->symdefs;
   bed = get_elf_backend_data (abfd);
@@ -5022,7 +4995,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
          struct bfd_link_hash_entry *undefs_tail;
          symindex mark;
 
-         if (defined[i] || included[i])
+         if (included[i])
            continue;
          if (symdef->file_offset == last)
            {
@@ -5057,7 +5030,8 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
          else if (h->root.type != bfd_link_hash_undefined)
            {
              if (h->root.type != bfd_link_hash_undefweak)
-               defined[i] = TRUE;
+               /* Symbol must be defined.  Don't check it again.  */
+               included[i] = TRUE;
              continue;
            }
 
@@ -5069,16 +5043,6 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
          if (! bfd_check_format (element, bfd_object))
            goto error_return;
 
-         /* Doublecheck that we have not included this object
-            already--it should be impossible, but there may be
-            something wrong with the archive.  */
-         if (element->archive_pass != 0)
-           {
-             bfd_set_error (bfd_error_bad_value);
-             goto error_return;
-           }
-         element->archive_pass = 1;
-
          undefs_tail = info->hash->undefs_tail;
 
          if (!(*info->callbacks
@@ -5116,14 +5080,11 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
     }
   while (loop);
 
-  free (defined);
   free (included);
 
   return TRUE;
 
  error_return:
-  if (defined != NULL)
-    free (defined);
   if (included != NULL)
     free (included);
   return FALSE;
@@ -5489,7 +5450,7 @@ _bfd_elf_size_group_sections (struct bfd_link_info *info)
 {
   bfd *ibfd;
 
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour
        && !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr))
       return FALSE;
@@ -5616,7 +5577,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       for (inputobj = info->input_bfds;
           inputobj;
-          inputobj = inputobj->link_next)
+          inputobj = inputobj->link.next)
        {
          asection *s;
 
@@ -5882,7 +5843,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
              asection *o;
 
              for (sub = info->input_bfds; sub != NULL;
-                  sub = sub->link_next)
+                  sub = sub->link.next)
                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
@@ -6712,7 +6673,7 @@ _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
   if (!is_elf_hash_table (info->hash))
     return FALSE;
 
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  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
@@ -6902,6 +6863,7 @@ _bfd_elf_link_hash_table_create (bfd *abfd)
       free (ret);
       return NULL;
     }
+  ret->root.hash_table_free = _bfd_elf_link_hash_table_free;
 
   return &ret->root;
 }
@@ -6909,13 +6871,15 @@ _bfd_elf_link_hash_table_create (bfd *abfd)
 /* Destroy an ELF linker hash table.  */
 
 void
-_bfd_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
+_bfd_elf_link_hash_table_free (bfd *obfd)
 {
-  struct elf_link_hash_table *htab = (struct elf_link_hash_table *) hash;
+  struct elf_link_hash_table *htab;
+
+  htab = (struct elf_link_hash_table *) obfd->link.hash;
   if (htab->dynstr != NULL)
     _bfd_elf_strtab_free (htab->dynstr);
   _bfd_merge_sections_free (htab->merge_info);
-  _bfd_generic_link_hash_table_free (hash);
+  _bfd_generic_link_hash_table_free (obfd);
 }
 
 /* This is a hook for the ELF emulation code in the generic linker to
@@ -10727,12 +10691,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       esdo->rela.count = 0;
     }
 
-  _bfd_elf_assign_file_positions_for_relocs (abfd);
-
   /* We have now assigned file positions for all the sections except
-     .symtab and .strtab.  We start the .symtab section at the current
-     file position, and write directly to it.  We build the .strtab
-     section in memory.  */
+     .symtab, .strtab, and non-loaded reloc sections.  We start the
+     .symtab section at the current file position, and write directly
+     to it.  We build the .strtab section in memory.  */
   bfd_get_symcount (abfd) = 0;
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   /* sh_name is set in prep_headers.  */
@@ -10930,7 +10892,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
      we could write the relocs out and then read them again; I don't
      know how bad the memory loss will be.  */
 
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     sub->output_has_begun = FALSE;
   for (o = abfd->sections; o != NULL; o = o->next)
     {
@@ -10992,7 +10954,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   /* Free symbol buffer if needed.  */
   if (!info->reduce_memory_overheads)
     {
-      for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+      for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
        if (bfd_get_flavour (sub) == bfd_target_elf_flavour
            && elf_tdata (sub)->symbuf)
          {
@@ -11678,7 +11640,7 @@ _bfd_elf_gc_mark_hook (asection *sec,
            {
              bfd *i;
 
-             for (i = info->input_bfds; i; i = i->link_next)
+             for (i = info->input_bfds; i; i = i->link.next)
                {
                  sec = bfd_get_section_by_name (i, sec_name);
                  if (sec)
@@ -11827,7 +11789,7 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
 {
   bfd *ibfd;
 
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       asection *isec;
       bfd_boolean some_kept;
@@ -11955,7 +11917,7 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
   unsigned long section_sym_count;
   struct elf_gc_sweep_symbol_info sweep_info;
 
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     {
       asection *o;
 
@@ -12195,6 +12157,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
   bfd *sub;
   elf_gc_mark_hook_fn gc_mark_hook;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct elf_link_hash_table *htab;
 
   if (!bed->can_gc_sections
       || !is_elf_hash_table (info->hash))
@@ -12204,11 +12167,11 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
     }
 
   bed->gc_keep (info);
+  htab = elf_hash_table (info);
 
   /* Try to parse each bfd's .eh_frame section.  Point elf_eh_frame_section
      at the .eh_frame section if we can mark the FDEs individually.  */
-  _bfd_elf_begin_eh_frame_parsing (info);
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     {
       asection *sec;
       struct elf_reloc_cookie cookie;
@@ -12224,31 +12187,24 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
          sec = bfd_get_next_section_by_name (sec);
        }
     }
-  _bfd_elf_end_eh_frame_parsing (info);
 
   /* Apply transitive closure to the vtable entry usage info.  */
-  elf_link_hash_traverse (elf_hash_table (info),
-                         elf_gc_propagate_vtable_entries_used,
-                         &ok);
+  elf_link_hash_traverse (htab, elf_gc_propagate_vtable_entries_used, &ok);
   if (!ok)
     return FALSE;
 
   /* Kill the vtable relocations that were not used.  */
-  elf_link_hash_traverse (elf_hash_table (info),
-                         elf_gc_smash_unused_vtentry_relocs,
-                         &ok);
+  elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok);
   if (!ok)
     return FALSE;
 
   /* Mark dynamically referenced symbols.  */
-  if (elf_hash_table (info)->dynamic_sections_created)
-    elf_link_hash_traverse (elf_hash_table (info),
-                           bed->gc_mark_dynamic_ref,
-                           info);
+  if (htab->dynamic_sections_created)
+    elf_link_hash_traverse (htab, bed->gc_mark_dynamic_ref, info);
 
   /* Grovel through relocs to find out who stays ...  */
   gc_mark_hook = bed->gc_mark_hook;
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     {
       asection *o;
 
@@ -12557,7 +12513,7 @@ bfd_elf_gc_common_finalize_got_offsets (bfd *abfd,
     gotoff = bed->got_header_size;
 
   /* Do the local .got entries first.  */
-  for (i = info->input_bfds; i; i = i->link_next)
+  for (i = info->input_bfds; i; i = i->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_size_type j, locsymcount;
@@ -12646,10 +12602,10 @@ 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)
-             && discarded_section (h->root.u.def.section))
+             && (h->root.u.def.section->owner != rcookie->abfd
+                 || h->root.u.def.section->kept_section != NULL
+                 || discarded_section (h->root.u.def.section)))
            return TRUE;
-         else
-           return FALSE;
        }
       else
        {
@@ -12662,7 +12618,9 @@ 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);
-         if (isec != NULL && discarded_section (isec))
+         if (isec != NULL
+             && (isec->kept_section != NULL
+                 || discarded_section (isec)))
            return TRUE;
        }
       return FALSE;
@@ -12671,94 +12629,105 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
 }
 
 /* Discard unneeded references to discarded sections.
-   Returns TRUE if any section's size was changed.  */
-/* This function assumes that the relocations are in sorted order,
-   which is true for all known assemblers.  */
+   Returns -1 on error, 1 if any section's size was changed, 0 if
+   nothing changed.  This function assumes that the relocations are in
+   sorted order, which is true for all known assemblers.  */
 
-bfd_boolean
+int
 bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 {
   struct elf_reloc_cookie cookie;
-  asection *stab, *eh;
-  const struct elf_backend_data *bed;
+  asection *o;
   bfd *abfd;
-  bfd_boolean ret = FALSE;
+  int changed = 0;
 
   if (info->traditional_format
       || !is_elf_hash_table (info->hash))
-    return FALSE;
+    return 0;
 
-  _bfd_elf_begin_eh_frame_parsing (info);
-  for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+  o = bfd_get_section_by_name (output_bfd, ".stab");
+  if (o != NULL)
     {
-      if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
-       continue;
+      asection *i;
 
-      bed = get_elf_backend_data (abfd);
-
-      eh = NULL;
-      if (!info->relocatable)
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
        {
-         eh = bfd_get_section_by_name (abfd, ".eh_frame");
-         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->sec_info_type != SEC_INFO_TYPE_STABS))
-       stab = NULL;
+         if (i->size == 0
+             || i->reloc_count == 0
+             || i->sec_info_type != SEC_INFO_TYPE_STABS)
+           continue;
 
-      if (stab == NULL
-         && eh == NULL
-         && bed->elf_backend_discard_info == NULL)
-       continue;
+         abfd = i->owner;
+         if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+           continue;
 
-      if (!init_reloc_cookie (&cookie, info, abfd))
-       return FALSE;
+         if (!init_reloc_cookie_for_section (&cookie, info, i))
+           return -1;
 
-      if (stab != NULL
-         && stab->reloc_count > 0
-         && init_reloc_cookie_rels (&cookie, info, abfd, stab))
-       {
-         if (_bfd_discard_section_stabs (abfd, stab,
-                                         elf_section_data (stab)->sec_info,
+         if (_bfd_discard_section_stabs (abfd, i,
+                                         elf_section_data (i)->sec_info,
                                          bfd_elf_reloc_symbol_deleted_p,
                                          &cookie))
-           ret = TRUE;
-         fini_reloc_cookie_rels (&cookie, stab);
+           changed = 1;
+
+         fini_reloc_cookie_for_section (&cookie, i);
        }
+    }
 
-      while (eh != NULL
-            && init_reloc_cookie_rels (&cookie, info, abfd, eh))
+  o = bfd_get_section_by_name (output_bfd, ".eh_frame");
+  if (o != NULL)
+    {
+      asection *i;
+
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
        {
-         _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
-         if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
+         if (i->size == 0)
+           continue;
+
+         abfd = i->owner;
+         if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+           continue;
+
+         if (!init_reloc_cookie_for_section (&cookie, info, i))
+           return -1;
+
+         _bfd_elf_parse_eh_frame (abfd, info, i, &cookie);
+         if (_bfd_elf_discard_section_eh_frame (abfd, info, i,
                                                 bfd_elf_reloc_symbol_deleted_p,
                                                 &cookie))
-           ret = TRUE;
-         fini_reloc_cookie_rels (&cookie, eh);
-         eh = bfd_get_next_section_by_name (eh);
+           changed = 1;
+
+         fini_reloc_cookie_for_section (&cookie, i);
        }
+    }
 
-      if (bed->elf_backend_discard_info != NULL
-         && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
-       ret = TRUE;
+  for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
+    {
+      const struct elf_backend_data *bed;
+
+      if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+       continue;
 
-      fini_reloc_cookie (&cookie, abfd);
+      bed = get_elf_backend_data (abfd);
+
+      if (bed->elf_backend_discard_info != NULL)
+       {
+         if (!init_reloc_cookie (&cookie, info, abfd))
+           return -1;
+
+         if ((*bed->elf_backend_discard_info) (abfd, &cookie, info))
+           changed = 1;
+
+         fini_reloc_cookie (&cookie, abfd);
+       }
     }
-  _bfd_elf_end_eh_frame_parsing (info);
 
   if (info->eh_frame_hdr
       && !info->relocatable
       && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info))
-    ret = TRUE;
+    changed = 1;
 
-  return ret;
+  return changed;
 }
 
 bfd_boolean
@@ -13042,17 +13011,24 @@ _bfd_elf_make_dynamic_reloc_section (asection *         sec,
   return reloc_sec;
 }
 
-/* Copy the ELF symbol type associated with a linker hash entry.  */
+/* Copy the ELF symbol type and other attributes for a linker script
+   assignment from HSRC to HDEST.  Generally this should be treated as
+   if we found a strong non-dynamic definition for HDEST (except that
+   ld ignores multiple definition errors).  */
 void
-_bfd_elf_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED,
-    struct bfd_link_hash_entry * hdest,
-    struct bfd_link_hash_entry * hsrc)
+_bfd_elf_copy_link_hash_symbol_type (bfd *abfd,
+                                    struct bfd_link_hash_entry *hdest,
+                                    struct bfd_link_hash_entry *hsrc)
 {
-  struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *)hdest;
-  struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc;
+  struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *) hdest;
+  struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *) hsrc;
+  Elf_Internal_Sym isym;
 
   ehdest->type = ehsrc->type;
   ehdest->target_internal = ehsrc->target_internal;
+
+  isym.st_other = ehsrc->other;
+  elf_merge_st_other (abfd, ehdest, &isym, TRUE, FALSE);
 }
 
 /* Append a RELA relocation REL to section S in BFD.  */