* linker.c (enum link_action): Add CIND.
authorIan Lance Taylor <ian@airs.com>
Tue, 25 Oct 1994 15:47:59 +0000 (15:47 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 25 Oct 1994 15:47:59 +0000 (15:47 +0000)
(link_action): Change COMMON_ROW\indr from MDEF to CREF.  Change
INDR_ROW\common from MDEF to CIND.
(_bfd_generic_link_add_one_symbol): In CREF case, handle an
existing symbol which is indirect rather than defined.  Add new
CIND case.

bfd/ChangeLog
bfd/linker.c

index 89635b4ecfd9968640d0c27b95f22665ce14bdb5..cd47d04e978f82111d7b07cf8c4990fe6159f49a 100644 (file)
@@ -1,3 +1,12 @@
+Tue Oct 25 11:44:38 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+       * linker.c (enum link_action): Add CIND.
+       (link_action): Change COMMON_ROW\indr from MDEF to CREF.  Change
+       INDR_ROW\common from MDEF to CIND.
+       (_bfd_generic_link_add_one_symbol): In CREF case, handle an
+       existing symbol which is indirect rather than defined.  Add new
+       CIND case.
+
 Mon Oct 24 15:33:16 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
 
        Change S-record backend to use multiple sections to handle gaps in
index 3c7f823d614df3b31c288ed776dafe468b0aad47..760653464504f574cc9d9e6d47f7ff956c602bc8 100644 (file)
@@ -1,5 +1,5 @@
 /* linker.c -- BFD linker routines
-   Copyright (C) 1993, 94 Free Software Foundation, Inc.
+   Copyright (C) 1993, 1994 Free Software Foundation, Inc.
    Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -427,6 +427,8 @@ static boolean generic_link_check_archive_element
 static boolean generic_link_add_symbol_list
   PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
           boolean collect));
+static void set_symbol_from_hash
+  PARAMS ((asymbol *, struct bfd_link_hash_entry *));
 static boolean generic_add_output_symbol
   PARAMS ((bfd *, size_t *psymalloc, asymbol *));
 static boolean default_fill_link_order
@@ -434,7 +436,7 @@ static boolean default_fill_link_order
           struct bfd_link_order *));
 static boolean default_indirect_link_order
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
-          struct bfd_link_order *));
+          struct bfd_link_order *, 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
@@ -897,7 +899,10 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
       l->next = NULL;
     }
 
-  pass = 1;
+  /* The archive_pass field in the archive itself is used to
+     initialize PASS, sine we may search the same archive multiple
+     times.  */
+  pass = abfd->archive_pass + 1;
 
   /* New undefined symbols are added to the end of the list, so we
      only need to look through it once.  */
@@ -987,6 +992,9 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
 
   archive_hash_table_free (&arsym_hash);
 
+  /* Save PASS in case we are called again.  */
+  abfd->archive_pass = pass;
+
   return true;
 
  error_return:
@@ -1089,6 +1097,8 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
       if (h->type == bfd_link_hash_undefined)
        {
          bfd *symbfd;
+         bfd_vma size;
+         unsigned int power;
 
          symbfd = h->u.undef.abfd;
          if (symbfd == (bfd *) NULL)
@@ -1111,7 +1121,21 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
             attached to symbfd to ensure that it is in a BFD which
             will be linked in.  */
          h->type = bfd_link_hash_common;
-         h->u.c.size = bfd_asymbol_value (p);
+
+         size = bfd_asymbol_value (p);
+         h->u.c.size = size;
+         if (h->u.c.size != size)
+           {
+             /* The size did not fit in the bitfield.  */
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+
+         power = bfd_log2 (size);
+         if (power > 4)
+           power = 4;
+         h->u.c.alignment_power = power;
+
          if (p->section == bfd_com_section_ptr)
            h->u.c.section = bfd_make_section_old_way (symbfd, "COMMON");
          else
@@ -1218,8 +1242,10 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
 
              /* Store a back pointer from the symbol to the hash
                 table entry for the benefit of relaxation code until
-                it gets rewritten to not use asymbol structures.  */
-             p->udata = (PTR) h;
+                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;
            }
        }
     }
@@ -1267,6 +1293,7 @@ enum link_action
   MDEF,                /* Multiple definition error.  */
   MIND,                /* Multiple indirect symbols.  */
   IND,         /* Make indirect symbol.  */
+  CIND,                /* Make indirect symbol from existing common symbol.  */
   SET,         /* Add value to set.  */
   MWARN,       /* Make warning symbol.  */
   WARN,                /* Issue warning.  */
@@ -1286,8 +1313,8 @@ static const enum link_action link_action[8][7] =
   /* UNDEFW_ROW        */  {WEAK,  WEAK,  NOACT, REF,   NOACT, REFC,  WARNC },
   /* DEF_ROW   */  {DEF,   DEF,   DEF,   MDEF,  CDEF,  MDEF,  CYCLE },
   /* DEFW_ROW  */  {DEF,   DEF,   DEF,   NOACT, NOACT, NOACT, CYCLE },
-  /* COMMON_ROW        */  {COM,   COM,   COM,   CREF,  BIG,   MDEF,  WARNC },
-  /* INDR_ROW  */  {IND,   IND,   IND,   MDEF,  MDEF,  MIND,  CYCLE },
+  /* COMMON_ROW        */  {COM,   COM,   COM,   CREF,  BIG,   CREF,  WARNC },
+  /* INDR_ROW  */  {IND,   IND,   IND,   MDEF,  CIND,  MIND,  CYCLE },
   /* WARN_ROW   */  {MWARN, WARN,  WARN,  CWARN, WARN,  CWARN, CYCLE },
   /* SET_ROW   */  {SET,   SET,   SET,   SET,   SET,   CYCLE, CYCLE }
 };
@@ -1491,6 +1518,34 @@ _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.size = value;
+         if (h->u.c.size != value)
+           {
+             /* The size did not fit in the bitfield.  */
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+
+         /* Select a default alignment based on the size.  This may
+             be overridden by the caller.  */
+         {
+           unsigned int power;
+
+           power = bfd_log2 (value);
+           if (power > 4)
+             power = 4;
+           h->u.c.alignment_power = power;
+         }
+
+         /* The section of a common symbol is only used if the common
+             symbol is actually allocated.  It basically provides a
+             hook for the linker script to decide which output section
+             the common symbols should be put in.  In most cases, the
+             section of a common symbol will be bfd_com_section_ptr,
+             the code here will choose a common symbol section named
+             "COMMON", and the linker script will contain *(COMMON) in
+             the appropriate place.  A few targets use separate common
+             sections for small symbols, and they require special
+             handling.  */
          if (section == bfd_com_section_ptr)
            {
              h->u.c.section = bfd_make_section_old_way (abfd, "COMMON");
@@ -1522,18 +1577,37 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
                  abfd, bfd_link_hash_common, value)))
            return false;
          if (value > h->u.c.size)
-           h->u.c.size = value;
+           {
+             unsigned int power;
+
+             h->u.c.size = value;
+
+             /* Select a default alignment based on the size.  This may
+                be overridden by the caller.  */
+             power = bfd_log2 (value);
+             if (power > 4)
+               power = 4;
+             h->u.c.alignment_power = power;
+           }
          break;
 
        case CREF:
-         /* We have found a common definition for a symbol which was
-            already defined.  */
-         BFD_ASSERT (h->type == bfd_link_hash_defined);
-         if (! ((*info->callbacks->multiple_common)
-                (info, name,
-                 h->u.def.section->owner, bfd_link_hash_defined, (bfd_vma) 0,
-                 abfd, bfd_link_hash_common, value)))
-           return false;
+         {
+           bfd *obfd;
+
+           /* We have found a common definition for a symbol which
+              was already defined.  FIXME: It would nice if we could
+              report the BFD which defined an indirect symbol, but we
+              don't have anywhere to store the information.  */
+           if (h->type == bfd_link_hash_defined)
+             obfd = h->u.def.section->owner;
+           else
+             obfd = NULL;
+           if (! ((*info->callbacks->multiple_common)
+                  (info, name, obfd, h->type, (bfd_vma) 0,
+                   abfd, bfd_link_hash_common, value)))
+             return false;
+         }
          break;
 
        case MIND:
@@ -1573,6 +1647,15 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
          }
          break;
 
+       case CIND:
+         /* Create an indirect symbol from an existing common symbol.  */
+         BFD_ASSERT (h->type == bfd_link_hash_common);
+         if (! ((*info->callbacks->multiple_common)
+                (info, name,
+                 h->u.c.section->owner, bfd_link_hash_common, h->u.c.size,
+                 abfd, bfd_link_hash_indirect, (bfd_vma) 0)))
+           return false;
+         /* Fall through.  */
        case IND:
          /* Create an indirect symbol.  */
          {
@@ -1805,6 +1888,10 @@ _bfd_generic_final_link (abfd, info)
              if (! _bfd_generic_reloc_link_order (abfd, info, o, p))
                return false;
              break;
+           case bfd_indirect_link_order:
+             if (! default_indirect_link_order (abfd, info, o, p, true))
+               return false;
+             break;
            default:
              if (! _bfd_default_link_order (abfd, info, o, p))
                return false;
@@ -2045,6 +2132,50 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
   return true;
 }
 
+/* Set the section and value of a generic BFD symbol based on a linker
+   hash table entry.  */
+
+static void
+set_symbol_from_hash (sym, h)
+     asymbol *sym;
+     struct bfd_link_hash_entry *h;
+{
+  switch (h->type)
+    {
+    default:
+    case bfd_link_hash_new:
+      abort ();
+    case bfd_link_hash_undefined:
+      sym->section = bfd_und_section_ptr;
+      sym->value = 0;
+      break;
+    case bfd_link_hash_weak:
+      sym->section = bfd_und_section_ptr;
+      sym->value = 0;
+      sym->flags |= BSF_WEAK;
+      break;
+    case bfd_link_hash_defined:
+      sym->section = h->u.def.section;
+      sym->value = h->u.def.value;
+      break;
+    case bfd_link_hash_common:
+      sym->value = h->u.c.size;
+      if (sym->section == NULL)
+       sym->section = bfd_com_section_ptr;
+      else if (! bfd_is_com_section (sym->section))
+       {
+         BFD_ASSERT (bfd_is_und_section (sym->section));
+         sym->section = bfd_com_section_ptr;
+       }
+      /* Do not set the section; see _bfd_generic_link_output_symbols.  */
+      break;
+    case bfd_link_hash_indirect:
+    case bfd_link_hash_warning:
+      /* FIXME: What should we do here?  */
+      break;
+    }
+}
+
 /* Write out a global symbol, if it hasn't already been written out.
    This is called for each symbol in the hash table.  */
 
@@ -2082,40 +2213,7 @@ _bfd_generic_link_write_global_symbol (h, data)
       sym->flags = 0;
     }
 
-  switch (h->root.type)
-    {
-    default:
-    case bfd_link_hash_new:
-      abort ();
-    case bfd_link_hash_undefined:
-      sym->section = bfd_und_section_ptr;
-      sym->value = 0;
-      break;
-    case bfd_link_hash_weak:
-      sym->section = bfd_und_section_ptr;
-      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 (sym->section == NULL)
-       sym->section = bfd_com_section_ptr;
-      else if (! bfd_is_com_section (sym->section))
-       {
-         BFD_ASSERT (bfd_is_und_section (sym->section));
-         sym->section = bfd_com_section_ptr;
-       }
-      /* Do not set the section; see _bfd_generic_link_output_symbols.  */
-      break;
-    case bfd_link_hash_indirect:
-    case bfd_link_hash_warning:
-      /* FIXME: What should we do here?  */
-      break;
-    }
+  set_symbol_from_hash (sym, &h->root);
 
   sym->flags |= BSF_GLOBAL;
 
@@ -2289,7 +2387,8 @@ _bfd_default_link_order (abfd, info, sec, link_order)
     default:
       abort ();
     case bfd_indirect_link_order:
-      return default_indirect_link_order (abfd, info, sec, link_order);
+      return default_indirect_link_order (abfd, info, sec, link_order,
+                                         false);
     case bfd_fill_link_order:
       return default_fill_link_order (abfd, info, sec, link_order);
     case bfd_data_link_order:
@@ -2341,11 +2440,13 @@ default_fill_link_order (abfd, info, sec, link_order)
 /* Default routine to handle a bfd_indirect_link_order.  */
 
 static boolean
-default_indirect_link_order (output_bfd, info, output_section, link_order)
+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;
+     boolean generic_linker;
 {
   asection *input_section;
   bfd *input_bfd;
@@ -2376,12 +2477,54 @@ default_indirect_link_order (output_bfd, info, output_section, link_order)
       abort ();
     }
 
-  /* Get the canonical symbols.  The generic linker will always have
-     retrieved them by this point, but we may be being called by a
-     specific linker when linking different types of object files
-     together.  */
-  if (! generic_link_read_symbols (input_bfd))
-    return false;
+  if (! generic_linker)
+    {
+      asymbol **sympp;
+      asymbol **symppend;
+
+      /* Get the canonical symbols.  The generic linker will always
+        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))
+       return false;
+
+      /* Since we have been called by a specific linker, rather than
+        the generic linker, the values of the symbols will not be
+        right.  They will be the values as seen in the input file,
+        not the values of the final link.  We need to fix them up
+        before we can relocate the section.  */
+      sympp = _bfd_generic_link_get_symbols (input_bfd);
+      symppend = sympp + _bfd_generic_link_get_symcount (input_bfd);
+      for (; sympp < symppend; sympp++)
+       {
+         asymbol *sym;
+         struct bfd_link_hash_entry *h;
+
+         sym = *sympp;
+
+         if ((sym->flags & (BSF_INDIRECT
+                            | BSF_WARNING
+                            | BSF_GLOBAL
+                            | BSF_CONSTRUCTOR
+                            | BSF_WEAK)) != 0
+             || bfd_is_und_section (bfd_get_section (sym))
+             || bfd_is_com_section (bfd_get_section (sym))
+             || bfd_is_ind_section (bfd_get_section (sym)))
+           {
+             /* 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;
+             else
+               h = bfd_link_hash_lookup (info->hash,
+                                         bfd_asymbol_name (sym),
+                                         false, false, true);
+             if (h != NULL)
+               set_symbol_from_hash (sym, h);
+           }
+       }         
+    }
 
   /* Get and relocate the section contents.  */
   contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section));