* xcofflink.c: Numerous changes to get closer to a working XCOFF
authorIan Lance Taylor <ian@airs.com>
Thu, 26 Oct 1995 18:25:13 +0000 (18:25 +0000)
committerIan Lance Taylor <ian@airs.com>
Thu, 26 Oct 1995 18:25:13 +0000 (18:25 +0000)
linker.
* libcoff-in.h (struct xcoff_tdata): Add full_aouthdr,
toc_section, and entry_section fields.
(struct xcoff_section_tdata): Remove ldrel_count field.
* libcoff.h: Rebuild.
* coffcode.h (coff_mkobject_hook): Initialize new xcoff_data
fields.
(coff_compute_section_file_positions): If RS6000COFF_C, generate
full a.out header if full_aouthdr is set in xcoff_data.
(coff_write_object_contents): Likewise.  Set o_snentry and o_sntoc
based on sections stored in xcoff_data.
* coff-rs6000.c (xcoff_copy_private_bfd_data): Copy new xcoff_data
fields.
* coffgen.c (coff_get_symbol_info): If fix_value is set, fix the
value stored in ret rather than returning a pointer value.

bfd/ChangeLog
bfd/coff-rs6000.c
bfd/coffcode.h
bfd/coffgen.c
bfd/libcoff-in.h
bfd/libcoff.h
bfd/xcofflink.c

index f3cfd6d81e7e9d119bfb5195e2051c564ce9b00c..963176aef039544c2515e1a506cfb5a11c9491cd 100644 (file)
@@ -1,3 +1,22 @@
+Thu Oct 26 14:16:47 1995  Ian Lance Taylor  <ian@cygnus.com>
+
+       * xcofflink.c: Numerous changes to get closer to a working XCOFF
+       linker.
+       * libcoff-in.h (struct xcoff_tdata): Add full_aouthdr,
+       toc_section, and entry_section fields.
+       (struct xcoff_section_tdata): Remove ldrel_count field.
+       * libcoff.h: Rebuild.
+       * coffcode.h (coff_mkobject_hook): Initialize new xcoff_data
+       fields.
+       (coff_compute_section_file_positions): If RS6000COFF_C, generate
+       full a.out header if full_aouthdr is set in xcoff_data.
+       (coff_write_object_contents): Likewise.  Set o_snentry and o_sntoc
+       based on sections stored in xcoff_data.
+       * coff-rs6000.c (xcoff_copy_private_bfd_data): Copy new xcoff_data
+       fields.
+       * coffgen.c (coff_get_symbol_info): If fix_value is set, fix the
+       value stored in ret rather than returning a pointer value.
+       
 Wed Oct 25 23:10:39 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
 
        * config.bfd (powerpc{,le}-{elf,sysv4,eabi,solaris2}): Remove MAC
index 10d5450bf0293defe1167ed56fa2692663901e4e..f837a08414aa93415b97e74b131e0ab4f5b1f7b8 100644 (file)
@@ -102,7 +102,16 @@ xcoff_copy_private_bfd_data (ibfd, obfd)
     return true;
   ix = xcoff_data (ibfd);
   ox = xcoff_data (obfd);
+  ox->full_aouthdr = ix->full_aouthdr;
   ox->toc = ix->toc;
+  if (ix->toc_section == NULL)
+    ox->toc_section = NULL;
+  else
+    ox->toc_section = ix->toc_section->output_section;
+  if (ix->entry_section == NULL)
+    ox->entry_section = NULL;
+  else
+    ox->entry_section = ix->entry_section->output_section;
   ox->text_align_power = ix->text_align_power;
   ox->data_align_power = ix->data_align_power;
   ox->modtype = ix->modtype;
index e3eeb13c06801b64d8ca5d4e80efacc54893a648..ff1406aa428ff5df28df60fc4c7657ee54e4331d 100644 (file)
@@ -1002,7 +1002,18 @@ coff_mkobject_hook (abfd, filehdr, aouthdr)
       struct xcoff_tdata *xcoff;
 
       xcoff = xcoff_data (abfd);
+      xcoff->full_aouthdr = true;
       xcoff->toc = internal_a->o_toc;
+      if (internal_a->o_sntoc == 0)
+       xcoff->toc_section = NULL;
+      else
+       xcoff->toc_section =
+         coff_section_from_bfd_index (abfd, internal_a->o_sntoc);
+      if (internal_a->o_snentry == 0)
+       xcoff->entry_section = NULL;
+      else
+       xcoff->entry_section =
+         coff_section_from_bfd_index (abfd, internal_a->o_snentry);
       xcoff->text_align_power = internal_a->o_algntext;
       xcoff->data_align_power = internal_a->o_algndata;
       xcoff->modtype = internal_a->o_modtype;
@@ -1764,6 +1775,8 @@ coff_compute_section_file_positions (abfd)
   if (abfd->flags & EXEC_P)
     sofar += AOUTSZ;
 #ifdef RS6000COFF_C
+  else if (xcoff_data (abfd)->full_aouthdr)
+    sofar += AOUTSZ;
   else
     sofar += SMALL_AOUTSZ;
 #endif
@@ -2003,7 +2016,10 @@ coff_write_object_contents (abfd)
     {
       scn_base = FILHSZ;
 #ifdef RS6000COFF_C
-      scn_base += SMALL_AOUTSZ;
+      if (xcoff_data (abfd)->full_aouthdr)
+       scn_base += AOUTSZ;
+      else
+       scn_base += SMALL_AOUTSZ;
 #endif
     }
 
@@ -2135,8 +2151,10 @@ coff_write_object_contents (abfd)
     {
       internal_f.f_opthdr = 0;
 #ifdef RS6000COFF_C
-      /* XCOFF seems to always write at least a small a.out header.  */
-      internal_f.f_opthdr = SMALL_AOUTSZ;
+      if (xcoff_data (abfd)->full_aouthdr)
+       internal_f.f_opthdr = AOUTSZ;
+      else
+       internal_f.f_opthdr = SMALL_AOUTSZ;
 #endif
     }
 
@@ -2311,22 +2329,20 @@ coff_write_object_contents (abfd)
   internal_f.f_nsyms = obj_raw_syment_count (abfd);
 
 #ifdef RS6000COFF_C
-  if ((abfd->flags & EXEC_P) != 0)
+  if (xcoff_data (abfd)->full_aouthdr)
     {
-      bfd_vma entry, toc;
+      bfd_vma toc;
       asection *loader_sec;
 
-      entry = bfd_get_start_address (abfd);
-      if (text_sec != NULL
-         && entry >= text_sec->vma
-         && entry < text_sec->vma + bfd_section_size (abfd, text_sec))
-       internal_a.o_snentry = text_sec->target_index;
-      else if (data_sec != NULL
-              && entry >= data_sec->vma
-              && entry < data_sec->vma + bfd_section_size (abfd, data_sec))
-       internal_a.o_snentry = data_sec->target_index;
+      if (xcoff_data (abfd)->entry_section != NULL)
+       internal_a.o_snentry = xcoff_data (abfd)->entry_section->target_index;
       else
-       internal_a.o_snentry = 0;
+       {
+         internal_a.o_snentry = 0;
+         if (internal_a.entry == 0)
+           internal_a.entry = (bfd_vma) -1;
+       }
+
       if (text_sec != NULL)
        {
          internal_a.o_sntext = text_sec->target_index;
@@ -2359,16 +2375,10 @@ coff_write_object_contents (abfd)
 
       toc = xcoff_data (abfd)->toc;
       internal_a.o_toc = toc;
-      if (text_sec != NULL
-         && toc >= text_sec->vma
-         && toc < text_sec->vma + bfd_section_size (abfd, text_sec))
-       internal_a.o_sntoc = text_sec->target_index;
-      else if (data_sec != NULL
-              && toc >= data_sec->vma
-              && toc < data_sec->vma + bfd_section_size (abfd, data_sec))
-       internal_a.o_sntoc = data_sec->target_index;
-      else
+      if (xcoff_data (abfd)->toc_section == NULL)
        internal_a.o_sntoc = 0;
+      else
+       internal_a.o_sntoc = xcoff_data (abfd)->toc_section->target_index;
 
       internal_a.o_modtype = xcoff_data (abfd)->modtype;
       if (xcoff_data (abfd)->cputype != -1)
@@ -2415,9 +2425,15 @@ coff_write_object_contents (abfd)
   else
     {
       AOUTHDR buff;
+      size_t size;
+
       /* XCOFF seems to always write at least a small a.out header.  */
       coff_swap_aouthdr_out (abfd, (PTR) &internal_a, (PTR) &buff);
-      if (bfd_write ((PTR) &buff, 1, SMALL_AOUTSZ, abfd) != SMALL_AOUTSZ)
+      if (xcoff_data (abfd)->full_aouthdr)
+       size = AOUTSZ;
+      else
+       size = SMALL_AOUTSZ;
+      if (bfd_write ((PTR) &buff, 1, size, abfd) != size)
        return false;
     }
 #endif
index a65776de918d3fa0c30c031393f881842cbc446e..9ccd2b7e8042dfd5d35eefb3aae9b32c0c6d254e 100644 (file)
@@ -329,6 +329,147 @@ coff_get_symtab (abfd, alocation)
   return bfd_get_symcount (abfd);
 }
 
+/* Get the name of a symbol.  The caller must pass in a buffer of size
+   >= SYMNMLEN + 1.  */
+
+const char *
+_bfd_coff_internal_syment_name (abfd, sym, buf)
+     bfd *abfd;
+     const struct internal_syment *sym;
+     char *buf;
+{
+  /* FIXME: It's not clear this will work correctly if sizeof
+     (_n_zeroes) != 4.  */
+  if (sym->_n._n_n._n_zeroes != 0
+      || sym->_n._n_n._n_offset == 0)
+    {
+      memcpy (buf, sym->_n._n_name, SYMNMLEN);
+      buf[SYMNMLEN] = '\0';
+      return buf;
+    }
+  else
+    {
+      const char *strings;
+
+      BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE);
+      strings = obj_coff_strings (abfd);
+      if (strings == NULL)
+       {
+         strings = _bfd_coff_read_string_table (abfd);
+         if (strings == NULL)
+           return NULL;
+       }
+      return strings + sym->_n._n_n._n_offset;
+    }
+}
+
+/* Read in and swap the relocs.  This returns a buffer holding the
+   relocs for section SEC in file ABFD.  If CACHE is true and
+   INTERNAL_RELOCS is NULL, the relocs read in will be saved in case
+   the function is called again.  If EXTERNAL_RELOCS is not NULL, it
+   is a buffer large enough to hold the unswapped relocs.  If
+   INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold
+   the swapped relocs.  If REQUIRE_INTERNAL is true, then the return
+   value must be INTERNAL_RELOCS.  The function returns NULL on error.  */
+
+struct internal_reloc *
+_bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs,
+                               require_internal, internal_relocs)
+     bfd *abfd;
+     asection *sec;
+     boolean cache;
+     bfd_byte *external_relocs;
+     boolean require_internal;
+     struct internal_reloc *internal_relocs;
+{
+  bfd_size_type relsz;
+  bfd_byte *free_external = NULL;
+  struct internal_reloc *free_internal = NULL;
+  bfd_byte *erel;
+  bfd_byte *erel_end;
+  struct internal_reloc *irel;
+
+  if (coff_section_data (abfd, sec) != NULL
+      && coff_section_data (abfd, sec)->relocs != NULL)
+    {
+      if (! require_internal)
+       return coff_section_data (abfd, sec)->relocs;
+      memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs,
+             sec->reloc_count * sizeof (struct internal_reloc));
+      return internal_relocs;
+    }
+
+  relsz = bfd_coff_relsz (abfd);
+
+  if (external_relocs == NULL)
+    {
+      free_external = (bfd_byte *) malloc (sec->reloc_count * relsz);
+      if (free_external == NULL && sec->reloc_count > 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+      external_relocs = free_external;
+    }
+
+  if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
+      || (bfd_read (external_relocs, relsz, sec->reloc_count, abfd)
+         != relsz * sec->reloc_count))
+    goto error_return;
+
+  if (internal_relocs == NULL)
+    {
+      free_internal = ((struct internal_reloc *)
+                      malloc (sec->reloc_count
+                              * sizeof (struct internal_reloc)));
+      if (free_internal == NULL && sec->reloc_count > 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+      internal_relocs = free_internal;
+    }
+
+  /* Swap in the relocs.  */
+  erel = external_relocs;
+  erel_end = erel + relsz * sec->reloc_count;
+  irel = internal_relocs;
+  for (; erel < erel_end; erel += relsz, irel++)
+    bfd_coff_swap_reloc_in (abfd, (PTR) erel, (PTR) irel);
+
+  if (free_external != NULL)
+    {
+      free (free_external);
+      free_external = NULL;
+    }
+
+  if (cache && free_internal != NULL)
+    {
+      if (coff_section_data (abfd, sec) == NULL)
+       {
+         sec->used_by_bfd =
+           (PTR) bfd_zalloc (abfd,
+                             sizeof (struct coff_section_tdata));
+         if (sec->used_by_bfd == NULL)
+           {
+             bfd_set_error (bfd_error_no_memory);
+             goto error_return;
+           }
+         coff_section_data (abfd, sec)->contents = NULL;
+       }
+      coff_section_data (abfd, sec)->relocs = free_internal;
+    }
+
+  return internal_relocs;
+
+ error_return:
+  if (free_external != NULL)
+    free (free_external);
+  if (free_internal != NULL)
+    free (free_internal);
+  return NULL;
+}
+
 /* Set lineno_count for the output sections of a COFF file.  */
 
 int
@@ -1688,6 +1829,15 @@ coff_get_symbol_info (abfd, symbol, ret)
      symbol_info *ret;
 {
   bfd_symbol_info (symbol, ret);
+  if (coffsymbol (symbol)->native != NULL
+      && coffsymbol (symbol)->native->fix_value)
+    {
+      combined_entry_type *psym;
+
+      psym = ((combined_entry_type *)
+             coffsymbol (symbol)->native->u.syment.n_value);
+      ret->value = (bfd_vma) (psym - obj_raw_syments (abfd));
+    }
 }
 
 /* Print out information about COFF symbol.  */
@@ -1974,7 +2124,7 @@ coff_find_nearest_line (abfd, section, ignore_symbols, offset, filename_ptr,
       section->used_by_bfd =
        ((PTR) bfd_zalloc (abfd,
                           sizeof (struct coff_section_tdata)));
-      sec_data = section->used_by_bfd;
+      sec_data = (struct coff_section_tdata *) section->used_by_bfd;
     }
   if (sec_data != NULL)
     {
index 0dd01846b018682f0a32c1b36c6d7d12593bc1eb..7b818aa413bee54d5f751ee1f42542f649eec222 100644 (file)
@@ -105,9 +105,18 @@ struct xcoff_tdata
   /* Basic COFF information.  */
   coff_data_type coff;
 
+  /* True if a large a.out header should be generated.  */
+  boolean full_aouthdr;
+
   /* TOC value.  */
   bfd_vma toc;
 
+  /* Section holding TOC.  */
+  asection *toc_section;
+
+  /* Section holding entry point.  */
+  asection *entry_section;
+
   /* .text alignment from optional header.  */
   int text_align_power;
 
@@ -178,8 +187,6 @@ struct xcoff_section_tdata
      by this csect.  */
   unsigned long first_symndx;
   unsigned long last_symndx;
-  /* The number of .loader relocs in this csect.  */
-  size_t ldrel_count;
 };
 
 /* An accessor macro the xcoff_section_tdata structure.  */
index ebdcdfbb0d8b2391956bb81c5caf2c8adcc78d34..f75c42b92a4f54e694f2b932a15c982a5daf2d7c 100644 (file)
@@ -105,9 +105,18 @@ struct xcoff_tdata
   /* Basic COFF information.  */
   coff_data_type coff;
 
+  /* True if a large a.out header should be generated.  */
+  boolean full_aouthdr;
+
   /* TOC value.  */
   bfd_vma toc;
 
+  /* Section holding TOC.  */
+  asection *toc_section;
+
+  /* Section holding entry point.  */
+  asection *entry_section;
+
   /* .text alignment from optional header.  */
   int text_align_power;
 
@@ -178,8 +187,6 @@ struct xcoff_section_tdata
      by this csect.  */
   unsigned long first_symndx;
   unsigned long last_symndx;
-  /* The number of .loader relocs in this csect.  */
-  size_t ldrel_count;
 };
 
 /* An accessor macro the xcoff_section_tdata structure.  */
index 60396207df4a4fa74238fdadccc5595f80d1cfe7..0e272f5d24e9d37aabc919d8fa08fbbf3d56825f 100644 (file)
@@ -25,10 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "coff/internal.h"
 #include "libcoff.h"
 
-/* This file holds the XCOFF linker code.  A lot of it is very similar
-   to the COFF linker code.  However, it is different enough that I
-   chose to avoid trying to hack up the COFF code to support XCOFF.
-   That leads to a certain amount of duplicated code, alas.  */
+/* This file holds the XCOFF linker code.  */
 
 #define STRING_SIZE_SIZE (4)
 
@@ -1216,34 +1213,47 @@ xcoff_link_add_symbols (abfd, info)
                                                                relbuf);
                      if (relname == NULL)
                        goto error_return;
-                     copy = (! info->keep_memory
-                             || relsym._n._n_n._n_zeroes != 0
-                             || relsym._n._n_n._n_offset == 0);
-                     h = xcoff_link_hash_lookup (xcoff_hash_table (info),
-                                                 relname, true, copy, false);
-                     if (h == NULL)
-                       goto error_return;
-
-                     /* At this point h->root.type could be
-                        bfd_link_hash_new.  That should be OK, since
-                        we know for sure that we will come across
-                        this symbol as we step through the file.  */
-
-                     /* We store h in *sym_hash for the convenience
-                        of the relocate_section function.  */
-                     *sym_hash = h;
 
-                     if (h->toc_section != NULL)
+                     /* We only merge TOC entries if the TC name is
+                         the same as the symbol name.  This handles
+                         the normal case, but not common cases like
+                         SYM.P4 which gcc generates to store SYM + 4
+                         in the TOC.  FIXME.  */
+                     if (strcmp (name, relname) == 0)
                        {
-                         /* We already have a TOC entry for this
-                            symbol, so we can just ignore this one.  */
-                         *rel_csect = bfd_und_section_ptr;
-                         break;
-                       }
+                         copy = (! info->keep_memory
+                                 || relsym._n._n_n._n_zeroes != 0
+                                 || relsym._n._n_n._n_offset == 0);
+                         h = xcoff_link_hash_lookup (xcoff_hash_table (info),
+                                                     relname, true, copy,
+                                                     false);
+                         if (h == NULL)
+                           goto error_return;
+
+                         /* At this point h->root.type could be
+                            bfd_link_hash_new.  That should be OK,
+                            since we know for sure that we will come
+                            across this symbol as we step through the
+                            file.  */
+
+                         /* We store h in *sym_hash for the
+                            convenience of the relocate_section
+                            function.  */
+                         *sym_hash = h;
+
+                         if (h->toc_section != NULL)
+                           {
+                             /* We already have a TOC entry for this
+                                symbol, so we can just ignore this
+                                one.  */
+                             *rel_csect = bfd_und_section_ptr;
+                             break;
+                           }
 
-                     /* We are about to create a TOC entry for this
-                        symbol.  */
-                     set_toc = h;
+                         /* We are about to create a TOC entry for
+                            this symbol.  */
+                         set_toc = h;
+                       }
                    }
                }
            }
@@ -1431,7 +1441,7 @@ xcoff_link_add_symbols (abfd, info)
          csect = bfd_make_section_anyway (abfd, ".bss");
          if (csect == NULL)
            goto error_return;
-         csect->vma = 0;
+         csect->vma = sym.n_value;
          csect->_raw_size = aux.x_csect.x_scnlen.l;
          csect->flags |= SEC_ALLOC;
          csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp);
@@ -1524,6 +1534,21 @@ xcoff_link_add_symbols (abfd, info)
                  (struct bfd_link_hash_entry **) sym_hash)))
            goto error_return;
 
+         if (smtyp == XTY_CM)
+           {
+             if ((*sym_hash)->root.type != bfd_link_hash_common
+                 || (*sym_hash)->root.u.c.p->section != csect)
+               {
+                 /* We don't need the common csect we just created.  */
+                 csect->_raw_size = 0;
+               }
+             else
+               {
+                 (*sym_hash)->root.u.c.p->alignment_power
+                    = csect->alignment_power;
+               }
+           }
+
          if (info->hash->creator == abfd->xvec)
            {
              int flag;
@@ -1574,75 +1599,49 @@ xcoff_link_add_symbols (abfd, info)
                  goto error_return;
                }
 
-             /* We need to copy all relocs which are not PC relative
-                and not TOC relative into the .loader section.
-
-                We also identify all symbols which are called, so
-                that we can create glue code for calls to functions
-                imported from dynamic objects.  */
-
+             /* We identify all symbols which are called, so that we
+                can create glue code for calls to functions imported
+                from dynamic objects.  */
              if (info->hash->creator == abfd->xvec
-                 && *rel_csect != bfd_und_section_ptr)
+                 && *rel_csect != bfd_und_section_ptr
+                 && (rel->r_type == R_BR
+                     || rel->r_type == R_RBR)
+                 && obj_xcoff_sym_hashes (abfd)[rel->r_symndx] != NULL)
                {
                  struct xcoff_link_hash_entry *h;
 
-                 switch (rel->r_type)
+                 h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx];
+                 h->flags |= XCOFF_CALLED;
+                 /* If the symbol name starts with a period, it is
+                     the code of a function.  If the symbol is
+                     currently undefined, then add an undefined symbol
+                     for the function descriptor.  This should do no
+                     harm, because any regular object that defines the
+                     function should also define the function
+                     descriptor.  It helps, because it means that we
+                     will identify the function descriptor with a
+                     dynamic object if a dynamic object defines it.  */
+                 if (h->root.root.string[0] == '.'
+                     && h->descriptor == NULL)
                    {
-                   default:
-                     break;
-                   case R_POS:
-                   case R_NEG:
-                   case R_RL:
-                   case R_RLA:
-                     ++xcoff_hash_table (info)->ldrel_count;
-                     ++xcoff_section_data (abfd, *rel_csect)->ldrel_count;
-                     h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx];
-                     if (h != NULL)
-                       h->flags |= XCOFF_LDREL;
-                     break;
-                   case R_BR:
-                   case R_RBR:
-                     h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx];
-                     if (h != NULL)
+                     struct xcoff_link_hash_entry *hds;
+
+                     hds = xcoff_link_hash_lookup (xcoff_hash_table (info),
+                                                   h->root.root.string + 1,
+                                                   true, false, true);
+                     if (hds == NULL)
+                       goto error_return;
+                     if (hds->root.type == bfd_link_hash_new)
                        {
-                         h->flags |= XCOFF_CALLED;
-                         /* If the symbol name starts with a period,
-                             it is the code of a function.  If the
-                             symbol is currently undefined, then add
-                             an undefined symbol for the function
-                             descriptor.  This should do no harm,
-                             because any regular object that defines
-                             the function should also define the
-                             function descriptor.  It helps, because
-                             it means that we will identify the
-                             function descriptor with a dynamic object
-                             if a dynamic object defines it.  */
-                         if (h->root.root.string[0] == '.'
-                             && h->descriptor == NULL)
-                           {
-                             struct xcoff_link_hash_entry *hds;
-
-                             hds = (xcoff_link_hash_lookup
-                                    (xcoff_hash_table (info),
-                                     h->root.root.string + 1, true, false,
-                                     true));
-                             if (hds == NULL)
-                               goto error_return;
-                             if (hds->root.type == bfd_link_hash_new)
-                               {
-                                 if (! (_bfd_generic_link_add_one_symbol
-                                        (info, abfd, hds->root.root.string,
-                                         (flagword) 0, bfd_und_section_ptr,
-                                         (bfd_vma) 0, (const char *) NULL,
-                                         false, false,
-                                         ((struct bfd_link_hash_entry **)
-                                          NULL))))
-                                   goto error_return;
-                               }
-                             h->descriptor = hds;
-                           }
+                         if (! (_bfd_generic_link_add_one_symbol
+                                (info, abfd, hds->root.root.string,
+                                 (flagword) 0, bfd_und_section_ptr,
+                                 (bfd_vma) 0, (const char *) NULL, false,
+                                 false,
+                                 (struct bfd_link_hash_entry **) NULL)))
+                           goto error_return;
                        }
-                     break;
+                     h->descriptor = hds;
                    }
                }
            }
@@ -1773,10 +1772,12 @@ xcoff_link_add_dynamic_symbols (abfd, info)
 
              /* If the symbol is undefined, and the current BFD is
                 not a dynamic object, change the BFD to this dynamic
-                object, so that we can get the import file ID
-                correctly.  */
-             if (h->root.u.undef.abfd == NULL
-                 || (h->root.u.undef.abfd->flags & DYNAMIC) == 0)
+                object, so that we can get the correct import file
+                ID.  */
+             if ((h->root.type == bfd_link_hash_undefined
+                  || h->root.type == bfd_link_hash_undefweak)
+                 && (h->root.u.undef.abfd == NULL
+                     || (h->root.u.undef.abfd->flags & DYNAMIC) == 0))
                h->root.u.undef.abfd = abfd;
 
              if (h->smclas == XMC_UA
@@ -2024,7 +2025,13 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
   hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry,
                                   false, false, true);
   if (hentry != NULL)
-    hentry->flags |= XCOFF_ENTRY;
+    {
+      hentry->flags |= XCOFF_ENTRY;
+      if (hentry->root.type == bfd_link_hash_defined
+         || hentry->root.type == bfd_link_hash_defweak)
+       xcoff_data (output_bfd)->entry_section =
+         hentry->root.u.def.section->output_section;
+    }
 
   /* Garbage collect unused sections.  */
   if (info->relocateable
@@ -2035,6 +2042,22 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
     {
       gc = false;
       xcoff_hash_table (info)->gc = false;
+
+      /* We still need to call xcoff_mark, in order to set ldrel_count
+         correctly.  */
+      for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+       {
+         asection *o;
+
+         for (o = sub->sections; o != NULL; o = o->next)
+           {
+             if ((o->flags & SEC_MARK) == 0)
+               {
+                 if (! xcoff_mark (info, o))
+                   goto error_return;
+               }
+           }
+       }
     }
   else
     {
@@ -2284,7 +2307,10 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
 }
 
 /* The mark phase of garbage collection.  For a given section, mark
-   it, and all the sections which define symbols to which it refers.  */
+   it, and all the sections which define symbols to which it refers.
+   Because this function needs to look at the relocs, we also count
+   the number of relocs which need to be copied into the .loader
+   section.  */
 
 static boolean
 xcoff_mark (info, sec)
@@ -2393,6 +2419,35 @@ xcoff_mark (info, sec)
                  if (! xcoff_mark (info, rsec))
                    return false;
                }
+
+             /* See if this reloc needs to be copied into the .loader
+                 section.  */
+             switch (rel->r_type)
+               {
+               default:
+                 if (h == NULL
+                     || h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak
+                     || h->root.type == bfd_link_hash_common)
+                   break;
+                 /* Fall through.  */
+               case R_POS:
+               case R_NEG:
+               case R_RL:
+               case R_RLA:
+                 ++xcoff_hash_table (info)->ldrel_count;
+                 if (h != NULL)
+                   h->flags |= XCOFF_LDREL;
+                 break;
+               case R_TOC:
+               case R_GL:
+               case R_TCL:
+               case R_TRL:
+               case R_TRLA:
+                 /* We should never need a .loader reloc for a TOC
+                    relative reloc.  */
+                 break;
+               }
            }
 
          if (! info->keep_memory
@@ -2441,10 +2496,6 @@ xcoff_sweep (info)
                  o->_raw_size = 0;
                  o->reloc_count = 0;
                  o->lineno_count = 0;
-                 if (coff_section_data (sub, o) != NULL
-                     && xcoff_section_data (sub, o) != NULL)
-                   xcoff_hash_table (info)->ldrel_count -=
-                     xcoff_section_data (sub, o)->ldrel_count;
                }
            }
        }
@@ -2520,11 +2571,12 @@ xcoff_build_ldsyms (h, p)
 
   /* We need to add a symbol to the .loader section if it is mentioned
      in a reloc which we are copying to the .loader section and it was
-     not defined, or if it is the entry point.  */
+     not defined or common, or if it is the entry point.  */
 
   if (((h->flags & XCOFF_LDREL) == 0
        || h->root.type == bfd_link_hash_defined
-       || h->root.type == bfd_link_hash_defweak)
+       || h->root.type == bfd_link_hash_defweak
+       || h->root.type == bfd_link_hash_common)
       && (h->flags & XCOFF_ENTRY) == 0)
     {
       h->ldsym = NULL;
@@ -2660,6 +2712,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
                  + xcoff_hash_table (info)->ldhdr.l_nsyms * LDSYMSZ));
 
   xcoff_data (abfd)->coff.link_info = info;
+  xcoff_data (abfd)->full_aouthdr = true;
 
   finfo.strtab = _bfd_stringtab_init ();
   if (finfo.strtab == NULL)
@@ -2728,13 +2781,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
              code knows what compute_section_file_positions is going
              to do.  */
          sofar = bfd_coff_filhsz (abfd);
-         if ((abfd->flags & EXEC_P) != 0)
-           sofar += bfd_coff_aoutsz (abfd);
-         else
-           {
-             /* FIXME.  */
-             sofar += 28;
-           }
+         sofar += bfd_coff_aoutsz (abfd);
          sofar += abfd->section_count * bfd_coff_scnhsz (abfd);
 
          for (o = abfd->sections; o != NULL; o = o->next)
@@ -3420,6 +3467,8 @@ xcoff_link_input_bfd (finfo, input_bfd)
                 + (*csectpp)->output_offset
                 + isym.n_value
                 - (*csectpp)->vma);
+             xcoff_data (finfo->output_bfd)->toc_section =
+               (*csectpp)->output_section;
              require = true;
            }
        }
@@ -3441,7 +3490,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
       if (! skip
          && isym.n_sclass == C_EXT
          && smtyp == XTY_CM
-         && ((*sym_hash)->flags & XCOFF_DEF_REGULAR) != 0)
+         && (*sym_hash)->root.type != bfd_link_hash_common)
        skip = true;
 
       /* Skip local symbols if we are discarding them.  */
@@ -3531,26 +3580,9 @@ xcoff_link_input_bfd (finfo, input_bfd)
                }
            }
 
-         if (isym.n_sclass == C_BSTAT)
-           {
-             unsigned long indx;
-
-             /* The value of a C_BSTAT symbol is the symbol table
-                 index of the containing csect.  */
-
-             indx = isym.n_value;
-             if (indx < obj_raw_syment_count (input_bfd))
-               {
-                 long symindx;
-
-                 symindx = finfo->sym_indices[indx];
-                 if (symindx < 0)
-                   isym.n_value = 0;
-                 else
-                   isym.n_value = symindx;
-               }
-           }
-         else if (isym.n_scnum > 0)
+         if (isym.n_sclass != C_BSTAT
+             && isym.n_sclass != C_ESTAT
+             && isym.n_scnum > 0)
            {
              isym.n_scnum = (*csectpp)->output_section->target_index;
              isym.n_value += ((*csectpp)->output_section->vma
@@ -3635,9 +3667,10 @@ xcoff_link_input_bfd (finfo, input_bfd)
        *indexp++ = -1;
     }
 
-  /* Fix up the aux entries.  This must be done in a separate pass,
-     because we don't know the correct symbol indices until we have
-     already decided which symbols we are going to keep.  */
+  /* Fix up the aux entries and the C_BSTAT symbols.  This must be
+     done in a separate pass, because we don't know the correct symbol
+     indices until we have already decided which symbols we are going
+     to keep.  */
 
   esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
   esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
@@ -3657,6 +3690,27 @@ xcoff_link_input_bfd (finfo, input_bfd)
        {
          int i;
 
+         if (isymp->n_sclass == C_BSTAT)
+           {
+             unsigned long indx;
+
+             /* The value of a C_BSTAT symbol is the symbol table
+                 index of the containing csect.  */
+             indx = isymp->n_value;
+             if (indx < obj_raw_syment_count (input_bfd))
+               {
+                 long symindx;
+
+                 symindx = finfo->sym_indices[indx];
+                 if (symindx < 0)
+                   isymp->n_value = 0;
+                 else
+                   isymp->n_value = symindx;
+                 bfd_coff_swap_sym_out (output_bfd, (PTR) isymp,
+                                        (PTR) outsym);
+               }
+           }
+
          esym += isymesz;
          outsym += osymesz;
 
@@ -4066,7 +4120,12 @@ xcoff_link_input_bfd (finfo, input_bfd)
              switch (irel->r_type)
                {
                default:
-                 break;
+                 if (h == NULL
+                     || h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak
+                     || h->root.type == bfd_link_hash_common)
+                   break;
+                 /* Fall through.  */
                case R_POS:
                case R_NEG:
                case R_RL:
@@ -4076,30 +4135,36 @@ xcoff_link_input_bfd (finfo, input_bfd)
                  ldrel.l_vaddr = irel->r_vaddr;
                  if (r_symndx == -1)
                    ldrel.l_symndx = -1;
-                 else if (h == NULL)
+                 else if (h == NULL
+                          || (h->root.type == bfd_link_hash_defined
+                              || h->root.type == bfd_link_hash_defweak
+                              || h->root.type == bfd_link_hash_common))
                    {
                      asection *sec;
 
-                     sec = xcoff_data (input_bfd)->csects[r_symndx];
-                     if ((sec->flags & SEC_CODE) != 0)
-                       ldrel.l_symndx = 0;
-                     else if ((sec->flags & SEC_HAS_CONTENTS) != 0)
-                       ldrel.l_symndx = 1;
+                     if (h == NULL)
+                       sec = xcoff_data (input_bfd)->csects[r_symndx];
+                     else if (h->root.type == bfd_link_hash_common)
+                       sec = h->root.u.c.p->section;
                      else
-                       ldrel.l_symndx = 2;
-                   }
-                 else if (h->root.type == bfd_link_hash_defined
-                          || h->root.type == bfd_link_hash_defweak)
-                   {
-                     asection *sec;
+                       sec = h->root.u.def.section;
+                     sec = sec->output_section;
 
-                     sec = h->root.u.def.section->output_section;
-                     if ((sec->flags & SEC_CODE) != 0)
+                     if (strcmp (sec->name, ".text") == 0)
                        ldrel.l_symndx = 0;
-                     else if ((sec->flags & SEC_HAS_CONTENTS) != 0)
+                     else if (strcmp (sec->name, ".data") == 0)
                        ldrel.l_symndx = 1;
-                     else
+                     else if (strcmp (sec->name, ".bss") == 0)
                        ldrel.l_symndx = 2;
+                     else
+                       {
+                         (*_bfd_error_handler)
+                           ("%s: loader reloc in unrecognized section `%s'",
+                            bfd_get_filename (input_bfd),
+                            sec->name);
+                         bfd_set_error (bfd_error_nonrepresentable_section);
+                         return false;
+                       }
                    }
                  else
                    {
@@ -4117,7 +4182,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                  ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
                  ldrel.l_rsecnm = o->output_section->target_index;
                  if (xcoff_hash_table (finfo->info)->textro
-                     && (o->output_section->flags & SEC_CODE) != 0)
+                     && strcmp (o->output_section->name, ".text") == 0)
                    {
                      (*_bfd_error_handler)
                        ("%s: loader reloc in read-only section %s",
@@ -4131,6 +4196,16 @@ xcoff_link_input_bfd (finfo, input_bfd)
                                        finfo->ldrel);
                  BFD_ASSERT (sizeof (struct external_ldrel) == LDRELSZ);
                  ++finfo->ldrel;
+                 break;
+
+               case R_TOC:
+               case R_GL:
+               case R_TCL:
+               case R_TRL:
+               case R_TRLA:
+                 /* We should never need a .loader reloc for a TOC
+                    relative reloc.  */
+                 break;
                }
            }