import gdb-2000-02-02 snapshot
[external/binutils.git] / bfd / xcofflink.c
index 3892f17..9ec75bd 100644 (file)
@@ -1,5 +1,5 @@
 /* POWER/PowerPC XCOFF linker support.
-   Copyright 1995, 1996 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.
@@ -269,7 +269,9 @@ struct xcoff_link_hash_entry
   /* 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.  */
@@ -443,6 +445,7 @@ 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 *));
@@ -459,6 +462,8 @@ static bfd_size_type xcoff_find_reloc
 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
@@ -608,7 +613,8 @@ xcoff_get_section_contents (abfd, sec)
 
   if (coff_section_data (abfd, sec)->contents == NULL)
     {
-      coff_section_data (abfd, sec)->contents = bfd_malloc (sec->_raw_size);
+      coff_section_data (abfd, sec)->contents =
+       (bfd_byte *) bfd_malloc (sec->_raw_size);
       if (coff_section_data (abfd, sec)->contents == NULL)
        return false;
 
@@ -715,7 +721,7 @@ _bfd_xcoff_canonicalize_dynamic_symtab (abfd, psyms)
            if (ldsym._l._l_name[i] == '\0')
              break;
          if (i < SYMNMLEN)
-           symbuf->symbol.name = elsym->_l._l_name;
+           symbuf->symbol.name = (char *) elsym->_l._l_name;
          else
            {
              char *c;
@@ -1408,6 +1414,8 @@ 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)
     {
@@ -1470,7 +1478,8 @@ xcoff_link_add_symbols (abfd, info)
          dsec->alignment_power = 2;
        }
       /* Likewise for the .debug section.  */
-      if (xcoff_hash_table (info)->debug_section == NULL)
+      if (xcoff_hash_table (info)->debug_section == NULL
+         && info->strip != strip_all)
        {
          asection *dsec;
 
@@ -1571,7 +1580,6 @@ xcoff_link_add_symbols (abfd, info)
     }
 
   /* 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;
@@ -1650,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;
@@ -1702,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;
@@ -1725,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;
@@ -1737,7 +1745,7 @@ 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);
@@ -1776,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);
@@ -1900,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;
@@ -1919,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;
@@ -1935,8 +1943,7 @@ 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)
              goto error_return;
            coff_section_data (abfd, csect)->tdata =
@@ -2024,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;
@@ -2036,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)
            {
@@ -2047,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;
@@ -2062,8 +2075,7 @@ 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)
            goto error_return;
          coff_section_data (abfd, csect)->tdata =
@@ -2143,6 +2155,14 @@ xcoff_link_add_symbols (abfd, info)
             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.  */
@@ -2188,6 +2208,14 @@ xcoff_link_add_symbols (abfd, info)
                      (*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)
                    {
@@ -2314,7 +2342,7 @@ xcoff_link_add_symbols (abfd, info)
              if (*rel_csect == NULL)
                {
                  (*_bfd_error_handler)
-                   ("%s: reloc %s:%d not in csect",
+                   (_("%s: reloc %s:%d not in csect"),
                     bfd_get_filename (abfd), o->name, i);
                  bfd_set_error (bfd_error_bad_value);
                  goto error_return;
@@ -2449,7 +2477,7 @@ 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;
@@ -2470,7 +2498,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
   if (lsec == NULL)
     {
       (*_bfd_error_handler)
-       ("%s: dynamic object with no .loader section",
+       (_("%s: dynamic object with no .loader section"),
         bfd_get_filename (abfd));
       bfd_set_error (bfd_error_no_symbols);
       return false;
@@ -2560,6 +2588,61 @@ xcoff_link_add_dynamic_symbols (abfd, info)
          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)
+           {
+             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)
+               {
+                 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;
+           }
+       }
     }
 
   if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
@@ -2630,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;
@@ -2658,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;
@@ -2740,7 +2825,6 @@ xcoff_mark (info, sec)
                          && h->root.root.string[0] == '.'
                          && h->descriptor != NULL
                          && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0
-                             || info->shared
                              || ((h->descriptor->flags & XCOFF_IMPORT) != 0
                                  && (h->descriptor->flags
                                      & XCOFF_DEF_REGULAR) == 0))))
@@ -2870,6 +2954,42 @@ 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)
@@ -2890,16 +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)
-       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;
@@ -2932,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;
@@ -2945,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;
 
@@ -3022,7 +3138,7 @@ bfd_xcoff_link_count_reloc (output_bfd, info, name)
                                     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;
     }
@@ -3156,10 +3272,15 @@ 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)
-    hentry->flags |= XCOFF_ENTRY;
+  if (entry == NULL)
+    hentry = NULL;
+  else
+    {
+      hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry,
+                                      false, false, true);
+      if (hentry != NULL)
+       hentry->flags |= XCOFF_ENTRY;
+    }
 
   /* Garbage collect unused sections.  */
   if (info->relocateable
@@ -3365,7 +3486,7 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
       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.  */
@@ -3425,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;
 
@@ -3457,7 +3579,8 @@ xcoff_build_ldsyms (h, p)
       && (h->flags & XCOFF_DEF_REGULAR) == 0
       && (h->flags & XCOFF_REF_REGULAR) != 0
       && (h->flags & XCOFF_DEF_DYNAMIC) == 0
-      && (h->root.u.def.section->owner->flags & 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
@@ -3466,7 +3589,47 @@ xcoff_build_ldsyms (h, p)
   if (ldinfo->export_defineds
       && (h->flags & XCOFF_DEF_REGULAR) != 0
       && h->root.root.string[0] != '.')
-    h->flags |= XCOFF_EXPORT;
+    {
+      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.  */
@@ -3479,17 +3642,16 @@ xcoff_build_ldsyms (h, p)
              != ldinfo->info->hash->creator)))
     h->flags |= XCOFF_MARK;
 
-  /* If this symbol is called and defined in a dynamic object, or not
-     defined at all when building a shared object, or 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 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->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
-         || ldinfo->info->shared
          || ((h->descriptor->flags & XCOFF_IMPORT) != 0
              && (h->descriptor->flags & XCOFF_DEF_REGULAR) == 0))
       && (! xcoff_hash_table (ldinfo->info)->gc
@@ -3568,7 +3730,7 @@ xcoff_build_ldsyms (h, p)
       else
        {
          (*_bfd_error_handler)
-           ("warning: attempt to export undefined symbol `%s'",
+           (_("warning: attempt to export undefined symbol `%s'"),
             h->root.root.string);
          h->ldsym = NULL;
          return true;
@@ -3619,20 +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;
-         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;
@@ -3807,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
@@ -3876,7 +4036,8 @@ _bfd_xcoff_bfd_final_link (abfd, info)
            }
        }
 
-      bfd_coff_compute_section_file_positions (abfd);
+      if (! bfd_coff_compute_section_file_positions (abfd))
+       goto error_return;
     }
 
   /* Allocate space for the pointers we need to keep for the relocs.  */
@@ -3909,9 +4070,17 @@ _bfd_xcoff_bfd_final_link (abfd, info)
        o->rel_filepos = 0;
       else
        {
-         o->flags |= SEC_RELOC;
-         o->rel_filepos = rel_filepos;
-         rel_filepos += o->reloc_count * relsz;
+         /* 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;
+           }
 
          /* We don't know the indices of global symbols until we have
              written out all the local symbols.  For each section in
@@ -3967,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;
@@ -4094,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)
     {
@@ -4109,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;
 
@@ -4524,7 +4697,8 @@ xcoff_link_input_bfd (finfo, input_bfd)
                  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.  */
+                 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);
@@ -4532,7 +4706,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
              if (tocval + 0x10000 < tocend)
                {
                  (*_bfd_error_handler)
-                   ("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling",
+                   (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling"),
                     (unsigned long) (tocend - tocval));
                  bfd_set_error (bfd_error_file_too_big);
                  return false;
@@ -4617,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;
        }
 
@@ -5195,9 +5368,13 @@ 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
                      && h->smclas != XMC_TD
                      && (irel->r_type == R_TOC
@@ -5354,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);
@@ -5376,7 +5553,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                      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);
@@ -5391,7 +5568,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                      && ! 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));
@@ -5455,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
@@ -5563,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;
@@ -5590,6 +5770,66 @@ 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 this symbol is a specially defined function descriptor, write
@@ -5647,7 +5887,7 @@ xcoff_write_global_symbol (h, p)
       else
        {
          (*_bfd_error_handler)
-           ("%s: loader reloc in unrecognized section `%s'",
+           (_("%s: loader reloc in unrecognized section `%s'"),
             bfd_get_filename (output_bfd),
             esec->output_section->name);
          bfd_set_error (bfd_error_nonrepresentable_section);
@@ -5684,7 +5924,7 @@ xcoff_write_global_symbol (h, p)
       else
        {
          (*_bfd_error_handler)
-           ("%s: loader reloc in unrecognized section `%s'",
+           (_("%s: loader reloc in unrecognized section `%s'"),
             bfd_get_filename (output_bfd),
             tsec->output_section->name);
          bfd_set_error (bfd_error_nonrepresentable_section);
@@ -5696,8 +5936,11 @@ xcoff_write_global_symbol (h, p)
       ++finfo->ldrel;
     }
 
-  if (h->indx >= 0)
-    return true;
+  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
@@ -5705,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);
 
@@ -5743,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)
     {
@@ -5793,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.  */
 
@@ -5983,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;
@@ -5994,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);
@@ -6190,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;
@@ -6236,7 +6494,7 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
              if (h->toc_section == NULL)
                {
                  (*_bfd_error_handler)
-                   ("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry",
+                   (_("%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);