* symfile.c (add_psymbol_to_list, add_psymbol_addr_to_list):
[binutils-gdb.git] / bfd / xcofflink.c
index 189d73b50c983886cb71574d8f74ba8cedb061e6..aedc72a3ad5e66e6c8193e784f550b4ef1b6a251 100644 (file)
@@ -1,5 +1,5 @@
 /* POWER/PowerPC XCOFF linker support.
-   Copyright 1995 Free Software Foundation, Inc.
+   Copyright 1995, 1996 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.
@@ -261,7 +261,9 @@ struct xcoff_link_hash_entry
     } 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.  */
@@ -276,8 +278,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 +298,8 @@ 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)
 
   /* The storage mapping class.  */
   unsigned char smclas;
@@ -332,6 +336,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 +359,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,8 +427,12 @@ 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_out
@@ -451,12 +466,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 +507,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 +553,8 @@ xcoff_swap_ldsym_out (abfd, src, dst)
   bfd_put_32 (abfd, src->l_parm, dst->l_parm);
 }
 
+/* As it happens, we never need to swap in the ldrel structure.  */
+
 /* Swap out the ldrel structure.  */
 
 static void
@@ -529,10 +585,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 +618,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 +632,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
@@ -815,7 +867,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;
@@ -896,18 +953,14 @@ xcoff_link_add_symbols (abfd, info)
 
   if ((abfd->flags & DYNAMIC) != 0
       && ! info->static_link)
-    return xcoff_link_add_dynamic_symbols (abfd, info);
-
-  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 (! xcoff_link_add_dynamic_symbols (abfd, info))
+       return false;
+    }
 
   /* 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.  */
+     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;
@@ -928,6 +981,7 @@ xcoff_link_add_symbols (abfd, info)
        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)
@@ -941,6 +995,18 @@ xcoff_link_add_symbols (abfd, info)
       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;
+
+      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)
     {
@@ -953,6 +1019,17 @@ xcoff_link_add_symbols (abfd, info)
       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;
   else
@@ -967,10 +1044,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 *));
@@ -981,10 +1055,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 *));
 
@@ -994,13 +1065,10 @@ 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));
 
@@ -1016,12 +1084,9 @@ xcoff_link_add_symbols (abfd, info)
            xcoff_read_internal_relocs (abfd, o, true, (bfd_byte *) NULL,
                                        false, (struct internal_reloc *) NULL);
          reloc_info[o->target_index].csects =
-           (asection **) malloc (o->reloc_count * sizeof (asection *));
+           (asection **) bfd_malloc (o->reloc_count * sizeof (asection *));
          if (reloc_info[o->target_index].csects == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             goto error_return;
-           }
+           goto error_return;
          memset (reloc_info[o->target_index].csects, 0,
                  o->reloc_count * sizeof (asection *));
        }
@@ -1031,12 +1096,9 @@ xcoff_link_add_symbols (abfd, info)
        {
          bfd_byte *linenos;
 
-         linenos = (bfd_byte *) malloc (o->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;
-           }
+           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)
@@ -1218,7 +1280,16 @@ xcoff_link_add_symbols (abfd, info)
              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:
@@ -1404,17 +1475,11 @@ xcoff_link_add_symbols (abfd, info)
              ((struct coff_section_tdata *)
               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;
@@ -1537,17 +1602,11 @@ xcoff_link_add_symbols (abfd, info)
            ((struct coff_section_tdata *)
             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)
@@ -1564,6 +1623,33 @@ 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)
+       {
+         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.  */
 
@@ -1738,9 +1824,13 @@ 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;
                    }
                }
@@ -1807,9 +1897,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 = NULL;
+  struct internal_ldhdr ldhdr;
+  const char *strings;
+  struct external_ldsym *elsym, *elsymend;
   struct xcoff_import_file *n;
   const char *bname;
   const char *mname;
@@ -1825,75 +1917,124 @@ xcoff_link_add_dynamic_symbols (abfd, info)
        ("%s: XCOFF shared object when not producing XCOFF output",
         bfd_get_filename (abfd));
       bfd_set_error (bfd_error_invalid_operation);
-      return false;
+      goto error_return;
+    }
+
+  /* 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);
+      goto error_return;
     }
 
+  buf = (bfd_byte *) bfd_malloc (lsec->_raw_size);
+  if (buf == NULL && lsec->_raw_size > 0)
+    goto error_return;
+
+  if (! bfd_get_section_contents (abfd, lsec, (PTR) buf, (file_ptr) 0,
+                                 lsec->_raw_size))
+    goto error_return;
+
   /* 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 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.  */
 
-         /* 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)
-           {
-             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)
-               {
-                 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;
-               }
-           }
+      h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true,
+                                 true, true);
+      if (h == NULL)
+       goto error_return;
+
+      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;
+
+      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.  */
        }
 
-      esym += (sym.n_numaux + 1) * symesz;
+      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 (buf != NULL)
+    {
+      free (buf);
+      buf = NULL;
     }
 
   /* Record this file in the import files.  */
@@ -1901,10 +2042,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;
-    }
+    goto error_return;
   n->next = NULL;
 
   /* For some reason, the path entry in the import file list for a
@@ -1938,6 +2076,11 @@ xcoff_link_add_dynamic_symbols (abfd, info)
   xcoff_data (abfd)->import_file_id = c;
 
   return true;
+
+ error_return:
+  if (buf != NULL)
+    free (buf);
+  return false;
 }
 \f
 /* Routines that are called after all the input files have been
@@ -2066,12 +2209,12 @@ 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
-                             || info->shared)
                          && (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
+                             || info->shared)))
                    break;
                  /* Fall through.  */
                case R_POS:
@@ -2132,6 +2275,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
@@ -2168,10 +2312,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;
@@ -2204,7 +2345,9 @@ bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile,
 
   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,
@@ -2223,10 +2366,7 @@ bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile,
       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;
-       }
+       return false;
     }
 
   if (imppath == NULL)
@@ -2255,10 +2395,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;
@@ -2291,10 +2428,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;
 }
 
@@ -2367,6 +2542,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.  */
@@ -2382,12 +2559,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;
@@ -2398,10 +2586,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;
@@ -2413,11 +2604,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;
@@ -2475,6 +2671,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.  */
@@ -2526,10 +2735,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,
@@ -2574,27 +2780,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
@@ -2631,10 +2837,7 @@ 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
@@ -2642,12 +2845,9 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
         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;
@@ -2724,6 +2924,11 @@ xcoff_build_ldsyms (h, p)
   struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
   size_t len;
 
+  /* If all defined symbols should be exported, mark them now.  */
+  if (ldinfo->export_defineds
+      && (h->flags & XCOFF_DEF_REGULAR) != 0)
+    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
@@ -2735,17 +2940,17 @@ 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,
-     or if we are creating a dynamic object and it is not defined at
-     all, 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 not
+     defined at all when building a shared 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 ((h->flags & XCOFF_CALLED) != 0
-      && (h->flags & XCOFF_DEF_REGULAR) == 0
       && (h->root.type == bfd_link_hash_undefined
          || h->root.type == bfd_link_hash_undefweak)
-      && ((h->flags & XCOFF_REF_DYNAMIC) != 0
-         || ldinfo->info->shared)
       && h->root.root.string[0] == '.'
+      && h->descriptor != NULL
+      && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0
+         || ldinfo->info->shared)
       && (! xcoff_hash_table (ldinfo->info)->gc
          || (h->flags & XCOFF_MARK) != 0))
     {
@@ -2757,6 +2962,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
@@ -2764,9 +2970,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
-                     || ldinfo->info->shared));
+                 && (hds->flags & XCOFF_DEF_REGULAR) == 0);
       hds->flags |= XCOFF_MARK;
       if (hds->toc_section == NULL)
        {
@@ -2784,6 +2988,53 @@ 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)
+           ("attempt to export undefined symbol `%s'",
+            h->root.root.string);
+         ldinfo->failed = true;
+         bfd_set_error (bfd_error_invalid_operation);
+         return false;
+       }
+    }
+
   /* 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.  */
@@ -2838,7 +3089,6 @@ xcoff_build_ldsyms (h, p)
       if (h->ldsym == NULL)
        {
          ldinfo->failed = true;
-         bfd_set_error (bfd_error_no_memory);
          return false;
        }
     }
@@ -2865,15 +3115,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;
@@ -2949,6 +3195,48 @@ _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;
+
+             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)
     {
@@ -3014,6 +3302,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)
            {
@@ -3042,72 +3333,18 @@ _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;
-       }
-    }
-
   /* Allocate space for the pointers we need to keep for the relocs.  */
   {
     unsigned int i;
 
     /* 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;
@@ -3116,24 +3353,20 @@ _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;
-       }
+         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
@@ -3149,21 +3382,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.  */
@@ -3190,25 +3436,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;
@@ -3410,13 +3653,18 @@ _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,
                                     o->output_offset, o->_raw_size))
     goto error_return;
   o = xcoff_hash_table (info)->toc_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;
+  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))
@@ -3630,11 +3878,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)
@@ -3712,12 +3960,33 @@ 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.  If the TOC anchor is too far into the .toc
+                 section, the relocation routine will report
+                 overflows.  */
+             tocend = ((*csectpp)->output_section->vma
+                       + (*csectpp)->output_section->_raw_size);
+             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 = tocval;
              xcoff_data (finfo->output_bfd)->toc_section =
                (*csectpp)->output_section;
              require = true;
@@ -4380,10 +4649,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;
@@ -4641,11 +4907,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)
@@ -4694,7 +4960,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)
@@ -4739,6 +5005,109 @@ xcoff_write_global_symbol (h, p)
       ++finfo->ldrel;
     }
 
+  /* 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 = xcoff_data (output_bfd)->toc_section;
+
+      ++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)
     return true;
 
@@ -4948,10 +5317,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)
@@ -5166,10 +5532,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
@@ -5192,7 +5564,7 @@ _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.  */