Fix LTO vs. COFF archives
[deliverable/binutils-gdb.git] / bfd / linker.c
index 5868b955d1379d47a4422ac7733ae05f416fa67e..a31e473417175aa07ac702ec5b42827f8dabc7c2 100644 (file)
@@ -1,13 +1,12 @@
 /* linker.c -- BFD linker routines
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1993-2014 Free Software Foundation, Inc.
    Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
 
    This file is part of BFD, the Binary File Descriptor library.
 
    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,
 
    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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
 #include "bfdlink.h"
 #include "genlink.h"
@@ -149,9 +149,9 @@ SUBSUBSECTION
 
        Sometimes the <<_bfd_link_add_symbols>> function must store
        some information in the hash table entry to be used by the
-       <<_bfd_final_link>> function.  In such a case the <<creator>>
-       field of the hash table must be checked to make sure that the
-       hash table was created by an object file of the same format.
+       <<_bfd_final_link>> function.  In such a case the output bfd
+       xvec must be checked to make sure that the hash table was
+       created by an object file of the same format.
 
        The <<_bfd_final_link>> routine must be prepared to handle a
        hash entry without any extra information added by the
@@ -163,7 +163,7 @@ SUBSUBSECTION
        initialization function.
 
        See <<ecoff_link_add_externals>> for an example of how to
-       check the <<creator>> field before saving information (in this
+       check the output bfd before saving information (in this
        case, the ECOFF external symbol debugging information) in a
        hash table entry.
 
@@ -221,27 +221,22 @@ SUBSUBSECTION
        archive and decide which elements of the archive should be
        included in the link.  For each such element it must call the
        <<add_archive_element>> linker callback, and it must add the
-       symbols from the object file to the linker hash table.
+       symbols from the object file to the linker hash table.  (The
+       callback may in fact indicate that a replacement BFD should be
+       used, in which case the symbols from that BFD should be added
+       to the linker hash table instead.)
 
 @findex _bfd_generic_link_add_archive_symbols
        In most cases the work of looking through the symbols in the
        archive should be done by the
-       <<_bfd_generic_link_add_archive_symbols>> function.  This
-       function builds a hash table from the archive symbol table and
-       looks through the list of undefined symbols to see which
-       elements should be included.
+       <<_bfd_generic_link_add_archive_symbols>> function.
        <<_bfd_generic_link_add_archive_symbols>> is passed a function
        to call to make the final decision about adding an archive
        element to the link and to do the actual work of adding the
-       symbols to the linker hash table.
-
-       The function passed to
-       <<_bfd_generic_link_add_archive_symbols>> must read the
-       symbols of the archive element and decide whether the archive
-       element should be included in the link.  If the element is to
+       symbols to the linker hash table.  If the element is to
        be included, the <<add_archive_element>> linker callback
        routine must be called with the element as an argument, and
-       the elements symbols must be added to the linker hash table
+       the element's symbols must be added to the linker hash table
        just as though the element had itself been passed to the
        <<_bfd_link_add_symbols>> function.
 
@@ -255,7 +250,8 @@ SUBSUBSECTION
        symbol) it calls the <<add_archive_element>> callback and then
        <<aout_link_check_archive_element>> calls
        <<aout_link_add_symbols>> to actually add the symbols to the
-       linker hash table.
+       linker hash table - possibly those of a substitute BFD, if the
+       <<add_archive_element>> callback avails itself of that option.
 
        The ECOFF back end is unusual in that it does not normally
        call <<_bfd_generic_link_add_archive_symbols>>, because ECOFF
@@ -305,11 +301,11 @@ SUBSUBSECTION
 
        The <<input_bfds>> field of the <<bfd_link_info>> structure
        will point to a list of all the input files included in the
-       link.  These files are linked through the <<link_next>> field
+       link.  These files are linked through the <<link.next>> field
        of the <<bfd>> structure.
 
        Each section in the output file will have a list of
-       <<link_order>> structures attached to the <<link_order_head>>
+       <<link_order>> structures attached to the <<map_head.link_order>>
        field (the <<link_order>> structure is defined in
        <<bfdlink.h>>).  These structures describe how to create the
        contents of the output section in terms of the contents of
@@ -411,11 +407,14 @@ static bfd_boolean generic_link_add_object_symbols
 static bfd_boolean generic_link_add_symbols
   (bfd *, struct bfd_link_info *, bfd_boolean);
 static bfd_boolean generic_link_check_archive_element_no_collect
-  (bfd *, struct bfd_link_info *, bfd_boolean *);
+  (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
+   bfd_boolean *);
 static bfd_boolean generic_link_check_archive_element_collect
-  (bfd *, struct bfd_link_info *, bfd_boolean *);
+  (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
+   bfd_boolean *);
 static bfd_boolean generic_link_check_archive_element
-  (bfd *, struct bfd_link_info *, bfd_boolean *, bfd_boolean);
+  (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
+   bfd_boolean *, bfd_boolean);
 static bfd_boolean generic_link_add_symbol_list
   (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
    bfd_boolean);
@@ -442,7 +441,8 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry,
      subclass.  */
   if (entry == NULL)
     {
-      entry = bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
+      entry = (struct bfd_hash_entry *)
+          bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
       if (entry == NULL)
        return entry;
     }
@@ -454,8 +454,8 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry,
       struct bfd_link_hash_entry *h = (struct bfd_link_hash_entry *) entry;
 
       /* Initialize the local fields.  */
-      h->type = bfd_link_hash_new;
-      h->u.undef.next = NULL;
+      memset ((char *) &h->root + sizeof (h->root), 0,
+             sizeof (*h) - sizeof (h->root));
     }
 
   return entry;
@@ -467,17 +467,28 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry,
 bfd_boolean
 _bfd_link_hash_table_init
   (struct bfd_link_hash_table *table,
-   bfd *abfd,
+   bfd *abfd ATTRIBUTE_UNUSED,
    struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
                                      struct bfd_hash_table *,
-                                     const char *))
+                                     const char *),
+   unsigned int entsize)
 {
-  table->creator = abfd->xvec;
+  bfd_boolean ret;
+
+  BFD_ASSERT (!abfd->is_linker_output && !abfd->link.hash);
   table->undefs = NULL;
   table->undefs_tail = NULL;
   table->type = bfd_link_generic_hash_table;
 
-  return bfd_hash_table_init (&table->table, newfunc);
+  ret = bfd_hash_table_init (&table->table, newfunc, entsize);
+  if (ret)
+    {
+      /* Arrange for destruction of this hash table on closing ABFD.  */
+      table->hash_table_free = _bfd_generic_link_hash_table_free;
+      abfd->link.hash = table;
+      abfd->is_linker_output = TRUE;
+    }
+  return ret;
 }
 
 /* Look up a symbol in a link hash table.  If follow is TRUE, we
@@ -544,7 +555,7 @@ bfd_wrapped_link_hash_lookup (bfd *abfd,
              references to SYM with references to __wrap_SYM.  */
 
          amt = strlen (l) + sizeof WRAP + 1;
-         n = bfd_malloc (amt);
+         n = (char *) bfd_malloc (amt);
          if (n == NULL)
            return NULL;
 
@@ -557,13 +568,11 @@ bfd_wrapped_link_hash_lookup (bfd *abfd,
          return h;
        }
 
-#undef WRAP
-
-#undef REAL
+#undef  REAL
 #define REAL "__real_"
 
       if (*l == '_'
-         && strncmp (l, REAL, sizeof REAL - 1) == 0
+         && CONST_STRNEQ (l, REAL)
          && bfd_hash_lookup (info->wrap_hash, l + sizeof REAL - 1,
                              FALSE, FALSE) != NULL)
        {
@@ -575,7 +584,7 @@ bfd_wrapped_link_hash_lookup (bfd *abfd,
              with references to SYM.  */
 
          amt = strlen (l + sizeof REAL - 1) + 2;
-         n = bfd_malloc (amt);
+         n = (char *) bfd_malloc (amt);
          if (n == NULL)
            return NULL;
 
@@ -593,21 +602,68 @@ bfd_wrapped_link_hash_lookup (bfd *abfd,
   return bfd_link_hash_lookup (info->hash, string, create, copy, follow);
 }
 
-/* Traverse a generic link hash table.  The only reason this is not a
-   macro is to do better type checking.  This code presumes that an
-   argument passed as a struct bfd_hash_entry * may be caught as a
-   struct bfd_link_hash_entry * with no explicit cast required on the
-   call.  */
+/* If H is a wrapped symbol, ie. the symbol name starts with "__wrap_"
+   and the remainder is found in wrap_hash, return the real symbol.  */
+
+struct bfd_link_hash_entry *
+unwrap_hash_lookup (struct bfd_link_info *info,
+                   bfd *input_bfd,
+                   struct bfd_link_hash_entry *h)
+{
+  const char *l = h->root.string;
+
+  if (*l == bfd_get_symbol_leading_char (input_bfd)
+      || *l == info->wrap_char)
+    ++l;
+
+  if (CONST_STRNEQ (l, WRAP))
+    {
+      l += sizeof WRAP - 1;
+
+      if (bfd_hash_lookup (info->wrap_hash, l, FALSE, FALSE) != NULL)
+       {
+         char save = 0;
+         if (l - (sizeof WRAP - 1) != h->root.string)
+           {
+             --l;
+             save = *l;
+             *(char *) l = *h->root.string;
+           }
+         h = bfd_link_hash_lookup (info->hash, l, FALSE, FALSE, FALSE);
+         if (save)
+           *(char *) l = save;
+       }
+    }
+  return h;
+}
+#undef WRAP
+
+/* Traverse a generic link hash table.  Differs from bfd_hash_traverse
+   in the treatment of warning symbols.  When warning symbols are
+   created they replace the real symbol, so you don't get to see the
+   real symbol in a bfd_hash_travere.  This traversal calls func with
+   the real symbol.  */
 
 void
 bfd_link_hash_traverse
-  (struct bfd_link_hash_table *table,
+  (struct bfd_link_hash_table *htab,
    bfd_boolean (*func) (struct bfd_link_hash_entry *, void *),
    void *info)
 {
-  bfd_hash_traverse (&table->table,
-                    (bfd_boolean (*) (struct bfd_hash_entry *, void *)) func,
-                    info);
+  unsigned int i;
+
+  htab->table.frozen = 1;
+  for (i = 0; i < htab->table.size; i++)
+    {
+      struct bfd_link_hash_entry *p;
+
+      p = (struct bfd_link_hash_entry *) htab->table.table[i];
+      for (; p != NULL; p = (struct bfd_link_hash_entry *) p->root.next)
+       if (!(*func) (p->type == bfd_link_hash_warning ? p->u.i.link : p, info))
+         goto out;
+    }
+ out:
+  htab->table.frozen = 0;
 }
 
 /* Add a symbol to the linker hash table undefs list.  */
@@ -674,7 +730,7 @@ _bfd_generic_link_hash_newfunc (struct bfd_hash_entry *entry,
      subclass.  */
   if (entry == NULL)
     {
-      entry =
+      entry = (struct bfd_hash_entry *)
        bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry));
       if (entry == NULL)
        return entry;
@@ -703,11 +759,12 @@ _bfd_generic_link_hash_table_create (bfd *abfd)
   struct generic_link_hash_table *ret;
   bfd_size_type amt = sizeof (struct generic_link_hash_table);
 
-  ret = bfd_malloc (amt);
+  ret = (struct generic_link_hash_table *) bfd_malloc (amt);
   if (ret == NULL)
     return NULL;
   if (! _bfd_link_hash_table_init (&ret->root, abfd,
-                                  _bfd_generic_link_hash_newfunc))
+                                  _bfd_generic_link_hash_newfunc,
+                                  sizeof (struct generic_link_hash_entry)))
     {
       free (ret);
       return NULL;
@@ -716,13 +773,16 @@ _bfd_generic_link_hash_table_create (bfd *abfd)
 }
 
 void
-_bfd_generic_link_hash_table_free (struct bfd_link_hash_table *hash)
+_bfd_generic_link_hash_table_free (bfd *obfd)
 {
-  struct generic_link_hash_table *ret
-    = (struct generic_link_hash_table *) hash;
+  struct generic_link_hash_table *ret;
 
+  BFD_ASSERT (obfd->is_linker_output && obfd->link.hash);
+  ret = (struct generic_link_hash_table *) obfd->link.hash;
   bfd_hash_table_free (&ret->root.table);
   free (ret);
+  obfd->link.hash = NULL;
+  obfd->is_linker_output = FALSE;
 }
 
 /* Grab the symbols for an object file when doing a generic link.  We
@@ -732,8 +792,8 @@ _bfd_generic_link_hash_table_free (struct bfd_link_hash_table *hash)
    the hash table pointing to different instances of the symbol
    structure.  */
 
-static bfd_boolean
-generic_link_read_symbols (bfd *abfd)
+bfd_boolean
+bfd_generic_link_read_symbols (bfd *abfd)
 {
   if (bfd_get_outsymbols (abfd) == NULL)
     {
@@ -743,7 +803,8 @@ generic_link_read_symbols (bfd *abfd)
       symsize = bfd_get_symtab_upper_bound (abfd);
       if (symsize < 0)
        return FALSE;
-      bfd_get_outsymbols (abfd) = bfd_alloc (abfd, symsize);
+      bfd_get_outsymbols (abfd) = (struct bfd_symbol **) bfd_alloc (abfd,
+                                                                    symsize);
       if (bfd_get_outsymbols (abfd) == NULL && symsize != 0)
        return FALSE;
       symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd));
@@ -786,10 +847,21 @@ void
 _bfd_generic_link_just_syms (asection *sec,
                             struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
+  sec->sec_info_type = SEC_INFO_TYPE_JUST_SYMS;
   sec->output_section = bfd_abs_section_ptr;
   sec->output_offset = sec->vma;
 }
 
+/* Copy the symbol type and other attributes for a linker script
+   assignment from HSRC to HDEST.
+   The default implementation does nothing.  */
+void
+_bfd_generic_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED,
+    struct bfd_link_hash_entry *hdest ATTRIBUTE_UNUSED,
+    struct bfd_link_hash_entry *hsrc ATTRIBUTE_UNUSED)
+{
+}
+
 /* Add symbols from an object file to the global hash table.  */
 
 static bfd_boolean
@@ -829,141 +901,39 @@ generic_link_add_object_symbols (bfd *abfd,
   bfd_size_type symcount;
   struct bfd_symbol **outsyms;
 
-  if (! generic_link_read_symbols (abfd))
+  if (!bfd_generic_link_read_symbols (abfd))
     return FALSE;
   symcount = _bfd_generic_link_get_symcount (abfd);
   outsyms = _bfd_generic_link_get_symbols (abfd);
   return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect);
 }
 \f
-/* We build a hash table of all symbols defined in an archive.  */
-
-/* An archive symbol may be defined by multiple archive elements.
-   This linked list is used to hold the elements.  */
-
-struct archive_list
-{
-  struct archive_list *next;
-  unsigned int indx;
-};
-
-/* An entry in an archive hash table.  */
-
-struct archive_hash_entry
-{
-  struct bfd_hash_entry root;
-  /* Where the symbol is defined.  */
-  struct archive_list *defs;
-};
-
-/* An archive hash table itself.  */
-
-struct archive_hash_table
-{
-  struct bfd_hash_table table;
-};
-
-/* Create a new entry for an archive hash table.  */
-
-static struct bfd_hash_entry *
-archive_hash_newfunc (struct bfd_hash_entry *entry,
-                     struct bfd_hash_table *table,
-                     const char *string)
-{
-  struct archive_hash_entry *ret = (struct archive_hash_entry *) entry;
-
-  /* Allocate the structure if it has not already been allocated by a
-     subclass.  */
-  if (ret == NULL)
-    ret = bfd_hash_allocate (table, sizeof (struct archive_hash_entry));
-  if (ret == NULL)
-    return NULL;
-
-  /* Call the allocation method of the superclass.  */
-  ret = ((struct archive_hash_entry *)
-        bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
-
-  if (ret)
-    {
-      /* Initialize the local fields.  */
-      ret->defs = NULL;
-    }
-
-  return &ret->root;
-}
-
-/* Initialize an archive hash table.  */
-
-static bfd_boolean
-archive_hash_table_init
-  (struct archive_hash_table *table,
-   struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
-                                     struct bfd_hash_table *,
-                                     const char *))
-{
-  return bfd_hash_table_init (&table->table, newfunc);
-}
-
-/* Look up an entry in an archive hash table.  */
-
-#define archive_hash_lookup(t, string, create, copy) \
-  ((struct archive_hash_entry *) \
-   bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
-
-/* Allocate space in an archive hash table.  */
-
-#define archive_hash_allocate(t, size) bfd_hash_allocate (&(t)->table, (size))
-
-/* Free an archive hash table.  */
-
-#define archive_hash_table_free(t) bfd_hash_table_free (&(t)->table)
-
 /* Generic function to add symbols from an archive file to the global
    hash file.  This function presumes that the archive symbol table
    has already been read in (this is normally done by the
-   bfd_check_format entry point).  It looks through the undefined and
-   common symbols and searches the archive symbol table for them.  If
-   it finds an entry, it includes the associated object file in the
-   link.
-
-   The old linker looked through the archive symbol table for
-   undefined symbols.  We do it the other way around, looking through
-   undefined symbols for symbols defined in the archive.  The
-   advantage of the newer scheme is that we only have to look through
-   the list of undefined symbols once, whereas the old method had to
-   re-search the symbol table each time a new object file was added.
-
-   The CHECKFN argument is used to see if an object file should be
-   included.  CHECKFN should set *PNEEDED to TRUE if the object file
-   should be included, and must also call the bfd_link_info
-   add_archive_element callback function and handle adding the symbols
-   to the global hash table.  CHECKFN should only return FALSE if some
-   sort of error occurs.
-
-   For some formats, such as a.out, it is possible to look through an
-   object file but not actually include it in the link.  The
-   archive_pass field in a BFD is used to avoid checking the symbols
-   of an object files too many times.  When an object is included in
-   the link, archive_pass is set to -1.  If an object is scanned but
-   not included, archive_pass is set to the pass number.  The pass
-   number is incremented each time a new object file is included.  The
-   pass number is used because when a new object file is included it
-   may create new undefined symbols which cause a previously examined
-   object file to be included.  */
+   bfd_check_format entry point).  It looks through the archive symbol
+   table for symbols that are undefined or common in the linker global
+   symbol hash table.  When one is found, the CHECKFN argument is used
+   to see if an object file should be included.  This allows targets
+   to customize common symbol behaviour.  CHECKFN should set *PNEEDED
+   to TRUE if the object file should be included, and must also call
+   the bfd_link_info add_archive_element callback function and handle
+   adding the symbols to the global hash table.  CHECKFN must notice
+   if the callback indicates a substitute BFD, and arrange to add
+   those symbols instead if it does so.  CHECKFN should only return
+   FALSE if some sort of error occurs.  */
 
 bfd_boolean
 _bfd_generic_link_add_archive_symbols
   (bfd *abfd,
    struct bfd_link_info *info,
-   bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *, bfd_boolean *))
+   bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *,
+                          struct bfd_link_hash_entry *, const char *,
+                          bfd_boolean *))
 {
-  carsym *arsyms;
-  carsym *arsym_end;
-  register carsym *arsym;
-  int pass;
-  struct archive_hash_table arsym_hash;
-  unsigned int indx;
-  struct bfd_link_hash_entry **pundef;
+  bfd_boolean loop;
+  bfd_size_type amt;
+  unsigned char *included;
 
   if (! bfd_has_map (abfd))
     {
@@ -974,147 +944,103 @@ _bfd_generic_link_add_archive_symbols
       return FALSE;
     }
 
-  arsyms = bfd_ardata (abfd)->symdefs;
-  arsym_end = arsyms + bfd_ardata (abfd)->symdef_count;
-
-  /* In order to quickly determine whether an symbol is defined in
-     this archive, we build a hash table of the symbols.  */
-  if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc))
+  amt = bfd_ardata (abfd)->symdef_count;
+  if (amt == 0)
+    return TRUE;
+  amt *= sizeof (*included);
+  included = (unsigned char *) bfd_zmalloc (amt);
+  if (included == NULL)
     return FALSE;
-  for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
-    {
-      struct archive_hash_entry *arh;
-      struct archive_list *l, **pp;
 
-      arh = archive_hash_lookup (&arsym_hash, arsym->name, TRUE, FALSE);
-      if (arh == NULL)
-       goto error_return;
-      l = ((struct archive_list *)
-          archive_hash_allocate (&arsym_hash, sizeof (struct archive_list)));
-      if (l == NULL)
-       goto error_return;
-      l->indx = indx;
-      for (pp = &arh->defs; *pp != NULL; pp = &(*pp)->next)
-       ;
-      *pp = l;
-      l->next = NULL;
-    }
-
-  /* The archive_pass field in the archive itself is used to
-     initialize PASS, sine we may search the same archive multiple
-     times.  */
-  pass = abfd->archive_pass + 1;
-
-  /* New undefined symbols are added to the end of the list, so we
-     only need to look through it once.  */
-  pundef = &info->hash->undefs;
-  while (*pundef != NULL)
+  do
     {
-      struct bfd_link_hash_entry *h;
-      struct archive_hash_entry *arh;
-      struct archive_list *l;
-
-      h = *pundef;
-
-      /* When a symbol is defined, it is not necessarily removed from
-        the list.  */
-      if (h->type != bfd_link_hash_undefined
-         && h->type != bfd_link_hash_common)
+      carsym *arsyms;
+      carsym *arsym_end;
+      carsym *arsym;
+      unsigned int indx;
+      file_ptr last_ar_offset = -1;
+      bfd_boolean needed = FALSE;
+      bfd *element = NULL;
+
+      loop = FALSE;
+      arsyms = bfd_ardata (abfd)->symdefs;
+      arsym_end = arsyms + bfd_ardata (abfd)->symdef_count;
+      for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
        {
-         /* Remove this entry from the list, for general cleanliness
-            and because we are going to look through the list again
-            if we search any more libraries.  We can't remove the
-            entry if it is the tail, because that would lose any
-            entries we add to the list later on (it would also cause
-            us to lose track of whether the symbol has been
-            referenced).  */
-         if (*pundef != info->hash->undefs_tail)
-           *pundef = (*pundef)->u.undef.next;
-         else
-           pundef = &(*pundef)->u.undef.next;
-         continue;
-       }
-
-      /* Look for this symbol in the archive symbol map.  */
-      arh = archive_hash_lookup (&arsym_hash, h->root.string, FALSE, FALSE);
-      if (arh == NULL)
-       {
-         /* If we haven't found the exact symbol we're looking for,
-            let's look for its import thunk */
-         if (info->pei386_auto_import)
-           {
-             bfd_size_type amt = strlen (h->root.string) + 10;
-             char *buf = bfd_malloc (amt);
-             if (buf == NULL)
-               return FALSE;
+         struct bfd_link_hash_entry *h;
+         struct bfd_link_hash_entry *undefs_tail;
 
-             sprintf (buf, "__imp_%s", h->root.string);
-             arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE);
-             free(buf);
-           }
-         if (arh == NULL)
+         if (included[indx])
+           continue;
+         if (needed && arsym->file_offset == last_ar_offset)
            {
-             pundef = &(*pundef)->u.undef.next;
+             included[indx] = 1;
              continue;
            }
-       }
-      /* Look at all the objects which define this symbol.  */
-      for (l = arh->defs; l != NULL; l = l->next)
-       {
-         bfd *element;
-         bfd_boolean needed;
-
-         /* If the symbol has gotten defined along the way, quit.  */
-         if (h->type != bfd_link_hash_undefined
-             && h->type != bfd_link_hash_common)
-           break;
 
-         element = bfd_get_elt_at_index (abfd, l->indx);
-         if (element == NULL)
-           goto error_return;
+         h = bfd_link_hash_lookup (info->hash, arsym->name,
+                                   FALSE, FALSE, TRUE);
 
-         /* If we've already included this element, or if we've
-            already checked it on this pass, continue.  */
-         if (element->archive_pass == -1
-             || element->archive_pass == pass)
+         if (h == NULL
+             && info->pei386_auto_import
+             && CONST_STRNEQ (arsym->name, "__imp_"))
+           h = bfd_link_hash_lookup (info->hash, arsym->name + 6,
+                                     FALSE, FALSE, TRUE);
+         if (h == NULL)
            continue;
 
-         /* If we can't figure this element out, just ignore it.  */
-         if (! bfd_check_format (element, bfd_object))
+         if (h->type != bfd_link_hash_undefined
+             && h->type != bfd_link_hash_common)
            {
-             element->archive_pass = -1;
+             if (h->type != bfd_link_hash_undefweak)
+               /* Symbol must be defined.  Don't check it again.  */
+               included[indx] = 1;
              continue;
            }
 
+         if (last_ar_offset != arsym->file_offset)
+           {
+             last_ar_offset = arsym->file_offset;
+             element = _bfd_get_elt_at_filepos (abfd, last_ar_offset);
+             if (element == NULL
+                 || !bfd_check_format (element, bfd_object))
+               goto error_return;
+           }
+
+         undefs_tail = info->hash->undefs_tail;
+
          /* CHECKFN will see if this element should be included, and
             go ahead and include it if appropriate.  */
-         if (! (*checkfn) (element, info, &needed))
+         if (! (*checkfn) (element, info, h, arsym->name, &needed))
            goto error_return;
 
-         if (! needed)
-           element->archive_pass = pass;
-         else
+         if (needed)
            {
-             element->archive_pass = -1;
+             unsigned int mark;
+
+             /* Look backward to mark all symbols from this object file
+                which we have already seen in this pass.  */
+             mark = indx;
+             do
+               {
+                 included[mark] = 1;
+                 if (mark == 0)
+                   break;
+                 --mark;
+               }
+             while (arsyms[mark].file_offset == last_ar_offset);
 
-             /* Increment the pass count to show that we may need to
-                recheck object files which were already checked.  */
-             ++pass;
+             if (undefs_tail != info->hash->undefs_tail)
+               loop = TRUE;
            }
        }
+    } while (loop);
 
-      pundef = &(*pundef)->u.undef.next;
-    }
-
-  archive_hash_table_free (&arsym_hash);
-
-  /* Save PASS in case we are called again.  */
-  abfd->archive_pass = pass;
-
+  free (included);
   return TRUE;
 
  error_return:
-  archive_hash_table_free (&arsym_hash);
+  free (included);
   return FALSE;
 }
 \f
@@ -1124,12 +1050,14 @@ _bfd_generic_link_add_archive_symbols
    for finding them.  */
 
 static bfd_boolean
-generic_link_check_archive_element_no_collect (
-                                              bfd *abfd,
+generic_link_check_archive_element_no_collect (bfd *abfd,
                                               struct bfd_link_info *info,
+                                              struct bfd_link_hash_entry *h,
+                                              const char *name,
                                               bfd_boolean *pneeded)
 {
-  return generic_link_check_archive_element (abfd, info, pneeded, FALSE);
+  return generic_link_check_archive_element (abfd, info, h, name, pneeded,
+                                            FALSE);
 }
 
 /* See if we should include an archive element.  This version is used
@@ -1139,9 +1067,12 @@ generic_link_check_archive_element_no_collect (
 static bfd_boolean
 generic_link_check_archive_element_collect (bfd *abfd,
                                            struct bfd_link_info *info,
+                                           struct bfd_link_hash_entry *h,
+                                           const char *name,
                                            bfd_boolean *pneeded)
 {
-  return generic_link_check_archive_element (abfd, info, pneeded, TRUE);
+  return generic_link_check_archive_element (abfd, info, h, name, pneeded,
+                                            TRUE);
 }
 
 /* See if we should include an archive element.  Optionally collect
@@ -1150,6 +1081,8 @@ generic_link_check_archive_element_collect (bfd *abfd,
 static bfd_boolean
 generic_link_check_archive_element (bfd *abfd,
                                    struct bfd_link_info *info,
+                                   struct bfd_link_hash_entry *h,
+                                   const char *name ATTRIBUTE_UNUSED,
                                    bfd_boolean *pneeded,
                                    bfd_boolean collect)
 {
@@ -1157,7 +1090,7 @@ generic_link_check_archive_element (bfd *abfd,
 
   *pneeded = FALSE;
 
-  if (! generic_link_read_symbols (abfd))
+  if (!bfd_generic_link_read_symbols (abfd))
     return FALSE;
 
   pp = _bfd_generic_link_get_symbols (abfd);
@@ -1165,7 +1098,6 @@ generic_link_check_archive_element (bfd *abfd,
   for (; pp < ppend; pp++)
     {
       asymbol *p;
-      struct bfd_link_hash_entry *h;
 
       p = *pp;
 
@@ -1192,10 +1124,17 @@ generic_link_check_archive_element (bfd *abfd,
        {
          bfd_size_type symcount;
          asymbol **symbols;
+         bfd *oldbfd = abfd;
 
          /* This object file defines this symbol, so pull it in.  */
-         if (! (*info->callbacks->add_archive_element) (info, abfd,
-                                                        bfd_asymbol_name (p)))
+         if (!(*info->callbacks
+               ->add_archive_element) (info, abfd, bfd_asymbol_name (p),
+                                       &abfd))
+           return FALSE;
+         /* Potentially, the add_archive_element hook may have set a
+            substitute BFD for us.  */
+         if (abfd != oldbfd
+             && !bfd_generic_link_read_symbols (abfd))
            return FALSE;
          symcount = _bfd_generic_link_get_symcount (abfd);
          symbols = _bfd_generic_link_get_symbols (abfd);
@@ -1220,9 +1159,13 @@ generic_link_check_archive_element (bfd *abfd,
              /* This symbol was created as undefined from outside
                 BFD.  We assume that we should link in the object
                 file.  This is for the -u option in the linker.  */
-             if (! (*info->callbacks->add_archive_element)
-                 (info, abfd, bfd_asymbol_name (p)))
+             if (!(*info->callbacks
+                   ->add_archive_element) (info, abfd, bfd_asymbol_name (p),
+                                           &abfd))
                return FALSE;
+             /* Potentially, the add_archive_element hook may have set a
+                substitute BFD for us.  But no symbols are going to get
+                registered by anything we're returning to from here.  */
              *pneeded = TRUE;
              return TRUE;
            }
@@ -1235,7 +1178,7 @@ generic_link_check_archive_element (bfd *abfd,
             attached to symbfd to ensure that it is in a BFD which
             will be linked in.  */
          h->type = bfd_link_hash_common;
-         h->u.c.p =
+         h->u.c.p = (struct bfd_link_hash_common_entry *)
            bfd_hash_allocate (&info->hash->table,
                               sizeof (struct bfd_link_hash_common_entry));
          if (h->u.c.p == NULL)
@@ -1254,7 +1197,7 @@ generic_link_check_archive_element (bfd *abfd,
          else
            h->u.c.p->section = bfd_make_section_old_way (symbfd,
                                                          p->section->name);
-         h->u.c.p->section->flags = SEC_ALLOC;
+         h->u.c.p->section->flags |= SEC_ALLOC;
        }
       else
        {
@@ -1308,7 +1251,7 @@ generic_link_add_symbol_list (bfd *abfd,
          struct generic_link_hash_entry *h;
          struct bfd_link_hash_entry *bh;
 
-         name = bfd_asymbol_name (p);
+         string = name = bfd_asymbol_name (p);
          if (((p->flags & BSF_INDIRECT) != 0
               || bfd_is_ind_section (p->section))
              && pp + 1 < ppend)
@@ -1321,12 +1264,9 @@ generic_link_add_symbol_list (bfd *abfd,
            {
              /* The name of P is actually the warning string, and the
                 next symbol is the one to warn about.  */
-             string = name;
              pp++;
              name = bfd_asymbol_name (*pp);
            }
-         else
-           string = NULL;
 
          bh = NULL;
          if (! (_bfd_generic_link_add_one_symbol
@@ -1354,7 +1294,7 @@ generic_link_add_symbol_list (bfd *abfd,
             hash table other than the generic hash table, so we only
             do this if we are certain that the hash table is a
             generic one.  */
-         if (info->hash->creator == abfd->xvec)
+         if (info->output_bfd->xvec == abfd->xvec)
            {
              if (h->sym == NULL
                  || (! bfd_is_und_section (bfd_get_section (p))
@@ -1529,6 +1469,8 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
   struct bfd_link_hash_entry *h;
   bfd_boolean cycle;
 
+  BFD_ASSERT (section != NULL);
+
   if (bfd_is_ind_section (section)
       || (flags & BSF_INDIRECT) != 0)
     row = INDR_ROW;
@@ -1546,7 +1488,13 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
   else if ((flags & BSF_WEAK) != 0)
     row = DEFW_ROW;
   else if (bfd_is_com_section (section))
-    row = COMMON_ROW;
+    {
+      row = COMMON_ROW;
+      if (strcmp (name, "__gnu_lto_slim") == 0)
+       (*_bfd_error_handler)
+         (_("%s: plugin needed to handle lto object"),
+          bfd_get_filename (abfd));
+    }
   else
     row = DEF_ROW;
 
@@ -1570,8 +1518,8 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
       || (info->notice_hash != NULL
          && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL))
     {
-      if (! (*info->callbacks->notice) (info, h->root.string, abfd, section,
-                                       value))
+      if (! (*info->callbacks->notice) (info, h,
+                                       abfd, section, value, flags, string))
        return FALSE;
     }
 
@@ -1604,7 +1552,6 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
          /* Make a new weak undefined symbol.  */
          h->type = bfd_link_hash_undefweak;
          h->u.undef.abfd = abfd;
-         h->u.undef.weak = abfd;
          break;
 
        case CDEF:
@@ -1612,9 +1559,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
             previously common.  */
          BFD_ASSERT (h->type == bfd_link_hash_common);
          if (! ((*info->callbacks->multiple_common)
-                (info, h->root.string,
-                 h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
-                 abfd, bfd_link_hash_defined, 0)))
+                (info, h, abfd, bfd_link_hash_defined, 0)))
            return FALSE;
          /* Fall through.  */
        case DEF:
@@ -1653,8 +1598,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
                s = name + 1;
                while (*s == '_')
                  ++s;
-               if (s[0] == 'G'
-                   && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0)
+               if (s[0] == 'G' && CONST_STRNEQ (s, CONS_PREFIX))
                  {
                    char c;
 
@@ -1688,7 +1632,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
          if (h->type == bfd_link_hash_new)
            bfd_link_add_undef (info->hash, h);
          h->type = bfd_link_hash_common;
-         h->u.c.p =
+         h->u.c.p = (struct bfd_link_hash_common_entry *)
            bfd_hash_allocate (&info->hash->table,
                               sizeof (struct bfd_link_hash_common_entry));
          if (h->u.c.p == NULL)
@@ -1720,13 +1664,13 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
          if (section == bfd_com_section_ptr)
            {
              h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON");
-             h->u.c.p->section->flags = SEC_ALLOC;
+             h->u.c.p->section->flags |= SEC_ALLOC;
            }
          else if (section->owner != abfd)
            {
              h->u.c.p->section = bfd_make_section_old_way (abfd,
                                                            section->name);
-             h->u.c.p->section->flags = SEC_ALLOC;
+             h->u.c.p->section->flags |= SEC_ALLOC;
            }
          else
            h->u.c.p->section = section;
@@ -1744,9 +1688,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
             two sizes, and use the section required by the larger symbol.  */
          BFD_ASSERT (h->type == bfd_link_hash_common);
          if (! ((*info->callbacks->multiple_common)
-                (info, h->root.string,
-                 h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
-                 abfd, bfd_link_hash_common, value)))
+                (info, h, abfd, bfd_link_hash_common, value)))
            return FALSE;
          if (value > h->u.c.size)
            {
@@ -1769,13 +1711,13 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
                {
                  h->u.c.p->section
                    = bfd_make_section_old_way (abfd, "COMMON");
-                 h->u.c.p->section->flags = SEC_ALLOC;
+                 h->u.c.p->section->flags |= SEC_ALLOC;
                }
              else if (section->owner != abfd)
                {
                  h->u.c.p->section
                    = bfd_make_section_old_way (abfd, section->name);
-                 h->u.c.p->section->flags = SEC_ALLOC;
+                 h->u.c.p->section->flags |= SEC_ALLOC;
                }
              else
                h->u.c.p->section = section;
@@ -1783,23 +1725,11 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
          break;
 
        case CREF:
-         {
-           bfd *obfd;
-
-           /* We have found a common definition for a symbol which
-              was already defined.  FIXME: It would nice if we could
-              report the BFD which defined an indirect symbol, but we
-              don't have anywhere to store the information.  */
-           if (h->type == bfd_link_hash_defined
-               || h->type == bfd_link_hash_defweak)
-             obfd = h->u.def.section->owner;
-           else
-             obfd = NULL;
-           if (! ((*info->callbacks->multiple_common)
-                  (info, h->root.string, obfd, h->type, 0,
-                   abfd, bfd_link_hash_common, value)))
-             return FALSE;
-         }
+         /* We have found a common definition for a symbol which
+            was already defined.  */
+         if (! ((*info->callbacks->multiple_common)
+                (info, h, abfd, bfd_link_hash_common, value)))
+           return FALSE;
          break;
 
        case MIND:
@@ -1810,47 +1740,16 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
          /* Fall through.  */
        case MDEF:
          /* Handle a multiple definition.  */
-         if (!info->allow_multiple_definition)
-           {
-             asection *msec = NULL;
-             bfd_vma mval = 0;
-
-             switch (h->type)
-               {
-               case bfd_link_hash_defined:
-                 msec = h->u.def.section;
-                 mval = h->u.def.value;
-                 break;
-               case bfd_link_hash_indirect:
-                 msec = bfd_ind_section_ptr;
-                 mval = 0;
-                 break;
-               default:
-                 abort ();
-               }
-
-             /* Ignore a redefinition of an absolute symbol to the
-                same value; it's harmless.  */
-             if (h->type == bfd_link_hash_defined
-                 && bfd_is_abs_section (msec)
-                 && bfd_is_abs_section (section)
-                 && value == mval)
-               break;
-
-             if (! ((*info->callbacks->multiple_definition)
-                    (info, h->root.string, msec->owner, msec, mval,
-                     abfd, section, value)))
-               return FALSE;
-           }
+         if (! ((*info->callbacks->multiple_definition)
+                (info, h, abfd, section, value)))
+           return FALSE;
          break;
 
        case CIND:
          /* Create an indirect symbol from an existing common symbol.  */
          BFD_ASSERT (h->type == bfd_link_hash_common);
          if (! ((*info->callbacks->multiple_common)
-                (info, h->root.string,
-                 h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
-                 abfd, bfd_link_hash_indirect, 0)))
+                (info, h, abfd, bfd_link_hash_indirect, 0)))
            return FALSE;
          /* Fall through.  */
        case IND:
@@ -1969,7 +1868,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
                char *w;
                size_t len = strlen (string) + 1;
 
-               w = bfd_hash_allocate (&info->hash->table, len);
+               w = (char *) bfd_hash_allocate (&info->hash->table, len);
                if (w == NULL)
                  return FALSE;
                memcpy (w, string, len);
@@ -2007,12 +1906,12 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info)
 
   /* Mark all sections which will be included in the output file.  */
   for (o = abfd->sections; o != NULL; o = o->next)
-    for (p = o->link_order_head; p != NULL; p = p->next)
+    for (p = o->map_head.link_order; p != NULL; p = p->next)
       if (p->type == bfd_indirect_link_order)
        p->u.indirect.section->linker_mark = TRUE;
 
   /* Build the output symbol table.  */
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc))
       return FALSE;
 
@@ -2036,7 +1935,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info)
       for (o = abfd->sections; o != NULL; o = o->next)
        {
          o->reloc_count = 0;
-         for (p = o->link_order_head; p != NULL; p = p->next)
+         for (p = o->map_head.link_order; p != NULL; p = p->next)
            {
              if (p->type == bfd_section_reloc_link_order
                  || p->type == bfd_symbol_reloc_link_order)
@@ -2056,7 +1955,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info)
                                                       input_section);
                  if (relsize < 0)
                    return FALSE;
-                 relocs = bfd_malloc (relsize);
+                 relocs = (arelent **) bfd_malloc (relsize);
                  if (!relocs && relsize != 0)
                    return FALSE;
                  symbols = _bfd_generic_link_get_symbols (input_bfd);
@@ -2078,7 +1977,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info)
 
              amt = o->reloc_count;
              amt *= sizeof (arelent *);
-             o->orelocation = bfd_alloc (abfd, amt);
+             o->orelocation = (struct reloc_cache_entry **) bfd_alloc (abfd, amt);
              if (!o->orelocation)
                return FALSE;
              o->flags |= SEC_RELOC;
@@ -2092,7 +1991,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info)
   /* Handle all the link order information for the sections.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
-      for (p = o->link_order_head; p != NULL; p = p->next)
+      for (p = o->map_head.link_order; p != NULL; p = p->next)
        {
          switch (p->type)
            {
@@ -2132,7 +2031,7 @@ generic_add_output_symbol (bfd *output_bfd, size_t *psymalloc, asymbol *sym)
        *psymalloc *= 2;
       amt = *psymalloc;
       amt *= sizeof (asymbol *);
-      newsyms = bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
+      newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
       if (newsyms == NULL)
        return FALSE;
       bfd_get_outsymbols (output_bfd) = newsyms;
@@ -2156,7 +2055,7 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
   asymbol **sym_ptr;
   asymbol **sym_end;
 
-  if (! generic_link_read_symbols (input_bfd))
+  if (!bfd_generic_link_read_symbols (input_bfd))
     return FALSE;
 
   /* Create a filename symbol if we are supposed to.  */
@@ -2209,7 +2108,7 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
          || bfd_is_ind_section (bfd_get_section (sym)))
        {
          if (sym->udata.p != NULL)
-           h = sym->udata.p;
+           h = (struct generic_link_hash_entry *) sym->udata.p;
          else if ((sym->flags & BSF_CONSTRUCTOR) != 0)
            {
              /* This case normally means that the main linker code
@@ -2239,7 +2138,7 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
                 this routine will be called with a hash table
                 other than a generic hash table, so we double
                 check that.  */
-             if (info->hash->creator == input_bfd->xvec)
+             if (info->output_bfd->xvec == input_bfd->xvec)
                {
                  if (h->sym != NULL)
                    *sym_ptr = sym = h->sym;
@@ -2357,16 +2256,21 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
          else
            output = FALSE;
        }
+      else if (sym->flags == 0
+              && (sym->section->owner->flags & BFD_PLUGIN) != 0)
+       /* LTO doesn't set symbol information.  We get here with the
+          generic linker for a symbol that was "common" but no longer
+          needs to be global.  */
+       output = FALSE;
       else
        abort ();
 
       /* If this symbol is in a section which is not being included
-        in the output file, then we don't want to output the symbol.
-
-        Gross.  .bss and similar sections won't have the linker_mark
-        field set.  */
-      if ((sym->section->flags & SEC_HAS_CONTENTS) != 0
-         && ! sym->section->linker_mark)
+        in the output file, then we don't want to output the
+        symbol.  */
+      if (!bfd_is_abs_section (sym->section)
+         && bfd_section_removed_from_list (output_bfd,
+                                           sym->section->output_section))
        output = FALSE;
 
       if (output)
@@ -2449,12 +2353,10 @@ bfd_boolean
 _bfd_generic_link_write_global_symbol (struct generic_link_hash_entry *h,
                                       void *data)
 {
-  struct generic_write_global_symbol_info *wginfo = data;
+  struct generic_write_global_symbol_info *wginfo =
+      (struct generic_write_global_symbol_info *) data;
   asymbol *sym;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct generic_link_hash_entry *) h->root.u.i.link;
-
   if (h->written)
     return TRUE;
 
@@ -2506,7 +2408,7 @@ _bfd_generic_reloc_link_order (bfd *abfd,
   if (sec->orelocation == NULL)
     abort ();
 
-  r = bfd_alloc (abfd, sizeof (arelent));
+  r = (arelent *) bfd_alloc (abfd, sizeof (arelent));
   if (r == NULL)
     return FALSE;
 
@@ -2554,7 +2456,7 @@ _bfd_generic_reloc_link_order (bfd *abfd,
       file_ptr loc;
 
       size = bfd_get_reloc_size (r->howto);
-      buf = bfd_zmalloc (size);
+      buf = (bfd_byte *) bfd_zmalloc (size);
       if (buf == NULL)
        return FALSE;
       rstat = _bfd_relocate_contents (r->howto, abfd,
@@ -2602,21 +2504,21 @@ struct bfd_link_order *
 bfd_new_link_order (bfd *abfd, asection *section)
 {
   bfd_size_type amt = sizeof (struct bfd_link_order);
-  struct bfd_link_order *new;
+  struct bfd_link_order *new_lo;
 
-  new = bfd_zalloc (abfd, amt);
-  if (!new)
+  new_lo = (struct bfd_link_order *) bfd_zalloc (abfd, amt);
+  if (!new_lo)
     return NULL;
 
-  new->type = bfd_undefined_link_order;
+  new_lo->type = bfd_undefined_link_order;
 
-  if (section->link_order_tail != NULL)
-    section->link_order_tail->next = new;
+  if (section->map_tail.link_order != NULL)
+    section->map_tail.link_order->next = new_lo;
   else
-    section->link_order_head = new;
-  section->link_order_tail = new;
+    section->map_head.link_order = new_lo;
+  section->map_tail.link_order = new_lo;
 
-  return new;
+  return new_lo;
 }
 
 /* Default link order processing routine.  Note that we can not handle
@@ -2666,10 +2568,17 @@ default_data_link_order (bfd *abfd,
 
   fill = link_order->u.data.contents;
   fill_size = link_order->u.data.size;
-  if (fill_size != 0 && fill_size < size)
+  if (fill_size == 0)
+    {
+      fill = abfd->arch_info->fill (size, bfd_big_endian (abfd),
+                                   (sec->flags & SEC_CODE) != 0);
+      if (fill == NULL)
+       return FALSE;
+    }
+  else if (fill_size < size)
     {
       bfd_byte *p;
-      fill = bfd_malloc (size);
+      fill = (bfd_byte *) bfd_malloc (size);
       if (fill == NULL)
        return FALSE;
       p = fill;
@@ -2716,11 +2625,10 @@ default_indirect_link_order (bfd *output_bfd,
 
   BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
 
-  if (link_order->size == 0)
-    return TRUE;
-
   input_section = link_order->u.indirect.section;
   input_bfd = input_section->owner;
+  if (input_section->size == 0)
+    return TRUE;
 
   BFD_ASSERT (input_section->output_section == output_section);
   BFD_ASSERT (input_section->output_offset == link_order->offset);
@@ -2751,7 +2659,7 @@ default_indirect_link_order (bfd *output_bfd,
         have retrieved them by this point, but we are being called by
         a specific linker, presumably because we are linking
         different types of object files together.  */
-      if (! generic_link_read_symbols (input_bfd))
+      if (!bfd_generic_link_read_symbols (input_bfd))
        return FALSE;
 
       /* Since we have been called by a specific linker, rather than
@@ -2780,7 +2688,7 @@ default_indirect_link_order (bfd *output_bfd,
              /* sym->udata may have been set by
                 generic_link_add_symbol_list.  */
              if (sym->udata.p != NULL)
-               h = sym->udata.p;
+               h = (struct bfd_link_hash_entry *) sym->udata.p;
              else if (bfd_is_und_section (bfd_get_section (sym)))
                h = bfd_wrapped_link_hash_lookup (output_bfd, info,
                                                  bfd_asymbol_name (sym),
@@ -2795,23 +2703,41 @@ default_indirect_link_order (bfd *output_bfd,
        }
     }
 
-  /* Get and relocate the section contents.  */
-  sec_size = (input_section->rawsize > input_section->size
-             ? input_section->rawsize
-             : input_section->size);
-  contents = bfd_malloc (sec_size);
-  if (contents == NULL && sec_size != 0)
-    goto error_return;
-  new_contents = (bfd_get_relocated_section_contents
-                 (output_bfd, info, link_order, contents, info->relocatable,
-                  _bfd_generic_link_get_symbols (input_bfd)));
-  if (!new_contents)
-    goto error_return;
+  if ((output_section->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP
+      && input_section->size != 0)
+    {
+      /* Group section contents are set by bfd_elf_set_group_contents.  */
+      if (!output_bfd->output_has_begun)
+       {
+         /* FIXME: This hack ensures bfd_elf_set_group_contents is called.  */
+         if (!bfd_set_section_contents (output_bfd, output_section, "", 0, 1))
+           goto error_return;
+       }
+      new_contents = output_section->contents;
+      BFD_ASSERT (new_contents != NULL);
+      BFD_ASSERT (input_section->output_offset == 0);
+    }
+  else
+    {
+      /* Get and relocate the section contents.  */
+      sec_size = (input_section->rawsize > input_section->size
+                 ? input_section->rawsize
+                 : input_section->size);
+      contents = (bfd_byte *) bfd_malloc (sec_size);
+      if (contents == NULL && sec_size != 0)
+       goto error_return;
+      new_contents = (bfd_get_relocated_section_contents
+                     (output_bfd, info, link_order, contents,
+                      info->relocatable,
+                      _bfd_generic_link_get_symbols (input_bfd)));
+      if (!new_contents)
+       goto error_return;
+    }
 
   /* Output the section contents.  */
-  loc = link_order->offset * bfd_octets_per_byte (output_bfd);
+  loc = input_section->output_offset * bfd_octets_per_byte (output_bfd);
   if (! bfd_set_section_contents (output_bfd, output_section,
-                                 new_contents, loc, link_order->size))
+                                 new_contents, loc, input_section->size))
     goto error_return;
 
   if (contents != NULL)
@@ -2873,14 +2799,16 @@ FUNCTION
        bfd_section_already_linked
 
 SYNOPSIS
-        void bfd_section_already_linked (bfd *abfd, asection *sec);
+        bfd_boolean bfd_section_already_linked (bfd *abfd,
+                                               asection *sec,
+                                               struct bfd_link_info *info);
 
 DESCRIPTION
-       Check if @var{sec} has been already linked during a reloceatable
-       or final link.
+       Check if @var{data} has been already linked during a reloceatable
+       or final link.  Return TRUE if it has.
 
-.#define bfd_section_already_linked(abfd, sec) \
-.       BFD_SEND (abfd, _section_already_linked, (abfd, sec))
+.#define bfd_section_already_linked(abfd, sec, info) \
+.       BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
 .
 
 */
@@ -2888,7 +2816,7 @@ DESCRIPTION
 /* Sections marked with the SEC_LINK_ONCE flag should only be linked
    once into the output.  This routine checks each section, and
    arrange to discard it if a section of the same name has already
-   been linked.  This code assumes that all relevant sections have the 
+   been linked.  This code assumes that all relevant sections have the
    SEC_LINK_ONCE flag set; that is, it does not depend solely upon the
    section name.  bfd_section_already_linked is called via
    bfd_map_over_sections.  */
@@ -2920,7 +2848,7 @@ bfd_section_already_linked_table_lookup (const char *name)
                           TRUE, FALSE));
 }
 
-void
+bfd_boolean
 bfd_section_already_linked_table_insert
   (struct bfd_section_already_linked_hash_entry *already_linked_list,
    asection *sec)
@@ -2929,10 +2857,14 @@ bfd_section_already_linked_table_insert
 
   /* Allocate the memory from the same obstack as the hash table is
      kept in.  */
-  l = bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l);
+  l = (struct bfd_section_already_linked *)
+      bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l);
+  if (l == NULL)
+    return FALSE;
   l->sec = sec;
   l->next = already_linked_list->entry;
   already_linked_list->entry = l;
+  return TRUE;
 }
 
 static struct bfd_hash_entry *
@@ -2941,7 +2873,11 @@ already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED,
                        const char *string ATTRIBUTE_UNUSED)
 {
   struct bfd_section_already_linked_hash_entry *ret =
-    bfd_hash_allocate (table, sizeof *ret);
+    (struct bfd_section_already_linked_hash_entry *)
+      bfd_hash_allocate (table, sizeof *ret);
+
+  if (ret == NULL)
+    return NULL;
 
   ret->entry = NULL;
 
@@ -2952,7 +2888,9 @@ bfd_boolean
 bfd_section_already_linked_table_init (void)
 {
   return bfd_hash_table_init_n (&_bfd_section_already_linked_table,
-                               already_linked_newfunc, 42);
+                               already_linked_newfunc,
+                               sizeof (struct bfd_section_already_linked_hash_entry),
+                               42);
 }
 
 void
@@ -2961,19 +2899,109 @@ bfd_section_already_linked_table_free (void)
   bfd_hash_table_free (&_bfd_section_already_linked_table);
 }
 
+/* Report warnings as appropriate for duplicate section SEC.
+   Return FALSE if we decide to keep SEC after all.  */
+
+bfd_boolean
+_bfd_handle_already_linked (asection *sec,
+                           struct bfd_section_already_linked *l,
+                           struct bfd_link_info *info)
+{
+  switch (sec->flags & SEC_LINK_DUPLICATES)
+    {
+    default:
+      abort ();
+
+    case SEC_LINK_DUPLICATES_DISCARD:
+      /* If we found an LTO IR match for this comdat group on
+        the first pass, replace it with the LTO output on the
+        second pass.  We can't simply choose real object
+        files over IR because the first pass may contain a
+        mix of LTO and normal objects and we must keep the
+        first match, be it IR or real.  */
+      if (info->loading_lto_outputs
+         && (l->sec->owner->flags & BFD_PLUGIN) != 0)
+       {
+         l->sec = sec;
+         return FALSE;
+       }
+      break;
+
+    case SEC_LINK_DUPLICATES_ONE_ONLY:
+      info->callbacks->einfo
+       (_("%B: ignoring duplicate section `%A'\n"),
+        sec->owner, sec);
+      break;
+
+    case SEC_LINK_DUPLICATES_SAME_SIZE:
+      if ((l->sec->owner->flags & BFD_PLUGIN) != 0)
+       ;
+      else if (sec->size != l->sec->size)
+       info->callbacks->einfo
+         (_("%B: duplicate section `%A' has different size\n"),
+          sec->owner, sec);
+      break;
+
+    case SEC_LINK_DUPLICATES_SAME_CONTENTS:
+      if ((l->sec->owner->flags & BFD_PLUGIN) != 0)
+       ;
+      else if (sec->size != l->sec->size)
+       info->callbacks->einfo
+         (_("%B: duplicate section `%A' has different size\n"),
+          sec->owner, sec);
+      else if (sec->size != 0)
+       {
+         bfd_byte *sec_contents, *l_sec_contents = NULL;
+
+         if (!bfd_malloc_and_get_section (sec->owner, sec, &sec_contents))
+           info->callbacks->einfo
+             (_("%B: could not read contents of section `%A'\n"),
+              sec->owner, sec);
+         else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
+                                               &l_sec_contents))
+           info->callbacks->einfo
+             (_("%B: could not read contents of section `%A'\n"),
+              l->sec->owner, l->sec);
+         else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
+           info->callbacks->einfo
+             (_("%B: duplicate section `%A' has different contents\n"),
+              sec->owner, sec);
+
+         if (sec_contents)
+           free (sec_contents);
+         if (l_sec_contents)
+           free (l_sec_contents);
+       }
+      break;
+    }
+
+  /* Set the output_section field so that lang_add_section
+     does not create a lang_input_section structure for this
+     section.  Since there might be a symbol in the section
+     being discarded, we must retain a pointer to the section
+     which we are really going to use.  */
+  sec->output_section = bfd_abs_section_ptr;
+  sec->kept_section = l->sec;
+  return TRUE;
+}
+
 /* This is used on non-ELF inputs.  */
 
-void
-_bfd_generic_section_already_linked (bfd *abfd, asection *sec)
+bfd_boolean
+_bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED,
+                                    asection *sec,
+                                    struct bfd_link_info *info)
 {
-  flagword flags;
   const char *name;
   struct bfd_section_already_linked *l;
   struct bfd_section_already_linked_hash_entry *already_linked_list;
 
-  flags = sec->flags;
-  if ((flags & SEC_LINK_ONCE) == 0)
-    return;
+  if ((sec->flags & SEC_LINK_ONCE) == 0)
+    return FALSE;
+
+  /* The generic linker doesn't handle section groups.  */
+  if ((sec->flags & SEC_GROUP) != 0)
+    return FALSE;
 
   /* FIXME: When doing a relocatable link, we may have trouble
      copying relocations in other sections that refer to local symbols
@@ -2992,78 +3020,309 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec)
 
   already_linked_list = bfd_section_already_linked_table_lookup (name);
 
-  for (l = already_linked_list->entry; l != NULL; l = l->next)
+  l = already_linked_list->entry;
+  if (l != NULL)
     {
-      bfd_boolean skip = FALSE;
-      struct coff_comdat_info *s_comdat
-       = bfd_coff_get_comdat_section (abfd, sec);
-      struct coff_comdat_info *l_comdat
-       = bfd_coff_get_comdat_section (l->sec->owner, l->sec);
-
-      /* We may have 3 different sections on the list: group section,
-        comdat section and linkonce section. SEC may be a linkonce or
-        comdat section. We always ignore group section. For non-COFF
-        inputs, we also ignore comdat section.
-
-        FIXME: Is that safe to match a linkonce section with a comdat
-        section for COFF inputs?  */
-      if ((l->sec->flags & SEC_GROUP) != 0)
-       skip = TRUE;
-      else if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
+      /* The section has already been linked.  See if we should
+        issue a warning.  */
+      return _bfd_handle_already_linked (sec, l, info);
+    }
+
+  /* This is the first section with this name.  Record it.  */
+  if (!bfd_section_already_linked_table_insert (already_linked_list, sec))
+    info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
+  return FALSE;
+}
+
+/* Choose a neighbouring section to S in OBFD that will be output, or
+   the absolute section if ADDR is out of bounds of the neighbours.  */
+
+asection *
+_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr)
+{
+  asection *next, *prev, *best;
+
+  /* Find preceding kept section.  */
+  for (prev = s->prev; prev != NULL; prev = prev->prev)
+    if ((prev->flags & SEC_EXCLUDE) == 0
+       && !bfd_section_removed_from_list (obfd, prev))
+      break;
+
+  /* Find following kept section.  Start at prev->next because
+     other sections may have been added after S was removed.  */
+  if (s->prev != NULL)
+    next = s->prev->next;
+  else
+    next = s->owner->sections;
+  for (; next != NULL; next = next->next)
+    if ((next->flags & SEC_EXCLUDE) == 0
+       && !bfd_section_removed_from_list (obfd, next))
+      break;
+
+  /* Choose better of two sections, based on flags.  The idea
+     is to choose a section that will be in the same segment
+     as S would have been if it was kept.  */
+  best = next;
+  if (prev == NULL)
+    {
+      if (next == NULL)
+       best = bfd_abs_section_ptr;
+    }
+  else if (next == NULL)
+    best = prev;
+  else if (((prev->flags ^ next->flags)
+           & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
+    {
+      if (((next->flags ^ s->flags)
+          & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
+         /* We prefer to choose a loaded section.  Section S
+            doesn't have SEC_LOAD set (it being excluded, that
+            part of the flag processing didn't happen) so we
+            can't compare that flag to those of NEXT and PREV.  */
+         || ((prev->flags & SEC_LOAD) != 0
+             && (next->flags & SEC_LOAD) == 0))
+       best = prev;
+    }
+  else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0)
+    {
+      if (((next->flags ^ s->flags) & SEC_READONLY) != 0)
+       best = prev;
+    }
+  else if (((prev->flags ^ next->flags) & SEC_CODE) != 0)
+    {
+      if (((next->flags ^ s->flags) & SEC_CODE) != 0)
+       best = prev;
+    }
+  else
+    {
+      /* Flags we care about are the same.  Prefer the following
+        section if that will result in a positive valued sym.  */
+      if (addr < next->vma)
+       best = prev;
+    }
+
+  return best;
+}
+
+/* Convert symbols in excluded output sections to use a kept section.  */
+
+static bfd_boolean
+fix_syms (struct bfd_link_hash_entry *h, void *data)
+{
+  bfd *obfd = (bfd *) data;
+
+  if (h->type == bfd_link_hash_defined
+      || h->type == bfd_link_hash_defweak)
+    {
+      asection *s = h->u.def.section;
+      if (s != NULL
+         && s->output_section != NULL
+         && (s->output_section->flags & SEC_EXCLUDE) != 0
+         && bfd_section_removed_from_list (obfd, s->output_section))
        {
-         if (s_comdat != NULL
-             && l_comdat != NULL
-             && strcmp (s_comdat->name, l_comdat->name) != 0)
-           skip = TRUE;
+         asection *op;
+
+         h->u.def.value += s->output_offset + s->output_section->vma;
+         op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value);
+         h->u.def.value -= op->vma;
+         h->u.def.section = op;
        }
-      else if (l_comdat != NULL)
-       skip = TRUE;
+    }
+
+  return TRUE;
+}
 
-      if (!skip)
+void
+_bfd_fix_excluded_sec_syms (bfd *obfd, struct bfd_link_info *info)
+{
+  bfd_link_hash_traverse (info->hash, fix_syms, obfd);
+}
+
+/*
+FUNCTION
+       bfd_generic_define_common_symbol
+
+SYNOPSIS
+       bfd_boolean bfd_generic_define_common_symbol
+         (bfd *output_bfd, struct bfd_link_info *info,
+          struct bfd_link_hash_entry *h);
+
+DESCRIPTION
+       Convert common symbol @var{h} into a defined symbol.
+       Return TRUE on success and FALSE on failure.
+
+.#define bfd_define_common_symbol(output_bfd, info, h) \
+.       BFD_SEND (output_bfd, _bfd_define_common_symbol, (output_bfd, info, h))
+.
+*/
+
+bfd_boolean
+bfd_generic_define_common_symbol (bfd *output_bfd,
+                                 struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                                 struct bfd_link_hash_entry *h)
+{
+  unsigned int power_of_two;
+  bfd_vma alignment, size;
+  asection *section;
+
+  BFD_ASSERT (h != NULL && h->type == bfd_link_hash_common);
+
+  size = h->u.c.size;
+  power_of_two = h->u.c.p->alignment_power;
+  section = h->u.c.p->section;
+
+  /* Increase the size of the section to align the common symbol.
+     The alignment must be a power of two.  */
+  alignment = bfd_octets_per_byte (output_bfd) << power_of_two;
+  BFD_ASSERT (alignment != 0 && (alignment & -alignment) == alignment);
+  section->size += alignment - 1;
+  section->size &= -alignment;
+
+  /* Adjust the section's overall alignment if necessary.  */
+  if (power_of_two > section->alignment_power)
+    section->alignment_power = power_of_two;
+
+  /* Change the symbol from common to defined.  */
+  h->type = bfd_link_hash_defined;
+  h->u.def.section = section;
+  h->u.def.value = section->size;
+
+  /* Increase the size of the section.  */
+  section->size += size;
+
+  /* Make sure the section is allocated in memory, and make sure that
+     it is no longer a common section.  */
+  section->flags |= SEC_ALLOC;
+  section->flags &= ~SEC_IS_COMMON;
+  return TRUE;
+}
+
+/*
+FUNCTION
+       bfd_find_version_for_sym
+
+SYNOPSIS
+       struct bfd_elf_version_tree * bfd_find_version_for_sym
+         (struct bfd_elf_version_tree *verdefs,
+          const char *sym_name, bfd_boolean *hide);
+
+DESCRIPTION
+       Search an elf version script tree for symbol versioning
+       info and export / don't-export status for a given symbol.
+       Return non-NULL on success and NULL on failure; also sets
+       the output @samp{hide} boolean parameter.
+
+*/
+
+struct bfd_elf_version_tree *
+bfd_find_version_for_sym (struct bfd_elf_version_tree *verdefs,
+                         const char *sym_name,
+                         bfd_boolean *hide)
+{
+  struct bfd_elf_version_tree *t;
+  struct bfd_elf_version_tree *local_ver, *global_ver, *exist_ver;
+  struct bfd_elf_version_tree *star_local_ver, *star_global_ver;
+
+  local_ver = NULL;
+  global_ver = NULL;
+  star_local_ver = NULL;
+  star_global_ver = NULL;
+  exist_ver = NULL;
+  for (t = verdefs; t != NULL; t = t->next)
+    {
+      if (t->globals.list != NULL)
        {
-         /* The section has already been linked.  See if we should
-             issue a warning.  */
-         switch (flags & SEC_LINK_DUPLICATES)
+         struct bfd_elf_version_expr *d = NULL;
+
+         while ((d = (*t->match) (&t->globals, d, sym_name)) != NULL)
            {
-           default:
-             abort ();
+             if (d->literal || strcmp (d->pattern, "*") != 0)
+               global_ver = t;
+             else
+               star_global_ver = t;
+             if (d->symver)
+               exist_ver = t;
+             d->script = 1;
+             /* If the match is a wildcard pattern, keep looking for
+                a more explicit, perhaps even local, match.  */
+             if (d->literal)
+               break;
+           }
 
-           case SEC_LINK_DUPLICATES_DISCARD:
-             break;
+         if (d != NULL)
+           break;
+       }
 
-           case SEC_LINK_DUPLICATES_ONE_ONLY:
-             (*_bfd_error_handler)
-               (_("%B: warning: ignoring duplicate section `%A'\n"),
-                abfd, sec);
-             break;
+      if (t->locals.list != NULL)
+       {
+         struct bfd_elf_version_expr *d = NULL;
 
-           case SEC_LINK_DUPLICATES_SAME_CONTENTS:
-             /* FIXME: We should really dig out the contents of both
-                 sections and memcmp them.  The COFF/PE spec says that
-                 the Microsoft linker does not implement this
-                 correctly, so I'm not going to bother doing it
-                 either.  */
-             /* Fall through.  */
-           case SEC_LINK_DUPLICATES_SAME_SIZE:
-             if (sec->size != l->sec->size)
-               (*_bfd_error_handler)
-                 (_("%B: warning: duplicate section `%A' has different size\n"),
-                  abfd, sec);
-             break;
+         while ((d = (*t->match) (&t->locals, d, sym_name)) != NULL)
+           {
+             if (d->literal || strcmp (d->pattern, "*") != 0)
+               local_ver = t;
+             else
+               star_local_ver = t;
+             /* If the match is a wildcard pattern, keep looking for
+                a more explicit, perhaps even global, match.  */
+             if (d->literal)
+               {
+                 /* An exact match overrides a global wildcard.  */
+                 global_ver = NULL;
+                 star_global_ver = NULL;
+                 break;
+               }
            }
 
-         /* Set the output_section field so that lang_add_section
-            does not create a lang_input_section structure for this
-            section.  Since there might be a symbol in the section
-            being discarded, we must retain a pointer to the section
-            which we are really going to use.  */
-         sec->output_section = bfd_abs_section_ptr;
-         sec->kept_section = l->sec;
-
-         return;
+         if (d != NULL)
+           break;
        }
     }
 
-  /* This is the first section with this name.  Record it.  */
-  bfd_section_already_linked_table_insert (already_linked_list, sec);
+  if (global_ver == NULL && local_ver == NULL)
+    global_ver = star_global_ver;
+
+  if (global_ver != NULL)
+    {
+      /* If we already have a versioned symbol that matches the
+        node for this symbol, then we don't want to create a
+        duplicate from the unversioned symbol.  Instead hide the
+        unversioned symbol.  */
+      *hide = exist_ver == global_ver;
+      return global_ver;
+    }
+
+  if (local_ver == NULL)
+    local_ver = star_local_ver;
+
+  if (local_ver != NULL)
+    {
+      *hide = TRUE;
+      return local_ver;
+    }
+
+  return NULL;
+}
+
+/*
+FUNCTION
+       bfd_hide_sym_by_version
+
+SYNOPSIS
+       bfd_boolean bfd_hide_sym_by_version
+         (struct bfd_elf_version_tree *verdefs, const char *sym_name);
+
+DESCRIPTION
+       Search an elf version script tree for symbol versioning
+       info for a given symbol.  Return TRUE if the symbol is hidden.
+
+*/
+
+bfd_boolean
+bfd_hide_sym_by_version (struct bfd_elf_version_tree *verdefs,
+                        const char *sym_name)
+{
+  bfd_boolean hidden = FALSE;
+  bfd_find_version_for_sym (verdefs, sym_name, &hidden);
+  return hidden;
 }
This page took 0.069585 seconds and 4 git commands to generate.