Contribute sh64-elf.
[deliverable/binutils-gdb.git] / bfd / linker.c
index 6e9ee65581b1a3eceaca902db117ed72fd2321ac..e3828957da05c18b80dc0ce385be3b1267bccf9c 100644 (file)
@@ -1,5 +1,5 @@
 /* linker.c -- BFD linker routines
-   Copyright (C) 1993, 94, 95, 96, 97, 98, 1999
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
    Free Software Foundation, Inc.
    Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
 
@@ -60,7 +60,7 @@ SECTION
        a.out (in <<aoutx.h>>) and ECOFF (in <<ecoff.c>>).  The a.out
        routines are used as examples throughout this section.
 
-@menu  
+@menu
 @* Creating a Linker Hash Table::
 @* Adding Symbols to the Hash Table::
 @* Performing the Final Link::
@@ -445,28 +445,27 @@ _bfd_link_hash_newfunc (entry, table, string)
      struct bfd_hash_table *table;
      const char *string;
 {
-  struct bfd_link_hash_entry *ret = (struct bfd_link_hash_entry *) entry;
-
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
-  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)
-    return NULL;
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
+      if (entry == NULL)
+       return entry;
+    }
 
   /* Call the allocation method of the superclass.  */
-  ret = ((struct bfd_link_hash_entry *)
-        bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
-
-  if (ret)
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry)
     {
+      struct bfd_link_hash_entry *h = (struct bfd_link_hash_entry *) entry;
+
       /* Initialize the local fields.  */
-      ret->type = bfd_link_hash_new;
-      ret->next = NULL;
+      h->type = bfd_link_hash_new;
+      h->next = NULL;
     }
 
-  return (struct bfd_hash_entry *) ret;
+  return entry;
 }
 
 /* Initialize a link hash table.  The BFD argument is the one
@@ -483,6 +482,8 @@ _bfd_link_hash_table_init (table, abfd, newfunc)
   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);
 }
 
@@ -526,6 +527,8 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
      boolean copy;
      boolean follow;
 {
+  bfd_size_type amt;
+
   if (info->wrap_hash != NULL)
     {
       const char *l;
@@ -545,7 +548,8 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
          /* This symbol is being wrapped.  We want to replace all
              references to SYM with references to __wrap_SYM.  */
 
-         n = (char *) bfd_malloc (strlen (l) + sizeof WRAP + 1);
+         amt = strlen (l) + sizeof WRAP + 1;
+         n = (char *) bfd_malloc (amt);
          if (n == NULL)
            return NULL;
 
@@ -576,7 +580,8 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
              wrapped.  We want to replace all references to __real_SYM
              with references to SYM.  */
 
-         n = (char *) bfd_malloc (strlen (l + sizeof REAL - 1) + 2);
+         amt = strlen (l + sizeof REAL - 1) + 2;
+         n = (char *) bfd_malloc (amt);
          if (n == NULL)
            return NULL;
 
@@ -601,7 +606,7 @@ bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow)
    struct bfd_link_hash_entry * with no explicit cast required on the
    call.  */
 
-void 
+void
 bfd_link_hash_traverse (table, func, info)
      struct bfd_link_hash_table *table;
      boolean (*func) PARAMS ((struct bfd_link_hash_entry *, PTR));
@@ -636,30 +641,29 @@ _bfd_generic_link_hash_newfunc (entry, table, string)
      struct bfd_hash_table *table;
      const char *string;
 {
-  struct generic_link_hash_entry *ret =
-    (struct generic_link_hash_entry *) entry;
-
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
-  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)
-    return NULL;
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+                                sizeof (struct generic_link_hash_entry));
+      if (entry == NULL)
+       return entry;
+    }
 
   /* Call the allocation method of the superclass.  */
-  ret = ((struct generic_link_hash_entry *)
-        _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
-                                table, string));
-
-  if (ret)
+  entry = _bfd_link_hash_newfunc (entry, table, string);
+  if (entry)
     {
+      struct generic_link_hash_entry *ret;
+
       /* Set local fields.  */
+      ret = (struct generic_link_hash_entry *) entry;
       ret->written = false;
       ret->sym = NULL;
     }
 
-  return (struct bfd_hash_entry *) ret;
+  return entry;
 }
 
 /* Create an generic link hash table.  */
@@ -669,9 +673,9 @@ _bfd_generic_link_hash_table_create (abfd)
      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_alloc (abfd, sizeof (struct generic_link_hash_table)));
+  ret = (struct generic_link_hash_table *) bfd_alloc (abfd, amt);
   if (ret == NULL)
     return (struct bfd_link_hash_table *) NULL;
   if (! _bfd_link_hash_table_init (&ret->root, abfd,
@@ -702,7 +706,8 @@ generic_link_read_symbols (abfd)
       symsize = bfd_get_symtab_upper_bound (abfd);
       if (symsize < 0)
        return false;
-      bfd_get_outsymbols (abfd) = (asymbol **) bfd_alloc (abfd, symsize);
+      bfd_get_outsymbols (abfd) =
+       (asymbol **) bfd_alloc (abfd, (bfd_size_type) symsize);
       if (bfd_get_outsymbols (abfd) == NULL && symsize != 0)
        return false;
       symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd));
@@ -779,12 +784,14 @@ generic_link_add_object_symbols (abfd, info, collect)
      struct bfd_link_info *info;
      boolean collect;
 {
+  bfd_size_type symcount;
+  struct symbol_cache_entry **outsyms;
+
   if (! generic_link_read_symbols (abfd))
     return false;
-  return generic_link_add_symbol_list (abfd, info,
-                                      _bfd_generic_link_get_symcount (abfd),
-                                      _bfd_generic_link_get_symbols (abfd),
-                                      collect);
+  symcount = _bfd_generic_link_get_symcount (abfd);
+  outsyms = _bfd_generic_link_get_symbols (abfd);
+  return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect);
 }
 \f
 /* We build a hash table of all symbols defined in an archive.  */
@@ -795,7 +802,7 @@ generic_link_add_object_symbols (abfd, info, collect)
 struct archive_list
 {
   struct archive_list *next;
-  int indx;
+  unsigned int indx;
 };
 
 /* An entry in an archive hash table.  */
@@ -924,7 +931,7 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
   register carsym *arsym;
   int pass;
   struct archive_hash_table arsym_hash;
-  int indx;
+  unsigned int indx;
   struct bfd_link_hash_entry **pundef;
 
   if (! bfd_has_map (abfd))
@@ -1003,10 +1010,25 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
       arh = archive_hash_lookup (&arsym_hash, h->root.string, false, false);
       if (arh == (struct archive_hash_entry *) NULL)
        {
-         pundef = &(*pundef)->next;
-         continue;
-       }
+         /* 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);
+             if (buf == NULL)
+               return false;
 
+             sprintf (buf, "__imp_%s", h->root.string);
+             arh = archive_hash_lookup (&arsym_hash, buf, false, false);
+             free(buf);
+           }
+         if (arh == (struct archive_hash_entry *) NULL)
+           {
+             pundef = &(*pundef)->next;
+             continue;
+           }
+       }
       /* Look at all the objects which define this symbol.  */
       for (l = arh->defs; l != (struct archive_list *) NULL; l = l->next)
        {
@@ -1361,7 +1383,7 @@ enum link_row
 
 enum link_action
 {
-  FAIL,                /* Abort. */
+  FAIL,                /* Abort.  */
   UND,         /* Mark symbol undefined.  */
   WEAK,                /* Mark symbol weak undefined.  */
   DEF,         /* Mark symbol defined.  */
@@ -1395,7 +1417,7 @@ static const enum link_action link_action[8][8] =
   /* UNDEFW_ROW        */  {WEAK,  NOACT, NOACT, REF,   REF,   NOACT, REFC,  WARNC },
   /* DEF_ROW   */  {DEF,   DEF,   DEF,   MDEF,  DEF,   CDEF,  MDEF,  CYCLE },
   /* DEFW_ROW  */  {DEFW,  DEFW,  DEFW,  NOACT, NOACT, NOACT, NOACT, CYCLE },
-  /* COMMON_ROW        */  {COM,   COM,   COM,   CREF,  CREF,  BIG,   REFC,  WARNC },
+  /* COMMON_ROW        */  {COM,   COM,   COM,   CREF,  COM,   BIG,   REFC,  WARNC },
   /* INDR_ROW  */  {IND,   IND,   IND,   MDEF,  IND,   CIND,  MIND,  CYCLE },
   /* WARN_ROW   */  {MWARN, WARN,  WARN,  CWARN, CWARN, WARN,  CWARN, MWARN },
   /* SET_ROW   */  {SET,   SET,   SET,   SET,   SET,   SET,   CYCLE, CYCLE }
@@ -1464,7 +1486,7 @@ hash_entry_bfd (h)
      or destructor names as collect2 does.
    HASHP, if not NULL, is a place to store the created hash table
      entry; if *HASHP is not NULL, the caller has already looked up
-     the hash table entry, and stored it in *HASHP. */
+     the hash table entry, and stored it in *HASHP.  */
 
 boolean
 _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
@@ -1698,7 +1720,7 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
        case BIG:
          /* We have found a common definition for a symbol which
             already had a common definition.  Use the maximum of the
-            two sizes.  */
+            two sizes, and use the section required by the larger symbol.  */
          BFD_ASSERT (h->type == bfd_link_hash_common);
          if (! ((*info->callbacks->multiple_common)
                 (info, h->root.string,
@@ -1717,6 +1739,25 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
              if (power > 4)
                power = 4;
              h->u.c.p->alignment_power = power;
+
+             /* Some systems have special treatment for small commons,
+                hence we want to select the section used by the larger
+                symbol.  This makes sure the symbol does not go in a
+                small common section if it is now too large.  */
+             if (section == bfd_com_section_ptr)
+               {
+                 h->u.c.p->section
+                   = bfd_make_section_old_way (abfd, "COMMON");
+                 h->u.c.p->section->flags = SEC_ALLOC;
+               }
+             else if (section->owner != abfd)
+               {
+                 h->u.c.p->section
+                   = bfd_make_section_old_way (abfd, section->name);
+                 h->u.c.p->section->flags = SEC_ALLOC;
+               }
+             else
+               h->u.c.p->section = section;
            }
          break;
 
@@ -1801,6 +1842,15 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
                                                copy, false);
            if (inh == (struct bfd_link_hash_entry *) 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);
+               bfd_set_error (bfd_error_invalid_operation);
+               return false;
+             }
            if (inh->type == bfd_link_hash_new)
              {
                inh->type = bfd_link_hash_undefined;
@@ -1995,7 +2045,7 @@ _bfd_generic_final_link (abfd, info)
                                                       input_section);
                  if (relsize < 0)
                    return false;
-                 relocs = (arelent **) bfd_malloc ((size_t) relsize);
+                 relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize);
                  if (!relocs && relsize != 0)
                    return false;
                  symbols = _bfd_generic_link_get_symbols (input_bfd);
@@ -2013,10 +2063,11 @@ _bfd_generic_final_link (abfd, info)
            }
          if (o->reloc_count > 0)
            {
-             o->orelocation = ((arelent **)
-                               bfd_alloc (abfd,
-                                          (o->reloc_count
-                                           * sizeof (arelent *))));
+             bfd_size_type amt;
+
+             amt = o->reloc_count;
+             amt *= sizeof (arelent *);
+             o->orelocation = (arelent **) bfd_alloc (abfd, amt);
              if (!o->orelocation)
                return false;
              o->flags |= SEC_RELOC;
@@ -2054,7 +2105,7 @@ _bfd_generic_final_link (abfd, info)
            }
        }
     }
-  
+
   return true;
 }
 
@@ -2069,13 +2120,15 @@ generic_add_output_symbol (output_bfd, psymalloc, sym)
   if (bfd_get_symcount (output_bfd) >= *psymalloc)
     {
       asymbol **newsyms;
+      bfd_size_type amt;
 
       if (*psymalloc == 0)
        *psymalloc = 124;
       else
        *psymalloc *= 2;
-      newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd),
-                                         *psymalloc * sizeof (asymbol *));
+      amt = *psymalloc;
+      amt *= sizeof (asymbol *);
+      newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
       if (newsyms == (asymbol **) NULL)
        return false;
       bfd_get_outsymbols (output_bfd) = newsyms;
@@ -2279,6 +2332,12 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
                case discard_all:
                  output = false;
                  break;
+               case discard_sec_merge:
+                 output = true;
+                 if (info->relocateable
+                     || ! (sym->section->flags & SEC_MERGE))
+                   break;
+                 /* FALLTHROUGH */
                case discard_l:
                  if (bfd_is_local_label (input_bfd, sym))
                    output = false;
@@ -2449,10 +2508,10 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
   if (sec->orelocation == (arelent **) NULL)
     abort ();
 
-  r = (arelent *) bfd_alloc (abfd, sizeof (arelent));
+  r = (arelent *) bfd_alloc (abfd, (bfd_size_type) sizeof (arelent));
   if (r == (arelent *) NULL)
     return false;
-      
+
   r->address = link_order->offset;
   r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
   if (r->howto == 0)
@@ -2495,13 +2554,15 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
       bfd_reloc_status_type rstat;
       bfd_byte *buf;
       boolean ok;
+      file_ptr loc;
 
       size = bfd_get_reloc_size (r->howto);
       buf = (bfd_byte *) bfd_zmalloc (size);
       if (buf == (bfd_byte *) NULL)
        return false;
       rstat = _bfd_relocate_contents (r->howto, abfd,
-                                     link_order->u.reloc.p->addend, buf);
+                                     (bfd_vma) link_order->u.reloc.p->addend,
+                                     buf);
       switch (rstat)
        {
        case bfd_reloc_ok:
@@ -2523,10 +2584,9 @@ _bfd_generic_reloc_link_order (abfd, info, sec, link_order)
            }
          break;
        }
-      ok = bfd_set_section_contents (abfd, sec, (PTR) buf,
-                                    (file_ptr) 
-                                     (link_order->offset *
-                                      bfd_octets_per_byte (abfd)), size);
+      loc = link_order->offset * bfd_octets_per_byte (abfd);
+      ok = bfd_set_section_contents (abfd, sec, (PTR) buf, loc,
+                                    (bfd_size_type) size);
       free (buf);
       if (! ok)
        return false;
@@ -2547,10 +2607,8 @@ bfd_new_link_order (abfd, section)
      bfd *abfd;
      asection *section;
 {
-  struct bfd_link_order *new;
-
-  new = ((struct bfd_link_order *)
-        bfd_alloc (abfd, sizeof (struct bfd_link_order)));
+  bfd_size_type amt = sizeof (struct bfd_link_order);
+  struct bfd_link_order *new = (struct bfd_link_order *) bfd_alloc (abfd, amt);
   if (!new)
     return NULL;
 
@@ -2579,6 +2637,8 @@ _bfd_default_link_order (abfd, info, sec, link_order)
      asection *sec;
      struct bfd_link_order *link_order;
 {
+  file_ptr loc;
+
   switch (link_order->type)
     {
     case bfd_undefined_link_order:
@@ -2592,18 +2652,15 @@ _bfd_default_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:
+      loc = link_order->offset * bfd_octets_per_byte (abfd);
       return bfd_set_section_contents (abfd, sec,
                                       (PTR) link_order->u.data.contents,
-                                      (file_ptr) 
-                                       (link_order->offset *
-                                        bfd_octets_per_byte (abfd)),
-                                      link_order->size);
+                                      loc, link_order->size);
     }
 }
 
 /* Default routine to handle a bfd_fill_link_order.  */
 
-/*ARGSUSED*/
 static boolean
 default_fill_link_order (abfd, info, sec, link_order)
      bfd *abfd;
@@ -2611,29 +2668,36 @@ default_fill_link_order (abfd, info, sec, link_order)
      asection *sec;
      struct bfd_link_order *link_order;
 {
-  size_t size;
-  char *space;
+  bfd_size_type size;
+  unsigned char *space;
   size_t i;
-  int fill;
+  unsigned int fill;
+  file_ptr loc;
   boolean result;
 
   BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0);
 
-  size = (size_t) link_order->size;
-  space = (char *) bfd_malloc (size);
-  if (space == NULL && size != 0)
+  size = link_order->size;
+  if (size == 0)
+    return true;
+
+  space = (unsigned char *) bfd_malloc (size);
+  if (space == NULL)
     return false;
 
   fill = link_order->u.fill.value;
-  for (i = 0; i < size; i += 2)
+  for (i = 0; i < size; i += 4)
+    space[i] = fill >> 24;
+  for (i = 1; i < size; i += 4)
+    space[i] = fill >> 16;
+  for (i = 2; i < size; i += 4)
     space[i] = fill >> 8;
-  for (i = 1; i < size; i += 2)
+  for (i = 3; i < size; i += 4)
     space[i] = fill;
-  result = bfd_set_section_contents (abfd, sec, space,
-                                    (file_ptr) 
-                                     (link_order->offset * 
-                                      bfd_octets_per_byte (abfd)),
-                                    link_order->size);
+
+  loc = link_order->offset * bfd_octets_per_byte (abfd);
+  result = bfd_set_section_contents (abfd, sec, space, loc, size);
+
   free (space);
   return result;
 }
@@ -2653,6 +2717,8 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
   bfd *input_bfd;
   bfd_byte *contents = NULL;
   bfd_byte *new_contents;
+  bfd_size_type sec_size;
+  file_ptr loc;
 
   BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
 
@@ -2732,13 +2798,13 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
              if (h != NULL)
                set_symbol_from_hash (sym, h);
            }
-       }         
+       }
     }
 
   /* Get and relocate the section contents.  */
-  contents = ((bfd_byte *)
-             bfd_malloc (bfd_section_size (input_bfd, input_section)));
-  if (contents == NULL && bfd_section_size (input_bfd, input_section) != 0)
+  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,
@@ -2747,12 +2813,9 @@ default_indirect_link_order (output_bfd, info, output_section, link_order,
     goto error_return;
 
   /* Output the section contents.  */
+  loc = link_order->offset * bfd_octets_per_byte (output_bfd);
   if (! bfd_set_section_contents (output_bfd, output_section,
-                                 (PTR) new_contents,
-                                 (file_ptr)
-                                  (link_order->offset * 
-                                   bfd_octets_per_byte (output_bfd)), 
-                                  link_order->size))
+                                 (PTR) new_contents, loc, link_order->size))
     goto error_return;
 
   if (contents != NULL)
@@ -2803,8 +2866,6 @@ DESCRIPTION
 
 */
 
-
-
 boolean
 _bfd_generic_link_split_section (abfd, sec)
      bfd *abfd ATTRIBUTE_UNUSED;
This page took 0.032126 seconds and 4 git commands to generate.