* elflink.c (is_reloc_section): New function. Returns true if the
[deliverable/binutils-gdb.git] / bfd / linker.c
index c0e3236f853e04b3d95c05848cb0bdeb61c82b12..5080d7d44cb6eb9a41710a4333ce65c2a7c563a6 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
    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"
@@ -88,7 +90,7 @@ SUBSECTION
 
        For example, with each entry in the hash table the a.out
        linker keeps the index the symbol has in the final output file
-       (this index number is used so that when doing a relocateable
+       (this index number is used so that when doing a relocatable
        link the symbol index used in the output file can be quickly
        filled in when copying over a reloc).  The a.out linker code
        defines the required structures and functions for a hash table
@@ -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.
 
@@ -277,7 +279,7 @@ SUBSECTION
        the input sections and copy the data into the output sections.
        It must build an output symbol table including any local
        symbols from the input files and the global symbols from the
-       hash table.  When producing relocateable output, it must
+       hash table.  When producing relocatable output, it must
        modify the input relocs and write them into the output file.
        There may also be object format dependent work to be done.
 
@@ -309,7 +311,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
@@ -317,7 +319,7 @@ SUBSUBSECTION
        types of information.  They also describe relocs that must be
        created by the BFD backend, but do not correspond to any input
        file; this is used to support -Ur, which builds constructors
-       while generating a relocateable object file.
+       while generating a relocatable object file.
 
 INODE
 Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link
@@ -339,7 +341,7 @@ SUBSUBSECTION
        input files.  The <<_bfd_final_link>> function should read the
        contents of the section and any associated relocs, apply the
        relocs to the section contents, and write out the modified
-       section contents.  If performing a relocateable link, the
+       section contents.  If performing a relocatable link, the
        relocs themselves must also be modified and written out.
 
 @findex _bfd_relocate_contents
@@ -406,34 +408,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 +436,15 @@ 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));
+      entry = bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
       if (entry == NULL)
        return entry;
     }
@@ -465,7 +457,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 +469,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 +489,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 +515,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_"
@@ -552,12 +548,11 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
              references to SYM with references to __wrap_SYM.  */
 
          amt = strlen (l) + sizeof WRAP + 1;
-         n = (char *) bfd_malloc (amt);
+         n = bfd_malloc (amt);
          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 +563,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)
        {
@@ -584,12 +579,11 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
              with references to SYM.  */
 
          amt = strlen (l + sizeof REAL - 1) + 2;
-         n = (char *) bfd_malloc (amt);
+         n = bfd_malloc (amt);
          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,45 +604,81 @@ 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.  */
   if (entry == NULL)
     {
-      entry = (struct bfd_hash_entry *)
+      entry =
        bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry));
       if (entry == NULL)
        return entry;
@@ -672,27 +702,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);
+  ret = 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 +737,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 +748,7 @@ 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) = 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 +765,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 +778,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,9 +788,8 @@ _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;
@@ -776,10 +798,9 @@ _bfd_generic_link_just_syms (sec, info)
 /* 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 +827,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 +868,20 @@ 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 = bfd_hash_allocate (table, sizeof (struct archive_hash_entry));
+  if (ret == NULL)
     return NULL;
 
   /* Call the allocation method of the superclass.  */
@@ -881,22 +891,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.  */
@@ -947,11 +958,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 +974,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 +985,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 +994,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 +1015,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,22 +1036,22 @@ _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 */
          if (info->pei386_auto_import)
            {
              bfd_size_type amt = strlen (h->root.string) + 10;
-             char *buf = (char *) bfd_malloc (amt);
+             char *buf = bfd_malloc (amt);
              if (buf == NULL)
                return FALSE;
 
@@ -1050,14 +1059,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 +1077,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 +1110,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 +1131,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 +1144,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 +1155,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 +1188,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;
@@ -1215,7 +1222,7 @@ 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
@@ -1236,9 +1243,8 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
             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)));
+           bfd_hash_allocate (&info->hash->table,
+                              sizeof (struct bfd_link_hash_common_entry));
          if (h->u.c.p == NULL)
            return FALSE;
 
@@ -1279,12 +1285,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 +1315,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 +1328,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 +1358,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 +1379,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 +1479,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 +1518,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 +1571,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 +1608,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 +1618,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 +1657,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;
 
@@ -1694,9 +1692,8 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
            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)));
+           bfd_hash_allocate (&info->hash->table,
+                              sizeof (struct bfd_link_hash_common_entry));
          if (h->u.c.p == NULL)
            return FALSE;
 
@@ -1740,8 +1737,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 +1799,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 +1853,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 +1865,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 +1910,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 +1924,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 +1933,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 +1959,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;
@@ -2004,9 +1996,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 +2004,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 +2025,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
@@ -2043,17 +2033,13 @@ _bfd_generic_final_link (abfd, info)
   if (! generic_add_output_symbol (abfd, &outsymalloc, NULL))
     return FALSE;
 
-  if (info->relocateable)
+  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 +2059,7 @@ _bfd_generic_final_link (abfd, info)
                                                       input_section);
                  if (relsize < 0)
                    return FALSE;
-                 relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize);
+                 relocs = bfd_malloc (relsize);
                  if (!relocs && relsize != 0)
                    return FALSE;
                  symbols = _bfd_generic_link_get_symbols (input_bfd);
@@ -2095,7 +2081,7 @@ _bfd_generic_final_link (abfd, info)
 
              amt = o->reloc_count;
              amt *= sizeof (arelent *);
-             o->orelocation = (arelent **) bfd_alloc (abfd, amt);
+             o->orelocation = bfd_alloc (abfd, amt);
              if (!o->orelocation)
                return FALSE;
              o->flags |= SEC_RELOC;
@@ -2107,13 +2093,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 +2122,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)
     {
@@ -2156,8 +2135,8 @@ generic_add_output_symbol (output_bfd, psymalloc, sym)
        *psymalloc *= 2;
       amt = *psymalloc;
       amt *= sizeof (asymbol *);
-      newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
-      if (newsyms == (asymbol **) NULL)
+      newsyms = bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
+      if (newsyms == NULL)
        return FALSE;
       bfd_get_outsymbols (output_bfd) = newsyms;
     }
@@ -2172,26 +2151,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 +2200,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
@@ -2236,7 +2212,7 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
          || bfd_is_ind_section (bfd_get_section (sym)))
        {
          if (sym->udata.p != NULL)
-           h = (struct generic_link_hash_entry *) sym->udata.p;
+           h = sym->udata.p;
          else if ((sym->flags & BSF_CONSTRUCTOR) != 0)
            {
              /* This case normally means that the main linker code
@@ -2259,16 +2235,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 +2296,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)
        {
@@ -2362,7 +2337,7 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
                  break;
                case discard_sec_merge:
                  output = TRUE;
-                 if (info->relocateable
+                 if (info->relocatable
                      || ! (sym->section->flags & SEC_MERGE))
                    break;
                  /* FALLTHROUGH */
@@ -2389,19 +2364,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 +2387,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 +2448,10 @@ 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 *wginfo = data;
   asymbol *sym;
 
   if (h->root.type == bfd_link_hash_warning)
@@ -2498,7 +2468,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 +2496,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->relocateable)
+  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 = bfd_alloc (abfd, sizeof (arelent));
+  if (r == NULL)
     return FALSE;
 
   r->address = link_order->offset;
@@ -2562,12 +2531,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;
@@ -2588,8 +2556,8 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
       file_ptr loc;
 
       size = bfd_get_reloc_size (r->howto);
-      buf = (bfd_byte *) bfd_zmalloc (size);
-      if (buf == (bfd_byte *) NULL)
+      buf = bfd_zmalloc (size);
+      if (buf == NULL)
        return FALSE;
       rstat = _bfd_relocate_contents (r->howto, abfd,
                                      (bfd_vma) link_order->u.reloc.p->addend,
@@ -2603,12 +2571,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 +2584,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,24 +2601,22 @@ _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;
 
-  new = (struct bfd_link_order *) bfd_zalloc (abfd, amt);
+  new = bfd_zalloc (abfd, amt);
   if (!new)
     return NULL;
 
   new->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;
   else
-    section->link_order_head = new;
-  section->link_order_tail = new;
+    section->map_head.link_order = new;
+  section->map_tail.link_order = new;
 
   return new;
 }
@@ -2661,11 +2626,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 +2649,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;
@@ -2708,7 +2671,7 @@ default_data_link_order (abfd, info, sec, link_order)
   if (fill_size != 0 && fill_size < size)
     {
       bfd_byte *p;
-      fill = (bfd_byte *) bfd_malloc (size);
+      fill = bfd_malloc (size);
       if (fill == NULL)
        return FALSE;
       p = fill;
@@ -2740,13 +2703,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 +2718,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->relocateable
+  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
@@ -2777,7 +2737,7 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
         types of object files.  Handling this case correctly is
         difficult, and sometimes impossible.  */
       (*_bfd_error_handler)
-       (_("Attempt to do relocateable link with %s input and %s output"),
+       (_("Attempt to do relocatable link with %s input and %s output"),
         bfd_get_target (input_bfd), bfd_get_target (output_bfd));
       bfd_set_error (bfd_error_wrong_format);
       return FALSE;
@@ -2792,7 +2752,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
@@ -2821,7 +2781,7 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
              /* sym->udata may have been set by
                 generic_link_add_symbol_list.  */
              if (sym->udata.p != NULL)
-               h = (struct bfd_link_hash_entry *) sym->udata.p;
+               h = 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),
@@ -2836,21 +2796,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->relocateable,
-                  _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_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 +2847,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 +2868,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 +2881,308 @@ 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 = 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 =
+    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"));
+}
+
+/* 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)) != 0)
+           {
+             if (((op->flags ^ s->flags)
+                  & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 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);
+}
This page took 0.051617 seconds and 4 git commands to generate.