* xcofflink.c: More improvements, mostly to fix handling of
authorIan Lance Taylor <ian@airs.com>
Fri, 27 Oct 1995 22:20:19 +0000 (22:20 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 27 Oct 1995 22:20:19 +0000 (22:20 +0000)
constructors and a few other special cases.
* coff-rs6000.c (rs6000coff_vec): Set symbol_leading_char back to
zero, reverting yesterday's change.
* bfd-in.h (bfd_xcoff_link_record_set): Declare.
(bfd_xcoff_link_count_reloc): Declare.
(bfd_xcoff_record_link_assignment): Declare.
* bfd-in2.h: Rebuild.

bfd/ChangeLog
bfd/bfd-in.h
bfd/bfd-in2.h
bfd/coff-rs6000.c
bfd/xcofflink.c

index e46d96bee8329b0b7f36f40c4820268ba3470aba..74c033c5627f70eb5e00c30722cd369a4b3d0b91 100644 (file)
@@ -1,3 +1,14 @@
+Fri Oct 27 18:14:39 1995  Ian Lance Taylor  <ian@cygnus.com>
+
+       * xcofflink.c: More improvements, mostly to fix handling of
+       constructors and a few other special cases.
+       * coff-rs6000.c (rs6000coff_vec): Set symbol_leading_char back to
+       zero, reverting yesterday's change.
+       * bfd-in.h (bfd_xcoff_link_record_set): Declare.
+       (bfd_xcoff_link_count_reloc): Declare.
+       (bfd_xcoff_record_link_assignment): Declare.
+       * bfd-in2.h: Rebuild.
+
 start-sanitize-gm
 Fri Oct 27 09:41:51 1995  Stu Grossman  (grossman@cygnus.com)
 
index be71f7396bdba712a65b55e9843604a0d5489515..d027196c907ded2b49a286aea2d4d5c0510c2c8e 100644 (file)
@@ -602,12 +602,19 @@ extern boolean bfd_linux_size_dynamic_sections
 
 /* XCOFF support routines for the linker.  */
 
+extern boolean bfd_xcoff_link_record_set
+  PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
+          bfd_size_type));
 extern boolean bfd_xcoff_import_symbol
   PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
           bfd_vma, const char *, const char *, const char *));
 extern boolean bfd_xcoff_export_symbol
   PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
           boolean));
+extern boolean bfd_xcoff_link_count_reloc
+  PARAMS ((bfd *, struct bfd_link_info *, const char *));
+extern boolean bfd_xcoff_record_link_assignment
+  PARAMS ((bfd *, struct bfd_link_info *, const char *));
 extern boolean bfd_xcoff_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *,
           unsigned long, unsigned long, unsigned long, boolean,
index 7747b19d21b8ed969e0b1ee7c1c816cf9b660591..109c1fc3db9744ce63a9cf82e6250f75b3b62b85 100644 (file)
@@ -602,12 +602,19 @@ extern boolean bfd_linux_size_dynamic_sections
 
 /* XCOFF support routines for the linker.  */
 
+extern boolean bfd_xcoff_link_record_set
+  PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
+          bfd_size_type));
 extern boolean bfd_xcoff_import_symbol
   PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
           bfd_vma, const char *, const char *, const char *));
 extern boolean bfd_xcoff_export_symbol
   PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
           boolean));
+extern boolean bfd_xcoff_link_count_reloc
+  PARAMS ((bfd *, struct bfd_link_info *, const char *));
+extern boolean bfd_xcoff_record_link_assignment
+  PARAMS ((bfd *, struct bfd_link_info *, const char *));
 extern boolean bfd_xcoff_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *,
           unsigned long, unsigned long, unsigned long, boolean,
index 39ad311b0e418b4195f335072b74b4b5989aec72..242381d84baffac1f1a04de4c3cc3471b7c161d7 100644 (file)
@@ -1353,8 +1353,7 @@ const bfd_target rs6000coff_vec =
    HAS_SYMS | HAS_LOCALS | WP_TEXT),
 
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
-  /* Making the leading_char a period should make for nicer messages.  */
-  '.',                         /* leading char */
+  0,                           /* leading char */
   '/',                         /* ar_pad_char */
   15,                          /* ar_max_namelen??? FIXMEmgo */
 
index 843dc0676e39d830b1a60c25e6ae4ac99dde2542..9674563b49ad2130a67709941d95774ac5a98b2d 100644 (file)
@@ -286,6 +286,8 @@ struct xcoff_link_hash_entry
 #define XCOFF_BUILT_LDSYM (01000)
   /* Symbol is mentioned by a section which was not garbage collected.  */
 #define XCOFF_MARK (02000)
+  /* Symbol size is recorded in size_list list from hash table.  */
+#define XCOFF_HAS_SIZE (04000)
 
   /* The storage mapping class.  */
   unsigned char smclas;
@@ -333,6 +335,14 @@ struct xcoff_link_hash_table
 
   /* Whether garbage collection was done.  */
   boolean gc;
+
+  /* A linked list of symbols for which we have size information.  */
+  struct xcoff_link_size_list
+    {
+      struct xcoff_link_size_list *next;
+      struct xcoff_link_hash_entry *h;
+      bfd_size_type size;
+    } *size_list;
 };
 
 /* Information we keep for each section in the output file during the
@@ -345,6 +355,16 @@ struct xcoff_link_section_info
   /* For each reloc against a global symbol whose index was not known
      when the reloc was handled, the global hash table entry.  */
   struct xcoff_link_hash_entry **rel_hashes;
+  /* If there is a TOC relative reloc against a global symbol, and the
+     index of the TOC symbol is not known when the reloc was handled,
+     an entry is added to this linked list.  This is not an array,
+     like rel_hashes, because this case is quite uncommon.  */
+  struct xcoff_toc_rel_hash
+    {
+      struct xcoff_toc_rel_hash *next;
+      struct xcoff_link_hash_entry *h;
+      struct internal_reloc *rel;
+    } *toc_rel_hashes;
 };
 
 /* Information that we pass around while doing the final link step.  */
@@ -1564,7 +1584,8 @@ xcoff_link_add_symbols (abfd, info)
                flag = XCOFF_DEF_REGULAR;
              (*sym_hash)->flags |= flag;
 
-             if ((*sym_hash)->smclas == XMC_UA)
+             if ((*sym_hash)->smclas == XMC_UA
+                 || flag == XCOFF_DEF_REGULAR)
                (*sym_hash)->smclas = aux.x_csect.x_smclas;
            }
        }
@@ -1850,6 +1871,40 @@ xcoff_link_add_dynamic_symbols (abfd, info)
 /* Routines that are called after all the input files have been
    handled, but before the sections are laid out in memory.  */
 
+/* Record the number of elements in a set.  This is used to output the
+   correct csect length.  */
+
+boolean
+bfd_xcoff_link_record_set (output_bfd, info, harg, size)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     struct bfd_link_hash_entry *harg;
+     bfd_size_type size;
+{
+  struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg;
+  struct xcoff_link_size_list *n;
+
+  /* This will hardly ever be called.  I don't want to burn four bytes
+     per global symbol, so instead the size is kept on a linked list
+     attached to the hash table.  */
+
+  n = ((struct xcoff_link_size_list *)
+       bfd_alloc (output_bfd, sizeof (struct xcoff_link_size_list)));
+  if (n == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+  n->next = xcoff_hash_table (info)->size_list;
+  n->h = h;
+  n->size = size;
+  xcoff_hash_table (info)->size_list = n;
+
+  h->flags |= XCOFF_HAS_SIZE;
+
+  return true;
+}
+
 /* Import a symbol.  */
 
 boolean
@@ -1956,6 +2011,79 @@ bfd_xcoff_export_symbol (output_bfd, info, harg, syscall)
   return true;
 }
 
+/* Count a reloc against a symbol.  This is called for relocs
+   generated by the linker script, typically for global constructors
+   and destructors.  */
+
+boolean
+bfd_xcoff_link_count_reloc (output_bfd, info, name)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     const char *name;
+{
+  struct xcoff_link_hash_entry *h;
+
+  h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, false, false,
+                             false);
+  if (h == NULL)
+    {
+      (*_bfd_error_handler) ("%s: no such symbol", name);
+      bfd_set_error (bfd_error_no_symbols);
+      return false;
+    }
+
+  h->flags |= XCOFF_REF_REGULAR | XCOFF_LDREL;
+  ++xcoff_hash_table (info)->ldrel_count;
+  
+  /* Mark the symbol to avoid garbage collection.  */
+  if ((h->flags & XCOFF_MARK) == 0)
+    {
+      h->flags |= XCOFF_MARK;
+      if (h->root.type == bfd_link_hash_defined
+         || h->root.type == bfd_link_hash_defweak)
+       {
+         asection *hsec;
+
+         hsec = h->root.u.def.section;
+         if ((hsec->flags & SEC_MARK) == 0)
+           {
+             if (! xcoff_mark (info, hsec))
+               return false;
+           }
+       }
+
+      if (h->toc_section != NULL
+         && (h->toc_section->flags & SEC_MARK) == 0)
+       {
+         if (! xcoff_mark (info, h->toc_section))
+           return false;
+       }
+    }
+
+  return true;
+}
+
+/* This function is called for each symbol to which the linker script
+   assigns a value.  */
+
+boolean
+bfd_xcoff_record_link_assignment (output_bfd, info, name)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     const char *name;
+{
+  struct xcoff_link_hash_entry *h;
+
+  h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true, true,
+                             false);
+  if (h == NULL)
+    return false;
+
+  h->flags |= XCOFF_DEF_REGULAR;
+
+  return true;
+}
+
 /* This structure is used to pass information through
    xcoff_link_hash_traverse.  */
 
@@ -2904,6 +3032,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
       {
        finfo.section_info[i].relocs = NULL;
        finfo.section_info[i].rel_hashes = NULL;
+       finfo.section_info[i].toc_rel_hashes = NULL;
       }
   }
 
@@ -3107,6 +3236,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
       struct internal_reloc *irel;
       struct internal_reloc *irelend;
       struct xcoff_link_hash_entry **rel_hash;
+      struct xcoff_toc_rel_hash *toc_rel_hash;
       bfd_byte *erel;
 
       if (o->reloc_count == 0)
@@ -3131,6 +3261,21 @@ _bfd_xcoff_bfd_final_link (abfd, info)
            }
        }
 
+      for (toc_rel_hash = finfo.section_info[o->target_index].toc_rel_hashes;
+          toc_rel_hash != NULL;
+          toc_rel_hash = toc_rel_hash->next)
+       {
+         if (toc_rel_hash->h->u.toc_indx < 0)
+           {
+             if (! ((*info->callbacks->unattached_reloc)
+                    (info, toc_rel_hash->h->root.root.string,
+                     (bfd *) NULL, o, toc_rel_hash->rel->r_vaddr)))
+               goto error_return;
+             toc_rel_hash->h->u.toc_indx = 0;
+           }
+         toc_rel_hash->rel->r_symndx = toc_rel_hash->h->u.toc_indx;
+       }
+
       /* XCOFF requires that the relocs be sorted by address.  We tend
          to produce them in the order in which their containing csects
          appear in the symbol table, which is not necessarily by
@@ -4082,18 +4227,27 @@ xcoff_link_input_bfd (finfo, input_bfd)
                          not the symbol itself.  */
                      BFD_ASSERT (h->toc_section != NULL);
                      BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
-                     if (h->u.toc_indx == -1)
+                     if (h->u.toc_indx != -1)
+                       irel->r_symndx = h->u.toc_indx;
+                     else
                        {
-                         /* We could handle this case if we had to,
-                             but I don't think it can arise.  */
-                         (*_bfd_error_handler)
-                           ("%s: unattached TOC reloc against `%s'",
-                            bfd_get_filename (input_bfd),
-                            h->root.root.string);
-                         bfd_set_error (bfd_error_bad_value);
-                         return false;
+                         struct xcoff_toc_rel_hash *n;
+                         struct xcoff_link_section_info *si;
+
+                         n = ((struct xcoff_toc_rel_hash *)
+                              bfd_alloc (finfo->output_bfd,
+                                         sizeof (struct xcoff_toc_rel_hash)));
+                         if (n == NULL)
+                           {
+                             bfd_set_error (bfd_error_no_memory);
+                             return false;
+                           }
+                         si = finfo->section_info + target_index;
+                         n->next = si->toc_rel_hashes;
+                         n->h = h;
+                         n->rel = irel;
+                         si->toc_rel_hashes = n;
                        }
-                     irel->r_symndx = h->u.toc_indx;
                    }
                  else if (h != NULL)
                    {
@@ -4493,13 +4647,37 @@ xcoff_write_global_symbol (h, p)
   else if (h->root.type == bfd_link_hash_defined
           || h->root.type == bfd_link_hash_defweak)
     {
+      struct xcoff_link_size_list *l;
+
       isym.n_value = (h->root.u.def.section->output_section->vma
                      + h->root.u.def.section->output_offset
                      + h->root.u.def.value);
       isym.n_scnum = h->root.u.def.section->output_section->target_index;
       isym.n_sclass = C_HIDEXT;
       aux.x_csect.x_smtyp = XTY_SD;
-      /* I don't know what the csect length should be in this case.  */
+
+      if ((h->flags & XCOFF_HAS_SIZE) != 0)
+       {
+         for (l = xcoff_hash_table (finfo->info)->size_list;
+              l != NULL;
+              l = l->next)
+           {
+             if (l->h == h)
+               {
+                 aux.x_csect.x_scnlen.l = l->size;
+                 break;
+               }
+           }
+       }
+    }
+  else if (h->root.type == bfd_link_hash_common)
+    {
+      isym.n_value = (h->root.u.c.p->section->output_section->vma
+                     + h->root.u.c.p->section->output_offset);
+      isym.n_scnum = h->root.u.c.p->section->output_section->target_index;
+      isym.n_sclass = C_EXT;
+      aux.x_csect.x_smtyp = XTY_CM;
+      aux.x_csect.x_scnlen.l = h->root.u.c.size;
     }
   else
     abort ();
@@ -4559,8 +4737,22 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
      struct bfd_link_order *link_order;
 {
   reloc_howto_type *howto;
+  struct xcoff_link_hash_entry *h;
+  asection *hsec;
+  bfd_vma hval;
+  bfd_vma addend;
   struct internal_reloc *irel;
   struct xcoff_link_hash_entry **rel_hash_ptr;
+  struct internal_ldrel ldrel;
+
+  if (link_order->type == bfd_section_reloc_link_order)
+    {
+      /* We need to somehow locate a symbol in the right section.  The
+         symbol must either have a value of zero, or we must adjust
+         the addend by the value of the symbol.  FIXME: Write this
+         when we need it.  The old linker couldn't handle this anyhow.  */
+      abort ();
+    }
 
   howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
   if (howto == NULL)
@@ -4569,7 +4761,42 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
       return false;
     }
 
-  if (link_order->u.reloc.p->addend != 0)
+  h = xcoff_link_hash_lookup (xcoff_hash_table (finfo->info),
+                             link_order->u.reloc.p->u.name,
+                             false, false, true);
+  if (h == NULL)
+    {
+      if (! ((*finfo->info->callbacks->unattached_reloc)
+            (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL,
+             (asection *) NULL, (bfd_vma) 0)))
+       return false;
+      return true;
+    }
+
+  if (h->root.type == bfd_link_hash_common)
+    {
+      hsec = h->root.u.c.p->section;
+      hval = 0;
+    }
+  else if (h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+    {
+      hsec = h->root.u.def.section;
+      hval = h->root.u.def.value;
+    }
+  else
+    {
+      hsec = NULL;
+      hval = 0;
+    }
+
+  addend = link_order->u.reloc.p->addend;
+  if (hsec != NULL)
+    addend += (hsec->output_section->vma
+              + hsec->output_offset
+              + hval);
+
+  if (addend != 0)
     {
       bfd_size_type size;
       bfd_byte *buf;
@@ -4584,8 +4811,7 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
          return false;
        }
 
-      rstat = _bfd_relocate_contents (howto, output_bfd,
-                                     link_order->u.reloc.p->addend, buf);
+      rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
       switch (rstat)
        {
        case bfd_reloc_ok:
@@ -4595,13 +4821,9 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
          abort ();
        case bfd_reloc_overflow:
          if (! ((*finfo->info->callbacks->reloc_overflow)
-                (finfo->info,
-                 (link_order->type == bfd_section_reloc_link_order
-                  ? bfd_section_name (output_bfd,
-                                      link_order->u.reloc.p->u.section)
-                  : link_order->u.reloc.p->u.name),
-                 howto->name, link_order->u.reloc.p->addend,
-                 (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+                (finfo->info, link_order->u.reloc.p->u.name,
+                 howto->name, addend, (bfd *) NULL, (asection *) NULL,
+                 (bfd_vma) 0)))
            {
              free (buf);
              return false;
@@ -4628,52 +4850,66 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
 
   irel->r_vaddr = output_section->vma + link_order->offset;
 
-  if (link_order->type == bfd_section_reloc_link_order)
+  if (h->indx >= 0)
+    irel->r_symndx = h->indx;
+  else
     {
-      /* We need to somehow locate a symbol in the right section.  The
-         symbol must either have a value of zero, or we must adjust
-         the addend by the value of the symbol.  FIXME: Write this
-         when we need it.  The old linker couldn't handle this anyhow.  */
-      abort ();
-      *rel_hash_ptr = NULL;
+      /* Set the index to -2 to force this symbol to get written out.  */
+      h->indx = -2;
+      *rel_hash_ptr = h;
       irel->r_symndx = 0;
     }
-  else
+
+  irel->r_type = howto->type;
+  irel->r_size = howto->bitsize - 1;
+  if (howto->complain_on_overflow == complain_overflow_signed)
+    irel->r_size |= 0x80;
+
+  ++output_section->reloc_count;
+
+  /* Now output the reloc to the .loader section.  */
+
+  ldrel.l_vaddr = irel->r_vaddr;
+
+  if (hsec != NULL)
     {
-      struct xcoff_link_hash_entry *h;
+      const char *secname;
+
+      secname = hsec->output_section->name;
 
-      h = xcoff_link_hash_lookup (xcoff_hash_table (finfo->info),
-                                 link_order->u.reloc.p->u.name,
-                                 false, false, true);
-      if (h != NULL)
+      if (strcmp (secname, ".text") == 0)
+       ldrel.l_symndx = 0;
+      else if (strcmp (secname, ".data") == 0)
+       ldrel.l_symndx = 1;
+      else if (strcmp (secname, ".bss") == 0)
+       ldrel.l_symndx = 2;
+      else
        {
-         if (h->indx >= 0)
-           irel->r_symndx = h->indx;
-         else
-           {
-             /* Set the index to -2 to force this symbol to get
-                written out.  */
-             h->indx = -2;
-             *rel_hash_ptr = h;
-             irel->r_symndx = 0;
-           }
+         (*_bfd_error_handler)
+           ("%s: loader reloc in unrecognized section `%s'",
+            bfd_get_filename (output_bfd), secname);
+         bfd_set_error (bfd_error_nonrepresentable_section);
+         return false;
        }
-      else
+    }
+  else
+    {
+      if (h->ldindx < 0)
        {
-         if (! ((*finfo->info->callbacks->unattached_reloc)
-                (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL,
-                 (asection *) NULL, (bfd_vma) 0)))
-           return false;
-         irel->r_symndx = 0;
+         (*_bfd_error_handler)
+           ("%s: `%s' in loader reloc but not loader sym",
+            bfd_get_filename (output_bfd),
+            h->root.root.string);
+         bfd_set_error (bfd_error_bad_value);
+         return false;
        }
+      ldrel.l_symndx = h->ldindx;
     }
 
-  irel->r_type = howto->type;
-  irel->r_size = howto->bitsize - 1;
-  if (howto->complain_on_overflow == complain_overflow_signed)
-    irel->r_size |= 0x80;
-
-  ++output_section->reloc_count;
+  ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
+  ldrel.l_rsecnm = output_section->target_index;
+  xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+  ++finfo->ldrel;
 
   return true;
 }