]> Git Repo - binutils.git/blobdiff - bfd/linker.c
* targets.c (bfd_target): Add fields
[binutils.git] / bfd / linker.c
index f70f799437509e346cf59a5b44f7a04c18dadaba..276d476d54c3b62399f12fc34deb957528491e4a 100644 (file)
@@ -1,22 +1,22 @@
 /* linker.c -- BFD linker routines
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright (C) 1993, 94 Free Software Foundation, Inc.
    Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
 
-This file is part of BFD
+This file is part of BFD, the Binary File Descriptor library.
 
-GLD is free software; you can redistribute it and/or modify
+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, or (at your option)
-any later version.
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
 
-GLD is distributed in the hope that it will be useful,
+This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GLD; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
@@ -313,7 +313,10 @@ SUBSUBSECTION
        <<bfdlink.h>>).  These structures describe how to create the
        contents of the output section in terms of the contents of
        various input sections, fill constants, and, eventually, other
-       types of information.
+       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.
 
 INODE
 Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link
@@ -409,12 +412,19 @@ SUBSUBSECTION
 static struct bfd_hash_entry *generic_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
           const char *));
+static boolean generic_link_add_symbols
+  PARAMS ((bfd *, struct bfd_link_info *, boolean collect));
 static boolean generic_link_add_object_symbols
-  PARAMS ((bfd *, struct bfd_link_info *));
-static boolean generic_link_check_archive_element
+  PARAMS ((bfd *, struct bfd_link_info *, boolean collect));
+static boolean generic_link_check_archive_element_no_collect
+  PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
+static boolean generic_link_check_archive_element_collect
   PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
+static boolean generic_link_check_archive_element
+  PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded, boolean collect));
 static boolean generic_link_add_symbol_list
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **));
+  PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
+          boolean collect));
 static boolean generic_add_output_symbol
   PARAMS ((bfd *, size_t *psymalloc, asymbol *));
 static boolean default_fill_link_order
@@ -443,15 +453,23 @@ _bfd_link_hash_newfunc (entry, table, string)
   if (ret == (struct bfd_link_hash_entry *) NULL)
     ret = ((struct bfd_link_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry)));
+  if (ret == (struct bfd_link_hash_entry *) NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct bfd_link_hash_entry *)
         bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
 
-  /* Initialize the local fields.  */
-  ret->type = bfd_link_hash_new;
-  ret->written = false;
-  ret->next = NULL;
+  if (ret)
+    {
+      /* Initialize the local fields.  */
+      ret->type = bfd_link_hash_new;
+      ret->written = false;
+      ret->next = NULL;
+    }
 
   return (struct bfd_hash_entry *) ret;
 }
@@ -549,14 +567,22 @@ generic_link_hash_newfunc (entry, table, string)
   if (ret == (struct generic_link_hash_entry *) NULL)
     ret = ((struct generic_link_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry)));
+  if (ret == (struct generic_link_hash_entry *) NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct generic_link_hash_entry *)
         _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
                                 table, string));
 
-  /* Set local fields.  */
-  ret->sym = NULL;
+  if (ret)
+    {
+      /* Set local fields.  */
+      ret->sym = NULL;
+    }
 
   return (struct bfd_hash_entry *) ret;
 }
@@ -570,7 +596,12 @@ _bfd_generic_link_hash_table_create (abfd)
   struct generic_link_hash_table *ret;
 
   ret = ((struct generic_link_hash_table *)
-        bfd_xmalloc (sizeof (struct generic_link_hash_table)));
+        malloc (sizeof (struct generic_link_hash_table)));
+  if (!ret)
+      {
+       bfd_set_error (bfd_error_no_memory);
+       return (struct bfd_link_hash_table *) NULL;
+      }
   if (! _bfd_link_hash_table_init (&ret->root, abfd,
                                   generic_link_hash_newfunc))
     {
@@ -580,57 +611,89 @@ _bfd_generic_link_hash_table_create (abfd)
   return &ret->root;
 }
 \f
-/* Generic function to add symbols from an object file to the global
-   hash table.  */
+/* Generic function to add symbols to from an object file to the
+   global hash table.  This version does not automatically collect
+   constructors by name.  */
 
 boolean
 _bfd_generic_link_add_symbols (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
+{
+  return generic_link_add_symbols (abfd, info, false);
+}
+
+/* Generic function to add symbols from an object file to the global
+   hash table.  This version automatically collects constructors by
+   name, as the collect2 program does.  It should be used for any
+   target which does not provide some other mechanism for setting up
+   constructors and destructors; these are approximately those targets
+   for which gcc uses collect2 and do not support stabs.  */
+
+boolean
+_bfd_generic_link_add_symbols_collect (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  return generic_link_add_symbols (abfd, info, true);
+}
+
+/* Add symbols from an object file to the global hash table.  */
+
+static boolean
+generic_link_add_symbols (abfd, info, collect)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     boolean collect;
 {
   boolean ret;
 
   switch (bfd_get_format (abfd))
     {
     case bfd_object:
-      ret = generic_link_add_object_symbols (abfd, info);
+      ret = generic_link_add_object_symbols (abfd, info, collect);
       break;
     case bfd_archive:
-      ret = _bfd_generic_link_add_archive_symbols
-       (abfd, info, generic_link_check_archive_element);
+      ret = (_bfd_generic_link_add_archive_symbols
+            (abfd, info,
+             (collect
+              ? generic_link_check_archive_element_collect
+              : generic_link_check_archive_element_no_collect)));
       break;
     default:
-      bfd_error = wrong_format;
+      bfd_set_error (bfd_error_wrong_format);
       ret = false;
     }
 
-  /* If we might be using the C based alloca function, make sure we
-     have dumped the symbol tables we just allocated.  */
-#ifndef __GNUC__
-#ifndef alloca
-  alloca (0);
-#endif
-#endif
-
   return ret;
 }
 
 /* Add symbols from an object file to the global hash table.  */
 
 static boolean
-generic_link_add_object_symbols (abfd, info)
+generic_link_add_object_symbols (abfd, info, collect)
      bfd *abfd;
      struct bfd_link_info *info;
+     boolean collect;
 {
   size_t symsize;
   asymbol **symbols;
   bfd_size_type symbol_count;
+  boolean result;
 
   symsize = get_symtab_upper_bound (abfd);
-  symbols = (asymbol **) alloca (symsize);
+  symbols = (asymbol **) malloc (symsize);
+  if (symbols == NULL && symsize != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
   symbol_count = bfd_canonicalize_symtab (abfd, symbols);
 
-  return generic_link_add_symbol_list (abfd, info, symbol_count, symbols);
+  result = generic_link_add_symbol_list (abfd, info, symbol_count, symbols,
+                                        collect);
+  free (symbols);
+  return result;
 }
 \f
 /* We build a hash table of all symbols defined in an archive.  */
@@ -683,13 +746,21 @@ archive_hash_newfunc (entry, table, string)
   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)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct archive_hash_entry *)
         bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
 
-  /* Initialize the local fields.  */
-  ret->defs = (struct archive_list *) NULL;
+  if (ret)
+    {
+      /* Initialize the local fields.  */
+      ret->defs = (struct archive_list *) NULL;
+    }
 
   return (struct bfd_hash_entry *) ret;
 }
@@ -766,7 +837,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
 
   if (! bfd_has_map (abfd))
     {
-      bfd_error = no_symbols;
+      bfd_set_error (bfd_error_no_symbols);
       return false;
     }
 
@@ -780,15 +851,26 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
   for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
     {
       struct archive_hash_entry *arh;
-      struct archive_list *l;
+      struct archive_list *l, **pp;
 
       arh = archive_hash_lookup (&arsym_hash, arsym->name, true, false);
       if (arh == (struct archive_hash_entry *) NULL)
-       return false;
-      l = (struct archive_list *) alloca (sizeof (struct archive_list));
-      l->next = arh->defs;
-      arh->defs = l;
+       goto error_return;
+      l = (struct archive_list *)
+       obstack_alloc (&(&(&arsym_hash)->table)->memory,
+                      sizeof (struct archive_list));
+      if (l == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
       l->indx = indx;
+      for (pp = &arh->defs;
+          *pp != (struct archive_list *) NULL;
+          pp = &(*pp)->next)
+       ;
+      *pp = l;
+      l->next = NULL;
     }
 
   pass = 1;
@@ -842,7 +924,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
 
          element = bfd_get_elt_at_index (abfd, l->indx);
          if (element == (bfd *) NULL)
-           return false;
+           goto error_return;
 
          /* If we've already included this element, or if we've
             already checked it on this pass, continue.  */
@@ -860,7 +942,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
          /* CHECKFN will see if this element should be included, and
             go ahead and include it if appropriate.  */
          if (! (*checkfn) (element, info, &needed))
-           return false;
+           goto error_return;
 
          if (! needed)
            element->archive_pass = pass;
@@ -880,25 +962,64 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
   archive_hash_table_free (&arsym_hash);
 
   return true;
+
+ error_return:
+  archive_hash_table_free (&arsym_hash);
+  return false;
 }
 \f
-/* See if we should include an archive element.  */
+/* See if we should include an archive element.  This version is used
+   when we do not want to automatically collect constructors based on
+   the symbol name, presumably because we have some other mechanism
+   for finding them.  */
+
+static boolean
+generic_link_check_archive_element_no_collect (abfd, info, pneeded)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     boolean *pneeded;
+{
+  return generic_link_check_archive_element (abfd, info, pneeded, false);
+}
+
+/* See if we should include an archive element.  This version is used
+   when we want to automatically collect constructors based on the
+   symbol name, as collect2 does.  */
 
 static boolean
-generic_link_check_archive_element (abfd, info, pneeded)
+generic_link_check_archive_element_collect (abfd, info, pneeded)
      bfd *abfd;
      struct bfd_link_info *info;
      boolean *pneeded;
+{
+  return generic_link_check_archive_element (abfd, info, pneeded, true);
+}
+
+/* See if we should include an archive element.  Optionally collect
+   constructors.  */
+
+static boolean
+generic_link_check_archive_element (abfd, info, pneeded, collect)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     boolean *pneeded;
+     boolean collect;
 {
   size_t symsize;
-  asymbol **symbols;
+  asymbol **symbols = NULL;
   bfd_size_type symbol_count;
   asymbol **pp, **ppend;
 
   *pneeded = false;
 
   symsize = get_symtab_upper_bound (abfd);
-  symbols = (asymbol **) alloca (symsize);
+  symbols = (asymbol **) malloc (symsize);
+  if (symbols == NULL && symsize != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
+
   symbol_count = bfd_canonicalize_symtab (abfd, symbols);
 
   pp = symbols;
@@ -934,12 +1055,12 @@ generic_link_check_archive_element (abfd, info, pneeded)
          /* This object file defines this symbol, so pull it in.  */
          if (! (*info->callbacks->add_archive_element) (info, abfd,
                                                         bfd_asymbol_name (p)))
-           return false;
+           goto error_return;
          if (! generic_link_add_symbol_list (abfd, info, symbol_count,
-                                             symbols))
-           return false;
+                                             symbols, collect))
+           goto error_return;
          *pneeded = true;
-         return true;
+         goto successful_return;
        }
 
       /* P is a common symbol.  */
@@ -956,9 +1077,9 @@ generic_link_check_archive_element (abfd, info, pneeded)
                 file.  This is for the -u option in the linker.  */
              if (! (*info->callbacks->add_archive_element)
                  (info, abfd, bfd_asymbol_name (p)))
-               return false;
+               goto error_return;
              *pneeded = true;
-             return true;
+             goto successful_return;
            }
 
          /* Turn the symbol into a common symbol but do not link in
@@ -989,17 +1110,31 @@ generic_link_check_archive_element (abfd, info, pneeded)
     }
 
   /* This archive element is not needed.  */
+
+ successful_return:
+  if (symbols != NULL)
+    free (symbols);
   return true;
+
+ error_return:
+  if (symbols != NULL)
+    free (symbols);
+  return false;
 }
 
-/* Add the symbol from an object file to the global hash table.  */
+/* Add the symbols from an object file to the global hash table.  ABFD
+   is the object file.  INFO is the linker information.  SYMBOL_COUNT
+   is the number of symbols.  SYMBOLS is the list of symbols.  COLLECT
+   is true if constructors should be automatically collected by name
+   as is done by collect2.  */
 
 static boolean
-generic_link_add_symbol_list (abfd, info, symbol_count, symbols)
+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;
+     boolean collect;
 {
   asymbol **pp, **ppend;
 
@@ -1039,16 +1174,9 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols)
          else
            string = NULL;
 
-         /* We pass the constructor argument as false, for
-            compatibility.  As backends are converted they can
-            arrange to pass the right value (the right value is the
-            size of a function pointer if gcc uses collect2 for the
-            object file format, zero if it does not).
-            FIXME: We pass the bitsize as 32, which is just plain
-            wrong, but actually doesn't matter very much.  */
          if (! (_bfd_generic_link_add_one_symbol
                 (info, abfd, name, p->flags, bfd_get_section (p),
-                 p->value, string, false, 0, 32,
+                 p->value, string, false, collect,
                  (struct bfd_link_hash_entry **) &h)))
            return false;
 
@@ -1151,15 +1279,14 @@ static const enum link_action link_action[8][7] =
      which case it is the warning string.
    COPY is true if NAME or STRING must be copied into locally
      allocated memory if they need to be saved.
-   CONSTRUCTOR is true if we should automatically collect gcc
-     constructor or destructor names.
-   BITSIZE is the number of bits in constructor or set entries.
+   COLLECT is true if we should automatically collect gcc constructor
+     or destructor names as collect2 does.
    HASHP, if not NULL, is a place to store the created hash table
      entry.  */
 
 boolean
 _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
-                                 string, copy, constructor, bitsize, hashp)
+                                 string, copy, collect, hashp)
      struct bfd_link_info *info;
      bfd *abfd;
      const char *name;
@@ -1168,8 +1295,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
      bfd_vma value;
      const char *string;
      boolean copy;
-     boolean constructor;
-     unsigned int bitsize;
+     boolean collect;
      struct bfd_link_hash_entry **hashp;
 {
   enum link_row row;
@@ -1253,7 +1379,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
             and destructors and pass them up in a callback.  We only
             do this for certain object file types, since many object
             file types can handle this automatically.  */
-         if (constructor && name[0] == '_')
+         if (collect && name[0] == '_')
            {
              const char *s;
 
@@ -1281,7 +1407,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
                    {
                      if (! ((*info->callbacks->constructor)
                             (info,
-                             c == 'I' ? true : false, bitsize,
+                             c == 'I' ? true : false,
                              name, abfd, section, value)))
                        return false;
                    }
@@ -1377,8 +1503,8 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
          }
          break;
        case SET:
-         if (! (*info->callbacks->add_to_set) (info, h, bitsize, abfd,
-                                               section, value))
+         if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR,
+                                               abfd, section, value))
            return false;
          break;
        case WARN:
@@ -1405,6 +1531,11 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
            sub = ((struct bfd_link_hash_entry *)
                   bfd_hash_allocate (&info->hash->table,
                                      sizeof (struct bfd_link_hash_entry)));
+           if (!sub)
+             {
+               bfd_set_error (bfd_error_no_memory);
+               return false;
+             }
            *sub = *h;
            h->type = bfd_link_hash_warning;
            h->u.i.link = sub;
@@ -1452,6 +1583,7 @@ _bfd_generic_final_link (abfd, info)
       return false;
 
   /* Accumulate the global symbols.  */
+  wginfo.info = info;
   wginfo.output_bfd = abfd;
   wginfo.psymalloc = &outsymalloc;
   _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
@@ -1470,7 +1602,10 @@ _bfd_generic_final_link (abfd, info)
               p != (struct bfd_link_order *) NULL;
               p = p->next)
            {
-             if (p->type == bfd_indirect_link_order)
+             if (p->type == bfd_section_reloc_link_order
+                 || p->type == bfd_symbol_reloc_link_order)
+               ++o->reloc_count;
+             else if (p->type == bfd_indirect_link_order)
                {
                  asection *input_section;
                  bfd *input_bfd;
@@ -1482,7 +1617,12 @@ _bfd_generic_final_link (abfd, info)
                  input_bfd = input_section->owner;
                  relsize = bfd_get_reloc_upper_bound (input_bfd,
                                                       input_section);
-                 relocs = (arelent **) bfd_xmalloc (relsize);
+                 relocs = (arelent **) malloc ((size_t) relsize);
+                 if (!relocs && relsize != 0)
+                   {
+                     bfd_set_error (bfd_error_no_memory);
+                     return false;
+                   }
                  reloc_count =
                    bfd_canonicalize_reloc (input_bfd, input_section,
                                            relocs,
@@ -1498,6 +1638,12 @@ _bfd_generic_final_link (abfd, info)
                                bfd_alloc (abfd,
                                           (o->reloc_count
                                            * sizeof (arelent *))));
+             if (!o->orelocation)
+               {
+                 bfd_set_error (bfd_error_no_memory);
+                 return false;
+               }
+             o->flags |= SEC_RELOC;
              /* Reset the count so that it can be used as an index
                 when putting in the output relocs.  */
              o->reloc_count = 0;
@@ -1514,8 +1660,18 @@ _bfd_generic_final_link (abfd, info)
           p != (struct bfd_link_order *) NULL;
           p = p->next)
        {
-         if (! _bfd_default_link_order (abfd, info, o, p))
-           return false;
+         switch (p->type)
+           {
+           case bfd_section_reloc_link_order:
+           case bfd_symbol_reloc_link_order:
+             if (! _bfd_generic_reloc_link_order (abfd, info, o, p))
+               return false;
+             break;
+           default:
+             if (! _bfd_default_link_order (abfd, info, o, p))
+               return false;
+             break;
+           }
        }
     }
 
@@ -1545,7 +1701,7 @@ generic_add_output_symbol (output_bfd, psymalloc, sym)
                                        *psymalloc * sizeof (asymbol *));
       if (newsyms == (asymbol **) NULL)
        {
-         bfd_error = no_memory;
+         bfd_set_error (bfd_error_no_memory);
          return false;
        }
       output_bfd->outsymbols = newsyms;
@@ -1570,10 +1726,19 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
   asymbol **sym_ptr;
   asymbol **sym_end;
 
-  symsize = get_symtab_upper_bound (input_bfd);
-  input_bfd->outsymbols = (asymbol **) bfd_alloc (input_bfd, symsize);
-  input_bfd->symcount = bfd_canonicalize_symtab (input_bfd,
-                                                input_bfd->outsymbols);
+  /* Do not clobber outsymbols if they have already been created.  */
+  if (input_bfd->outsymbols == NULL)
+    {
+      symsize = get_symtab_upper_bound (input_bfd);
+      input_bfd->outsymbols = (asymbol **) bfd_alloc (input_bfd, symsize);
+      if (!input_bfd->outsymbols)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
+      input_bfd->symcount = bfd_canonicalize_symtab (input_bfd,
+                                                    input_bfd->outsymbols);
+    }
 
   /* Create a filename symbol if we are supposed to.  */
   if (info->create_object_symbols_section != (asection *) NULL)
@@ -1589,6 +1754,8 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
              asymbol *newsym;
 
              newsym = bfd_make_empty_symbol (input_bfd);
+             if (!newsym)
+               return false;
              newsym->name = input_bfd->filename;
              newsym->value = 0;
              newsym->flags = BSF_LOCAL | BSF_FILE;
@@ -1656,13 +1823,17 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
                case bfd_link_hash_common:
                  sym->value = h->root.u.c.size;
                  sym->flags |= BSF_GLOBAL;
+                 if (! bfd_is_com_section (sym->section))
+                   {
+                     BFD_ASSERT (sym->section == &bfd_und_section);
+                     sym->section = &bfd_com_section;
+                   }
                  /* We do not set the section of the symbol to
-                    c.section.  c.section is saved so that we know
-                    where to allocate the symbol if we define it.  In
-                    this case the type is still bfd_link_hash_common,
-                    so we did not define it, so we do not want to use
-                    that section.  */
-                 BFD_ASSERT (bfd_is_com_section (sym->section));
+                    h->root.u.c.section.  That value was saved so
+                    that we would know where to allocate the symbol
+                    if it was defined.  In this case the type is
+                    still bfd_link_hash_common, so we did not define
+                    it, so we do not want to use that section.  */
                  break;
                }
            }
@@ -1763,6 +1934,14 @@ _bfd_generic_link_write_global_symbol (h, data)
   if (h->root.written)
     return true;
 
+  h->root.written = true;
+
+  if (wginfo->info->strip == strip_all
+      || (wginfo->info->strip == strip_some
+         && bfd_hash_lookup (wginfo->info->keep_hash, h->root.root.string,
+                             false, false) == NULL))
+    return true;
+
   if (h->sym != (asymbol *) NULL)
     {
       sym = h->sym;
@@ -1771,6 +1950,8 @@ _bfd_generic_link_write_global_symbol (h, data)
   else
     {
       sym = bfd_make_empty_symbol (wginfo->output_bfd);
+      if (!sym)
+       return false;
       sym->name = h->root.root.string;
       sym->flags = 0;
     }
@@ -1788,14 +1969,19 @@ _bfd_generic_link_write_global_symbol (h, data)
       sym->section = &bfd_und_section;
       sym->value = 0;
       sym->flags |= BSF_WEAK;
+      break;
     case bfd_link_hash_defined:
       sym->section = h->root.u.def.section;
       sym->value = h->root.u.def.value;
       break;
     case bfd_link_hash_common:
       sym->value = h->root.u.c.size;
+      if (! bfd_is_com_section (sym->section))
+       {
+         BFD_ASSERT (sym->section == &bfd_und_section);
+         sym->section = &bfd_com_section;
+       }
       /* Do not set the section; see _bfd_generic_link_output_symbols.  */
-      BFD_ASSERT (bfd_is_com_section (sym->section));
       break;
     case bfd_link_hash_indirect:
     case bfd_link_hash_warning:
@@ -1812,7 +1998,115 @@ _bfd_generic_link_write_global_symbol (h, data)
       abort ();
     }
 
-  h->root.written = true;
+  return true;
+}
+
+/* Create a relocation.  */
+
+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;
+{
+  arelent *r;
+
+  if (! info->relocateable)
+    abort ();
+  if (sec->orelocation == (arelent **) NULL)
+    abort ();
+
+  r = (arelent *) bfd_alloc (abfd, sizeof (arelent));
+  if (r == (arelent *) NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+      
+  r->address = link_order->offset;
+  r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
+  if (r->howto == (const reloc_howto_type *) NULL)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return false;
+    }
+
+  /* Get the symbol to use for the relocation.  */
+  if (link_order->type == bfd_section_reloc_link_order)
+    r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
+  else
+    {
+      struct generic_link_hash_entry *h;
+
+      h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info),
+                                        link_order->u.reloc.p->u.name,
+                                        false, false, true);
+      if (h == (struct generic_link_hash_entry *) NULL
+         || ! h->root.written)
+       {
+         if (! ((*info->callbacks->unattached_reloc)
+                (info, link_order->u.reloc.p->u.name,
+                 (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+           return false;
+         bfd_set_error (bfd_error_bad_value);
+         return false;
+       }
+      r->sym_ptr_ptr = &h->sym;
+    }
+
+  /* If this is an inplace reloc, write the addend to the object file.
+     Otherwise, store it in the reloc addend.  */
+  if (! r->howto->partial_inplace)
+    r->addend = link_order->u.reloc.p->addend;
+  else
+    {
+      bfd_size_type size;
+      bfd_reloc_status_type rstat;
+      bfd_byte *buf;
+      boolean ok;
+
+      size = bfd_get_reloc_size (r->howto);
+      buf = (bfd_byte *) bfd_zmalloc (size);
+      if (buf == (bfd_byte *) NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
+      rstat = _bfd_relocate_contents (r->howto, abfd,
+                                     link_order->u.reloc.p->addend, buf);
+      switch (rstat)
+       {
+       case bfd_reloc_ok:
+         break;
+       default:
+       case bfd_reloc_outofrange:
+         abort ();
+       case bfd_reloc_overflow:
+         if (! ((*info->callbacks->reloc_overflow)
+                (info,
+                 (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)))
+           {
+             free (buf);
+             return false;
+           }
+         break;
+       }
+      ok = bfd_set_section_contents (abfd, sec, (PTR) buf,
+                                    (file_ptr) link_order->offset, size);
+      free (buf);
+      if (! ok)
+       return false;
+
+      r->addend = 0;
+    }
+
+  sec->orelocation[sec->reloc_count] = r;
+  ++sec->reloc_count;
 
   return true;
 }
@@ -1828,6 +2122,11 @@ bfd_new_link_order (abfd, section)
 
   new = ((struct bfd_link_order *)
         bfd_alloc_by_size_t (abfd, sizeof (struct bfd_link_order)));
+  if (!new)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
 
   new->type = bfd_undefined_link_order;
   new->offset = 0;
@@ -1843,7 +2142,9 @@ bfd_new_link_order (abfd, section)
   return new;
 }
 
-/* Default link order processing routine.  */
+/* Default link order processing routine.  Note that we can not handle
+   the reloc_link_order types here, since they depend upon the details
+   of how the particular backends generates relocs.  */
 
 boolean
 _bfd_default_link_order (abfd, info, sec, link_order)
@@ -1855,12 +2156,19 @@ _bfd_default_link_order (abfd, info, sec, link_order)
   switch (link_order->type)
     {
     case bfd_undefined_link_order:
+    case bfd_section_reloc_link_order:
+    case bfd_symbol_reloc_link_order:
     default:
       abort ();
     case bfd_indirect_link_order:
       return default_indirect_link_order (abfd, info, sec, link_order);
     case bfd_fill_link_order:
       return default_fill_link_order (abfd, info, sec, link_order);
+    case bfd_data_link_order:
+      return bfd_set_section_contents (abfd, sec,
+                                      (PTR) link_order->u.data.contents,
+                                      (file_ptr) link_order->offset,
+                                      link_order->size);
     }
 }
 
@@ -1878,19 +2186,28 @@ default_fill_link_order (abfd, info, sec, link_order)
   char *space;
   size_t i;
   int fill;
+  boolean result;
 
   BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0);
 
   size = (size_t) link_order->size;
-  space = (char *) alloca (size);
+  space = (char *) malloc (size);
+  if (space == NULL && size != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+
   fill = link_order->u.fill.value;
   for (i = 0; i < size; i += 2)
     space[i] = fill >> 8;
   for (i = 1; i < size; i += 2)
     space[i] = fill;
-  return bfd_set_section_contents (abfd, sec, space,
-                                  (file_ptr) link_order->offset,
-                                  link_order->size);
+  result = bfd_set_section_contents (abfd, sec, space,
+                                    (file_ptr) link_order->offset,
+                                    link_order->size);
+  free (space);
+  return result;
 }
 
 /* Default routine to handle a bfd_indirect_link_order.  */
@@ -1904,7 +2221,8 @@ default_indirect_link_order (output_bfd, info, output_section, link_order)
 {
   asection *input_section;
   bfd *input_bfd;
-  bfd_byte *contents;
+  bfd_byte *contents = NULL;
+  bfd_byte *new_contents;
 
   BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
 
@@ -1916,7 +2234,7 @@ default_indirect_link_order (output_bfd, info, output_section, link_order)
 
   BFD_ASSERT (input_section->output_section == output_section);
   BFD_ASSERT (input_section->output_offset == link_order->offset);
-  BFD_ASSERT (bfd_section_size (input_bfd, input_section) == link_order->size);
+  BFD_ASSERT (input_section->_cooked_size == link_order->size);
 
   if (info->relocateable
       && input_section->reloc_count > 0
@@ -1940,20 +2258,61 @@ default_indirect_link_order (output_bfd, info, output_section, link_order)
 
       symsize = get_symtab_upper_bound (input_bfd);
       input_bfd->outsymbols = (asymbol **) bfd_alloc (input_bfd, symsize);
+      if (!input_bfd->outsymbols)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
       input_bfd->symcount = bfd_canonicalize_symtab (input_bfd,
                                                     input_bfd->outsymbols);
     }
 
   /* Get and relocate the section contents.  */
-  contents = (bfd_byte *) alloca (bfd_section_size (input_bfd, input_section));
-  contents = (bfd_get_relocated_section_contents
-             (output_bfd, info, link_order, contents, info->relocateable,
-              bfd_get_outsymbols (input_bfd)));
+  contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section));
+  if (contents == NULL && bfd_section_size (input_bfd, input_section) != 0)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
+  new_contents = (bfd_get_relocated_section_contents
+                 (output_bfd, info, link_order, contents, info->relocateable,
+                  bfd_get_outsymbols (input_bfd)));
+  if (!new_contents)
+    goto error_return;
 
   /* Output the section contents.  */
-  if (! bfd_set_section_contents (output_bfd, output_section, (PTR) contents,
+  if (! bfd_set_section_contents (output_bfd, output_section,
+                                 (PTR) new_contents,
                                  link_order->offset, link_order->size))
-    return false;
+    goto error_return;
 
+  if (contents != NULL)
+    free (contents);
   return true;
+
+ error_return:
+  if (contents != NULL)
+    free (contents);
+  return false;
+}
+
+/* A little routine to count the number of relocs in a link_order
+   list.  */
+
+unsigned int
+_bfd_count_link_order_relocs (link_order)
+     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)
+    {
+      if (l->type == bfd_section_reloc_link_order
+         || l->type == bfd_symbol_reloc_link_order)
+       ++c;
+    }
+
+  return c;
 }
This page took 0.055048 seconds and 4 git commands to generate.