dummy commit before egcs merge
[deliverable/binutils-gdb.git] / bfd / xcofflink.c
index 9a52a9c045746025712e9756171b48a0d73d2a6a..6eb4eb3732bee44b3900e10ce8ce6fb7aec0abaa 100644 (file)
@@ -1,5 +1,5 @@
 /* POWER/PowerPC XCOFF linker support.
-   Copyright 1995, 1996 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997 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.  */
@@ -300,6 +302,8 @@ struct xcoff_link_hash_entry
 #define XCOFF_HAS_SIZE (04000)
   /* Symbol is a function descriptor.  */
 #define XCOFF_DESCRIPTOR (010000)
+  /* Multiple definitions have been for the symbol.  */
+#define XCOFF_MULTIPLY_DEFINED (020000)
 
   /* The storage mapping class.  */
   unsigned char smclas;
@@ -441,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 *));
@@ -457,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
@@ -606,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;
 
@@ -713,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;
@@ -1061,12 +1069,21 @@ _bfd_xcoff_bfd_link_add_symbols (abfd, info)
     {
     case bfd_object:
       return xcoff_link_add_object_symbols (abfd, info);
+
     case bfd_archive:
-      /* We need to look through the archive for stripped dynamic
-         objects, because they will not appear in the archive map even
-         though they should, perhaps, be included.  Also, if the
-         linker has no map, we just consider each object file in turn,
-         since that apparently is what the AIX native linker does.  */
+      /* If the archive has a map, do the usual search.  We then need
+         to check the archive for stripped dynamic objects, because
+         they will not appear in the archive map even though they
+         should, perhaps, be included.  If the archive has no map, we
+         just consider each object file in turn, since that apparently
+         is what the AIX native linker does.  */
+      if (bfd_has_map (abfd))
+       {
+         if (! (_bfd_generic_link_add_archive_symbols
+                (abfd, info, xcoff_link_check_archive_element)))
+           return false;
+       }
+
       {
        bfd *member;
 
@@ -1087,15 +1104,10 @@ _bfd_xcoff_bfd_link_add_symbols (abfd, info)
              }
            member = bfd_openr_next_archived_file (abfd, member);
          }
-
-       if (! bfd_has_map (abfd))
-         return true;
-
-       /* Now do the usual search.  */
-       return (_bfd_generic_link_add_archive_symbols
-               (abfd, info, xcoff_link_check_archive_element));
       }
 
+      return true;
+
     default:
       bfd_set_error (bfd_error_wrong_format);
       return false;
@@ -1402,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)
     {
@@ -1565,7 +1579,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;
@@ -1929,8 +1942,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 =
@@ -2056,8 +2068,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 =
@@ -2124,12 +2135,25 @@ xcoff_link_add_symbols (abfd, info)
              || sym._n._n_n._n_offset == 0)
            copy = true;
 
+         /* The AIX linker appears to only detect multiple symbol
+            definitions when there is a reference to the symbol.  If
+            a symbol is defined multiple times, and the only
+            references are from the same object file, the AIX linker
+            appears to permit it.  It does not merge the different
+            definitions, but handles them independently.  On the
+            other hand, if there is a reference, the linker reports
+            an error.
+
+            This matters because the AIX <net/net_globals.h> header
+            file actually defines an initialized array, so we have to
+            actually permit that to work.
+
+            We also have to handle the case of statically linking a
+            shared object, which will cause symbol redefinitions,
+            although this is an easier case to detect.  */
+
          if (info->hash->creator == abfd->xvec)
            {
-             /* If we are statically linking a shared object, it is
-                 OK for symbol redefinitions to occur.  I can't figure
-                 out just what the XCOFF linker is doing, but
-                 something like this is required for -bnso to work.  */
              if (! bfd_is_und_section (section))
                *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
                                                    name, true, copy, false);
@@ -2144,25 +2168,71 @@ xcoff_link_add_symbols (abfd, info)
                  && ! bfd_is_und_section (section)
                  && ! bfd_is_com_section (section))
                {
-                 /* If the existing symbol is to global linkage code,
-                     and this symbol is not global linkage code, then
-                     replace the existing symbol.  */
+                 /* This is a second definition of a defined symbol.  */
                  if ((abfd->flags & DYNAMIC) != 0
                      && ((*sym_hash)->smclas != XMC_GL
                          || aux.x_csect.x_smclas == XMC_GL
                          || ((*sym_hash)->root.u.def.section->owner->flags
                              & DYNAMIC) == 0))
                    {
+                     /* The new symbol is from a shared library, and
+                         either the existing symbol is not global
+                         linkage code or this symbol is global linkage
+                         code.  If the existing symbol is global
+                         linkage code and the new symbol is not, then
+                         we want to use the new symbol.  */
                      section = bfd_und_section_ptr;
                      value = 0;
                    }
                  else if (((*sym_hash)->root.u.def.section->owner->flags
                            & DYNAMIC) != 0)
                    {
+                     /* The existing symbol is from a shared library.
+                         Replace it.  */
                      (*sym_hash)->root.type = bfd_link_hash_undefined;
                      (*sym_hash)->root.u.undef.abfd =
                        (*sym_hash)->root.u.def.section->owner;
                    }
+                 else if ((*sym_hash)->root.next != NULL
+                          || info->hash->undefs_tail == &(*sym_hash)->root)
+                   {
+                     /* This symbol has been referenced.  In this
+                         case, we just continue and permit the
+                         multiple definition error.  See the comment
+                         above about the behaviour of the AIX linker.  */
+                   }
+                 else if ((*sym_hash)->smclas == aux.x_csect.x_smclas)
+                   {
+                     /* The symbols are both csects of the same
+                         class.  There is at least a chance that this
+                         is a semi-legitimate redefinition.  */
+                     section = bfd_und_section_ptr;
+                     value = 0;
+                     (*sym_hash)->flags |= XCOFF_MULTIPLY_DEFINED;
+                   }
+               }
+             else if (((*sym_hash)->flags & XCOFF_MULTIPLY_DEFINED) != 0
+                      && ((*sym_hash)->root.type == bfd_link_hash_defined
+                          || (*sym_hash)->root.type == bfd_link_hash_defweak)
+                      && (bfd_is_und_section (section)
+                          || bfd_is_com_section (section)))
+               {
+                 /* This is a reference to a multiply defined symbol.
+                    Report the error now.  See the comment above
+                    about the behaviour of the AIX linker.  We could
+                    also do this with warning symbols, but I'm not
+                    sure the XCOFF linker is wholly prepared to
+                    handle them, and that would only be a warning,
+                    not an error.  */
+                 if (! ((*info->callbacks->multiple_definition)
+                        (info, (*sym_hash)->root.root.string,
+                         (bfd *) NULL, (asection *) NULL, 0,
+                         (*sym_hash)->root.u.def.section->owner,
+                         (*sym_hash)->root.u.def.section,
+                         (*sym_hash)->root.u.def.value)))
+                   goto error_return;
+                 /* Try not to give this error too many times.  */
+                 (*sym_hash)->flags &= ~XCOFF_MULTIPLY_DEFINED;
                }
            }
 
@@ -2495,6 +2565,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)
@@ -2675,7 +2800,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))))
@@ -2825,16 +2949,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;
@@ -2867,7 +2987,7 @@ bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile,
          *pp = n;
        }
 
-      h->ldsym->l_ifile = c;
+      h->ldindx = c;
     }
 
   return true;
@@ -3300,7 +3420,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.  */
@@ -3401,7 +3521,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.  */
@@ -3414,17 +3574,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
@@ -3554,20 +3713,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;
@@ -3742,7 +3900,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
@@ -3811,7 +3968,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.  */
@@ -3902,9 +4060,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;
@@ -4029,12 +4187,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)
     {
@@ -4552,8 +4707,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;
        }
 
@@ -5120,6 +5274,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
            {
              struct xcoff_link_hash_entry *h = NULL;
              struct internal_ldrel ldrel;
+             boolean quiet;
 
              *rel_hash = NULL;
 
@@ -5245,6 +5400,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                    }
                }
 
+             quiet = false;
              switch (irel->r_type)
                {
                default:
@@ -5296,7 +5452,17 @@ xcoff_link_input_bfd (finfo, input_bfd)
                    }
                  else
                    {
-                     if (h->ldindx < 0)
+                     if (! finfo->info->relocateable
+                         && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+                         && (h->flags & XCOFF_IMPORT) == 0)
+                       {
+                         /* We already called the undefined_symbol
+                            callback for this relocation, in
+                            _bfd_ppc_xcoff_relocate_section.  Don't
+                            issue any more warnings.  */
+                         quiet = true;
+                       }
+                     if (h->ldindx < 0 && ! quiet)
                        {
                          (*_bfd_error_handler)
                            ("%s: `%s' in loader reloc but not loader sym",
@@ -5310,7 +5476,8 @@ xcoff_link_input_bfd (finfo, input_bfd)
                  ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
                  ldrel.l_rsecnm = o->output_section->target_index;
                  if (xcoff_hash_table (finfo->info)->textro
-                     && strcmp (o->output_section->name, ".text") == 0)
+                     && strcmp (o->output_section->name, ".text") == 0
+                     && ! quiet)
                    {
                      (*_bfd_error_handler)
                        ("%s: loader reloc in read-only section %s",
@@ -5377,6 +5544,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
@@ -5485,6 +5653,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;
@@ -5512,6 +5682,63 @@ 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 (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
@@ -5619,7 +5846,10 @@ xcoff_write_global_symbol (h, p)
     }
 
   if (h->indx >= 0)
-    return true;
+    {
+      BFD_ASSERT (outsym == finfo->outsyms);
+      return true;
+    }
 
   if (h->indx != -2
       && (finfo->info->strip == strip_all
@@ -5627,13 +5857,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);
 
@@ -5665,6 +5899,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)
     {
@@ -5715,8 +5959,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.  */
 
@@ -6087,6 +6332,10 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
                     (info, h->root.root.string, input_bfd, input_section,
                      rel->r_vaddr - input_section->vma)))
                return false;
+
+             /* Don't try to process the reloc.  It can't help, and
+                 it may generate another error.  */
+             continue;
            }
        }
 
This page took 0.047776 seconds and 4 git commands to generate.