import gdb-2000-02-02 snapshot
[external/binutils.git] / bfd / xcofflink.c
index 8c38dd6..9ec75bd 100644 (file)
@@ -1,5 +1,5 @@
 /* POWER/PowerPC XCOFF linker support.
-   Copyright 1995 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <ian@cygnus.com>, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -256,18 +256,22 @@ struct xcoff_link_hash_entry
         set), this is the offset in toc_section.  */
       bfd_vma toc_offset;
       /* If the TOC entry comes from an input file, this is set to the
-         symbo lindex of the C_HIDEXT XMC_TC symbol.  */
+         symbol index of the C_HIDEXT XMC_TC or XMC_TD symbol.  */
       long toc_indx;
     } u;
 
   /* If this symbol is a function entry point which is called, this
-     field holds a pointer to the function descriptor.  */
+     field holds a pointer to the function descriptor.  If this symbol
+     is a function descriptor, this field holds a pointer to the
+     function entry point.  */
   struct xcoff_link_hash_entry *descriptor;
 
   /* The .loader symbol table entry, if there is one.  */
   struct internal_ldsym *ldsym;
 
-  /* The .loader symbol table index.  */
+  /* If XCOFF_BUILT_LDSYM is set, this is the .loader symbol table
+     index.  If XCOFF_BUILD_LDSYM is clear, and XCOFF_IMPORT is set,
+     this is the l_ifile value.  */
   long ldindx;
 
   /* Some linker flags.  */
@@ -276,8 +280,8 @@ struct xcoff_link_hash_entry
 #define XCOFF_REF_REGULAR (01)
   /* Symbol is defined by a regular object.  */
 #define XCOFF_DEF_REGULAR (02)
-  /* Symbol is referenced by a dynamic object.  */
-#define XCOFF_REF_DYNAMIC (04)
+  /* Symbol is defined by a dynamic object.  */
+#define XCOFF_DEF_DYNAMIC (04)
   /* Symbol is used in a reloc being copied into the .loader section.  */
 #define XCOFF_LDREL (010)
   /* Symbol is the entry point.  */
@@ -296,6 +300,10 @@ struct xcoff_link_hash_entry
 #define XCOFF_MARK (02000)
   /* Symbol size is recorded in size_list list from hash table.  */
 #define XCOFF_HAS_SIZE (04000)
+  /* Symbol is a function descriptor.  */
+#define XCOFF_DESCRIPTOR (010000)
+  /* Multiple definitions have been for the symbol.  */
+#define XCOFF_MULTIPLY_DEFINED (020000)
 
   /* The storage mapping class.  */
   unsigned char smclas;
@@ -332,6 +340,10 @@ struct xcoff_link_hash_table
      linkage code.  */
   asection *toc_section;
 
+  /* The .ds section we use to hold function descriptors which we
+     create for exported symbols.  */
+  asection *descriptor_section;
+
   /* The list of import files.  */
   struct xcoff_import_file *imports;
 
@@ -351,6 +363,9 @@ struct xcoff_link_hash_table
       struct xcoff_link_hash_entry *h;
       bfd_size_type size;
     } *size_list;
+
+  /* Magic sections: _text, _etext, _data, _edata, _end, end.  */
+  asection *special_sections[6];
 };
 
 /* Information we keep for each section in the output file during the
@@ -416,14 +431,21 @@ struct xcoff_final_link_info
   bfd_byte *external_relocs;
 };
 
+static void xcoff_swap_ldhdr_in
+  PARAMS ((bfd *, const struct external_ldhdr *, struct internal_ldhdr *));
 static void xcoff_swap_ldhdr_out
   PARAMS ((bfd *, const struct internal_ldhdr *, struct external_ldhdr *));
+static void xcoff_swap_ldsym_in
+  PARAMS ((bfd *, const struct external_ldsym *, struct internal_ldsym *));
 static void xcoff_swap_ldsym_out
   PARAMS ((bfd *, const struct internal_ldsym *, struct external_ldsym *));
+static void xcoff_swap_ldrel_in
+  PARAMS ((bfd *, const struct external_ldrel *, struct internal_ldrel *));
 static void xcoff_swap_ldrel_out
   PARAMS ((bfd *, const struct internal_ldrel *, struct external_ldrel *));
 static struct bfd_hash_entry *xcoff_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static boolean xcoff_get_section_contents PARAMS ((bfd *, asection *));
 static struct internal_reloc *xcoff_read_internal_relocs
   PARAMS ((bfd *, asection *, boolean, bfd_byte *, boolean,
           struct internal_reloc *));
@@ -433,11 +455,15 @@ static boolean xcoff_link_check_archive_element
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static boolean xcoff_link_check_ar_symbols
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
+static boolean xcoff_link_check_dynamic_ar_symbols
+  PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static bfd_size_type xcoff_find_reloc
   PARAMS ((struct internal_reloc *, bfd_size_type, bfd_vma));
 static boolean xcoff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
 static boolean xcoff_link_add_dynamic_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
+static boolean xcoff_mark_symbol
+  PARAMS ((struct bfd_link_info *, struct xcoff_link_hash_entry *));
 static boolean xcoff_mark PARAMS ((struct bfd_link_info *, asection *));
 static void xcoff_sweep PARAMS ((struct bfd_link_info *));
 static boolean xcoff_build_ldsyms
@@ -451,12 +477,28 @@ static boolean xcoff_reloc_link_order
           struct bfd_link_order *));
 static int xcoff_sort_relocs PARAMS ((const PTR, const PTR));
 \f
-/* Routines to swap information in the XCOFF .loader section.  We only
-   need to swap this information out, not in.  I believe that only the
-   loader needs to swap this information in.  If we ever need to write
-   an XCOFF loader, this stuff will need to be moved to another file
-   shared by the linker (which XCOFF calls the ``binder'') and the
-   loader.  */
+/* Routines to swap information in the XCOFF .loader section.  If we
+   ever need to write an XCOFF loader, this stuff will need to be
+   moved to another file shared by the linker (which XCOFF calls the
+   ``binder'') and the loader.  */
+
+/* Swap in the ldhdr structure.  */
+
+static void
+xcoff_swap_ldhdr_in (abfd, src, dst)
+     bfd *abfd;
+     const struct external_ldhdr *src;
+     struct internal_ldhdr *dst;
+{
+  dst->l_version = bfd_get_32 (abfd, src->l_version);
+  dst->l_nsyms = bfd_get_32 (abfd, src->l_nsyms);
+  dst->l_nreloc = bfd_get_32 (abfd, src->l_nreloc);
+  dst->l_istlen = bfd_get_32 (abfd, src->l_istlen);
+  dst->l_nimpid = bfd_get_32 (abfd, src->l_nimpid);
+  dst->l_impoff = bfd_get_32 (abfd, src->l_impoff);
+  dst->l_stlen = bfd_get_32 (abfd, src->l_stlen);
+  dst->l_stoff = bfd_get_32 (abfd, src->l_stoff);
+}
 
 /* Swap out the ldhdr structure.  */
 
@@ -476,6 +518,29 @@ xcoff_swap_ldhdr_out (abfd, src, dst)
   bfd_put_32 (abfd, src->l_stoff, dst->l_stoff);
 }
 
+/* Swap in the ldsym structure.  */
+
+static void
+xcoff_swap_ldsym_in (abfd, src, dst)
+     bfd *abfd;
+     const struct external_ldsym *src;
+     struct internal_ldsym *dst;
+{
+  if (bfd_get_32 (abfd, src->_l._l_l._l_zeroes) != 0)
+    memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN);
+  else
+    {
+      dst->_l._l_l._l_zeroes = 0;
+      dst->_l._l_l._l_offset = bfd_get_32 (abfd, src->_l._l_l._l_offset);
+    }
+  dst->l_value = bfd_get_32 (abfd, src->l_value);
+  dst->l_scnum = bfd_get_16 (abfd, src->l_scnum);
+  dst->l_smtype = bfd_get_8 (abfd, src->l_smtype);
+  dst->l_smclas = bfd_get_8 (abfd, src->l_smclas);
+  dst->l_ifile = bfd_get_32 (abfd, src->l_ifile);
+  dst->l_parm = bfd_get_32 (abfd, src->l_parm);
+}
+
 /* Swap out the ldsym structure.  */
 
 static void
@@ -499,6 +564,20 @@ xcoff_swap_ldsym_out (abfd, src, dst)
   bfd_put_32 (abfd, src->l_parm, dst->l_parm);
 }
 
+/* Swap in the ldrel structure.  */
+
+static void
+xcoff_swap_ldrel_in (abfd, src, dst)
+     bfd *abfd;
+     const struct external_ldrel *src;
+     struct internal_ldrel *dst;
+{
+  dst->l_vaddr = bfd_get_32 (abfd, src->l_vaddr);
+  dst->l_symndx = bfd_get_32 (abfd, src->l_symndx);
+  dst->l_rtype = bfd_get_16 (abfd, src->l_rtype);
+  dst->l_rsecnm = bfd_get_16 (abfd, src->l_rsecnm);
+}
+
 /* Swap out the ldrel structure.  */
 
 static void
@@ -513,6 +592,317 @@ xcoff_swap_ldrel_out (abfd, src, dst)
   bfd_put_16 (abfd, src->l_rsecnm, dst->l_rsecnm);
 }
 \f
+/* Routines to read XCOFF dynamic information.  This don't really
+   belong here, but we already have the ldsym manipulation routines
+   here.  */
+
+/* Read the contents of a section.  */
+
+static boolean
+xcoff_get_section_contents (abfd, sec)
+     bfd *abfd;
+     asection *sec;
+{
+  if (coff_section_data (abfd, sec) == NULL)
+    {
+      sec->used_by_bfd = bfd_zalloc (abfd,
+                                    sizeof (struct coff_section_tdata));
+      if (sec->used_by_bfd == NULL)
+       return false;
+    }
+
+  if (coff_section_data (abfd, sec)->contents == NULL)
+    {
+      coff_section_data (abfd, sec)->contents =
+       (bfd_byte *) bfd_malloc (sec->_raw_size);
+      if (coff_section_data (abfd, sec)->contents == NULL)
+       return false;
+
+      if (! bfd_get_section_contents (abfd, sec,
+                                     coff_section_data (abfd, sec)->contents,
+                                     (file_ptr) 0, sec->_raw_size))
+       return false;
+    }
+
+  return true;
+}
+
+/* Get the size required to hold the dynamic symbols.  */
+
+long
+_bfd_xcoff_get_dynamic_symtab_upper_bound (abfd)
+     bfd *abfd;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  return (ldhdr.l_nsyms + 1) * sizeof (asymbol *);
+}
+
+/* Get the dynamic symbols.  */
+
+long
+_bfd_xcoff_canonicalize_dynamic_symtab (abfd, psyms)
+     bfd *abfd;
+     asymbol **psyms;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+  const char *strings;
+  struct external_ldsym *elsym, *elsymend;
+  coff_symbol_type *symbuf;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  coff_section_data (abfd, lsec)->keep_contents = true;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  strings = (char *) contents + ldhdr.l_stoff;
+
+  symbuf = ((coff_symbol_type *)
+           bfd_zalloc (abfd, ldhdr.l_nsyms * sizeof (coff_symbol_type)));
+  if (symbuf == NULL)
+    return -1;
+
+  elsym = (struct external_ldsym *) (contents + LDHDRSZ);
+  elsymend = elsym + ldhdr.l_nsyms;
+  for (; elsym < elsymend; elsym++, symbuf++, psyms++)
+    {
+      struct internal_ldsym ldsym;
+
+      xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
+
+      symbuf->symbol.the_bfd = abfd;
+
+      if (ldsym._l._l_l._l_zeroes == 0)
+       symbuf->symbol.name = strings + ldsym._l._l_l._l_offset;
+      else
+       {
+         int i;
+
+         for (i = 0; i < SYMNMLEN; i++)
+           if (ldsym._l._l_name[i] == '\0')
+             break;
+         if (i < SYMNMLEN)
+           symbuf->symbol.name = (char *) elsym->_l._l_name;
+         else
+           {
+             char *c;
+
+             c = bfd_alloc (abfd, SYMNMLEN + 1);
+             if (c == NULL)
+               return -1;
+             memcpy (c, ldsym._l._l_name, SYMNMLEN);
+             c[SYMNMLEN] = '\0';
+             symbuf->symbol.name = c;
+           }
+       }
+
+      if (ldsym.l_smclas == XMC_XO)
+       symbuf->symbol.section = bfd_abs_section_ptr;
+      else
+       symbuf->symbol.section = coff_section_from_bfd_index (abfd,
+                                                             ldsym.l_scnum);
+      symbuf->symbol.value = ldsym.l_value - symbuf->symbol.section->vma;
+
+      symbuf->symbol.flags = BSF_NO_FLAGS;
+      if ((ldsym.l_smtype & L_EXPORT) != 0)
+       symbuf->symbol.flags |= BSF_GLOBAL;
+
+      /* FIXME: We have no way to record the other information stored
+         with the loader symbol.  */
+
+      *psyms = (asymbol *) symbuf;
+    }
+
+  *psyms = NULL;
+
+  return ldhdr.l_nsyms;
+}
+
+/* Get the size required to hold the dynamic relocs.  */
+
+long
+_bfd_xcoff_get_dynamic_reloc_upper_bound (abfd)
+     bfd *abfd;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  return (ldhdr.l_nreloc + 1) * sizeof (arelent *);
+}
+
+/* The typical dynamic reloc.  */
+
+static reloc_howto_type xcoff_dynamic_reloc =
+  HOWTO (0,                    /* type */                                 
+        0,                     /* rightshift */                           
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
+        32,                    /* bitsize */                   
+        false,                 /* pc_relative */                          
+        0,                     /* bitpos */                               
+        complain_overflow_bitfield, /* complain_on_overflow */
+        0,                     /* special_function */                     
+        "R_POS",               /* name */                                 
+        true,                  /* partial_inplace */                      
+        0xffffffff,            /* src_mask */                             
+        0xffffffff,            /* dst_mask */                             
+        false);                /* pcrel_offset */
+
+/* Get the dynamic relocs.  */
+
+long
+_bfd_xcoff_canonicalize_dynamic_reloc (abfd, prelocs, syms)
+     bfd *abfd;
+     arelent **prelocs;
+     asymbol **syms;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+  arelent *relbuf;
+  struct external_ldrel *elrel, *elrelend;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  relbuf = (arelent *) bfd_alloc (abfd, ldhdr.l_nreloc * sizeof (arelent));
+  if (relbuf == NULL)
+    return -1;
+
+  elrel = ((struct external_ldrel *)
+          (contents + LDHDRSZ + ldhdr.l_nsyms * LDSYMSZ));
+  elrelend = elrel + ldhdr.l_nreloc;
+  for (; elrel < elrelend; elrel++, relbuf++, prelocs++)
+    {
+      struct internal_ldrel ldrel;
+
+      xcoff_swap_ldrel_in (abfd, elrel, &ldrel);
+
+      if (ldrel.l_symndx >= 3)
+       relbuf->sym_ptr_ptr = syms + (ldrel.l_symndx - 3);
+      else
+       {
+         const char *name;
+         asection *sec;
+
+         switch (ldrel.l_symndx)
+           {
+           case 0:
+             name = ".text";
+             break;
+           case 1:
+             name = ".data";
+             break;
+           case 2:
+             name = ".bss";
+             break;
+           default:
+             abort ();
+             break;
+           }
+
+         sec = bfd_get_section_by_name (abfd, name);
+         if (sec == NULL)
+           {
+             bfd_set_error (bfd_error_bad_value);
+             return -1;
+           }
+
+         relbuf->sym_ptr_ptr = sec->symbol_ptr_ptr;
+       }
+
+      relbuf->address = ldrel.l_vaddr;
+      relbuf->addend = 0;
+
+      /* Most dynamic relocs have the same type.  FIXME: This is only
+         correct if ldrel.l_rtype == 0.  In other cases, we should use
+         a different howto.  */
+      relbuf->howto = &xcoff_dynamic_reloc;
+
+      /* FIXME: We have no way to record the l_rsecnm field.  */
+
+      *prelocs = relbuf;
+    }
+
+  *prelocs = NULL;
+
+  return ldhdr.l_nreloc;
+}
+\f
 /* Routine to create an entry in an XCOFF link hash table.  */
 
 static struct bfd_hash_entry *
@@ -529,10 +919,7 @@ xcoff_link_hash_newfunc (entry, table, string)
     ret = ((struct xcoff_link_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct xcoff_link_hash_entry)));
   if (ret == (struct xcoff_link_hash_entry *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return (struct bfd_hash_entry *) ret;
-    }
+    return (struct bfd_hash_entry *) ret;
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct xcoff_link_hash_entry *)
@@ -565,10 +952,7 @@ _bfd_xcoff_bfd_link_hash_table_create (abfd)
   ret = ((struct xcoff_link_hash_table *)
         bfd_alloc (abfd, sizeof (struct xcoff_link_hash_table)));
   if (ret == (struct xcoff_link_hash_table *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return (struct bfd_link_hash_table *) NULL;
-    }
+    return (struct bfd_link_hash_table *) NULL;
   if (! _bfd_link_hash_table_init (&ret->root, abfd, xcoff_link_hash_newfunc))
     {
       bfd_release (abfd, ret);
@@ -582,10 +966,12 @@ _bfd_xcoff_bfd_link_hash_table_create (abfd)
   memset (&ret->ldhdr, 0, sizeof (struct internal_ldhdr));
   ret->linkage_section = NULL;
   ret->toc_section = NULL;
+  ret->descriptor_section = NULL;
   ret->imports = NULL;
   ret->file_align = 0;
   ret->textro = false;
   ret->gc = false;
+  memset (ret->special_sections, 0, sizeof ret->special_sections);
 
   /* The linker will always generate a full a.out header.  We need to
      record that fact now, before the sizeof_headers routine could be
@@ -683,9 +1069,45 @@ _bfd_xcoff_bfd_link_add_symbols (abfd, info)
     {
     case bfd_object:
       return xcoff_link_add_object_symbols (abfd, info);
+
     case bfd_archive:
-      return (_bfd_generic_link_add_archive_symbols
-             (abfd, info, xcoff_link_check_archive_element));
+      /* If the archive has a map, do the usual search.  We then need
+         to check the archive for stripped dynamic objects, because
+         they will not appear in the archive map even though they
+         should, perhaps, be included.  If the archive has no map, we
+         just consider each object file in turn, since that apparently
+         is what the AIX native linker does.  */
+      if (bfd_has_map (abfd))
+       {
+         if (! (_bfd_generic_link_add_archive_symbols
+                (abfd, info, xcoff_link_check_archive_element)))
+           return false;
+       }
+
+      {
+       bfd *member;
+
+       member = bfd_openr_next_archived_file (abfd, (bfd *) NULL);
+       while (member != NULL)
+         {
+           if (bfd_check_format (member, bfd_object)
+               && (! bfd_has_map (abfd)
+                   || ((member->flags & DYNAMIC) != 0
+                       && (member->flags & HAS_SYMS) == 0)))
+             {
+               boolean needed;
+
+               if (! xcoff_link_check_archive_element (member, info, &needed))
+                 return false;
+               if (needed)
+                 member->archive_pass = -1;
+             }
+           member = bfd_openr_next_archived_file (abfd, member);
+         }
+      }
+
+      return true;
+
     default:
       bfd_set_error (bfd_error_wrong_format);
       return false;
@@ -758,6 +1180,11 @@ xcoff_link_check_ar_symbols (abfd, info, pneeded)
 
   *pneeded = false;
 
+  if ((abfd->flags & DYNAMIC) != 0
+      && ! info->static_link
+      && info->hash->creator == abfd->xvec)
+    return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded);
+
   symesz = bfd_coff_symesz (abfd);
   esym = (bfd_byte *) obj_coff_external_syms (abfd);
   esym_end = esym + obj_raw_syment_count (abfd) * symesz;
@@ -787,7 +1214,10 @@ xcoff_link_check_ar_symbols (abfd, info, pneeded)
             defines it.  We also don't bring in symbols to satisfy
             undefined references in shared objects.  */
          if (h != (struct bfd_link_hash_entry *) NULL
-             && h->type == bfd_link_hash_undefined)
+             && h->type == bfd_link_hash_undefined
+             && (info->hash->creator != abfd->xvec
+                 || (((struct xcoff_link_hash_entry *) h)->flags
+                     & XCOFF_DEF_DYNAMIC) == 0))
            {
              if (! (*info->callbacks->add_archive_element) (info, abfd, name))
                return false;
@@ -803,6 +1233,91 @@ xcoff_link_check_ar_symbols (abfd, info, pneeded)
   return true;
 }
 
+/* Look through the loader symbols to see if this dynamic object
+   should be included in the link.  The native linker uses the loader
+   symbols, not the normal symbol table, so we do too.  */
+
+static boolean
+xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     boolean *pneeded;
+{
+  asection *lsec;
+  bfd_byte *buf;
+  struct internal_ldhdr ldhdr;
+  const char *strings;
+  struct external_ldsym *elsym, *elsymend;
+
+  *pneeded = false;
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      /* There are no symbols, so don't try to include it.  */
+      return true;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return false;
+  buf = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) buf, &ldhdr);
+
+  strings = (char *) buf + ldhdr.l_stoff;
+
+  elsym = (struct external_ldsym *) (buf + LDHDRSZ);
+  elsymend = elsym + ldhdr.l_nsyms;
+  for (; elsym < elsymend; elsym++)
+    {
+      struct internal_ldsym ldsym;
+      char nambuf[SYMNMLEN + 1];
+      const char *name;
+      struct bfd_link_hash_entry *h;
+
+      xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
+
+      /* We are only interested in exported symbols.  */
+      if ((ldsym.l_smtype & L_EXPORT) == 0)
+       continue;
+
+      if (ldsym._l._l_l._l_zeroes == 0)
+       name = strings + ldsym._l._l_l._l_offset;
+      else
+       {
+         memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
+         nambuf[SYMNMLEN] = '\0';
+         name = nambuf;
+       }
+
+      h = bfd_link_hash_lookup (info->hash, name, false, false, true);
+
+      /* We are only interested in symbols that are currently
+         undefined.  At this point we know that we are using an XCOFF
+         hash table.  */
+      if (h != NULL
+         && h->type == bfd_link_hash_undefined
+         && (((struct xcoff_link_hash_entry *) h)->flags
+             & XCOFF_DEF_DYNAMIC) == 0)
+       {
+         if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+           return false;
+         *pneeded = true;
+         return true;
+       }
+    }
+
+  /* We do not need this shared object.  */
+
+  if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
+    {
+      free (coff_section_data (abfd, lsec)->contents);
+      coff_section_data (abfd, lsec)->contents = NULL;
+    }
+
+  return true;
+}
+
 /* Returns the index of reloc in RELOCS with the least address greater
    than or equal to ADDRESS.  The relocs are sorted by address.  */
 
@@ -815,7 +1330,12 @@ xcoff_find_reloc (relocs, count, address)
   bfd_size_type min, max, this;
 
   if (count < 2)
-    return 0;
+    {
+      if (count == 1 && relocs[0].r_vaddr < address)
+       return 1;
+      else
+       return 0;
+    }
 
   min = 0;
   max = count;
@@ -878,7 +1398,8 @@ xcoff_link_add_symbols (abfd, info)
   struct xcoff_link_hash_entry **sym_hash;
   asection **csect_cache;
   bfd_size_type linesz;
-  asection *sub;
+  asection *o;
+  asection *last_real;
   boolean keep_syms;
   asection *csect;
   unsigned int csect_index;
@@ -893,63 +1414,93 @@ xcoff_link_add_symbols (abfd, info)
       bfd_byte *linenos;
     } *reloc_info = NULL;
 
+  keep_syms = obj_coff_keep_syms (abfd);
+
   if ((abfd->flags & DYNAMIC) != 0
       && ! info->static_link)
-    return xcoff_link_add_dynamic_symbols (abfd, info);
+    {
+      if (! xcoff_link_add_dynamic_symbols (abfd, info))
+       return false;
+    }
 
-  n_tmask = coff_data (abfd)->local_n_tmask;
-  n_btshft = coff_data (abfd)->local_n_btshft;
+  if (info->hash->creator == abfd->xvec)
+    {
+      /* We need to build a .loader section, so we do it here.  This
+        won't work if we're producing an XCOFF output file with no
+        XCOFF input files.  FIXME.  */
+      if (xcoff_hash_table (info)->loader_section == NULL)
+       {
+         asection *lsec;
 
-  /* Define macros so that ISFCN, et. al., macros work correctly.  */
-#define N_TMASK n_tmask
-#define N_BTSHFT n_btshft
+         lsec = bfd_make_section_anyway (abfd, ".loader");
+         if (lsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->loader_section = lsec;
+         lsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+       }
+      /* Likewise for the linkage section.  */
+      if (xcoff_hash_table (info)->linkage_section == NULL)
+       {
+         asection *lsec;
 
-  /* We need to build a .loader section, so we do it here.  This won't
-     work if we're producing an XCOFF output file with no non dynamic
-     XCOFF input files.  FIXME.  */
-  if (xcoff_hash_table (info)->loader_section == NULL)
-    {
-      asection *lsec;
+         lsec = bfd_make_section_anyway (abfd, ".gl");
+         if (lsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->linkage_section = lsec;
+         lsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                         | SEC_IN_MEMORY);
+         lsec->alignment_power = 2;
+       }
+      /* Likewise for the TOC section.  */
+      if (xcoff_hash_table (info)->toc_section == NULL)
+       {
+         asection *tsec;
 
-      lsec = bfd_make_section_anyway (abfd, ".loader");
-      if (lsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->loader_section = lsec;
-      lsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
-    }
-  /* Likewise for the linkage section.  */
-  if (xcoff_hash_table (info)->linkage_section == NULL)
-    {
-      asection *lsec;
+         tsec = bfd_make_section_anyway (abfd, ".tc");
+         if (tsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->toc_section = tsec;
+         tsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                         | SEC_IN_MEMORY);
+         tsec->alignment_power = 2;
+       }
+      /* Likewise for the descriptor section.  */
+      if (xcoff_hash_table (info)->descriptor_section == NULL)
+       {
+         asection *dsec;
 
-      lsec = bfd_make_section_anyway (abfd, ".gl");
-      if (lsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->linkage_section = lsec;
-      lsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
-    }
-  /* Likewise for the TOC section.  */
-  if (xcoff_hash_table (info)->toc_section == NULL)
-    {
-      asection *tsec;
+         dsec = bfd_make_section_anyway (abfd, ".ds");
+         if (dsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->descriptor_section = dsec;
+         dsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                         | SEC_IN_MEMORY);
+         dsec->alignment_power = 2;
+       }
+      /* Likewise for the .debug section.  */
+      if (xcoff_hash_table (info)->debug_section == NULL
+         && info->strip != strip_all)
+       {
+         asection *dsec;
 
-      tsec = bfd_make_section_anyway (abfd, ".tc");
-      if (tsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->toc_section = tsec;
-      tsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+         dsec = bfd_make_section_anyway (abfd, ".debug");
+         if (dsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->debug_section = dsec;
+         dsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+       }
     }
-  /* Likewise for the .debug section.  */
-  if (xcoff_hash_table (info)->debug_section == NULL)
-    {
-      asection *dsec;
 
-      dsec = bfd_make_section_anyway (abfd, ".debug");
-      if (dsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->debug_section = dsec;
-      dsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
-    }
+  if ((abfd->flags & DYNAMIC) != 0
+      && ! info->static_link)
+    return true;
+
+  n_tmask = coff_data (abfd)->local_n_tmask;
+  n_btshft = coff_data (abfd)->local_n_btshft;
+
+  /* Define macros so that ISFCN, et. al., macros work correctly.  */
+#define N_TMASK n_tmask
+#define N_BTSHFT n_btshft
 
   if (info->keep_memory)
     default_copy = false;
@@ -965,10 +1516,7 @@ xcoff_link_add_symbols (abfd, info)
                         (symcount
                          * sizeof (struct xcoff_link_hash_entry *))));
   if (sym_hash == NULL && symcount != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
   coff_data (abfd)->sym_hashes = (struct coff_link_hash_entry **) sym_hash;
   memset (sym_hash, 0,
          (size_t) symcount * sizeof (struct xcoff_link_hash_entry *));
@@ -979,10 +1527,7 @@ xcoff_link_add_symbols (abfd, info)
   csect_cache = ((asection **)
                 bfd_alloc (abfd, symcount * sizeof (asection *)));
   if (csect_cache == NULL && symcount != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
   xcoff_data (abfd)->csects = csect_cache;
   memset (csect_cache, 0, (size_t) symcount * sizeof (asection *));
 
@@ -992,57 +1537,49 @@ xcoff_link_add_symbols (abfd, info)
      scanning along the relocs as we process the csects.  We index
      into reloc_info using the section target_index.  */
   reloc_info = ((struct reloc_info_struct *)
-               malloc ((abfd->section_count + 1)
-                       * sizeof (struct reloc_info_struct)));
+               bfd_malloc ((abfd->section_count + 1)
+                           * sizeof (struct reloc_info_struct)));
   if (reloc_info == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
   memset ((PTR) reloc_info, 0,
          (abfd->section_count + 1) * sizeof (struct reloc_info_struct));
 
   /* Read in the relocs and line numbers for each section.  */
   linesz = bfd_coff_linesz (abfd);
-  for (sub = abfd->sections; sub != NULL; sub = sub->next)
+  last_real = NULL;
+  for (o = abfd->sections; o != NULL; o = o->next)
     {
-      if ((sub->flags & SEC_RELOC) != 0)
+      last_real = o;
+      if ((o->flags & SEC_RELOC) != 0)
        {
-         reloc_info[sub->target_index].relocs =
-           xcoff_read_internal_relocs (abfd, sub, true, (bfd_byte *) NULL,
+         reloc_info[o->target_index].relocs =
+           xcoff_read_internal_relocs (abfd, o, true, (bfd_byte *) NULL,
                                        false, (struct internal_reloc *) NULL);
-         reloc_info[sub->target_index].csects =
-           (asection **) malloc (sub->reloc_count * sizeof (asection *));
-         if (reloc_info[sub->target_index].csects == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             goto error_return;
-           }
-         memset (reloc_info[sub->target_index].csects, 0,
-                 sub->reloc_count * sizeof (asection *));
+         reloc_info[o->target_index].csects =
+           (asection **) bfd_malloc (o->reloc_count * sizeof (asection *));
+         if (reloc_info[o->target_index].csects == NULL)
+           goto error_return;
+         memset (reloc_info[o->target_index].csects, 0,
+                 o->reloc_count * sizeof (asection *));
        }
 
       if ((info->strip == strip_none || info->strip == strip_some)
-         && sub->lineno_count > 0)
+         && o->lineno_count > 0)
        {
          bfd_byte *linenos;
 
-         linenos = (bfd_byte *) malloc (sub->lineno_count * linesz);
+         linenos = (bfd_byte *) bfd_malloc (o->lineno_count * linesz);
          if (linenos == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             goto error_return;
-           }
-         reloc_info[sub->target_index].linenos = linenos;
-         if (bfd_seek (abfd, sub->line_filepos, SEEK_SET) != 0
-             || (bfd_read (linenos, linesz, sub->lineno_count, abfd)
-                 != linesz * sub->lineno_count))
+           goto error_return;
+         reloc_info[o->target_index].linenos = linenos;
+         if (bfd_seek (abfd, o->line_filepos, SEEK_SET) != 0
+             || (bfd_read (linenos, linesz, o->lineno_count, abfd)
+                 != linesz * o->lineno_count))
            goto error_return;
        }
     }
 
   /* Don't let the linker relocation routines discard the symbols.  */
-  keep_syms = obj_coff_keep_syms (abfd);
   obj_coff_keep_syms (abfd) = true;
 
   csect = NULL;
@@ -1121,7 +1658,7 @@ xcoff_link_add_symbols (abfd, info)
              if (enclosing == NULL)
                {
                  (*_bfd_error_handler)
-                   ("%s: `%s' has line numbers but no enclosing section",
+                   (_("%s: `%s' has line numbers but no enclosing section"),
                     bfd_get_filename (abfd), name);
                  bfd_set_error (bfd_error_bad_value);
                  goto error_return;
@@ -1173,7 +1710,7 @@ xcoff_link_add_symbols (abfd, info)
       if (sym.n_numaux == 0)
        {
          (*_bfd_error_handler)
-           ("%s: class %d symbol `%s' has no aux entries",
+           (_("%s: class %d symbol `%s' has no aux entries"),
             bfd_get_filename (abfd), sym.n_sclass, name);
          bfd_set_error (bfd_error_bad_value);
          goto error_return;
@@ -1196,7 +1733,7 @@ xcoff_link_add_symbols (abfd, info)
        {
        default:
          (*_bfd_error_handler)
-           ("%s: symbol `%s' has unrecognized csect type %d",
+           (_("%s: symbol `%s' has unrecognized csect type %d"),
             bfd_get_filename (abfd), name, smtyp);
          bfd_set_error (bfd_error_bad_value);
          goto error_return;
@@ -1208,13 +1745,22 @@ xcoff_link_add_symbols (abfd, info)
              || aux.x_csect.x_scnlen.l != 0)
            {
              (*_bfd_error_handler)
-               ("%s: bad XTY_ER symbol `%s': class %d scnum %d scnlen %d",
+               (_("%s: bad XTY_ER symbol `%s': class %d scnum %d scnlen %d"),
                 bfd_get_filename (abfd), name, sym.n_sclass, sym.n_scnum,
                 aux.x_csect.x_scnlen.l);
              bfd_set_error (bfd_error_bad_value);
              goto error_return;
            }
-         section = bfd_und_section_ptr;
+
+         /* An XMC_XO external reference is actually a reference to
+             an absolute location.  */
+         if (aux.x_csect.x_smclas != XMC_XO)
+           section = bfd_und_section_ptr;
+         else
+           {
+             section = bfd_abs_section_ptr;
+             value = sym.n_value;
+           }
          break;
 
        case XTY_SD:
@@ -1238,7 +1784,7 @@ xcoff_link_add_symbols (abfd, info)
                  || aux.x_csect.x_scnlen.l != 0)
                {
                  (*_bfd_error_handler)
-                   ("%s: XMC_TC0 symbol `%s' is class %d scnlen %d",
+                   (_("%s: XMC_TC0 symbol `%s' is class %d scnlen %d"),
                     bfd_get_filename (abfd), name, sym.n_sclass,
                     aux.x_csect.x_scnlen.l);
                  bfd_set_error (bfd_error_bad_value);
@@ -1362,7 +1908,7 @@ xcoff_link_add_symbols (abfd, info)
                || csect_name_by_class[aux.x_csect.x_smclas] == NULL)
              {
                (*_bfd_error_handler)
-                 ("%s: symbol `%s' has unrecognized smclas %d",
+                 (_("%s: symbol `%s' has unrecognized smclas %d"),
                   bfd_get_filename (abfd), name, aux.x_csect.x_smclas);
                bfd_set_error (bfd_error_bad_value);
                goto error_return;
@@ -1381,7 +1927,7 @@ xcoff_link_add_symbols (abfd, info)
                        > enclosing->vma + enclosing->_raw_size)))
              {
                (*_bfd_error_handler)
-                 ("%s: csect `%s' not in enclosing section",
+                 (_("%s: csect `%s' not in enclosing section"),
                   bfd_get_filename (abfd), name);
                bfd_set_error (bfd_error_bad_value);
                goto error_return;
@@ -1397,20 +1943,13 @@ xcoff_link_add_symbols (abfd, info)
            /* Record the enclosing section in the tdata for this new
               section.  */
            csect->used_by_bfd =
-             ((struct coff_section_tdata *)
-              bfd_zalloc (abfd, sizeof (struct coff_section_tdata)));
+             (PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata));
            if (csect->used_by_bfd == NULL)
-             {
-               bfd_set_error (bfd_error_no_memory);
-               goto error_return;
-             }
+             goto error_return;
            coff_section_data (abfd, csect)->tdata =
              bfd_zalloc (abfd, sizeof (struct xcoff_section_tdata));
            if (coff_section_data (abfd, csect)->tdata == NULL)
-             {
-               bfd_set_error (bfd_error_no_memory);
-               goto error_return;
-             }
+             goto error_return;
            xcoff_section_data (abfd, csect)->enclosing = enclosing;
            xcoff_section_data (abfd, csect)->lineno_count =
              enclosing->lineno_count;
@@ -1492,7 +2031,7 @@ xcoff_link_add_symbols (abfd, info)
            if (bad)
              {
                (*_bfd_error_handler)
-                 ("%s: misplaced XTY_LD `%s'",
+                 (_("%s: misplaced XTY_LD `%s'"),
                   bfd_get_filename (abfd), name);
                bfd_set_error (bfd_error_bad_value);
                goto error_return;
@@ -1504,8 +2043,11 @@ xcoff_link_add_symbols (abfd, info)
 
        case XTY_CM:
          /* This is an unitialized csect.  We could base the name on
-             the storage mapping class, but we don't bother.  If this
-             csect is externally visible, it is a common symbol.  */
+             the storage mapping class, but we don't bother except for
+             an XMC_TD symbol.  If this csect is externally visible,
+             it is a common symbol.  We put XMC_TD symbols in sections
+             named .tocbss, and rely on the linker script to put that
+             in the TOC area.  */
 
          if (csect != NULL)
            {
@@ -1515,7 +2057,10 @@ xcoff_link_add_symbols (abfd, info)
                 / symesz);
            }
 
-         csect = bfd_make_section_anyway (abfd, ".bss");
+         if (aux.x_csect.x_smclas == XMC_TD)
+           csect = bfd_make_section_anyway (abfd, ".tocbss");
+         else
+           csect = bfd_make_section_anyway (abfd, ".bss");
          if (csect == NULL)
            goto error_return;
          csect->vma = sym.n_value;
@@ -1530,20 +2075,13 @@ xcoff_link_add_symbols (abfd, info)
                         / symesz);
 
          csect->used_by_bfd =
-           ((struct coff_section_tdata *)
-            bfd_zalloc (abfd, sizeof (struct coff_section_tdata)));
+           (PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata));
          if (csect->used_by_bfd == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             goto error_return;
-           }
+           goto error_return;
          coff_section_data (abfd, csect)->tdata =
            bfd_zalloc (abfd, sizeof (struct xcoff_section_tdata));
          if (coff_section_data (abfd, csect)->tdata == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             goto error_return;
-           }
+           goto error_return;
          xcoff_section_data (abfd, csect)->first_symndx = csect_index;
 
          if (first_csect == NULL)
@@ -1560,6 +2098,34 @@ xcoff_link_add_symbols (abfd, info)
          break;
        }
 
+      /* Check for magic symbol names.  */
+      if ((smtyp == XTY_SD || smtyp == XTY_CM)
+         && aux.x_csect.x_smclas != XMC_TC
+         && aux.x_csect.x_smclas != XMC_TD)
+       {
+         int i;
+
+         i = -1;
+         if (name[0] == '_')
+           {
+             if (strcmp (name, "_text") == 0)
+               i = 0;
+             else if (strcmp (name, "_etext") == 0)
+               i = 1;
+             else if (strcmp (name, "_data") == 0)
+               i = 2;
+             else if (strcmp (name, "_edata") == 0)
+               i = 3;
+             else if (strcmp (name, "_end") == 0)
+               i = 4;
+           }
+         else if (name[0] == 'e' && strcmp (name, "end") == 0)
+           i = 5;
+
+         if (i != -1)
+           xcoff_hash_table (info)->special_sections[i] = csect;
+       }
+
       /* Now we have enough information to add the symbol to the
          linker hash table.  */
 
@@ -1576,14 +2142,40 @@ xcoff_link_add_symbols (abfd, info)
              || sym._n._n_n._n_offset == 0)
            copy = true;
 
+         /* The AIX linker appears to only detect multiple symbol
+            definitions when there is a reference to the symbol.  If
+            a symbol is defined multiple times, and the only
+            references are from the same object file, the AIX linker
+            appears to permit it.  It does not merge the different
+            definitions, but handles them independently.  On the
+            other hand, if there is a reference, the linker reports
+            an error.
+
+            This matters because the AIX <net/net_globals.h> header
+            file actually defines an initialized array, so we have to
+            actually permit that to work.
+
+            Just to make matters even more confusing, the AIX linker
+            appears to permit multiple symbol definitions whenever
+            the second definition is in an archive rather than an
+            object file.  This may be a consequence of the manner in
+            which it handles archives: I think it may load the entire
+            archive in as separate csects, and then let garbage
+            collection discard symbols.
+
+            We also have to handle the case of statically linking a
+            shared object, which will cause symbol redefinitions,
+            although this is an easier case to detect.  */
+
          if (info->hash->creator == abfd->xvec)
            {
-             /* If we are statically linking a shared object, it is
-                 OK for symbol redefinitions to occur.  I can't figure
-                 out just what the XCOFF linker is doing, but
-                 something like this is required for -bnso to work.  */
-             *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
-                                                 name, true, copy, false);
+             if (! bfd_is_und_section (section))
+               *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
+                                                   name, true, copy, false);
+             else
+               *sym_hash = ((struct xcoff_link_hash_entry *)
+                            bfd_wrapped_link_hash_lookup (abfd, info, name,
+                                                          true, copy, false));
              if (*sym_hash == NULL)
                goto error_return;
              if (((*sym_hash)->root.type == bfd_link_hash_defined
@@ -1591,26 +2183,100 @@ xcoff_link_add_symbols (abfd, info)
                  && ! bfd_is_und_section (section)
                  && ! bfd_is_com_section (section))
                {
-                 if ((abfd->flags & DYNAMIC) != 0)
+                 /* This is a second definition of a defined symbol.  */
+                 if ((abfd->flags & DYNAMIC) != 0
+                     && ((*sym_hash)->smclas != XMC_GL
+                         || aux.x_csect.x_smclas == XMC_GL
+                         || ((*sym_hash)->root.u.def.section->owner->flags
+                             & DYNAMIC) == 0))
                    {
+                     /* The new symbol is from a shared library, and
+                         either the existing symbol is not global
+                         linkage code or this symbol is global linkage
+                         code.  If the existing symbol is global
+                         linkage code and the new symbol is not, then
+                         we want to use the new symbol.  */
                      section = bfd_und_section_ptr;
                      value = 0;
                    }
                  else if (((*sym_hash)->root.u.def.section->owner->flags
                            & DYNAMIC) != 0)
                    {
+                     /* The existing symbol is from a shared library.
+                         Replace it.  */
                      (*sym_hash)->root.type = bfd_link_hash_undefined;
                      (*sym_hash)->root.u.undef.abfd =
                        (*sym_hash)->root.u.def.section->owner;
                    }
+                 else if (abfd->my_archive != NULL)
+                   {
+                     /* This is a redefinition in an object contained
+                         in an archive.  Just ignore it.  See the
+                         comment above.  */
+                     section = bfd_und_section_ptr;
+                     value = 0;
+                   }
+                 else if ((*sym_hash)->root.next != NULL
+                          || info->hash->undefs_tail == &(*sym_hash)->root)
+                   {
+                     /* This symbol has been referenced.  In this
+                         case, we just continue and permit the
+                         multiple definition error.  See the comment
+                         above about the behaviour of the AIX linker.  */
+                   }
+                 else if ((*sym_hash)->smclas == aux.x_csect.x_smclas)
+                   {
+                     /* The symbols are both csects of the same
+                         class.  There is at least a chance that this
+                         is a semi-legitimate redefinition.  */
+                     section = bfd_und_section_ptr;
+                     value = 0;
+                     (*sym_hash)->flags |= XCOFF_MULTIPLY_DEFINED;
+                   }
+               }
+             else if (((*sym_hash)->flags & XCOFF_MULTIPLY_DEFINED) != 0
+                      && ((*sym_hash)->root.type == bfd_link_hash_defined
+                          || (*sym_hash)->root.type == bfd_link_hash_defweak)
+                      && (bfd_is_und_section (section)
+                          || bfd_is_com_section (section)))
+               {
+                 /* This is a reference to a multiply defined symbol.
+                    Report the error now.  See the comment above
+                    about the behaviour of the AIX linker.  We could
+                    also do this with warning symbols, but I'm not
+                    sure the XCOFF linker is wholly prepared to
+                    handle them, and that would only be a warning,
+                    not an error.  */
+                 if (! ((*info->callbacks->multiple_definition)
+                        (info, (*sym_hash)->root.root.string,
+                         (bfd *) NULL, (asection *) NULL, 0,
+                         (*sym_hash)->root.u.def.section->owner,
+                         (*sym_hash)->root.u.def.section,
+                         (*sym_hash)->root.u.def.value)))
+                   goto error_return;
+                 /* Try not to give this error too many times.  */
+                 (*sym_hash)->flags &= ~XCOFF_MULTIPLY_DEFINED;
                }
            }
 
+         /* _bfd_generic_link_add_one_symbol may call the linker to
+            generate an error message, and the linker may try to read
+            the symbol table to give a good error.  Right now, the
+            line numbers are in an inconsistent state, since they are
+            counted both in the real sections and in the new csects.
+            We need to leave the count in the real sections so that
+            the linker can report the line number of the error
+            correctly, so temporarily clobber the link to the csects
+            so that the linker will not try to read the line numbers
+            a second time from the csects.  */
+         BFD_ASSERT (last_real->next == first_csect);
+         last_real->next = NULL;
          if (! (_bfd_generic_link_add_one_symbol
                 (info, abfd, name, flags, section, value,
                  (const char *) NULL, copy, true,
                  (struct bfd_link_hash_entry **) sym_hash)))
            goto error_return;
+         last_real->next = first_csect;
 
          if (smtyp == XTY_CM)
            {
@@ -1650,30 +2316,34 @@ xcoff_link_add_symbols (abfd, info)
       csect_cache += sym.n_numaux + 1;
     }
 
+  BFD_ASSERT (last_real == NULL || last_real->next == first_csect);
+
   /* Make sure that we have seen all the relocs.  */
-  for (sub = abfd->sections; sub != first_csect; sub = sub->next)
+  for (o = abfd->sections; o != first_csect; o = o->next)
     {
-      /* Reset the section size, since the data is now attached to the
-        csects.  Don't reset the size of the .debug section, since we
-        need to read it below in bfd_xcoff_size_dynamic_sections.  */
-      if (strcmp (bfd_get_section_name (abfd, sub), ".debug") != 0)
-       sub->_raw_size = 0;
+      /* Reset the section size and the line number count, since the
+        data is now attached to the csects.  Don't reset the size of
+        the .debug section, since we need to read it below in
+        bfd_xcoff_size_dynamic_sections.  */
+      if (strcmp (bfd_get_section_name (abfd, o), ".debug") != 0)
+       o->_raw_size = 0;
+      o->lineno_count = 0;
 
-      if ((sub->flags & SEC_RELOC) != 0)
+      if ((o->flags & SEC_RELOC) != 0)
        {
          bfd_size_type i;
          struct internal_reloc *rel;
          asection **rel_csect;
 
-         rel = reloc_info[sub->target_index].relocs;
-         rel_csect = reloc_info[sub->target_index].csects;
-         for (i = 0; i < sub->reloc_count; i++, rel++, rel_csect++)
+         rel = reloc_info[o->target_index].relocs;
+         rel_csect = reloc_info[o->target_index].csects;
+         for (i = 0; i < o->reloc_count; i++, rel++, rel_csect++)
            {
              if (*rel_csect == NULL)
                {
                  (*_bfd_error_handler)
-                   ("%s: reloc %s:%d not in csect",
-                    bfd_get_filename (abfd), sub->name, i);
+                   (_("%s: reloc %s:%d not in csect"),
+                    bfd_get_filename (abfd), o->name, i);
                  bfd_set_error (bfd_error_bad_value);
                  goto error_return;
                }
@@ -1717,41 +2387,43 @@ xcoff_link_add_symbols (abfd, info)
                                  (flagword) 0, bfd_und_section_ptr,
                                  (bfd_vma) 0, (const char *) NULL, false,
                                  true,
-                                 (struct bfd_link_hash_entry **) NULL)))
+                                 (struct bfd_link_hash_entry **) &hds)))
                            goto error_return;
                        }
+                     hds->flags |= XCOFF_DESCRIPTOR;
+                     BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0
+                                 && (h->flags & XCOFF_DESCRIPTOR) == 0);
+                     hds->descriptor = h;
                      h->descriptor = hds;
                    }
                }
            }
 
-         free (reloc_info[sub->target_index].csects);
-         reloc_info[sub->target_index].csects = NULL;
+         free (reloc_info[o->target_index].csects);
+         reloc_info[o->target_index].csects = NULL;
 
-         /* Reset SEC_RELOC, the reloc_count, and the lineno_count,
-            since the reloc and lineno information is now attached to
-            the csects.  */
-         sub->flags &=~ SEC_RELOC;
-         sub->reloc_count = 0;
-         sub->lineno_count = 0;
+         /* Reset SEC_RELOC and the reloc_count, since the reloc
+            information is now attached to the csects.  */
+         o->flags &=~ SEC_RELOC;
+         o->reloc_count = 0;
 
          /* If we are not keeping memory, free the reloc information.  */
          if (! info->keep_memory
-             && coff_section_data (abfd, sub) != NULL
-             && coff_section_data (abfd, sub)->relocs != NULL
-             && ! coff_section_data (abfd, sub)->keep_relocs)
+             && coff_section_data (abfd, o) != NULL
+             && coff_section_data (abfd, o)->relocs != NULL
+             && ! coff_section_data (abfd, o)->keep_relocs)
            {
-             free (coff_section_data (abfd, sub)->relocs);
-             coff_section_data (abfd, sub)->relocs = NULL;
+             free (coff_section_data (abfd, o)->relocs);
+             coff_section_data (abfd, o)->relocs = NULL;
            }
        }
 
       /* Free up the line numbers.  FIXME: We could cache these
          somewhere for the final link, to avoid reading them again.  */
-      if (reloc_info[sub->target_index].linenos != NULL)
+      if (reloc_info[o->target_index].linenos != NULL)
        {
-         free (reloc_info[sub->target_index].linenos);
-         reloc_info[sub->target_index].linenos = NULL;
+         free (reloc_info[o->target_index].linenos);
+         reloc_info[o->target_index].linenos = NULL;
        }
     }
 
@@ -1764,12 +2436,12 @@ xcoff_link_add_symbols (abfd, info)
  error_return:
   if (reloc_info != NULL)
     {
-      for (sub = abfd->sections; sub != NULL; sub = sub->next)
+      for (o = abfd->sections; o != NULL; o = o->next)
        {
-         if (reloc_info[sub->target_index].csects != NULL)
-           free (reloc_info[sub->target_index].csects);
-         if (reloc_info[sub->target_index].linenos != NULL)
-           free (reloc_info[sub->target_index].linenos);
+         if (reloc_info[o->target_index].csects != NULL)
+           free (reloc_info[o->target_index].csects);
+         if (reloc_info[o->target_index].linenos != NULL)
+           free (reloc_info[o->target_index].linenos);
        }
     free (reloc_info);
     }
@@ -1788,9 +2460,11 @@ xcoff_link_add_dynamic_symbols (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
-  bfd_size_type symesz;
-  bfd_byte *esym;
-  bfd_byte *esym_end;
+  asection *lsec;
+  bfd_byte *buf;
+  struct internal_ldhdr ldhdr;
+  const char *strings;
+  struct external_ldsym *elsym, *elsymend;
   struct xcoff_import_file *n;
   const char *bname;
   const char *mname;
@@ -1803,78 +2477,178 @@ xcoff_link_add_dynamic_symbols (abfd, info)
   if (info->hash->creator != abfd->xvec)
     {
       (*_bfd_error_handler)
-       ("%s: XCOFF shared object when not producing XCOFF output",
+       (_("%s: XCOFF shared object when not producing XCOFF output"),
         bfd_get_filename (abfd));
       bfd_set_error (bfd_error_invalid_operation);
       return false;
     }
 
+  /* The symbols we use from a dynamic object are not the symbols in
+     the normal symbol table, but, rather, the symbols in the export
+     table.  If there is a global symbol in a dynamic object which is
+     not in the export table, the loader will not be able to find it,
+     so we don't want to find it either.  Also, on AIX 4.1.3, shr.o in
+     libc.a has symbols in the export table which are not in the
+     symbol table.  */
+
+  /* Read in the .loader section.  FIXME: We should really use the
+     o_snloader field in the a.out header, rather than grabbing the
+     section by name.  */
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      (*_bfd_error_handler)
+       (_("%s: dynamic object with no .loader section"),
+        bfd_get_filename (abfd));
+      bfd_set_error (bfd_error_no_symbols);
+      return false;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return false;
+  buf = coff_section_data (abfd, lsec)->contents;
+
   /* Remove the sections from this object, so that they do not get
      included in the link.  */
   abfd->sections = NULL;
 
-  symesz = bfd_coff_symesz (abfd);
-  esym = (bfd_byte *) obj_coff_external_syms (abfd);
-  esym_end = esym + obj_raw_syment_count (abfd) * symesz;
-  while (esym < esym_end)
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) buf, &ldhdr);
+
+  strings = (char *) buf + ldhdr.l_stoff;
+
+  elsym = (struct external_ldsym *) (buf + LDHDRSZ);
+  elsymend = elsym + ldhdr.l_nsyms;
+  BFD_ASSERT (sizeof (struct external_ldsym) == LDSYMSZ);
+  for (; elsym < elsymend; elsym++)
     {
-      struct internal_syment sym;
+      struct internal_ldsym ldsym;
+      char nambuf[SYMNMLEN + 1];
+      const char *name;
+      struct xcoff_link_hash_entry *h;
 
-      bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
+      xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
 
-      /* I think that every symbol mentioned in a dynamic object must
-        be defined by that object, perhaps by importing it from
-        another dynamic object.  All we have to do is look up each
-        external symbol.  If we have already put it in the hash
-        table, we simply set a flag indicating that it appears in a
-        dynamic object.  */
+      /* We are only interested in exported symbols.  */
+      if ((ldsym.l_smtype & L_EXPORT) == 0)
+       continue;
 
-      if (sym.n_sclass == C_EXT)
+      if (ldsym._l._l_l._l_zeroes == 0)
+       name = strings + ldsym._l._l_l._l_offset;
+      else
        {
-         const char *name;
-         char buf[SYMNMLEN + 1];
-         struct xcoff_link_hash_entry *h;
+         memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
+         nambuf[SYMNMLEN] = '\0';
+         name = nambuf;
+       }
 
-         name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
-         if (name == NULL)
-           return false;
+      /* Normally we could not call xcoff_link_hash_lookup in an add
+        symbols routine, since we might not be using an XCOFF hash
+        table.  However, we verified above that we are using an XCOFF
+        hash table.  */
+
+      h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true,
+                                 true, true);
+      if (h == NULL)
+       return false;
+
+      h->flags |= XCOFF_DEF_DYNAMIC;
+
+      /* If the symbol is undefined, and the BFD it was found in is
+        not a dynamic object, change the BFD to this dynamic 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;
 
-         /* Normally we could not xcoff_link_hash_lookup in an add
-             symbols routine, since we might not be using an XCOFF
-             hash table.  However, we verified above that we are using
-             an XCOFF hash table.  */
-         h = xcoff_link_hash_lookup (xcoff_hash_table (info), name,
-                                     false, false, true);
-         if (h != NULL)
+      if (h->root.type == bfd_link_hash_new)
+       {
+         h->root.type = bfd_link_hash_undefined;
+         h->root.u.undef.abfd = abfd;
+         /* We do not want to add this to the undefined symbol list.  */
+       }
+
+      if (h->smclas == XMC_UA
+         || h->root.type == bfd_link_hash_undefined
+         || h->root.type == bfd_link_hash_undefweak)
+       h->smclas = ldsym.l_smclas;
+
+      /* Unless this is an XMC_XO symbol, we don't bother to actually
+         define it, since we don't have a section to put it in anyhow.
+         Instead, the relocation routines handle the DEF_DYNAMIC flag
+         correctly.  */
+
+      if (h->smclas == XMC_XO
+         && (h->root.type == bfd_link_hash_undefined
+             || h->root.type == bfd_link_hash_undefweak))
+       {
+         /* This symbol has an absolute value.  */
+         h->root.type = bfd_link_hash_defined;
+         h->root.u.def.section = bfd_abs_section_ptr;
+         h->root.u.def.value = ldsym.l_value;
+       }
+
+      /* If this symbol defines a function descriptor, then it
+        implicitly defines the function code as well.  */
+      if (h->smclas == XMC_DS
+         || (h->smclas == XMC_XO && name[0] != '.'))
+       h->flags |= XCOFF_DESCRIPTOR;
+      if ((h->flags & XCOFF_DESCRIPTOR) != 0)
+       {
+         struct xcoff_link_hash_entry *hds;
+
+         hds = h->descriptor;
+         if (hds == NULL)
            {
-             h->flags |= XCOFF_REF_DYNAMIC;
-
-             /* 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 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
-                 && sym.n_numaux > 0)
+             char *dsnm;
+
+             dsnm = bfd_malloc (strlen (name) + 2);
+             if (dsnm == NULL)
+               return false;
+             dsnm[0] = '.';
+             strcpy (dsnm + 1, name);
+             hds = xcoff_link_hash_lookup (xcoff_hash_table (info), dsnm,
+                                           true, true, true);
+             free (dsnm);
+             if (hds == NULL)
+               return false;
+
+             if (hds->root.type == bfd_link_hash_new)
                {
-                 union internal_auxent aux;
-
-                 bfd_coff_swap_aux_in (abfd,
-                                       (PTR) (esym + symesz * sym.n_numaux),
-                                       sym.n_type, sym.n_sclass,
-                                       sym.n_numaux - 1, sym.n_numaux,
-                                       (PTR) &aux);
-                 h->smclas = aux.x_csect.x_smclas;
+                 hds->root.type = bfd_link_hash_undefined;
+                 hds->root.u.undef.abfd = abfd;
+                 /* We do not want to add this to the undefined
+                     symbol list.  */
                }
+
+             hds->descriptor = h;
+             h->descriptor = hds;
+           }
+
+         hds->flags |= XCOFF_DEF_DYNAMIC;
+         if (hds->smclas == XMC_UA)
+           hds->smclas = XMC_PR;
+
+         /* An absolute symbol appears to actually define code, not a
+            function descriptor.  This is how some math functions are
+            implemented on AIX 4.1.  */
+         if (h->smclas == XMC_XO
+             && (hds->root.type == bfd_link_hash_undefined
+                 || hds->root.type == bfd_link_hash_undefweak))
+           {
+             hds->smclas = XMC_XO;
+             hds->root.type = bfd_link_hash_defined;
+             hds->root.u.def.section = bfd_abs_section_ptr;
+             hds->root.u.def.value = ldsym.l_value;
            }
        }
+    }
 
-      esym += (sym.n_numaux + 1) * symesz;
+  if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
+    {
+      free (coff_section_data (abfd, lsec)->contents);
+      coff_section_data (abfd, lsec)->contents = NULL;
     }
 
   /* Record this file in the import files.  */
@@ -1882,10 +2656,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
   n = ((struct xcoff_import_file *)
        bfd_alloc (abfd, sizeof (struct xcoff_import_file)));
   if (n == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
   n->next = NULL;
 
   /* For some reason, the path entry in the import file list for a
@@ -1942,7 +2713,8 @@ xcoff_mark_symbol (info, h)
       asection *hsec;
 
       hsec = h->root.u.def.section;
-      if ((hsec->flags & SEC_MARK) == 0)
+      if (! bfd_is_abs_section (hsec)
+         && (hsec->flags & SEC_MARK) == 0)
        {
          if (! xcoff_mark (info, hsec))
            return false;
@@ -1970,7 +2742,8 @@ xcoff_mark (info, sec)
      struct bfd_link_info *info;
      asection *sec;
 {
-  if ((sec->flags & SEC_MARK) != 0)
+  if (bfd_is_abs_section (sec)
+      || (sec->flags & SEC_MARK) != 0)
     return true;
 
   sec->flags |= SEC_MARK;
@@ -2047,11 +2820,14 @@ xcoff_mark (info, sec)
                      || h->root.type == bfd_link_hash_defweak
                      || h->root.type == bfd_link_hash_common
                      || ((h->flags & XCOFF_CALLED) != 0
-                         && (h->flags & XCOFF_DEF_REGULAR) == 0
-                         && (h->flags & XCOFF_REF_DYNAMIC) != 0
                          && (h->root.type == bfd_link_hash_undefined
                              || h->root.type == bfd_link_hash_undefweak)
-                         && h->root.root.string[0] == '.'))
+                         && h->root.root.string[0] == '.'
+                         && h->descriptor != NULL
+                         && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0
+                             || ((h->descriptor->flags & XCOFF_IMPORT) != 0
+                                 && (h->descriptor->flags
+                                     & XCOFF_DEF_REGULAR) == 0))))
                    break;
                  /* Fall through.  */
                case R_POS:
@@ -2112,6 +2888,7 @@ xcoff_sweep (info)
                  || o == xcoff_hash_table (info)->loader_section
                  || o == xcoff_hash_table (info)->linkage_section
                  || o == xcoff_hash_table (info)->toc_section
+                 || o == xcoff_hash_table (info)->descriptor_section
                  || strcmp (o->name, ".debug") == 0)
                o->flags |= SEC_MARK;
              else
@@ -2148,10 +2925,7 @@ bfd_xcoff_link_record_set (output_bfd, info, harg, size)
   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;
-    }
+    return false;
   n->next = xcoff_hash_table (info)->size_list;
   n->h = h;
   n->size = size;
@@ -2180,11 +2954,49 @@ bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile,
   if (! XCOFF_XVECP (output_bfd->xvec))
     return true;
 
+  /* A symbol name which starts with a period is the code for a
+     function.  If the symbol is undefined, then add an undefined
+     symbol for the function descriptor, and import that instead.  */
+  if (h->root.root.string[0] == '.'
+      && h->root.type == bfd_link_hash_undefined
+      && val == (bfd_vma) -1)
+    {
+      struct xcoff_link_hash_entry *hds;
+
+      hds = h->descriptor;
+      if (hds == NULL)
+       {
+         hds = xcoff_link_hash_lookup (xcoff_hash_table (info),
+                                       h->root.root.string + 1,
+                                       true, false, true);
+         if (hds == NULL)
+           return false;
+         if (hds->root.type == bfd_link_hash_new)
+           {
+             hds->root.type = bfd_link_hash_undefined;
+             hds->root.u.undef.abfd = h->root.u.undef.abfd;
+           }
+         hds->flags |= XCOFF_DESCRIPTOR;
+         BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0
+                     && (h->flags & XCOFF_DESCRIPTOR) == 0);
+         hds->descriptor = h;
+         h->descriptor = hds;
+       }
+
+      /* Now, if the descriptor is undefined, import the descriptor
+         rather than the symbol we were told to import.  FIXME: Is
+         this correct in all cases?  */
+      if (hds->root.type == bfd_link_hash_undefined)
+       h = hds;
+    }
+
   h->flags |= XCOFF_IMPORT;
 
   if (val != (bfd_vma) -1)
     {
-      if (h->root.type == bfd_link_hash_defined)
+      if (h->root.type == bfd_link_hash_defined
+         && (! bfd_is_abs_section (h->root.u.def.section)
+             || h->root.u.def.value != val))
        {
          if (! ((*info->callbacks->multiple_definition)
                 (info, h->root.root.string, h->root.u.def.section->owner,
@@ -2198,19 +3010,12 @@ bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile,
       h->root.u.def.value = val;
     }
 
-  if (h->ldsym == NULL)
-    {
-      h->ldsym = ((struct internal_ldsym *)
-                 bfd_zalloc (output_bfd, sizeof (struct internal_ldsym)));
-      if (h->ldsym == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
-    }
-
+  /* We overload the ldindx field to hold the l_ifile value for this
+     symbol.  */
+  BFD_ASSERT (h->ldsym == NULL);
+  BFD_ASSERT ((h->flags & XCOFF_BUILT_LDSYM) == 0);
   if (imppath == NULL)
-    h->ldsym->l_ifile = (bfd_size_type) -1;
+    h->ldindx = -1;
   else
     {
       unsigned int c;
@@ -2235,10 +3040,7 @@ bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile,
          n = ((struct xcoff_import_file *)
               bfd_alloc (output_bfd, sizeof (struct xcoff_import_file)));
          if (n == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             return false;
-           }
+           return false;
          n->next = NULL;
          n->path = imppath;
          n->file = impfile;
@@ -2246,7 +3048,7 @@ bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile,
          *pp = n;
        }
 
-      h->ldsym->l_ifile = c;
+      h->ldindx = c;
     }
 
   return true;
@@ -2259,7 +3061,7 @@ bfd_xcoff_export_symbol (output_bfd, info, harg, syscall)
      bfd *output_bfd;
      struct bfd_link_info *info;
      struct bfd_link_hash_entry *harg;
-     boolean syscall;
+     boolean syscall ATTRIBUTE_UNUSED;
 {
   struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg;
 
@@ -2271,10 +3073,48 @@ bfd_xcoff_export_symbol (output_bfd, info, harg, syscall)
   /* FIXME: I'm not at all sure what syscall is supposed to mean, so
      I'm just going to ignore it until somebody explains it.  */
 
+  /* See if this is a function descriptor.  It may be one even though
+     it is not so marked.  */
+  if ((h->flags & XCOFF_DESCRIPTOR) == 0
+      && h->root.root.string[0] != '.')
+    {
+      char *fnname;
+      struct xcoff_link_hash_entry *hfn;
+
+      fnname = (char *) bfd_malloc (strlen (h->root.root.string) + 2);
+      if (fnname == NULL)
+       return false;
+      fnname[0] = '.';
+      strcpy (fnname + 1, h->root.root.string);
+      hfn = xcoff_link_hash_lookup (xcoff_hash_table (info),
+                                   fnname, false, false, true);
+      free (fnname);
+      if (hfn != NULL
+         && hfn->smclas == XMC_PR
+         && (hfn->root.type == bfd_link_hash_defined
+             || hfn->root.type == bfd_link_hash_defweak))
+       {
+         h->flags |= XCOFF_DESCRIPTOR;
+         h->descriptor = hfn;
+         hfn->descriptor = h;
+       }
+    }
+
   /* Make sure we don't garbage collect this symbol.  */
   if (! xcoff_mark_symbol (info, h))
     return false;
 
+  /* If this is a function descriptor, make sure we don't garbage
+     collect the associated function code.  We normally don't have to
+     worry about this, because the descriptor will be attached to a
+     section with relocs, but if we are creating the descriptor
+     ourselves those relocs will not be visible to the mark code.  */
+  if ((h->flags & XCOFF_DESCRIPTOR) != 0)
+    {
+      if (! xcoff_mark_symbol (info, h->descriptor))
+       return false;
+    }
+
   return true;
 }
 
@@ -2293,11 +3133,12 @@ bfd_xcoff_link_count_reloc (output_bfd, info, name)
   if (! XCOFF_XVECP (output_bfd->xvec))
     return true;
 
-  h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, false, false,
-                             false);
+  h = ((struct xcoff_link_hash_entry *)
+       bfd_wrapped_link_hash_lookup (output_bfd, info, name, false, false,
+                                    false));
   if (h == NULL)
     {
-      (*_bfd_error_handler) ("%s: no such symbol", name);
+      (*_bfd_error_handler) (_("%s: no such symbol"), name);
       bfd_set_error (bfd_error_no_symbols);
       return false;
     }
@@ -2347,6 +3188,8 @@ struct xcoff_loader_info
   bfd *output_bfd;
   /* Link information structure.  */
   struct bfd_link_info *info;
+  /* Whether all defined symbols should be exported.  */
+  boolean export_defineds;
   /* Number of ldsym structures.  */
   size_t ldsym_count;
   /* Size of string table.  */
@@ -2362,12 +3205,23 @@ struct xcoff_loader_info
    .loader section before the linker lays out the output file.
    LIBPATH is the library path to search for shared objects; this is
    normally built from the -L arguments passed to the linker.  ENTRY
-   is the name of the entry point symbol.  */
+   is the name of the entry point symbol (the -e linker option).
+   FILE_ALIGN is the alignment to use for sections within the file
+   (the -H linker option).  MAXSTACK is the maximum stack size (the
+   -bmaxstack linker option).  MAXDATA is the maximum data size (the
+   -bmaxdata linker option).  GC is whether to do garbage collection
+   (the -bgc linker option).  MODTYPE is the module type (the
+   -bmodtype linker option).  TEXTRO is whether the text section must
+   be read only (the -btextro linker option).  EXPORT_DEFINEDS is
+   whether all defined symbols should be exported (the -unix linker
+   option).  SPECIAL_SECTIONS is set by this routine to csects with
+   magic names like _end.  */
 
 boolean
 bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
                                 file_align, maxstack, maxdata, gc,
-                                modtype, textro)
+                                modtype, textro, export_defineds,
+                                special_sections)
      bfd *output_bfd;
      struct bfd_link_info *info;
      const char *libpath;
@@ -2378,10 +3232,13 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
      boolean gc;
      int modtype;
      boolean textro;
+     boolean export_defineds;
+     asection **special_sections;
 {
   struct xcoff_link_hash_entry *hentry;
   asection *lsec;
   struct xcoff_loader_info ldinfo;
+  int i;
   size_t impsize, impcount;
   struct xcoff_import_file *fl;
   struct internal_ldhdr *ldhdr;
@@ -2393,11 +3250,16 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
   bfd_byte *debug_contents = NULL;
 
   if (! XCOFF_XVECP (output_bfd->xvec))
-    return true;
+    {
+      for (i = 0; i < 6; i++)
+       special_sections[i] = NULL;
+      return true;
+    }
 
   ldinfo.failed = false;
   ldinfo.output_bfd = output_bfd;
   ldinfo.info = info;
+  ldinfo.export_defineds = export_defineds;
   ldinfo.ldsym_count = 0;
   ldinfo.string_size = 0;
   ldinfo.strings = NULL;
@@ -2410,15 +3272,14 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
   xcoff_hash_table (info)->file_align = file_align;
   xcoff_hash_table (info)->textro = textro;
 
-  hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry,
-                                  false, false, true);
-  if (hentry != NULL)
+  if (entry == NULL)
+    hentry = NULL;
+  else
     {
-      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;
+      hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry,
+                                      false, false, true);
+      if (hentry != NULL)
+       hentry->flags |= XCOFF_ENTRY;
     }
 
   /* Garbage collect unused sections.  */
@@ -2455,6 +3316,19 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
       xcoff_hash_table (info)->gc = true;
     }
 
+  /* Return special sections to the caller.  */
+  for (i = 0; i < 6; i++)
+    {
+      asection *sec;
+
+      sec = xcoff_hash_table (info)->special_sections[i];
+      if (sec != NULL
+         && gc
+         && (sec->flags & SEC_MARK) == 0)
+       sec = NULL;
+      special_sections[i] = sec;
+    }
+
   if (info->input_bfds == NULL)
     {
       /* I'm not sure what to do in this bizarre case.  */
@@ -2506,10 +3380,7 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
   lsec->_raw_size = stoff + ldhdr->l_stlen;
   lsec->contents = (bfd_byte *) bfd_zalloc (output_bfd, lsec->_raw_size);
   if (lsec->contents == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   /* Set up the header.  */
   xcoff_swap_ldhdr_out (output_bfd, ldhdr,
@@ -2554,27 +3425,27 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
      when the corresponding normal relocs are handled in
      xcoff_link_input_bfd.  */
 
-  /* Allocate space for the global linkage section and the global toc
-     section.  */
+  /* Allocate space for the magic sections.  */
   sec = xcoff_hash_table (info)->linkage_section;
   if (sec->_raw_size > 0)
     {
       sec->contents = (bfd_byte *) bfd_zalloc (output_bfd, sec->_raw_size);
       if (sec->contents == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         goto error_return;
-       }
+       goto error_return;
     }
   sec = xcoff_hash_table (info)->toc_section;
   if (sec->_raw_size > 0)
     {
       sec->contents = (bfd_byte *) bfd_zalloc (output_bfd, sec->_raw_size);
       if (sec->contents == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         goto error_return;
-       }
+       goto error_return;
+    }
+  sec = xcoff_hash_table (info)->descriptor_section;
+  if (sec->_raw_size > 0)
+    {
+      sec->contents = (bfd_byte *) bfd_zalloc (output_bfd, sec->_raw_size);
+      if (sec->contents == NULL)
+       goto error_return;
     }
 
   /* Now that we've done garbage collection, figure out the contents
@@ -2611,23 +3482,17 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
       debug_index = ((unsigned long *)
                     bfd_zalloc (sub, symcount * sizeof (unsigned long)));
       if (debug_index == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         goto error_return;
-       }
+       goto error_return;
       xcoff_data (sub)->debug_indices = debug_index;
 
       /* Grab the contents of the .debug section.  We use malloc and
-        copy the neams into the debug stringtab, rather than
+        copy the names into the debug stringtab, rather than
         bfd_alloc, because I expect that, when linking many files
         together, many of the strings will be the same.  Storing the
         strings in the hash table should save space in this case.  */
-      debug_contents = (bfd_byte *) malloc (subdeb->_raw_size);
+      debug_contents = (bfd_byte *) bfd_malloc (subdeb->_raw_size);
       if (debug_contents == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         goto error_return;
-       }
+       goto error_return;
       if (! bfd_get_section_contents (sub, subdeb, (PTR) debug_contents,
                                      (file_ptr) 0, subdeb->_raw_size))
        goto error_return;
@@ -2681,8 +3546,9 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
        }
     }
 
-  xcoff_hash_table (info)->debug_section->_raw_size =
-    _bfd_stringtab_size (debug_strtab);
+  if (info->strip != strip_all)
+    xcoff_hash_table (info)->debug_section->_raw_size =
+      _bfd_stringtab_size (debug_strtab);
 
   return true;
 
@@ -2704,6 +3570,67 @@ xcoff_build_ldsyms (h, p)
   struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
   size_t len;
 
+  /* If this is a final link, and the symbol was defined as a common
+     symbol in a regular object file, and there was no definition in
+     any dynamic object, then the linker will have allocated space for
+     the symbol in a common section but the XCOFF_DEF_REGULAR flag
+     will not have been set.  */
+  if (h->root.type == bfd_link_hash_defined
+      && (h->flags & XCOFF_DEF_REGULAR) == 0
+      && (h->flags & XCOFF_REF_REGULAR) != 0
+      && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+      && (bfd_is_abs_section (h->root.u.def.section)
+         || (h->root.u.def.section->owner->flags & DYNAMIC) == 0))
+    h->flags |= XCOFF_DEF_REGULAR;
+
+  /* If all defined symbols should be exported, mark them now.  We
+     don't want to export the actual functions, just the function
+     descriptors.  */
+  if (ldinfo->export_defineds
+      && (h->flags & XCOFF_DEF_REGULAR) != 0
+      && h->root.root.string[0] != '.')
+    {
+      boolean export;
+
+      /* We don't export a symbol which is being defined by an object
+        included from an archive which contains a shared object.  The
+        rationale is that if an archive contains both an unshared and
+        a shared object, then there must be some reason that the
+        unshared object is unshared, and we don't want to start
+        providing a shared version of it.  In particular, this solves
+        a bug involving the _savefNN set of functions.  gcc will call
+        those functions without providing a slot to restore the TOC,
+        so it is essential that these functions be linked in directly
+        and not from a shared object, which means that a shared
+        object which also happens to link them in must not export
+        them.  This is confusing, but I haven't been able to think of
+        a different approach.  Note that the symbols can, of course,
+        be exported explicitly.  */
+      export = true;
+      if ((h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+         && h->root.u.def.section->owner != NULL
+         && h->root.u.def.section->owner->my_archive != NULL)
+       {
+         bfd *arbfd, *member;
+
+         arbfd = h->root.u.def.section->owner->my_archive;
+         member = bfd_openr_next_archived_file (arbfd, (bfd *) NULL);
+         while (member != NULL)
+           {
+             if ((member->flags & DYNAMIC) != 0)
+               {
+                 export = false;
+                 break;
+               }
+             member = bfd_openr_next_archived_file (arbfd, member);
+           }
+       }
+
+      if (export)
+       h->flags |= XCOFF_EXPORT;
+    }
+
   /* We don't want to garbage collect symbols which are not defined in
      XCOFF files.  This is a convenient place to mark them.  */
   if (xcoff_hash_table (ldinfo->info)->gc
@@ -2715,15 +3642,18 @@ xcoff_build_ldsyms (h, p)
              != ldinfo->info->hash->creator)))
     h->flags |= XCOFF_MARK;
 
-  /* If this symbol is called, and it is defined in a dynamic object,
-     then we need to set up global linkage code for it.  (Unless we
-     did garbage collection and we didn't need this symbol.)  */
+  /* If this symbol is called and defined in a dynamic object, or it
+     is imported, then we need to set up global linkage code for it.
+     (Unless we did garbage collection and we didn't need this
+     symbol.)  */
   if ((h->flags & XCOFF_CALLED) != 0
-      && (h->flags & XCOFF_DEF_REGULAR) == 0
-      && (h->flags & XCOFF_REF_DYNAMIC) != 0
       && (h->root.type == bfd_link_hash_undefined
          || h->root.type == bfd_link_hash_undefweak)
       && h->root.root.string[0] == '.'
+      && h->descriptor != NULL
+      && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0
+         || ((h->descriptor->flags & XCOFF_IMPORT) != 0
+             && (h->descriptor->flags & XCOFF_DEF_REGULAR) == 0))
       && (! xcoff_hash_table (ldinfo->info)->gc
          || (h->flags & XCOFF_MARK) != 0))
     {
@@ -2735,6 +3665,7 @@ xcoff_build_ldsyms (h, p)
       h->root.u.def.section = sec;
       h->root.u.def.value = sec->_raw_size;
       h->smclas = XMC_GL;
+      h->flags |= XCOFF_DEF_REGULAR;
       sec->_raw_size += XCOFF_GLINK_SIZE;
 
       /* The global linkage code requires a TOC entry for the
@@ -2742,8 +3673,7 @@ xcoff_build_ldsyms (h, p)
       hds = h->descriptor;
       BFD_ASSERT ((hds->root.type == bfd_link_hash_undefined
                   || hds->root.type == bfd_link_hash_undefweak)
-                 && (hds->flags & XCOFF_DEF_REGULAR) == 0
-                 && (hds->flags & XCOFF_REF_DYNAMIC) != 0);
+                 && (hds->flags & XCOFF_DEF_REGULAR) == 0);
       hds->flags |= XCOFF_MARK;
       if (hds->toc_section == NULL)
        {
@@ -2761,6 +3691,52 @@ xcoff_build_ldsyms (h, p)
        }
     }
 
+  /* If this symbol is exported, but not defined, we need to try to
+     define it.  */
+  if ((h->flags & XCOFF_EXPORT) != 0
+      && (h->flags & XCOFF_IMPORT) == 0
+      && (h->flags & XCOFF_DEF_REGULAR) == 0
+      && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+      && (h->root.type == bfd_link_hash_undefined
+         || h->root.type == bfd_link_hash_undefweak))
+    {
+      if ((h->flags & XCOFF_DESCRIPTOR) != 0
+         && (h->descriptor->root.type == bfd_link_hash_defined
+             || h->descriptor->root.type == bfd_link_hash_defweak))
+       {
+         asection *sec;
+
+         /* This is an undefined function descriptor associated with
+             a defined entry point.  We can build up a function
+             descriptor ourselves.  Believe it or not, the AIX linker
+             actually does this, and there are cases where we need to
+             do it as well.  */
+         sec = xcoff_hash_table (ldinfo->info)->descriptor_section;
+         h->root.type = bfd_link_hash_defined;
+         h->root.u.def.section = sec;
+         h->root.u.def.value = sec->_raw_size;
+         h->smclas = XMC_DS;
+         h->flags |= XCOFF_DEF_REGULAR;
+         sec->_raw_size += 12;
+
+         /* A function descriptor uses two relocs: one for the
+             associated code, and one for the TOC address.  */
+         xcoff_hash_table (ldinfo->info)->ldrel_count += 2;
+         sec->reloc_count += 2;
+
+         /* We handle writing out the contents of the descriptor in
+             xcoff_write_global_symbol.  */
+       }
+      else
+       {
+         (*_bfd_error_handler)
+           (_("warning: attempt to export undefined symbol `%s'"),
+            h->root.root.string);
+         h->ldsym = NULL;
+         return true;
+       }
+    }
+
   /* If this is still a common symbol, and it wasn't garbage
      collected, we need to actually allocate space for it in the .bss
      section.  */
@@ -2805,21 +3781,19 @@ xcoff_build_ldsyms (h, p)
 
   /* We need to add this symbol to the .loader symbols.  */
 
-  /* h->ldsym will already have been allocated for an explicitly
-     imported symbol.  */
+  BFD_ASSERT (h->ldsym == NULL);
+  h->ldsym = ((struct internal_ldsym *)
+             bfd_zalloc (ldinfo->output_bfd,
+                         sizeof (struct internal_ldsym)));
   if (h->ldsym == NULL)
     {
-      h->ldsym = ((struct internal_ldsym *)
-                 bfd_zalloc (ldinfo->output_bfd,
-                             sizeof (struct internal_ldsym)));
-      if (h->ldsym == NULL)
-       {
-         ldinfo->failed = true;
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+      ldinfo->failed = true;
+      return false;
     }
 
+  if ((h->flags & XCOFF_IMPORT) != 0)
+    h->ldsym->l_ifile = h->ldindx;
+
   /* The first 3 symbol table indices are reserved to indicate the
      sections.  */
   h->ldindx = ldinfo->ldsym_count + 3;
@@ -2842,15 +3816,11 @@ xcoff_build_ldsyms (h, p)
          while (ldinfo->string_size + len + 3 > newalc)
            newalc *= 2;
 
-         if (ldinfo->strings == NULL)
-           newstrings = (bfd_byte *) malloc (newalc);
-         else
-           newstrings = ((bfd_byte *)
-                         realloc ((PTR) ldinfo->strings, newalc));
+         newstrings = ((bfd_byte *)
+                       bfd_realloc ((PTR) ldinfo->strings, newalc));
          if (newstrings == NULL)
            {
              ldinfo->failed = true;
-             bfd_set_error (bfd_error_no_memory);
              return false;
            }
          ldinfo->string_alc = newalc;
@@ -2894,6 +3864,9 @@ _bfd_xcoff_bfd_final_link (abfd, info)
   bfd_byte *external_relocs = NULL;
   char strbuf[STRING_SIZE_SIZE];
 
+  if (info->shared)
+    abfd->flags |= DYNAMIC;
+
   symesz = bfd_coff_symesz (abfd);
 
   finfo.info = info;
@@ -2923,6 +3896,54 @@ _bfd_xcoff_bfd_final_link (abfd, info)
   if (finfo.strtab == NULL)
     goto error_return;
 
+  /* Count the line number and relocation entries required for the
+     output file.  Determine a few maximum sizes.  */
+  max_contents_size = 0;
+  max_lineno_count = 0;
+  max_reloc_count = 0;
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      o->reloc_count = 0;
+      o->lineno_count = 0;
+      for (p = o->link_order_head; p != NULL; p = p->next)
+       {
+         if (p->type == bfd_indirect_link_order)
+           {
+             asection *sec;
+
+             sec = p->u.indirect.section;
+
+             /* Mark all sections which are to be included in the
+                link.  This will normally be every section.  We need
+                to do this so that we can identify any sections which
+                the linker has decided to not include.  */
+             sec->linker_mark = true;
+
+             if (info->strip == strip_none
+                 || info->strip == strip_some)
+               o->lineno_count += sec->lineno_count;
+
+             o->reloc_count += sec->reloc_count;
+
+             if (sec->_raw_size > max_contents_size)
+               max_contents_size = sec->_raw_size;
+             if (sec->lineno_count > max_lineno_count)
+               max_lineno_count = sec->lineno_count;
+             if (coff_section_data (sec->owner, sec) != NULL
+                 && xcoff_section_data (sec->owner, sec) != NULL
+                 && (xcoff_section_data (sec->owner, sec)->lineno_count
+                     > max_lineno_count))
+               max_lineno_count =
+                 xcoff_section_data (sec->owner, sec)->lineno_count;
+             if (sec->reloc_count > max_reloc_count)
+               max_reloc_count = sec->reloc_count;
+           }
+         else if (p->type == bfd_section_reloc_link_order
+                  || p->type == bfd_symbol_reloc_link_order)
+           ++o->reloc_count;
+       }
+    }
+
   /* Compute the file positions for all the sections.  */
   if (abfd->output_has_begun)
     {
@@ -2947,7 +3968,6 @@ _bfd_xcoff_bfd_final_link (abfd, info)
          saw_contents = true;
          for (op = &abfd->sections; *op != NULL; op = &(*op)->next)
            {
-             (*op)->target_index = indx;
              if (strcmp ((*op)->name, ".pad") == 0)
                saw_contents = false;
              else if (((*op)->flags & SEC_HAS_CONTENTS) != 0
@@ -2988,6 +4008,9 @@ _bfd_xcoff_bfd_final_link (abfd, info)
          sofar = bfd_coff_filhsz (abfd);
          sofar += bfd_coff_aoutsz (abfd);
          sofar += abfd->section_count * bfd_coff_scnhsz (abfd);
+         for (o = abfd->sections; o != NULL; o = o->next)
+           if (o->reloc_count >= 0xffff || o->lineno_count >= 0xffff)
+             sofar += bfd_coff_scnhsz (abfd);
 
          for (o = abfd->sections; o != NULL; o = o->next)
            {
@@ -3013,59 +4036,8 @@ _bfd_xcoff_bfd_final_link (abfd, info)
            }
        }
 
-      bfd_coff_compute_section_file_positions (abfd);
-    }
-
-  /* Count the line numbers and relocation entries required for the
-     output file.  Set the file positions for the relocs.  */
-  rel_filepos = obj_relocbase (abfd);
-  relsz = bfd_coff_relsz (abfd);
-  max_contents_size = 0;
-  max_lineno_count = 0;
-  max_reloc_count = 0;
-  for (o = abfd->sections; o != NULL; o = o->next)
-    {
-      o->reloc_count = 0;
-      o->lineno_count = 0;
-      for (p = o->link_order_head; p != NULL; p = p->next)
-       {
-         if (p->type == bfd_indirect_link_order)
-           {
-             asection *sec;
-
-             sec = p->u.indirect.section;
-
-             if (info->strip == strip_none
-                 || info->strip == strip_some)
-               o->lineno_count += sec->lineno_count;
-
-             o->reloc_count += sec->reloc_count;
-
-             if (sec->_raw_size > max_contents_size)
-               max_contents_size = sec->_raw_size;
-             if (sec->lineno_count > max_lineno_count)
-               max_lineno_count = sec->lineno_count;
-             if (coff_section_data (sec->owner, sec) != NULL
-                 && xcoff_section_data (sec->owner, sec) != NULL
-                 && (xcoff_section_data (sec->owner, sec)->lineno_count
-                     > max_lineno_count))
-               max_lineno_count =
-                 xcoff_section_data (sec->owner, sec)->lineno_count;
-             if (sec->reloc_count > max_reloc_count)
-               max_reloc_count = sec->reloc_count;
-           }
-         else if (p->type == bfd_section_reloc_link_order
-                  || p->type == bfd_symbol_reloc_link_order)
-           ++o->reloc_count;
-       }
-      if (o->reloc_count == 0)
-       o->rel_filepos = 0;
-      else
-       {
-         o->flags |= SEC_RELOC;
-         o->rel_filepos = rel_filepos;
-         rel_filepos += o->reloc_count * relsz;
-       }
+      if (! bfd_coff_compute_section_file_positions (abfd))
+       goto error_return;
     }
 
   /* Allocate space for the pointers we need to keep for the relocs.  */
@@ -3074,14 +4046,12 @@ _bfd_xcoff_bfd_final_link (abfd, info)
 
     /* We use section_count + 1, rather than section_count, because
        the target_index fields are 1 based.  */
-    finfo.section_info = ((struct xcoff_link_section_info *)
-                         malloc ((abfd->section_count + 1)
-                                 * sizeof (struct xcoff_link_section_info)));
+    finfo.section_info =
+      ((struct xcoff_link_section_info *)
+       bfd_malloc ((abfd->section_count + 1)
+                  * sizeof (struct xcoff_link_section_info)));
     if (finfo.section_info == NULL)
-      {
-       bfd_set_error (bfd_error_no_memory);
-       goto error_return;
-      }
+      goto error_return;
     for (i = 0; i <= abfd->section_count; i++)
       {
        finfo.section_info[i].relocs = NULL;
@@ -3090,24 +4060,28 @@ _bfd_xcoff_bfd_final_link (abfd, info)
       }
   }
 
-  /* We now know the size of the relocs, so we can determine the file
-     positions of the line numbers.  */
-  line_filepos = rel_filepos;
-  finfo.line_filepos = line_filepos;
-  linesz = bfd_coff_linesz (abfd);
+  /* Set the file positions for the relocs.  */
+  rel_filepos = obj_relocbase (abfd);
+  relsz = bfd_coff_relsz (abfd);
   max_output_reloc_count = 0;
   for (o = abfd->sections; o != NULL; o = o->next)
     {
-      if (o->lineno_count == 0)
-       o->line_filepos = 0;
+      if (o->reloc_count == 0)
+       o->rel_filepos = 0;
       else
        {
-         o->line_filepos = line_filepos;
-         line_filepos += o->lineno_count * linesz;
-       }
+         /* A stripped file has no relocs.  However, we still
+             allocate the buffers, so that later code doesn't have to
+             worry about whether we are stripping or not.  */
+         if (info->strip == strip_all)
+           o->rel_filepos = 0;
+         else
+           {
+             o->flags |= SEC_RELOC;
+             o->rel_filepos = rel_filepos;
+             rel_filepos += o->reloc_count * relsz;
+           }
 
-      if (o->reloc_count != 0)
-       {
          /* We don't know the indices of global symbols until we have
              written out all the local symbols.  For each section in
              the output file, we keep an array of pointers to hash
@@ -3123,21 +4097,34 @@ _bfd_xcoff_bfd_final_link (abfd, info)
             would be slow.  */
          finfo.section_info[o->target_index].relocs =
            ((struct internal_reloc *)
-            malloc (o->reloc_count * sizeof (struct internal_reloc)));
+            bfd_malloc (o->reloc_count * sizeof (struct internal_reloc)));
          finfo.section_info[o->target_index].rel_hashes =
            ((struct xcoff_link_hash_entry **)
-            malloc (o->reloc_count
+            bfd_malloc (o->reloc_count
                     * sizeof (struct xcoff_link_hash_entry *)));
          if (finfo.section_info[o->target_index].relocs == NULL
              || finfo.section_info[o->target_index].rel_hashes == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             goto error_return;
-           }
+           goto error_return;
 
          if (o->reloc_count > max_output_reloc_count)
            max_output_reloc_count = o->reloc_count;
        }
+    }
+
+  /* We now know the size of the relocs, so we can determine the file
+     positions of the line numbers.  */
+  line_filepos = rel_filepos;
+  finfo.line_filepos = line_filepos;
+  linesz = bfd_coff_linesz (abfd);
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if (o->lineno_count == 0)
+       o->line_filepos = 0;
+      else
+       {
+         o->line_filepos = line_filepos;
+         line_filepos += o->lineno_count * linesz;
+       }
 
       /* Reset the reloc and lineno counts, so that we can use them to
         count the number of entries we have output so far.  */
@@ -3149,9 +4136,9 @@ _bfd_xcoff_bfd_final_link (abfd, info)
 
   /* Figure out the largest number of symbols in an input BFD.  Take
      the opportunity to clear the output_has_begun fields of all the
-     input BFD's.  We want at least 4 symbols, since that is the
+     input BFD's.  We want at least 6 symbols, since that is the
      number which xcoff_write_global_symbol may need.  */
-  max_sym_count = 4;
+  max_sym_count = 6;
   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
       size_t sz;
@@ -3164,25 +4151,22 @@ _bfd_xcoff_bfd_final_link (abfd, info)
 
   /* Allocate some buffers used while linking.  */
   finfo.internal_syms = ((struct internal_syment *)
-                        malloc (max_sym_count
-                                * sizeof (struct internal_syment)));
-  finfo.sym_indices = (long *) malloc (max_sym_count * sizeof (long));
+                        bfd_malloc (max_sym_count
+                                    * sizeof (struct internal_syment)));
+  finfo.sym_indices = (long *) bfd_malloc (max_sym_count * sizeof (long));
   finfo.outsyms = ((bfd_byte *)
-                  malloc ((size_t) ((max_sym_count + 1) * symesz)));
-  finfo.linenos = (bfd_byte *) malloc (max_lineno_count
-                                      * bfd_coff_linesz (abfd));
-  finfo.contents = (bfd_byte *) malloc (max_contents_size);
-  finfo.external_relocs = (bfd_byte *) malloc (max_reloc_count * relsz);
+                  bfd_malloc ((size_t) ((max_sym_count + 1) * symesz)));
+  finfo.linenos = (bfd_byte *) bfd_malloc (max_lineno_count
+                                          * bfd_coff_linesz (abfd));
+  finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+  finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz);
   if ((finfo.internal_syms == NULL && max_sym_count > 0)
       || (finfo.sym_indices == NULL && max_sym_count > 0)
       || finfo.outsyms == NULL
       || (finfo.linenos == NULL && max_lineno_count > 0)
       || (finfo.contents == NULL && max_contents_size > 0)
       || (finfo.external_relocs == NULL && max_reloc_count > 0))
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   obj_raw_syment_count (abfd) = 0;
   xcoff_data (abfd)->toc = (bfd_vma) -1;
@@ -3279,12 +4263,9 @@ _bfd_xcoff_bfd_final_link (abfd, info)
   /* Now that we have written out all the global symbols, we know the
      symbol indices to use for relocs against them, and we can finally
      write out the relocs.  */
-  external_relocs = (bfd_byte *) malloc (max_output_reloc_count * relsz);
+  external_relocs = (bfd_byte *) bfd_malloc (max_output_reloc_count * relsz);
   if (external_relocs == NULL && max_output_reloc_count != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   for (o = abfd->sections; o != NULL; o = o->next)
     {
@@ -3294,6 +4275,13 @@ _bfd_xcoff_bfd_final_link (abfd, info)
       struct xcoff_toc_rel_hash *toc_rel_hash;
       bfd_byte *erel;
 
+      /* A stripped file has no relocs.  */
+      if (info->strip == strip_all)
+       {
+         o->reloc_count = 0;
+         continue;
+       }
+
       if (o->reloc_count == 0)
        continue;
 
@@ -3384,7 +4372,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
                                  o->_raw_size))
     goto error_return;
 
-  /* Write out the global linkage section and the toc section.  */
+  /* Write out the magic sections.  */
   o = xcoff_hash_table (info)->linkage_section;
   if (o->_raw_size > 0
       && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
@@ -3395,6 +4383,11 @@ _bfd_xcoff_bfd_final_link (abfd, info)
       && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
                                     o->output_offset, o->_raw_size))
     goto error_return;
+  o = xcoff_hash_table (info)->descriptor_section;
+  if (o->_raw_size > 0
+      && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
+                                    o->output_offset, o->_raw_size))
+    goto error_return;
 
   /* Write out the string table.  */
   if (bfd_seek (abfd,
@@ -3604,11 +4597,11 @@ xcoff_link_input_bfd (finfo, input_bfd)
 
          ldsym->l_smtype = smtyp;
          if (((h->flags & XCOFF_DEF_REGULAR) == 0
-              && (h->flags & XCOFF_REF_DYNAMIC) != 0)
+              && (h->flags & XCOFF_DEF_DYNAMIC) != 0)
              || (h->flags & XCOFF_IMPORT) != 0)
            ldsym->l_smtype |= L_IMPORT;
          if (((h->flags & XCOFF_DEF_REGULAR) != 0
-              && (h->flags & XCOFF_REF_DYNAMIC) != 0)
+              && (h->flags & XCOFF_DEF_DYNAMIC) != 0)
              || (h->flags & XCOFF_EXPORT) != 0)
            ldsym->l_smtype |= L_EXPORT;
          if ((h->flags & XCOFF_ENTRY) != 0)
@@ -3652,6 +4645,13 @@ xcoff_link_input_bfd (finfo, input_bfd)
          xcoff_swap_ldsym_out (finfo->output_bfd, ldsym,
                                finfo->ldsym + h->ldindx - 3);
          h->ldsym = NULL;
+
+         /* Fill in snentry now that we know the target_index.  */
+         if ((h->flags & XCOFF_ENTRY) != 0
+             && (h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak))
+           xcoff_data (output_bfd)->snentry =
+             h->root.u.def.section->output_section->target_index;
        }
 
       *indexp = -1;
@@ -3686,14 +4686,45 @@ xcoff_link_input_bfd (finfo, input_bfd)
            skip = true;
          else
            {
+             bfd_vma tocval, tocend;
+
+             tocval = ((*csectpp)->output_section->vma
+                       + (*csectpp)->output_offset
+                       + isym.n_value
+                       - (*csectpp)->vma);
+             /* We want to find out if tocval is a good value to use
+                 as the TOC anchor--that is, whether we can access all
+                 of the TOC using a 16 bit offset from tocval.  This
+                 test assumes that the TOC comes at the end of the
+                 output section, as it does in the default linker
+                 script.  FIXME: This doesn't handle .tocbss sections
+                 created from XMC_TD common symbols correctly.  */
+
+             tocend = ((*csectpp)->output_section->vma
+                       + (*csectpp)->output_section->_raw_size);
+
+             if (tocval + 0x10000 < tocend)
+               {
+                 (*_bfd_error_handler)
+                   (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling"),
+                    (unsigned long) (tocend - tocval));
+                 bfd_set_error (bfd_error_file_too_big);
+                 return false;
+               }
+
+             if (tocval + 0x8000 < tocend)
+               {
+                 bfd_vma tocadd;
+
+                 tocadd = tocend - (tocval + 0x8000);
+                 tocval += tocadd;
+                 isym.n_value += tocadd;
+               }
+
              finfo->toc_symindx = output_index;
-             xcoff_data (finfo->output_bfd)->toc =
-               ((*csectpp)->output_section->vma
-                + (*csectpp)->output_offset
-                + isym.n_value
-                - (*csectpp)->vma);
-             xcoff_data (finfo->output_bfd)->toc_section =
-               (*csectpp)->output_section;
+             xcoff_data (finfo->output_bfd)->toc = tocval;
+             xcoff_data (finfo->output_bfd)->sntoc =
+               (*csectpp)->output_section->target_index;
              require = true;
            }
        }
@@ -3760,8 +4791,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                  && (isym.n_sclass != C_EXT
                      && (isym.n_sclass != C_HIDEXT
                          || smtyp != XTY_SD))
-                 && strncmp (name, finfo->info->lprefix,
-                             finfo->info->lprefix_len) == 0))
+                 && bfd_is_local_label_name (input_bfd, name)))
            skip = true;
        }
 
@@ -4028,7 +5058,8 @@ xcoff_link_input_bfd (finfo, input_bfd)
 
                  if (ISFCN (isymp->n_type)
                      || ISTAG (isymp->n_sclass)
-                     || isymp->n_sclass == C_BLOCK)
+                     || isymp->n_sclass == C_BLOCK
+                     || isymp->n_sclass == C_FCN)
                    {
                      indx = aux.x_sym.x_fcnary.x_fcn.x_endndx.l;
                      if (indx > 0
@@ -4162,6 +5193,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                              struct internal_syment *iisp, *iispend;
                              long *iindp;
                              bfd_byte *oos;
+                             int iiadd;
 
                              /* Update any C_BINCL or C_EINCL symbols
                                  that refer to a line number in the
@@ -4173,8 +5205,9 @@ xcoff_link_input_bfd (finfo, input_bfd)
                              oos = finfo->outsyms;
                              while (iisp < iispend)
                                {
-                                 if ((iisp->n_sclass == C_BINCL
-                                      || iisp->n_sclass == C_EINCL)
+                                 if (*iindp >= 0
+                                     && (iisp->n_sclass == C_BINCL
+                                         || iisp->n_sclass == C_EINCL)
                                      && ((bfd_size_type) iisp->n_value
                                          >= enclosing->line_filepos + linoff)
                                      && ((bfd_size_type) iisp->n_value
@@ -4197,9 +5230,11 @@ xcoff_link_input_bfd (finfo, input_bfd)
                                      --incls;
                                    }
 
-                                 iisp += iisp->n_numaux + 1;
-                                 iindp += iisp->n_numaux + 1;
-                                 oos += (iisp->n_numaux + 1) * osymesz;
+                                 iiadd = 1 + iisp->n_numaux;
+                                 if (*iindp >= 0)
+                                   oos += iiadd * osymesz;
+                                 iisp += iiadd;
+                                 iindp += iiadd;
                                }
                            }
                        }
@@ -4260,6 +5295,12 @@ xcoff_link_input_bfd (finfo, input_bfd)
     {
       bfd_byte *contents;
 
+      if (! o->linker_mark)
+       {
+         /* This section was omitted from the link.  */
+         continue;
+       }
+
       if ((o->flags & SEC_HAS_CONTENTS) == 0
          || o->_raw_size == 0
          || (o->flags & SEC_IN_MEMORY) != 0)
@@ -4317,6 +5358,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
            {
              struct xcoff_link_hash_entry *h = NULL;
              struct internal_ldrel ldrel;
+             boolean quiet;
 
              *rel_hash = NULL;
 
@@ -4326,15 +5368,20 @@ xcoff_link_input_bfd (finfo, input_bfd)
 
              r_symndx = irel->r_symndx;
 
-             if (r_symndx != -1)
+             if (r_symndx == -1)
+               h = NULL;
+             else
+               h = obj_xcoff_sym_hashes (input_bfd)[r_symndx];
+
+             if (r_symndx != -1 && finfo->info->strip != strip_all)
                {
-                 h = obj_xcoff_sym_hashes (input_bfd)[r_symndx];
-                 if  (h != NULL
-                      && (irel->r_type == R_TOC
-                          || irel->r_type == R_GL
-                          || irel->r_type == R_TCL
-                          || irel->r_type == R_TRL
-                          || irel->r_type == R_TRLA))
+                 if (h != NULL
+                     && h->smclas != XMC_TD
+                     && (irel->r_type == R_TOC
+                         || irel->r_type == R_GL
+                         || irel->r_type == R_TCL
+                         || irel->r_type == R_TRL
+                         || irel->r_type == R_TRLA))
                    {
                      /* This is a TOC relative reloc with a symbol
                          attached.  The symbol should be the one which
@@ -4354,10 +5401,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                               bfd_alloc (finfo->output_bfd,
                                          sizeof (struct xcoff_toc_rel_hash)));
                          if (n == NULL)
-                           {
-                             bfd_set_error (bfd_error_no_memory);
-                             return false;
-                           }
+                           return false;
                          si = finfo->section_info + target_index;
                          n->next = si->toc_rel_hashes;
                          n->h = h;
@@ -4444,6 +5488,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                    }
                }
 
+             quiet = false;
              switch (irel->r_type)
                {
                default:
@@ -4486,7 +5531,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                      else
                        {
                          (*_bfd_error_handler)
-                           ("%s: loader reloc in unrecognized section `%s'",
+                           (_("%s: loader reloc in unrecognized section `%s'"),
                             bfd_get_filename (input_bfd),
                             sec->name);
                          bfd_set_error (bfd_error_nonrepresentable_section);
@@ -4495,10 +5540,20 @@ xcoff_link_input_bfd (finfo, input_bfd)
                    }
                  else
                    {
-                     if (h->ldindx < 0)
+                     if (! finfo->info->relocateable
+                         && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+                         && (h->flags & XCOFF_IMPORT) == 0)
+                       {
+                         /* We already called the undefined_symbol
+                            callback for this relocation, in
+                            _bfd_ppc_xcoff_relocate_section.  Don't
+                            issue any more warnings.  */
+                         quiet = true;
+                       }
+                     if (h->ldindx < 0 && ! quiet)
                        {
                          (*_bfd_error_handler)
-                           ("%s: `%s' in loader reloc but not loader sym",
+                           (_("%s: `%s' in loader reloc but not loader sym"),
                             bfd_get_filename (input_bfd),
                             h->root.root.string);
                          bfd_set_error (bfd_error_bad_value);
@@ -4509,10 +5564,11 @@ 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
-                     && strcmp (o->output_section->name, ".text") == 0)
+                     && strcmp (o->output_section->name, ".text") == 0
+                     && ! quiet)
                    {
                      (*_bfd_error_handler)
-                       ("%s: loader reloc in read-only section %s",
+                       (_("%s: loader reloc in read-only section %s"),
                         bfd_get_filename (input_bfd),
                         bfd_get_section_name (finfo->output_bfd,
                                               o->output_section));
@@ -4576,6 +5632,7 @@ xcoff_write_global_symbol (h, p)
   union internal_auxent aux;
 
   output_bfd = finfo->output_bfd;
+  outsym = finfo->outsyms;
 
   /* If this symbol was garbage collected, just skip it.  */
   if (xcoff_hash_table (finfo->info)->gc
@@ -4615,11 +5672,11 @@ xcoff_write_global_symbol (h, p)
        abort ();
 
       if (((h->flags & XCOFF_DEF_REGULAR) == 0
-          && (h->flags & XCOFF_REF_DYNAMIC) != 0)
+          && (h->flags & XCOFF_DEF_DYNAMIC) != 0)
          || (h->flags & XCOFF_IMPORT) != 0)
        ldsym->l_smtype |= L_IMPORT;
       if (((h->flags & XCOFF_DEF_REGULAR) != 0
-          && (h->flags & XCOFF_REF_DYNAMIC) != 0)
+          && (h->flags & XCOFF_DEF_DYNAMIC) != 0)
          || (h->flags & XCOFF_EXPORT) != 0)
        ldsym->l_smtype |= L_EXPORT;
       if ((h->flags & XCOFF_ENTRY) != 0)
@@ -4668,7 +5725,7 @@ xcoff_write_global_symbol (h, p)
                - xcoff_data (output_bfd)->toc);
       if ((h->descriptor->flags & XCOFF_SET_TOC) != 0)
        tocoff += h->descriptor->u.toc_offset;
-      bfd_put_32 (output_bfd, XCOFF_GLINK_FIRST | tocoff, p);
+      bfd_put_32 (output_bfd, XCOFF_GLINK_FIRST | (tocoff & 0xffff), p);
       for (i = 0, p += 4;
           i < sizeof xcoff_glink_code / sizeof xcoff_glink_code[0];
           i++, p += 4)
@@ -4684,6 +5741,8 @@ xcoff_write_global_symbol (h, p)
       int oindx;
       struct internal_reloc *irel;
       struct internal_ldrel ldrel;
+      struct internal_syment irsym;
+      union internal_auxent iraux;
 
       tocsec = h->toc_section;
       osec = tocsec->output_section;
@@ -4711,10 +5770,177 @@ xcoff_write_global_symbol (h, p)
       ldrel.l_rsecnm = oindx;
       xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
       ++finfo->ldrel;
+
+      /* We need to emit a symbol to define a csect which holds the
+         reloc.  */
+      if (finfo->info->strip != strip_all)
+       {
+         if (strlen (h->root.root.string) <= SYMNMLEN)
+           strncpy (irsym._n._n_name, h->root.root.string, SYMNMLEN);
+         else
+           {
+             boolean hash;
+             bfd_size_type indx;
+
+             hash = true;
+             if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
+               hash = false;
+             indx = _bfd_stringtab_add (finfo->strtab, h->root.root.string,
+                                        hash, false);
+             if (indx == (bfd_size_type) -1)
+               return false;
+             irsym._n._n_n._n_zeroes = 0;
+             irsym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
+           }
+
+         irsym.n_value = irel->r_vaddr;
+         irsym.n_scnum = osec->target_index;
+         irsym.n_sclass = C_HIDEXT;
+         irsym.n_type = T_NULL;
+         irsym.n_numaux = 1;
+
+         bfd_coff_swap_sym_out (output_bfd, (PTR) &irsym, (PTR) outsym);
+         outsym += bfd_coff_symesz (output_bfd);
+
+         memset (&iraux, 0, sizeof iraux);
+         iraux.x_csect.x_smtyp = XTY_SD;
+         iraux.x_csect.x_scnlen.l = 4;
+         iraux.x_csect.x_smclas = XMC_TC;
+
+         bfd_coff_swap_aux_out (output_bfd, (PTR) &iraux, T_NULL, C_HIDEXT,
+                                0, 1, (PTR) outsym);
+         outsym += bfd_coff_auxesz (output_bfd);
+
+         if (h->indx >= 0)
+           {
+             /* We aren't going to write out the symbols below, so we
+                need to write them out now.  */
+             if (bfd_seek (output_bfd,
+                           (obj_sym_filepos (output_bfd)
+                            + (obj_raw_syment_count (output_bfd)
+                               * bfd_coff_symesz (output_bfd))),
+                           SEEK_SET) != 0
+                 || (bfd_write (finfo->outsyms, outsym - finfo->outsyms, 1,
+                                output_bfd)
+                     != (bfd_size_type) (outsym - finfo->outsyms)))
+               return false;
+             obj_raw_syment_count (output_bfd) +=
+               (outsym - finfo->outsyms) / bfd_coff_symesz (output_bfd);
+
+             outsym = finfo->outsyms;
+           }
+       }
     }
 
-  if (h->indx >= 0)
-    return true;
+  /* If this symbol is a specially defined function descriptor, write
+     it out.  The first word is the address of the function code
+     itself, the second word is the address of the TOC, and the third
+     word is zero.  */
+  if ((h->flags & XCOFF_DESCRIPTOR) != 0
+      && h->root.type == bfd_link_hash_defined
+      && (h->root.u.def.section
+         == xcoff_hash_table (finfo->info)->descriptor_section))
+    {
+      asection *sec;
+      asection *osec;
+      int oindx;
+      bfd_byte *p;
+      struct xcoff_link_hash_entry *hentry;
+      asection *esec;
+      struct internal_reloc *irel;
+      struct internal_ldrel ldrel;
+      asection *tsec;
+
+      sec = h->root.u.def.section;
+      osec = sec->output_section;
+      oindx = osec->target_index;
+      p = sec->contents + h->root.u.def.value;
+
+      hentry = h->descriptor;
+      BFD_ASSERT (hentry != NULL
+                 && (hentry->root.type == bfd_link_hash_defined
+                     || hentry->root.type == bfd_link_hash_defweak));
+      esec = hentry->root.u.def.section;
+      bfd_put_32 (output_bfd,
+                 (esec->output_section->vma
+                  + esec->output_offset
+                  + hentry->root.u.def.value),
+                 p);
+
+      irel = finfo->section_info[oindx].relocs + osec->reloc_count;
+      irel->r_vaddr = (osec->vma
+                      + sec->output_offset
+                      + h->root.u.def.value);
+      irel->r_symndx = esec->output_section->target_index;
+      irel->r_type = R_POS;
+      irel->r_size = 31;
+      finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+      ++osec->reloc_count;
+
+      ldrel.l_vaddr = irel->r_vaddr;
+      if (strcmp (esec->output_section->name, ".text") == 0)
+       ldrel.l_symndx = 0;
+      else if (strcmp (esec->output_section->name, ".data") == 0)
+       ldrel.l_symndx = 1;
+      else if (strcmp (esec->output_section->name, ".bss") == 0)
+       ldrel.l_symndx = 2;
+      else
+       {
+         (*_bfd_error_handler)
+           (_("%s: loader reloc in unrecognized section `%s'"),
+            bfd_get_filename (output_bfd),
+            esec->output_section->name);
+         bfd_set_error (bfd_error_nonrepresentable_section);
+         return false;
+       }
+      ldrel.l_rtype = (31 << 8) | R_POS;
+      ldrel.l_rsecnm = oindx;
+      xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+      ++finfo->ldrel;
+
+      bfd_put_32 (output_bfd, xcoff_data (output_bfd)->toc, p + 4);
+
+      tsec = coff_section_from_bfd_index (output_bfd,
+                                         xcoff_data (output_bfd)->sntoc);
+
+      ++irel;
+      irel->r_vaddr = (osec->vma
+                      + sec->output_offset
+                      + h->root.u.def.value
+                      + 4);
+      irel->r_symndx = tsec->output_section->target_index;
+      irel->r_type = R_POS;
+      irel->r_size = 31;
+      finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+      ++osec->reloc_count;
+
+      ldrel.l_vaddr = irel->r_vaddr;
+      if (strcmp (tsec->output_section->name, ".text") == 0)
+       ldrel.l_symndx = 0;
+      else if (strcmp (tsec->output_section->name, ".data") == 0)
+       ldrel.l_symndx = 1;
+      else if (strcmp (tsec->output_section->name, ".bss") == 0)
+       ldrel.l_symndx = 2;
+      else
+       {
+         (*_bfd_error_handler)
+           (_("%s: loader reloc in unrecognized section `%s'"),
+            bfd_get_filename (output_bfd),
+            tsec->output_section->name);
+         bfd_set_error (bfd_error_nonrepresentable_section);
+         return false;
+       }
+      ldrel.l_rtype = (31 << 8) | R_POS;
+      ldrel.l_rsecnm = oindx;
+      xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+      ++finfo->ldrel;
+    }
+
+  if (h->indx >= 0 || finfo->info->strip == strip_all)
+    {
+      BFD_ASSERT (outsym == finfo->outsyms);
+      return true;
+    }
 
   if (h->indx != -2
       && (finfo->info->strip == strip_all
@@ -4722,13 +5948,17 @@ xcoff_write_global_symbol (h, p)
              && (bfd_hash_lookup (finfo->info->keep_hash,
                                   h->root.root.string, false, false)
                  == NULL))))
-    return true;
+    {
+      BFD_ASSERT (outsym == finfo->outsyms);
+      return true;
+    }
 
   if (h->indx != -2
       && (h->flags & (XCOFF_REF_REGULAR | XCOFF_DEF_REGULAR)) == 0)
-    return true;
-
-  outsym = finfo->outsyms;
+    {
+      BFD_ASSERT (outsym == finfo->outsyms);
+      return true;
+    }
 
   memset (&aux, 0, sizeof aux);
 
@@ -4760,6 +5990,16 @@ xcoff_write_global_symbol (h, p)
       isym.n_sclass = C_EXT;
       aux.x_csect.x_smtyp = XTY_ER;
     }
+  else if ((h->root.type == bfd_link_hash_defined
+           || h->root.type == bfd_link_hash_defweak)
+          && h->smclas == XMC_XO)
+    {
+      BFD_ASSERT (bfd_is_abs_section (h->root.u.def.section));
+      isym.n_value = h->root.u.def.value;
+      isym.n_scnum = N_UNDEF;
+      isym.n_sclass = C_EXT;
+      aux.x_csect.x_smtyp = XTY_ER;
+    }
   else if (h->root.type == bfd_link_hash_defined
           || h->root.type == bfd_link_hash_defweak)
     {
@@ -4810,8 +6050,9 @@ xcoff_write_global_symbol (h, p)
                         (PTR) outsym);
   outsym += bfd_coff_auxesz (output_bfd);
 
-  if (h->root.type == bfd_link_hash_defined
-      || h->root.type == bfd_link_hash_defweak)
+  if ((h->root.type == bfd_link_hash_defined
+       || h->root.type == bfd_link_hash_defweak)
+      && h->smclas != XMC_XO)
     {
       /* We just output an SD symbol.  Now output an LD symbol.  */
 
@@ -4877,9 +6118,10 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
       return false;
     }
 
-  h = xcoff_link_hash_lookup (xcoff_hash_table (finfo->info),
-                             link_order->u.reloc.p->u.name,
-                             false, false, true);
+  h = ((struct xcoff_link_hash_entry *)
+       bfd_wrapped_link_hash_lookup (output_bfd, finfo->info,
+                                    link_order->u.reloc.p->u.name,
+                                    false, false, true));
   if (h == NULL)
     {
       if (! ((*finfo->info->callbacks->unattached_reloc)
@@ -4922,10 +6164,7 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
       size = bfd_get_reloc_size (howto);
       buf = (bfd_byte *) bfd_zmalloc (size);
       if (buf == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
 
       rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
       switch (rstat)
@@ -5002,7 +6241,7 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
       else
        {
          (*_bfd_error_handler)
-           ("%s: loader reloc in unrecognized section `%s'",
+           (_("%s: loader reloc in unrecognized section `%s'"),
             bfd_get_filename (output_bfd), secname);
          bfd_set_error (bfd_error_nonrepresentable_section);
          return false;
@@ -5013,7 +6252,7 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
       if (h->ldindx < 0)
        {
          (*_bfd_error_handler)
-           ("%s: `%s' in loader reloc but not loader sym",
+           (_("%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);
@@ -5140,10 +6379,16 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
          else
            {
              sec = sections[symndx];
-              val = (sec->output_section->vma
-                    + sec->output_offset
-                    + sym->n_value
-                    - sec->vma);
+             /* Hack to make sure we use the right TOC anchor value
+                 if this reloc is against the TOC anchor.  */
+             if (sec->name[3] == '0'
+                 && strcmp (sec->name, ".tc0") == 0)
+               val = xcoff_data (output_bfd)->toc;
+             else
+               val = (sec->output_section->vma
+                      + sec->output_offset
+                      + sym->n_value
+                      - sec->vma);
            }
        }
       else
@@ -5166,19 +6411,22 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
              val = (sec->output_section->vma
                     + sec->output_offset);
            }
-         else if ((h->flags & XCOFF_REF_DYNAMIC) != 0
+         else if ((h->flags & XCOFF_DEF_DYNAMIC) != 0
                   || (h->flags & XCOFF_IMPORT) != 0)
            {
              /* Every symbol in a shared object is defined somewhere.  */
              val = 0;
            }
-         else if (! info->relocateable
-                  && ! info->shared)
+         else if (! info->relocateable)
            {
              if (! ((*info->callbacks->undefined_symbol)
                     (info, h->root.root.string, input_bfd, input_section,
                      rel->r_vaddr - input_section->vma)))
                return false;
+
+             /* Don't try to process the reloc.  It can't help, and
+                 it may generate another error.  */
+             continue;
            }
        }
 
@@ -5200,7 +6448,7 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
              not defined by the PowerOpen ABI.  */
        default:
          (*_bfd_error_handler)
-           ("%s: unsupported relocation type 0x%02x",
+           (_("%s: unsupported relocation type 0x%02x"),
             bfd_get_filename (input_bfd), (unsigned int) rel->r_type);
          bfd_set_error (bfd_error_bad_value);
          return false;
@@ -5241,21 +6489,23 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
              address instruction which may be changed to a load
              instruction.  FIXME: I don't know if this is the correct
              implementation.  */
-         if (h != NULL && h->toc_section == NULL)
-           {
-             (*_bfd_error_handler)
-               ("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry",
-                bfd_get_filename (input_bfd), rel->r_vaddr,
-                h->root.root.string);
-             bfd_set_error (bfd_error_bad_value);
-             return false;
-           }
-         if (h != NULL)
+         if (h != NULL && h->smclas != XMC_TD)
            {
+             if (h->toc_section == NULL)
+               {
+                 (*_bfd_error_handler)
+                   (_("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry"),
+                    bfd_get_filename (input_bfd), rel->r_vaddr,
+                    h->root.root.string);
+                 bfd_set_error (bfd_error_bad_value);
+                 return false;
+               }
+
              BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
              val = (h->toc_section->output_section->vma
                     + h->toc_section->output_offset);
            }
+
          val = ((val - xcoff_data (output_bfd)->toc)
                 - (sym->n_value - xcoff_data (input_bfd)->toc));
          addend = 0;
@@ -5328,7 +6578,11 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
 
          pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
          next = bfd_get_32 (input_bfd, pnext);
-         if (h->smclas == XMC_GL)
+
+         /* The _ptrgl function is magic.  It is used by the AIX
+             compiler to call a function through a pointer.  */
+         if (h->smclas == XMC_GL
+             || strcmp (h->root.root.string, "._ptrgl") == 0)
            {
              if (next == 0x4def7b82            /* cror 15,15,15 */
                  || next == 0x4ffffb82)        /* cror 31,31,31 */