* aoutx.h (aout_link_check_ar_symbols): Formatting.
[deliverable/binutils-gdb.git] / bfd / linker.c
index 72f8bfd909d0e8a0a6a5133fee45f4432ce8eb87..2b52ba965105930a4db2aa149a88d0181e0511f6 100644 (file)
@@ -1,5 +1,6 @@
 /* linker.c -- BFD linker routines
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
 
@@ -7,7 +8,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   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 +151,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 +165,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,7 +223,10 @@ 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
@@ -241,9 +246,13 @@ SUBSUBSECTION
        element should be included in the link.  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.
+       <<_bfd_link_add_symbols>> function.  The <<add_archive_element>>
+       callback has the option to indicate that it would like to
+       replace the element archive with a substitute BFD, in which
+       case it is the symbols of that substitute BFD that must be
+       added to the linker hash table instead.
 
        When the a.out <<_bfd_link_add_symbols>> function receives an
        archive, it calls <<_bfd_generic_link_add_archive_symbols>>
@@ -255,7 +264,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
@@ -309,7 +319,7 @@ SUBSUBSECTION
        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
@@ -406,34 +416,26 @@ SUBSUBSECTION
        file at the end of <<NAME(aout,final_link)>>.
 */
 
-static bfd_boolean generic_link_read_symbols
-  PARAMS ((bfd *));
-static bfd_boolean generic_link_add_symbols
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean collect));
 static bfd_boolean generic_link_add_object_symbols
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean collect));
+  (bfd *, struct bfd_link_info *, bfd_boolean collect);
+static bfd_boolean generic_link_add_symbols
+  (bfd *, struct bfd_link_info *, bfd_boolean);
 static bfd_boolean generic_link_check_archive_element_no_collect
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded));
+  (bfd *, struct bfd_link_info *, bfd_boolean *);
 static bfd_boolean generic_link_check_archive_element_collect
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded));
+  (bfd *, struct bfd_link_info *, bfd_boolean *);
 static bfd_boolean generic_link_check_archive_element
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded,
-          bfd_boolean collect));
+  (bfd *, struct bfd_link_info *, bfd_boolean *, bfd_boolean);
 static bfd_boolean generic_link_add_symbol_list
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
-          bfd_boolean collect));
-static bfd *hash_entry_bfd
-  PARAMS ((struct bfd_link_hash_entry *));
-static void set_symbol_from_hash
-  PARAMS ((asymbol *, struct bfd_link_hash_entry *));
+  (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
+   bfd_boolean);
 static bfd_boolean generic_add_output_symbol
-  PARAMS ((bfd *, size_t *psymalloc, asymbol *));
+  (bfd *, size_t *psymalloc, asymbol *);
 static bfd_boolean default_data_link_order
-  PARAMS ((bfd *, struct bfd_link_info *, asection *,
-          struct bfd_link_order *));
+  (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *);
 static bfd_boolean default_indirect_link_order
-  PARAMS ((bfd *, struct bfd_link_info *, asection *,
-          struct bfd_link_order *, bfd_boolean));
+  (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *,
+   bfd_boolean);
 
 /* The link hash table structure is defined in bfdlink.h.  It provides
    a base hash table which the backend specific hash tables are built
@@ -442,17 +444,16 @@ static bfd_boolean default_indirect_link_order
 /* Routine to create an entry in the link hash table.  */
 
 struct bfd_hash_entry *
-_bfd_link_hash_newfunc (entry, table, string)
-     struct bfd_hash_entry *entry;
-     struct bfd_hash_table *table;
-     const char *string;
+_bfd_link_hash_newfunc (struct bfd_hash_entry *entry,
+                       struct bfd_hash_table *table,
+                       const char *string)
 {
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
   if (entry == NULL)
     {
       entry = (struct bfd_hash_entry *)
-       bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
+          bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
       if (entry == NULL)
        return entry;
     }
@@ -465,7 +466,9 @@ _bfd_link_hash_newfunc (entry, table, string)
 
       /* Initialize the local fields.  */
       h->type = bfd_link_hash_new;
-      h->next = NULL;
+      memset (&h->u.undef.next, 0,
+             (sizeof (struct bfd_link_hash_entry)
+              - offsetof (struct bfd_link_hash_entry, u.undef.next)));
     }
 
   return entry;
@@ -475,19 +478,19 @@ _bfd_link_hash_newfunc (entry, table, string)
    responsible for creating this table.  */
 
 bfd_boolean
-_bfd_link_hash_table_init (table, abfd, newfunc)
-     struct bfd_link_hash_table *table;
-     bfd *abfd;
-     struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
-                                               struct bfd_hash_table *,
-                                               const char *));
+_bfd_link_hash_table_init
+  (struct bfd_link_hash_table *table,
+   bfd *abfd ATTRIBUTE_UNUSED,
+   struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
+                                     struct bfd_hash_table *,
+                                     const char *),
+   unsigned int entsize)
 {
-  table->creator = abfd->xvec;
   table->undefs = NULL;
   table->undefs_tail = NULL;
   table->type = bfd_link_generic_hash_table;
 
-  return bfd_hash_table_init (&table->table, newfunc);
+  return bfd_hash_table_init (&table->table, newfunc, entsize);
 }
 
 /* Look up a symbol in a link hash table.  If follow is TRUE, we
@@ -495,19 +498,18 @@ _bfd_link_hash_table_init (table, abfd, newfunc)
    the real symbol.  */
 
 struct bfd_link_hash_entry *
-bfd_link_hash_lookup (table, string, create, copy, follow)
-     struct bfd_link_hash_table *table;
-     const char *string;
-     bfd_boolean create;
-     bfd_boolean copy;
-     bfd_boolean follow;
+bfd_link_hash_lookup (struct bfd_link_hash_table *table,
+                     const char *string,
+                     bfd_boolean create,
+                     bfd_boolean copy,
+                     bfd_boolean follow)
 {
   struct bfd_link_hash_entry *ret;
 
   ret = ((struct bfd_link_hash_entry *)
         bfd_hash_lookup (&table->table, string, create, copy));
 
-  if (follow && ret != (struct bfd_link_hash_entry *) NULL)
+  if (follow && ret != NULL)
     {
       while (ret->type == bfd_link_hash_indirect
             || ret->type == bfd_link_hash_warning)
@@ -522,23 +524,26 @@ bfd_link_hash_lookup (table, string, create, copy, follow)
    undefined symbol, not for definitions of a symbol.  */
 
 struct bfd_link_hash_entry *
-bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     const char *string;
-     bfd_boolean create;
-     bfd_boolean copy;
-     bfd_boolean follow;
+bfd_wrapped_link_hash_lookup (bfd *abfd,
+                             struct bfd_link_info *info,
+                             const char *string,
+                             bfd_boolean create,
+                             bfd_boolean copy,
+                             bfd_boolean follow)
 {
   bfd_size_type amt;
 
   if (info->wrap_hash != NULL)
     {
       const char *l;
+      char prefix = '\0';
 
       l = string;
-      if (*l == bfd_get_symbol_leading_char (abfd))
-       ++l;
+      if (*l == bfd_get_symbol_leading_char (abfd) || *l == info->wrap_char)
+       {
+         prefix = *l;
+         ++l;
+       }
 
 #undef WRAP
 #define WRAP "__wrap_"
@@ -556,8 +561,7 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
          if (n == NULL)
            return NULL;
 
-         /* Note that symbol_leading_char may be '\0'.  */
-         n[0] = bfd_get_symbol_leading_char (abfd);
+         n[0] = prefix;
          n[1] = '\0';
          strcat (n, WRAP);
          strcat (n, l);
@@ -568,11 +572,11 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
 
 #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)
        {
@@ -588,8 +592,7 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
          if (n == NULL)
            return NULL;
 
-         /* Note that symbol_leading_char may be '\0'.  */
-         n[0] = bfd_get_symbol_leading_char (abfd);
+         n[0] = prefix;
          n[1] = '\0';
          strcat (n, l + sizeof REAL - 1);
          h = bfd_link_hash_lookup (info->hash, n, create, TRUE, follow);
@@ -610,39 +613,75 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
    call.  */
 
 void
-bfd_link_hash_traverse (table, func, info)
-     struct bfd_link_hash_table *table;
-     bfd_boolean (*func) PARAMS ((struct bfd_link_hash_entry *, PTR));
-     PTR info;
+bfd_link_hash_traverse
+  (struct bfd_link_hash_table *table,
+   bfd_boolean (*func) (struct bfd_link_hash_entry *, void *),
+   void *info)
 {
   bfd_hash_traverse (&table->table,
-                    ((bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR)))
-                     func),
+                    (bfd_boolean (*) (struct bfd_hash_entry *, void *)) func,
                     info);
 }
 
 /* Add a symbol to the linker hash table undefs list.  */
 
-INLINE void
-bfd_link_add_undef (table, h)
-     struct bfd_link_hash_table *table;
-     struct bfd_link_hash_entry *h;
+void
+bfd_link_add_undef (struct bfd_link_hash_table *table,
+                   struct bfd_link_hash_entry *h)
 {
-  BFD_ASSERT (h->next == NULL);
-  if (table->undefs_tail != (struct bfd_link_hash_entry *) NULL)
-    table->undefs_tail->next = h;
-  if (table->undefs == (struct bfd_link_hash_entry *) NULL)
+  BFD_ASSERT (h->u.undef.next == NULL);
+  if (table->undefs_tail != NULL)
+    table->undefs_tail->u.undef.next = h;
+  if (table->undefs == NULL)
     table->undefs = h;
   table->undefs_tail = h;
 }
+
+/* The undefs list was designed so that in normal use we don't need to
+   remove entries.  However, if symbols on the list are changed from
+   bfd_link_hash_undefined to either bfd_link_hash_undefweak or
+   bfd_link_hash_new for some reason, then they must be removed from the
+   list.  Failure to do so might result in the linker attempting to add
+   the symbol to the list again at a later stage.  */
+
+void
+bfd_link_repair_undef_list (struct bfd_link_hash_table *table)
+{
+  struct bfd_link_hash_entry **pun;
+
+  pun = &table->undefs;
+  while (*pun != NULL)
+    {
+      struct bfd_link_hash_entry *h = *pun;
+
+      if (h->type == bfd_link_hash_new
+         || h->type == bfd_link_hash_undefweak)
+       {
+         *pun = h->u.undef.next;
+         h->u.undef.next = NULL;
+         if (h == table->undefs_tail)
+           {
+             if (pun == &table->undefs)
+               table->undefs_tail = NULL;
+             else
+               /* pun points at an u.undef.next field.  Go back to
+                  the start of the link_hash_entry.  */
+               table->undefs_tail = (struct bfd_link_hash_entry *)
+                 ((char *) pun - ((char *) &h->u.undef.next - (char *) h));
+             break;
+           }
+       }
+      else
+       pun = &h->u.undef.next;
+    }
+}
 \f
 /* Routine to create an entry in a generic link hash table.  */
 
 struct bfd_hash_entry *
-_bfd_generic_link_hash_newfunc (entry, table, string)
-     struct bfd_hash_entry *entry;
-     struct bfd_hash_table *table;
-     const char *string;
+_bfd_generic_link_hash_newfunc (struct bfd_hash_entry *entry,
+                               struct bfd_hash_table *table,
+                               const char *string)
 {
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
@@ -672,27 +711,26 @@ _bfd_generic_link_hash_newfunc (entry, table, string)
 /* Create a generic link hash table.  */
 
 struct bfd_link_hash_table *
-_bfd_generic_link_hash_table_create (abfd)
-     bfd *abfd;
+_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 = (struct generic_link_hash_table *) bfd_malloc (amt);
   if (ret == NULL)
-    return (struct bfd_link_hash_table *) 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 (struct bfd_link_hash_table *) NULL;
+      return NULL;
     }
   return &ret->root;
 }
 
 void
-_bfd_generic_link_hash_table_free (hash)
-     struct bfd_link_hash_table *hash;
+_bfd_generic_link_hash_table_free (struct bfd_link_hash_table *hash)
 {
   struct generic_link_hash_table *ret
     = (struct generic_link_hash_table *) hash;
@@ -708,11 +746,10 @@ _bfd_generic_link_hash_table_free (hash)
    the hash table pointing to different instances of the symbol
    structure.  */
 
-static bfd_boolean
-generic_link_read_symbols (abfd)
-     bfd *abfd;
+bfd_boolean
+bfd_generic_link_read_symbols (bfd *abfd)
 {
-  if (bfd_get_outsymbols (abfd) == (asymbol **) NULL)
+  if (bfd_get_outsymbols (abfd) == NULL)
     {
       long symsize;
       long symcount;
@@ -720,8 +757,8 @@ generic_link_read_symbols (abfd)
       symsize = bfd_get_symtab_upper_bound (abfd);
       if (symsize < 0)
        return FALSE;
-      bfd_get_outsymbols (abfd) =
-       (asymbol **) bfd_alloc (abfd, (bfd_size_type) 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));
@@ -738,9 +775,7 @@ generic_link_read_symbols (abfd)
    constructors by name.  */
 
 bfd_boolean
-_bfd_generic_link_add_symbols (abfd, info)
-     bfd *abfd;
-     struct bfd_link_info *info;
+_bfd_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
 {
   return generic_link_add_symbols (abfd, info, FALSE);
 }
@@ -753,9 +788,7 @@ _bfd_generic_link_add_symbols (abfd, info)
    for which gcc uses collect2 and do not support stabs.  */
 
 bfd_boolean
-_bfd_generic_link_add_symbols_collect (abfd, info)
-     bfd *abfd;
-     struct bfd_link_info *info;
+_bfd_generic_link_add_symbols_collect (bfd *abfd, struct bfd_link_info *info)
 {
   return generic_link_add_symbols (abfd, info, TRUE);
 }
@@ -765,21 +798,30 @@ _bfd_generic_link_add_symbols_collect (abfd, info)
    file are absolute.  */
 
 void
-_bfd_generic_link_just_syms (sec, info)
-     asection *sec;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+_bfd_generic_link_just_syms (asection *sec,
+                            struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   sec->output_section = bfd_abs_section_ptr;
   sec->output_offset = sec->vma;
 }
 
+/* Copy the type of a symbol assiciated with a linker hast table entry.
+   Override this so that symbols created in linker scripts get their
+   type from the RHS of the assignment.
+   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
-generic_link_add_symbols (abfd, info, collect)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     bfd_boolean collect;
+generic_link_add_symbols (bfd *abfd,
+                         struct bfd_link_info *info,
+                         bfd_boolean collect)
 {
   bfd_boolean ret;
 
@@ -806,15 +848,14 @@ generic_link_add_symbols (abfd, info, collect)
 /* Add symbols from an object file to the global hash table.  */
 
 static bfd_boolean
-generic_link_add_object_symbols (abfd, info, collect)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     bfd_boolean collect;
+generic_link_add_object_symbols (bfd *abfd,
+                                struct bfd_link_info *info,
+                                bfd_boolean collect)
 {
   bfd_size_type symcount;
-  struct symbol_cache_entry **outsyms;
+  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);
@@ -848,30 +889,21 @@ struct archive_hash_table
   struct bfd_hash_table table;
 };
 
-static struct bfd_hash_entry *archive_hash_newfunc
-  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
-static bfd_boolean archive_hash_table_init
-  PARAMS ((struct archive_hash_table *,
-          struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
-                                      struct bfd_hash_table *,
-                                      const char *)));
-
 /* Create a new entry for an archive hash table.  */
 
 static struct bfd_hash_entry *
-archive_hash_newfunc (entry, table, string)
-     struct bfd_hash_entry *entry;
-     struct bfd_hash_table *table;
-     const char *string;
+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 == (struct archive_hash_entry *) NULL)
-    ret = ((struct archive_hash_entry *)
-          bfd_hash_allocate (table, sizeof (struct archive_hash_entry)));
-  if (ret == (struct archive_hash_entry *) NULL)
+  if (ret == NULL)
+    ret = (struct archive_hash_entry *)
+        bfd_hash_allocate (table, sizeof (struct archive_hash_entry));
+  if (ret == NULL)
     return NULL;
 
   /* Call the allocation method of the superclass.  */
@@ -881,22 +913,23 @@ archive_hash_newfunc (entry, table, string)
   if (ret)
     {
       /* Initialize the local fields.  */
-      ret->defs = (struct archive_list *) NULL;
+      ret->defs = NULL;
     }
 
-  return (struct bfd_hash_entry *) ret;
+  return &ret->root;
 }
 
 /* Initialize an archive hash table.  */
 
 static bfd_boolean
-archive_hash_table_init (table, newfunc)
-     struct archive_hash_table *table;
-     struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
-                                               struct bfd_hash_table *,
-                                               const char *));
+archive_hash_table_init
+  (struct archive_hash_table *table,
+   struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
+                                     struct bfd_hash_table *,
+                                     const char *),
+   unsigned int entsize)
 {
-  return bfd_hash_table_init (&table->table, newfunc);
+  return bfd_hash_table_init (&table->table, newfunc, entsize);
 }
 
 /* Look up an entry in an archive hash table.  */
@@ -932,8 +965,10 @@ archive_hash_table_init (table, newfunc)
    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.
+   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.
 
    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
@@ -947,11 +982,10 @@ archive_hash_table_init (table, newfunc)
    object file to be included.  */
 
 bfd_boolean
-_bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     bfd_boolean (*checkfn)
-       PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded));
+_bfd_generic_link_add_archive_symbols
+  (bfd *abfd,
+   struct bfd_link_info *info,
+   bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *, bfd_boolean *))
 {
   carsym *arsyms;
   carsym *arsym_end;
@@ -964,7 +998,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
   if (! bfd_has_map (abfd))
     {
       /* An empty archive is a special case.  */
-      if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL)
+      if (bfd_openr_next_archived_file (abfd, NULL) == NULL)
        return TRUE;
       bfd_set_error (bfd_error_no_armap);
       return FALSE;
@@ -975,7 +1009,8 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
 
   /* 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))
+  if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc,
+                                sizeof (struct archive_hash_entry)))
     return FALSE;
   for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
     {
@@ -983,16 +1018,14 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
       struct archive_list *l, **pp;
 
       arh = archive_hash_lookup (&arsym_hash, arsym->name, TRUE, FALSE);
-      if (arh == (struct archive_hash_entry *) NULL)
+      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 != (struct archive_list *) NULL;
-          pp = &(*pp)->next)
+      for (pp = &arh->defs; *pp != NULL; pp = &(*pp)->next)
        ;
       *pp = l;
       l->next = NULL;
@@ -1006,7 +1039,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
   /* 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 != (struct bfd_link_hash_entry *) NULL)
+  while (*pundef != NULL)
     {
       struct bfd_link_hash_entry *h;
       struct archive_hash_entry *arh;
@@ -1027,15 +1060,15 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
             us to lose track of whether the symbol has been
             referenced).  */
          if (*pundef != info->hash->undefs_tail)
-           *pundef = (*pundef)->next;
+           *pundef = (*pundef)->u.undef.next;
          else
-           pundef = &(*pundef)->next;
+           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 == (struct archive_hash_entry *) NULL)
+      if (arh == NULL)
        {
          /* If we haven't found the exact symbol we're looking for,
             let's look for its import thunk */
@@ -1050,14 +1083,14 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
              arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE);
              free(buf);
            }
-         if (arh == (struct archive_hash_entry *) NULL)
+         if (arh == NULL)
            {
-             pundef = &(*pundef)->next;
+             pundef = &(*pundef)->u.undef.next;
              continue;
            }
        }
       /* Look at all the objects which define this symbol.  */
-      for (l = arh->defs; l != (struct archive_list *) NULL; l = l->next)
+      for (l = arh->defs; l != NULL; l = l->next)
        {
          bfd *element;
          bfd_boolean needed;
@@ -1068,7 +1101,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
            break;
 
          element = bfd_get_elt_at_index (abfd, l->indx);
-         if (element == (bfd *) NULL)
+         if (element == NULL)
            goto error_return;
 
          /* If we've already included this element, or if we've
@@ -1101,7 +1134,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
            }
        }
 
-      pundef = &(*pundef)->next;
+      pundef = &(*pundef)->u.undef.next;
     }
 
   archive_hash_table_free (&arsym_hash);
@@ -1122,10 +1155,10 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
    for finding them.  */
 
 static bfd_boolean
-generic_link_check_archive_element_no_collect (abfd, info, pneeded)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     bfd_boolean *pneeded;
+generic_link_check_archive_element_no_collect (
+                                              bfd *abfd,
+                                              struct bfd_link_info *info,
+                                              bfd_boolean *pneeded)
 {
   return generic_link_check_archive_element (abfd, info, pneeded, FALSE);
 }
@@ -1135,10 +1168,9 @@ generic_link_check_archive_element_no_collect (abfd, info, pneeded)
    symbol name, as collect2 does.  */
 
 static bfd_boolean
-generic_link_check_archive_element_collect (abfd, info, pneeded)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     bfd_boolean *pneeded;
+generic_link_check_archive_element_collect (bfd *abfd,
+                                           struct bfd_link_info *info,
+                                           bfd_boolean *pneeded)
 {
   return generic_link_check_archive_element (abfd, info, pneeded, TRUE);
 }
@@ -1147,17 +1179,16 @@ generic_link_check_archive_element_collect (abfd, info, pneeded)
    constructors.  */
 
 static bfd_boolean
-generic_link_check_archive_element (abfd, info, pneeded, collect)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     bfd_boolean *pneeded;
-     bfd_boolean collect;
+generic_link_check_archive_element (bfd *abfd,
+                                   struct bfd_link_info *info,
+                                   bfd_boolean *pneeded,
+                                   bfd_boolean collect)
 {
   asymbol **pp, **ppend;
 
   *pneeded = FALSE;
 
-  if (! generic_link_read_symbols (abfd))
+  if (!bfd_generic_link_read_symbols (abfd))
     return FALSE;
 
   pp = _bfd_generic_link_get_symbols (abfd);
@@ -1181,7 +1212,7 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
         SVR4 ABI, p. 4-27.  */
       h = bfd_link_hash_lookup (info->hash, bfd_asymbol_name (p), FALSE,
                                FALSE, TRUE);
-      if (h == (struct bfd_link_hash_entry *) NULL
+      if (h == NULL
          || (h->type != bfd_link_hash_undefined
              && h->type != bfd_link_hash_common))
        continue;
@@ -1192,10 +1223,17 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
        {
          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);
@@ -1215,14 +1253,18 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
          unsigned int power;
 
          symbfd = h->u.undef.abfd;
-         if (symbfd == (bfd *) NULL)
+         if (symbfd == NULL)
            {
              /* 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,10 +1277,9 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
             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 =
-           ((struct bfd_link_hash_common_entry *)
-            bfd_hash_allocate (&info->hash->table,
-                               sizeof (struct bfd_link_hash_common_entry)));
+         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)
            return FALSE;
 
@@ -1279,12 +1320,11 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
    as is done by collect2.  */
 
 static bfd_boolean
-generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     bfd_size_type symbol_count;
-     asymbol **symbols;
-     bfd_boolean collect;
+generic_link_add_symbol_list (bfd *abfd,
+                             struct bfd_link_info *info,
+                             bfd_size_type symbol_count,
+                             asymbol **symbols,
+                             bfd_boolean collect)
 {
   asymbol **pp, **ppend;
 
@@ -1310,7 +1350,7 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
          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)
@@ -1323,12 +1363,9 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
            {
              /* 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
@@ -1356,9 +1393,9 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
             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 == (asymbol *) NULL
+             if (h->sym == NULL
                  || (! bfd_is_und_section (bfd_get_section (p))
                      && (! bfd_is_com_section (bfd_get_section (p))
                          || bfd_is_und_section (bfd_get_section (h->sym)))))
@@ -1377,7 +1414,7 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
             it gets rewritten to not use asymbol structures.
             Setting this is also used to check whether these
             symbols were set up by the generic linker.  */
-         p->udata.p = (PTR) h;
+         p->udata.p = h;
        }
     }
 
@@ -1477,8 +1514,7 @@ static const enum link_action link_action[8][8] =
 /* Return the BFD in which a hash entry has been defined, if known.  */
 
 static bfd *
-hash_entry_bfd (h)
-     struct bfd_link_hash_entry *h;
+hash_entry_bfd (struct bfd_link_hash_entry *h)
 {
   while (h->type == bfd_link_hash_warning)
     h = h->u.i.link;
@@ -1517,18 +1553,16 @@ hash_entry_bfd (h)
      the hash table entry, and stored it in *HASHP.  */
 
 bfd_boolean
-_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
-                                 string, copy, collect, hashp)
-     struct bfd_link_info *info;
-     bfd *abfd;
-     const char *name;
-     flagword flags;
-     asection *section;
-     bfd_vma value;
-     const char *string;
-     bfd_boolean copy;
-     bfd_boolean collect;
-     struct bfd_link_hash_entry **hashp;
+_bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
+                                 bfd *abfd,
+                                 const char *name,
+                                 flagword flags,
+                                 asection *section,
+                                 bfd_vma value,
+                                 const char *string,
+                                 bfd_boolean copy,
+                                 bfd_boolean collect,
+                                 struct bfd_link_hash_entry **hashp)
 {
   enum link_row row;
   struct bfd_link_hash_entry *h;
@@ -1572,16 +1606,15 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
     }
 
   if (info->notice_all
-      || (info->notice_hash != (struct bfd_hash_table *) NULL
-         && (bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE)
-             != (struct bfd_hash_entry *) NULL)))
+      || (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))
        return FALSE;
     }
 
-  if (hashp != (struct bfd_link_hash_entry **) NULL)
+  if (hashp != NULL)
     *hashp = h;
 
   do
@@ -1610,6 +1643,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
          /* 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:
@@ -1619,7 +1653,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
          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, (bfd_vma) 0)))
+                 abfd, bfd_link_hash_defined, 0)))
            return FALSE;
          /* Fall through.  */
        case DEF:
@@ -1658,8 +1692,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
                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;
 
@@ -1693,10 +1726,9 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
          if (h->type == bfd_link_hash_new)
            bfd_link_add_undef (info->hash, h);
          h->type = bfd_link_hash_common;
-         h->u.c.p =
-           ((struct bfd_link_hash_common_entry *)
-            bfd_hash_allocate (&info->hash->table,
-                               sizeof (struct bfd_link_hash_common_entry)));
+         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)
            return FALSE;
 
@@ -1740,8 +1772,8 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
 
        case REF:
          /* A reference to a defined symbol.  */
-         if (h->next == NULL && info->hash->undefs_tail != h)
-           h->next = h;
+         if (h->u.undef.next == NULL && info->hash->undefs_tail != h)
+           h->u.undef.next = h;
          break;
 
        case BIG:
@@ -1802,7 +1834,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
            else
              obfd = NULL;
            if (! ((*info->callbacks->multiple_common)
-                  (info, h->root.string, obfd, h->type, (bfd_vma) 0,
+                  (info, h->root.string, obfd, h->type, 0,
                    abfd, bfd_link_hash_common, value)))
              return FALSE;
          }
@@ -1856,7 +1888,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
          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, (bfd_vma) 0)))
+                 abfd, bfd_link_hash_indirect, 0)))
            return FALSE;
          /* Fall through.  */
        case IND:
@@ -1868,14 +1900,14 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
               to.  */
            inh = bfd_wrapped_link_hash_lookup (abfd, info, string, TRUE,
                                                copy, FALSE);
-           if (inh == (struct bfd_link_hash_entry *) NULL)
+           if (inh == NULL)
              return FALSE;
            if (inh->type == bfd_link_hash_indirect
                && inh->u.i.link == h)
              {
                (*_bfd_error_handler)
-                 (_("%s: indirect symbol `%s' to `%s' is a loop"),
-                  bfd_archive_filename (abfd), name, string);
+                 (_("%B: indirect symbol `%s' to `%s' is a loop"),
+                  abfd, name, string);
                bfd_set_error (bfd_error_invalid_operation);
                return FALSE;
              }
@@ -1913,8 +1945,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
            {
              if (! (*info->callbacks->warning) (info, h->u.i.warning,
                                                 h->root.string, abfd,
-                                                (asection *) NULL,
-                                                (bfd_vma) 0))
+                                                NULL, 0))
                return FALSE;
              /* Only issue a warning once.  */
              h->u.i.warning = NULL;
@@ -1928,8 +1959,8 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
 
        case REFC:
          /* A reference to an indirect symbol.  */
-         if (h->next == NULL && info->hash->undefs_tail != h)
-           h->next = h;
+         if (h->u.undef.next == NULL && info->hash->undefs_tail != h)
+           h->u.undef.next = h;
          h = h->u.i.link;
          cycle = TRUE;
          break;
@@ -1937,23 +1968,20 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
        case WARN:
          /* Issue a warning.  */
          if (! (*info->callbacks->warning) (info, string, h->root.string,
-                                            hash_entry_bfd (h),
-                                            (asection *) NULL, (bfd_vma) 0))
+                                            hash_entry_bfd (h), NULL, 0))
            return FALSE;
          break;
 
        case CWARN:
          /* Warn if this symbol has been referenced already,
             otherwise add a warning.  A symbol has been referenced if
-            the next field is not NULL, or it is the tail of the
+            the u.undef.next field is not NULL, or it is the tail of the
             undefined symbol list.  The REF case above helps to
             ensure this.  */
-         if (h->next != NULL || info->hash->undefs_tail == h)
+         if (h->u.undef.next != NULL || info->hash->undefs_tail == h)
            {
              if (! (*info->callbacks->warning) (info, string, h->root.string,
-                                                hash_entry_bfd (h),
-                                                (asection *) NULL,
-                                                (bfd_vma) 0))
+                                                hash_entry_bfd (h), NULL, 0))
                return FALSE;
              break;
            }
@@ -1966,8 +1994,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
            /* STRING is the warning to give.  */
            sub = ((struct bfd_link_hash_entry *)
                   ((*info->hash->table.newfunc)
-                   ((struct bfd_hash_entry *) NULL, &info->hash->table,
-                    h->root.string)));
+                   (NULL, &info->hash->table, h->root.string)));
            if (sub == NULL)
              return FALSE;
            *sub = *h;
@@ -1980,7 +2007,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
                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);
@@ -2004,9 +2031,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
 /* Generic final link routine.  */
 
 bfd_boolean
-_bfd_generic_final_link (abfd, info)
-     bfd *abfd;
-     struct bfd_link_info *info;
+_bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info)
 {
   bfd *sub;
   asection *o;
@@ -2014,18 +2039,18 @@ _bfd_generic_final_link (abfd, info)
   size_t outsymalloc;
   struct generic_write_global_symbol_info wginfo;
 
-  bfd_get_outsymbols (abfd) = (asymbol **) NULL;
+  bfd_get_outsymbols (abfd) = NULL;
   bfd_get_symcount (abfd) = 0;
   outsymalloc = 0;
 
   /* 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 != (bfd *) 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;
 
@@ -2035,7 +2060,7 @@ _bfd_generic_final_link (abfd, info)
   wginfo.psymalloc = &outsymalloc;
   _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
                                   _bfd_generic_link_write_global_symbol,
-                                  (PTR) &wginfo);
+                                  &wginfo);
 
   /* Make sure we have a trailing NULL pointer on OUTSYMBOLS.  We
      shouldn't really need one, since we have SYMCOUNT, but some old
@@ -2046,14 +2071,10 @@ _bfd_generic_final_link (abfd, info)
   if (info->relocatable)
     {
       /* Allocate space for the output relocs for each section.  */
-      for (o = abfd->sections;
-          o != (asection *) NULL;
-          o = o->next)
+      for (o = abfd->sections; o != NULL; o = o->next)
        {
          o->reloc_count = 0;
-         for (p = o->link_order_head;
-              p != (struct bfd_link_order *) 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)
@@ -2073,7 +2094,7 @@ _bfd_generic_final_link (abfd, info)
                                                       input_section);
                  if (relsize < 0)
                    return FALSE;
-                 relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize);
+                 relocs = (arelent **) bfd_malloc (relsize);
                  if (!relocs && relsize != 0)
                    return FALSE;
                  symbols = _bfd_generic_link_get_symbols (input_bfd);
@@ -2095,7 +2116,7 @@ _bfd_generic_final_link (abfd, info)
 
              amt = o->reloc_count;
              amt *= sizeof (arelent *);
-             o->orelocation = (arelent **) bfd_alloc (abfd, amt);
+             o->orelocation = (struct reloc_cache_entry **) bfd_alloc (abfd, amt);
              if (!o->orelocation)
                return FALSE;
              o->flags |= SEC_RELOC;
@@ -2107,13 +2128,9 @@ _bfd_generic_final_link (abfd, info)
     }
 
   /* Handle all the link order information for the sections.  */
-  for (o = abfd->sections;
-       o != (asection *) NULL;
-       o = o->next)
+  for (o = abfd->sections; o != NULL; o = o->next)
     {
-      for (p = o->link_order_head;
-          p != (struct bfd_link_order *) NULL;
-          p = p->next)
+      for (p = o->map_head.link_order; p != NULL; p = p->next)
        {
          switch (p->type)
            {
@@ -2140,10 +2157,7 @@ _bfd_generic_final_link (abfd, info)
 /* Add an output symbol to the output BFD.  */
 
 static bfd_boolean
-generic_add_output_symbol (output_bfd, psymalloc, sym)
-     bfd *output_bfd;
-     size_t *psymalloc;
-     asymbol *sym;
+generic_add_output_symbol (bfd *output_bfd, size_t *psymalloc, asymbol *sym)
 {
   if (bfd_get_symcount (output_bfd) >= *psymalloc)
     {
@@ -2157,7 +2171,7 @@ generic_add_output_symbol (output_bfd, psymalloc, sym)
       amt = *psymalloc;
       amt *= sizeof (asymbol *);
       newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
-      if (newsyms == (asymbol **) NULL)
+      if (newsyms == NULL)
        return FALSE;
       bfd_get_outsymbols (output_bfd) = newsyms;
     }
@@ -2172,26 +2186,23 @@ generic_add_output_symbol (output_bfd, psymalloc, sym)
 /* Handle the symbols for an input BFD.  */
 
 bfd_boolean
-_bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
-     bfd *output_bfd;
-     bfd *input_bfd;
-     struct bfd_link_info *info;
-     size_t *psymalloc;
+_bfd_generic_link_output_symbols (bfd *output_bfd,
+                                 bfd *input_bfd,
+                                 struct bfd_link_info *info,
+                                 size_t *psymalloc)
 {
   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.  */
-  if (info->create_object_symbols_section != (asection *) NULL)
+  if (info->create_object_symbols_section != NULL)
     {
       asection *sec;
 
-      for (sec = input_bfd->sections;
-          sec != (asection *) NULL;
-          sec = sec->next)
+      for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
        {
          if (sec->output_section == info->create_object_symbols_section)
            {
@@ -2224,7 +2235,7 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
       struct generic_link_hash_entry *h;
       bfd_boolean output;
 
-      h = (struct generic_link_hash_entry *) NULL;
+      h = NULL;
       sym = *sym_ptr;
       if ((sym->flags & (BSF_INDIRECT
                         | BSF_WARNING
@@ -2259,16 +2270,16 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
                                               bfd_asymbol_name (sym),
                                               FALSE, FALSE, TRUE);
 
-         if (h != (struct generic_link_hash_entry *) NULL)
+         if (h != NULL)
            {
              /* Force all references to this symbol to point to
                 the same area in memory.  It is possible that
                 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 != (asymbol *) NULL)
+                 if (h->sym != NULL)
                    *sym_ptr = sym = h->sym;
                }
 
@@ -2320,9 +2331,8 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
         write_file_locals in ldsym.c.  */
       if (info->strip == strip_all
          || (info->strip == strip_some
-             && (bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym),
-                                  FALSE, FALSE)
-                 == (struct bfd_hash_entry *) NULL)))
+             && bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym),
+                                 FALSE, FALSE) == NULL))
        output = FALSE;
       else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
        {
@@ -2389,19 +2399,18 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
        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)
        {
          if (! generic_add_output_symbol (output_bfd, psymalloc, sym))
            return FALSE;
-         if (h != (struct generic_link_hash_entry *) NULL)
+         if (h != NULL)
            h->written = TRUE;
        }
     }
@@ -2413,9 +2422,7 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
    hash table entry.  */
 
 static void
-set_symbol_from_hash (sym, h)
-     asymbol *sym;
-     struct bfd_link_hash_entry *h;
+set_symbol_from_hash (asymbol *sym, struct bfd_link_hash_entry *h)
 {
   switch (h->type)
     {
@@ -2476,12 +2483,11 @@ set_symbol_from_hash (sym, h)
    This is called for each symbol in the hash table.  */
 
 bfd_boolean
-_bfd_generic_link_write_global_symbol (h, data)
-     struct generic_link_hash_entry *h;
-     PTR data;
+_bfd_generic_link_write_global_symbol (struct generic_link_hash_entry *h,
+                                      void *data)
 {
   struct generic_write_global_symbol_info *wginfo =
-    (struct generic_write_global_symbol_info *) data;
+      (struct generic_write_global_symbol_info *) data;
   asymbol *sym;
 
   if (h->root.type == bfd_link_hash_warning)
@@ -2498,7 +2504,7 @@ _bfd_generic_link_write_global_symbol (h, data)
                              FALSE, FALSE) == NULL))
     return TRUE;
 
-  if (h->sym != (asymbol *) NULL)
+  if (h->sym != NULL)
     sym = h->sym;
   else
     {
@@ -2526,21 +2532,20 @@ _bfd_generic_link_write_global_symbol (h, data)
 /* Create a relocation.  */
 
 bfd_boolean
-_bfd_generic_reloc_link_order (abfd, info, sec, link_order)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     asection *sec;
-     struct bfd_link_order *link_order;
+_bfd_generic_reloc_link_order (bfd *abfd,
+                              struct bfd_link_info *info,
+                              asection *sec,
+                              struct bfd_link_order *link_order)
 {
   arelent *r;
 
   if (! info->relocatable)
     abort ();
-  if (sec->orelocation == (arelent **) NULL)
+  if (sec->orelocation == NULL)
     abort ();
 
-  r = (arelent *) bfd_alloc (abfd, (bfd_size_type) sizeof (arelent));
-  if (r == (arelent *) NULL)
+  r = (arelent *) bfd_alloc (abfd, sizeof (arelent));
+  if (r == NULL)
     return FALSE;
 
   r->address = link_order->offset;
@@ -2562,12 +2567,11 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
           bfd_wrapped_link_hash_lookup (abfd, info,
                                         link_order->u.reloc.p->u.name,
                                         FALSE, FALSE, TRUE));
-      if (h == (struct generic_link_hash_entry *) NULL
+      if (h == NULL
          || ! h->written)
        {
          if (! ((*info->callbacks->unattached_reloc)
-                (info, link_order->u.reloc.p->u.name,
-                 (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+                (info, link_order->u.reloc.p->u.name, NULL, NULL, 0)))
            return FALSE;
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
@@ -2589,7 +2593,7 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
 
       size = bfd_get_reloc_size (r->howto);
       buf = (bfd_byte *) bfd_zmalloc (size);
-      if (buf == (bfd_byte *) NULL)
+      if (buf == NULL)
        return FALSE;
       rstat = _bfd_relocate_contents (r->howto, abfd,
                                      (bfd_vma) link_order->u.reloc.p->addend,
@@ -2603,12 +2607,12 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
          abort ();
        case bfd_reloc_overflow:
          if (! ((*info->callbacks->reloc_overflow)
-                (info,
+                (info, NULL,
                  (link_order->type == bfd_section_reloc_link_order
                   ? bfd_section_name (abfd, link_order->u.reloc.p->u.section)
                   : link_order->u.reloc.p->u.name),
                  r->howto->name, link_order->u.reloc.p->addend,
-                 (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+                 NULL, NULL, 0)))
            {
              free (buf);
              return FALSE;
@@ -2616,8 +2620,7 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
          break;
        }
       loc = link_order->offset * bfd_octets_per_byte (abfd);
-      ok = bfd_set_section_contents (abfd, sec, (PTR) buf, loc,
-                                    (bfd_size_type) size);
+      ok = bfd_set_section_contents (abfd, sec, buf, loc, size);
       free (buf);
       if (! ok)
        return FALSE;
@@ -2634,26 +2637,24 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
 /* Allocate a new link_order for a section.  */
 
 struct bfd_link_order *
-bfd_new_link_order (abfd, section)
-     bfd *abfd;
-     asection *section;
+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 = (struct bfd_link_order *) 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 != (struct bfd_link_order *) 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
@@ -2661,11 +2662,10 @@ bfd_new_link_order (abfd, section)
    of how the particular backends generates relocs.  */
 
 bfd_boolean
-_bfd_default_link_order (abfd, info, sec, link_order)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     asection *sec;
-     struct bfd_link_order *link_order;
+_bfd_default_link_order (bfd *abfd,
+                        struct bfd_link_info *info,
+                        asection *sec,
+                        struct bfd_link_order *link_order)
 {
   switch (link_order->type)
     {
@@ -2685,11 +2685,10 @@ _bfd_default_link_order (abfd, info, sec, link_order)
 /* Default routine to handle a bfd_data_link_order.  */
 
 static bfd_boolean
-default_data_link_order (abfd, info, sec, link_order)
-     bfd *abfd;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
-     asection *sec;
-     struct bfd_link_order *link_order;
+default_data_link_order (bfd *abfd,
+                        struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                        asection *sec,
+                        struct bfd_link_order *link_order)
 {
   bfd_size_type size;
   size_t fill_size;
@@ -2740,13 +2739,11 @@ default_data_link_order (abfd, info, sec, link_order)
 /* Default routine to handle a bfd_indirect_link_order.  */
 
 static bfd_boolean
-default_indirect_link_order (output_bfd, info, output_section, link_order,
-                            generic_linker)
-     bfd *output_bfd;
-     struct bfd_link_info *info;
-     asection *output_section;
-     struct bfd_link_order *link_order;
-     bfd_boolean generic_linker;
+default_indirect_link_order (bfd *output_bfd,
+                            struct bfd_link_info *info,
+                            asection *output_section,
+                            struct bfd_link_order *link_order,
+                            bfd_boolean generic_linker)
 {
   asection *input_section;
   bfd *input_bfd;
@@ -2757,19 +2754,18 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
 
   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);
-  BFD_ASSERT (input_section->_cooked_size == link_order->size);
+  BFD_ASSERT (input_section->size == link_order->size);
 
   if (info->relocatable
       && input_section->reloc_count > 0
-      && output_section->orelocation == (arelent **) NULL)
+      && output_section->orelocation == NULL)
     {
       /* Space has not been allocated for the output relocations.
         This can happen when we are called by a specific backend
@@ -2792,7 +2788,7 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
         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
@@ -2836,21 +2832,41 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
        }
     }
 
-  /* Get and relocate the section contents.  */
-  sec_size = bfd_section_size (input_bfd, input_section);
-  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;
+  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,
-                                 (PTR) new_contents, loc, link_order->size))
+                                 new_contents, loc, input_section->size))
     goto error_return;
 
   if (contents != NULL)
@@ -2867,14 +2883,13 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
    list.  */
 
 unsigned int
-_bfd_count_link_order_relocs (link_order)
-     struct bfd_link_order *link_order;
+_bfd_count_link_order_relocs (struct bfd_link_order *link_order)
 {
   register unsigned int c;
   register struct bfd_link_order *l;
 
   c = 0;
-  for (l = link_order; l != (struct bfd_link_order *) NULL; l = l->next)
+  for (l = link_order; l != NULL; l = l->next)
     {
       if (l->type == bfd_section_reloc_link_order
          || l->type == bfd_symbol_reloc_link_order)
@@ -2889,7 +2904,7 @@ FUNCTION
        bfd_link_split_section
 
 SYNOPSIS
-        bfd_boolean bfd_link_split_section(bfd *abfd, asection *sec);
+        bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec);
 
 DESCRIPTION
        Return nonzero if @var{sec} should be split during a
@@ -2902,9 +2917,482 @@ DESCRIPTION
 */
 
 bfd_boolean
-_bfd_generic_link_split_section (abfd, sec)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     asection *sec ATTRIBUTE_UNUSED;
+_bfd_generic_link_split_section (bfd *abfd ATTRIBUTE_UNUSED,
+                                asection *sec ATTRIBUTE_UNUSED)
 {
   return FALSE;
 }
+
+/*
+FUNCTION
+       bfd_section_already_linked
+
+SYNOPSIS
+        void 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.
+
+.#define bfd_section_already_linked(abfd, sec, info) \
+.       BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
+.
+
+*/
+
+/* 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 
+   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.  */
+
+/* The hash table.  */
+
+static struct bfd_hash_table _bfd_section_already_linked_table;
+
+/* Support routines for the hash table used by section_already_linked,
+   initialize the table, traverse, lookup, fill in an entry and remove
+   the table.  */
+
+void
+bfd_section_already_linked_table_traverse
+  (bfd_boolean (*func) (struct bfd_section_already_linked_hash_entry *,
+                       void *), void *info)
+{
+  bfd_hash_traverse (&_bfd_section_already_linked_table,
+                    (bfd_boolean (*) (struct bfd_hash_entry *,
+                                      void *)) func,
+                    info);
+}
+
+struct bfd_section_already_linked_hash_entry *
+bfd_section_already_linked_table_lookup (const char *name)
+{
+  return ((struct bfd_section_already_linked_hash_entry *)
+         bfd_hash_lookup (&_bfd_section_already_linked_table, name,
+                          TRUE, FALSE));
+}
+
+bfd_boolean
+bfd_section_already_linked_table_insert
+  (struct bfd_section_already_linked_hash_entry *already_linked_list,
+   asection *sec)
+{
+  struct bfd_section_already_linked *l;
+
+  /* Allocate the memory from the same obstack as the hash table is
+     kept in.  */
+  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 *
+already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED,
+                       struct bfd_hash_table *table,
+                       const char *string ATTRIBUTE_UNUSED)
+{
+  struct bfd_section_already_linked_hash_entry *ret =
+    (struct bfd_section_already_linked_hash_entry *)
+      bfd_hash_allocate (table, sizeof *ret);
+
+  if (ret == NULL)
+    return NULL;
+
+  ret->entry = NULL;
+
+  return &ret->root;
+}
+
+bfd_boolean
+bfd_section_already_linked_table_init (void)
+{
+  return bfd_hash_table_init_n (&_bfd_section_already_linked_table,
+                               already_linked_newfunc,
+                               sizeof (struct bfd_section_already_linked_hash_entry),
+                               42);
+}
+
+void
+bfd_section_already_linked_table_free (void)
+{
+  bfd_hash_table_free (&_bfd_section_already_linked_table);
+}
+
+/* This is used on non-ELF inputs.  */
+
+void
+_bfd_generic_section_already_linked (bfd *abfd, 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;
+
+  /* FIXME: When doing a relocatable link, we may have trouble
+     copying relocations in other sections that refer to local symbols
+     in the section being discarded.  Those relocations will have to
+     be converted somehow; as of this writing I'm not sure that any of
+     the backends handle that correctly.
+
+     It is tempting to instead not discard link once sections when
+     doing a relocatable link (technically, they should be discarded
+     whenever we are building constructors).  However, that fails,
+     because the linker winds up combining all the link once sections
+     into a single large link once section, which defeats the purpose
+     of having link once sections in the first place.  */
+
+  name = bfd_get_section_name (abfd, sec);
+
+  already_linked_list = bfd_section_already_linked_table_lookup (name);
+
+  for (l = already_linked_list->entry; l != NULL; l = l->next)
+    {
+      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)
+       {
+         if (s_comdat != NULL
+             && l_comdat != NULL
+             && strcmp (s_comdat->name, l_comdat->name) != 0)
+           skip = TRUE;
+       }
+      else if (l_comdat != NULL)
+       skip = TRUE;
+
+      if (!skip)
+       {
+         /* The section has already been linked.  See if we should
+             issue a warning.  */
+         switch (flags & SEC_LINK_DUPLICATES)
+           {
+           default:
+             abort ();
+
+           case SEC_LINK_DUPLICATES_DISCARD:
+             break;
+
+           case SEC_LINK_DUPLICATES_ONE_ONLY:
+             (*_bfd_error_handler)
+               (_("%B: warning: ignoring duplicate section `%A'\n"),
+                abfd, sec);
+             break;
+
+           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;
+           }
+
+         /* 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;
+       }
+    }
+
+  /* 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"));
+}
+
+/* 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_warning)
+    h = h->u.i.link;
+
+  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))
+       {
+         asection *op, *op1;
+
+         h->u.def.value += s->output_offset + s->output_section->vma;
+
+         /* Find preceding kept section.  */
+         for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev)
+           if ((op1->flags & SEC_EXCLUDE) == 0
+               && !bfd_section_removed_from_list (obfd, op1))
+             break;
+
+         /* Find following kept section.  Start at prev->next because
+            other sections may have been added after S was removed.  */
+         if (s->output_section->prev != NULL)
+           op = s->output_section->prev->next;
+         else
+           op = s->output_section->owner->sections;
+         for (; op != NULL; op = op->next)
+           if ((op->flags & SEC_EXCLUDE) == 0
+               && !bfd_section_removed_from_list (obfd, op))
+             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.  */
+         if (op1 == NULL)
+           {
+             if (op == NULL)
+               op = bfd_abs_section_ptr;
+           }
+         else if (op == NULL)
+           op = op1;
+         else if (((op1->flags ^ op->flags)
+                   & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
+           {
+             if (((op->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 OP and OP1.  */
+                 || ((op1->flags & SEC_LOAD) != 0
+                     && (op->flags & SEC_LOAD) == 0))
+               op = op1;
+           }
+         else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0)
+           {
+             if (((op->flags ^ s->flags) & SEC_READONLY) != 0)
+               op = op1;
+           }
+         else if (((op1->flags ^ op->flags) & SEC_CODE) != 0)
+           {
+             if (((op->flags ^ s->flags) & SEC_CODE) != 0)
+               op = op1;
+           }
+         else
+           {
+             /* Flags we care about are the same.  Prefer the following
+                section if that will result in a positive valued sym.  */
+             if (h->u.def.value < op->vma)
+               op = op1;
+           }
+
+         h->u.def.value -= op->vma;
+         h->u.def.section = op;
+       }
+    }
+
+  return TRUE;
+}
+
+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)
+       {
+         struct bfd_elf_version_expr *d = NULL;
+
+         while ((d = (*t->match) (&t->globals, d, sym_name)) != NULL)
+           {
+             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;
+           }
+
+         if (d != NULL)
+           break;
+       }
+
+      if (t->locals.list != NULL)
+       {
+         struct bfd_elf_version_expr *d = NULL;
+
+         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;
+               }
+           }
+
+         if (d != NULL)
+           break;
+       }
+    }
+
+  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;
+}
This page took 0.050253 seconds and 4 git commands to generate.