bfd/
authorRichard Sandiford <rdsandiford@googlemail.com>
Sat, 14 Mar 2009 09:32:06 +0000 (09:32 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Sat, 14 Mar 2009 09:32:06 +0000 (09:32 +0000)
* libcoff-in.h (xcoff_tdata): Change debug_indices to a signed long.
* libcoff.h: Regenerate.
* xcofflink.c (xcoff_keep_symbol_p): New function, using the
"skip" logic from xcoff_link_input_bfd.
(bfd_xcoff_size_dynamic_sections): Explicitly skip dynamic
objects in a dynamic link, rather than checking whether csectpp
is null.  Always allocate debug_index for other objects,
and always go through the loop.  Update the type of debug_index
after the change above.  Read the auxillary csect information
and use xcoff_keep_symbol_p to decide whether a symbol should
be kept.  Set its debug_index to -2 if not.
(xcoff_link_input_bfd): Update the type of debug_index after
the change above and always expect it to be nonnull.  Use it to
test whether a symbol should be stripped, rather than making the
decision here.  Postpone all symbol creation to the second pass.

bfd/ChangeLog
bfd/libcoff-in.h
bfd/libcoff.h
bfd/xcofflink.c

index 0bd0d16500c94c46614fd4cd4d350cd149139279..0138510814fdd0f600bfb782ec298e928cb94c1c 100644 (file)
@@ -1,3 +1,21 @@
+2009-03-14  Richard Sandiford  <r.sandiford@uk.ibm.com>
+
+       * libcoff-in.h (xcoff_tdata): Change debug_indices to a signed long.
+       * libcoff.h: Regenerate.
+       * xcofflink.c (xcoff_keep_symbol_p): New function, using the
+       "skip" logic from xcoff_link_input_bfd.
+       (bfd_xcoff_size_dynamic_sections): Explicitly skip dynamic
+       objects in a dynamic link, rather than checking whether csectpp
+       is null.  Always allocate debug_index for other objects,
+       and always go through the loop.  Update the type of debug_index
+       after the change above.  Read the auxillary csect information
+       and use xcoff_keep_symbol_p to decide whether a symbol should
+       be kept.  Set its debug_index to -2 if not.
+       (xcoff_link_input_bfd): Update the type of debug_index after
+       the change above and always expect it to be nonnull.  Use it to
+       test whether a symbol should be stripped, rather than making the
+       decision here.  Postpone all symbol creation to the second pass.
+
 2009-03-14  Richard Sandiford  <r.sandiford@uk.ibm.com>
 
        * xcofflink.c: (xcoff_mark_symbol): Mark the TOC section when
index b1a6b598831e986a903fbd3743d5e9167dff3456..17cb3b6274ac1634e1f76444c40f0cbdc29bdba6 100644 (file)
@@ -165,7 +165,7 @@ struct xcoff_tdata
 
   /* Used by the XCOFF backend linker.  */
   asection **csects;
-  unsigned long *debug_indices;
+  long *debug_indices;
   unsigned int import_file_id;
 };
 
index 7b37d5744401797fca28f816ff90600ec2a1cc57..98cbd3d05d7804ad4773341b77dca232e8cfe892 100644 (file)
@@ -169,7 +169,7 @@ struct xcoff_tdata
 
   /* Used by the XCOFF backend linker.  */
   asection **csects;
-  unsigned long *debug_indices;
+  long *debug_indices;
   unsigned int import_file_id;
 };
 
index c6bdc9fe2c1062b626a3e9931ea5be907be26a7d..1385f9018d44b2aa400fba79f4fa503b67988549 100644 (file)
@@ -2981,6 +2981,104 @@ xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p)
 
   return TRUE;
 }
+
+/* INPUT_BFD includes XCOFF symbol ISYM, which is associated with linker
+   hash table entry H and csect CSECT.  AUX contains ISYM's auxillary
+   csect information, if any.  NAME is the function's name if the name
+   is stored in the .debug section, otherwise it is null.
+
+   Return 1 if we should include an appropriately-adjusted ISYM
+   in the output file, 0 if we should discard ISYM, or -1 if an
+   error occured.  */
+
+static int
+xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd,
+                    struct internal_syment *isym,
+                    union internal_auxent *aux,
+                    struct xcoff_link_hash_entry *h,
+                    asection *csect, const char *name)
+{
+  int smtyp;
+
+  /* If we are skipping this csect, we want to strip the symbol too.  */
+  if (csect == NULL)
+    return 0;
+
+  /* Likewise if we garbage-collected the csect.  */
+  if (xcoff_hash_table (info)->gc
+      && !bfd_is_abs_section (csect)
+      && !bfd_is_und_section (csect)
+      && (csect->flags & SEC_MARK) == 0)
+    return 0;
+
+  /* An XCOFF linker always removes C_STAT symbols.  */
+  if (isym->n_sclass == C_STAT)
+    return 0;
+
+  /* We generate the TOC anchor separately.  */
+  if (isym->n_sclass == C_HIDEXT
+      && aux->x_csect.x_smclas == XMC_TC0)
+    return 0;
+
+  /* If we are stripping all symbols, we want to discard this one.  */
+  if (info->strip == strip_all)
+    return 0;
+
+  /* We can ignore external references that were resolved by the link.  */
+  smtyp = SMTYP_SMTYP (aux->x_csect.x_smtyp);
+  if (isym->n_sclass == C_EXT
+      && smtyp == XTY_ER
+      && h->root.type != bfd_link_hash_undefined)
+    return 0;
+
+  /* We can ignore common symbols if they got defined somewhere else.  */
+  if (isym->n_sclass == C_EXT
+      && smtyp == XTY_CM
+      && (h->root.type != bfd_link_hash_common
+         || h->root.u.c.p->section != csect)
+      && (h->root.type != bfd_link_hash_defined
+         || h->root.u.def.section != csect))
+    return 0;
+
+  /* If we're discarding local symbols, check whether ISYM is local.  */
+  if (info->discard == discard_all
+      && isym->n_sclass != C_EXT
+      && (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD))
+    return 0;
+
+  /* If we're stripping debugging symbols, check whether ISYM is one.  */
+  if (info->strip == strip_debugger
+      && isym->n_scnum == N_DEBUG)
+    return 0;
+
+  /* If we are stripping symbols based on name, check how ISYM's
+     name should be handled.  */
+  if (info->strip == strip_some
+      || info->discard == discard_l)
+    {
+      char buf[SYMNMLEN + 1];
+
+      if (name == NULL)
+       {
+         name = _bfd_coff_internal_syment_name (input_bfd, isym, buf);
+         if (name == NULL)
+           return -1;
+       }
+
+      if (info->strip == strip_some
+         && bfd_hash_lookup (info->keep_hash, name, FALSE, FALSE) == NULL)
+       return 0;
+
+      if (info->discard == discard_l
+         && isym->n_sclass != C_EXT
+         && (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD)
+         && bfd_is_local_label_name (input_bfd, name))
+       return 0;
+    }
+
+  return 1;
+}
+
 /* Build the .loader section.  This is called by the XCOFF linker
    emulation before_allocation routine.  We must set the size of the
    .loader section before the linker lays out the output file.
@@ -3288,97 +3386,134 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
        goto error_return;
     }
 
-  /* Now that we've done garbage collection, figure out the contents
-     of the .debug section.  */
+  /* Now that we've done garbage collection, decide which symbols to keep,
+     and figure out the contents of the .debug section.  */
   debug_strtab = xcoff_hash_table (info)->debug_strtab;
 
   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
       asection *subdeb;
       bfd_size_type symcount;
-      unsigned long *debug_index;
+      long *debug_index;
       asection **csectpp;
+      struct xcoff_link_hash_entry **sym_hash;
       bfd_byte *esym, *esymend;
       bfd_size_type symesz;
 
       if (sub->xvec != info->output_bfd->xvec)
        continue;
-      subdeb = bfd_get_section_by_name (sub, ".debug");
-      if (subdeb == NULL || subdeb->size == 0)
-       continue;
 
-      if (info->strip == strip_all
-         || info->strip == strip_debugger
-         || info->discard == discard_all)
-       {
-         subdeb->size = 0;
-         continue;
-       }
+      if ((sub->flags & DYNAMIC) != 0
+         && !info->static_link)
+       continue;
 
       if (! _bfd_coff_get_external_symbols (sub))
        goto error_return;
 
       symcount = obj_raw_syment_count (sub);
-      debug_index = bfd_zalloc (sub, symcount * sizeof (unsigned long));
+      debug_index = bfd_zalloc (sub, symcount * sizeof (long));
       if (debug_index == NULL)
        goto error_return;
       xcoff_data (sub)->debug_indices = debug_index;
 
-      /* Grab the contents of the .debug section.  We use malloc and
-        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.  */
-      if (! bfd_malloc_and_get_section (sub, subdeb, &debug_contents))
-       goto error_return;
+      if (info->strip == strip_all
+         || info->strip == strip_debugger
+         || info->discard == discard_all)
+       /* We're stripping all debugging information, so there's no need
+          to read SUB's .debug section.  */
+       subdeb = NULL;
+      else
+       {
+         /* Grab the contents of SUB's .debug section, if any.  */
+         subdeb = bfd_get_section_by_name (sub, ".debug");
+         if (subdeb != NULL && subdeb->size > 0)
+           {
+             /* We use malloc and 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.  */
+             if (!bfd_malloc_and_get_section (sub, subdeb, &debug_contents))
+               goto error_return;
+           }
+       }
 
       csectpp = xcoff_data (sub)->csects;
+      sym_hash = obj_xcoff_sym_hashes (sub);
+      symesz = bfd_coff_symesz (sub);
+      esym = (bfd_byte *) obj_coff_external_syms (sub);
+      esymend = esym + symcount * symesz;
 
-      /* Dynamic object do not have csectpp's.  */
-      if (NULL != csectpp)
+      while (esym < esymend)
        {
-         symesz = bfd_coff_symesz (sub);
-         esym = (bfd_byte *) obj_coff_external_syms (sub);
-         esymend = esym + symcount * symesz;
+         struct internal_syment sym;
+         union internal_auxent aux;
+         const char *name;
+         int keep_p;
+
+         bfd_coff_swap_sym_in (sub, esym, &sym);
 
-         while (esym < esymend)
+         /* If this is a C_EXT or C_HIDEXT symbol, we need the csect
+            information too.  */
+         if (sym.n_sclass == C_EXT || sym.n_sclass == C_HIDEXT)
            {
-             struct internal_syment sym;
+             BFD_ASSERT (sym.n_numaux > 0);
+             bfd_coff_swap_aux_in (sub, esym + symesz * sym.n_numaux,
+                                   sym.n_type, sym.n_sclass,
+                                   sym.n_numaux - 1, sym.n_numaux, &aux);
+           }
 
-             bfd_coff_swap_sym_in (sub, (void *) esym, (void *) &sym);
+         /* If this symbol's name is stored in the debug section,
+            get a pointer to it.  */
+         if (debug_contents != NULL
+             && sym._n._n_n._n_zeroes == 0
+             && bfd_coff_symname_in_debug (sub, &sym))
+           name = (const char *) debug_contents + sym._n._n_n._n_offset;
+         else
+           name = NULL;
 
-             *debug_index = (unsigned long) -1;
+         /* Decide whether to copy this symbol to the output file.  */
+         keep_p = xcoff_keep_symbol_p (info, sub, &sym, &aux,
+                                       *sym_hash, *csectpp, name);
+         if (keep_p < 0)
+           return FALSE;
 
-             if (sym._n._n_n._n_zeroes == 0
-                 && *csectpp != NULL
-                 && (! gc
-                     || bfd_is_abs_section (*csectpp)
-                     || bfd_is_und_section (*csectpp)
-                     || ((*csectpp)->flags & SEC_MARK) != 0)
-                 && bfd_coff_symname_in_debug (sub, &sym))
+         if (!keep_p)
+           /* Use a debug_index of -2 to record that a symbol should
+              be stripped.  */
+           *debug_index = -2;
+         else
+           {
+             /* See whether we should store the symbol name in the
+                output .debug section.  */
+             if (name != NULL)
                {
-                 char *name;
                  bfd_size_type indx;
 
-                 name = (char *) debug_contents + sym._n._n_n._n_offset;
                  indx = _bfd_stringtab_add (debug_strtab, name, TRUE, TRUE);
                  if (indx == (bfd_size_type) -1)
                    goto error_return;
                  *debug_index = indx;
                }
-
-             esym += (sym.n_numaux + 1) * symesz;
-             csectpp += sym.n_numaux + 1;
-             debug_index += sym.n_numaux + 1;
+             else
+               *debug_index = -1;
            }
+
+         esym += (sym.n_numaux + 1) * symesz;
+         csectpp += sym.n_numaux + 1;
+         sym_hash += sym.n_numaux + 1;
+         debug_index += sym.n_numaux + 1;
        }
 
-      free (debug_contents);
-      debug_contents = NULL;
+      if (debug_contents)
+       {
+         free (debug_contents);
+         debug_contents = NULL;
 
-      /* Clear the size of subdeb, so that it is not included directly
-        in the output file.  */
-      subdeb->size = 0;
+         /* Clear the size of subdeb, so that it is not included directly
+            in the output file.  */
+         subdeb->size = 0;
+       }
 
       if (! info->keep_memory)
        {
@@ -3455,7 +3590,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
   struct xcoff_link_hash_entry **sym_hash;
   struct internal_syment *isymp;
   asection **csectpp;
-  unsigned long *debug_index;
+  long *debug_index;
   long *indexp;
   unsigned long output_index;
   bfd_byte *outsym;
@@ -3495,6 +3630,9 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
   if (! _bfd_coff_get_external_symbols (input_bfd))
     return FALSE;
 
+  /* Make one pass over the symbols and assign indices to symbols that
+     we have decided to keep.  Also use create .loader symbol information
+     and update information in hash table entries.  */
   esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
   esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
   sym_hash = obj_xcoff_sym_hashes (input_bfd);
@@ -3503,16 +3641,10 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
   isymp = finfo->internal_syms;
   indexp = finfo->sym_indices;
   output_index = syment_base;
-  outsym = finfo->outsyms;
-  incls = 0;
-  oline = NULL;
-
   while (esym < esym_end)
     {
-      struct internal_syment isym;
       union internal_auxent aux;
       int smtyp = 0;
-      bfd_boolean skip;
       int add;
 
       bfd_coff_swap_sym_in (input_bfd, (void *) esym, (void *) isymp);
@@ -3531,17 +3663,11 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
          smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp);
        }
 
-      /* Make a copy of *isymp so that the relocate_section function
-        always sees the original values.  This is more reliable than
-        always recomputing the symbol value even if we are stripping
-        the symbol.  */
-      isym = *isymp;
-
       /* If this symbol is in the .loader section, swap out the
         .loader symbol information.  If this is an external symbol
         reference to a defined symbol, though, then wait until we get
         to the definition.  */
-      if (isym.n_sclass == C_EXT
+      if (isymp->n_sclass == C_EXT
          && *sym_hash != NULL
          && (*sym_hash)->ldsym != NULL
          && (smtyp != XTY_ER
@@ -3552,18 +3678,18 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
 
          h = *sym_hash;
          ldsym = h->ldsym;
-         if (isym.n_scnum > 0)
+         if (isymp->n_scnum > 0)
            {
              ldsym->l_scnum = (*csectpp)->output_section->target_index;
-             ldsym->l_value = (isym.n_value
+             ldsym->l_value = (isymp->n_value
                                + (*csectpp)->output_section->vma
                                + (*csectpp)->output_offset
                                - (*csectpp)->vma);
            }
          else
            {
-             ldsym->l_scnum = isym.n_scnum;
-             ldsym->l_value = isym.n_value;
+             ldsym->l_scnum = isymp->n_scnum;
+             ldsym->l_value = isymp->n_value;
            }
 
          ldsym->l_smtype = smtyp;
@@ -3628,114 +3754,80 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
            }
        }
 
-      *indexp = -1;
-
-      skip = FALSE;
-      add = 1 + isym.n_numaux;
-
-      /* If we are skipping this csect, we want to skip this symbol.  */
-      if (*csectpp == NULL)
-       skip = TRUE;
-
-      /* If we garbage collected this csect, we want to skip this
-        symbol.  */
-      if (! skip
-         && xcoff_hash_table (finfo->info)->gc
-         && !bfd_is_abs_section (*csectpp)
-         && !bfd_is_und_section (*csectpp)
-         && ((*csectpp)->flags & SEC_MARK) == 0)
-       skip = TRUE;
-
-      /* An XCOFF linker always skips C_STAT symbols.  */
-      if (! skip
-         && isymp->n_sclass == C_STAT)
-       skip = TRUE;
-
-      /* We generate the TOC anchor separately.  */
-      if (! skip
-         && isymp->n_sclass == C_HIDEXT
-         && aux.x_csect.x_smclas == XMC_TC0)
-       skip = TRUE;
-
-      /* If we are stripping all symbols, we want to skip this one.  */
-      if (! skip
-         && finfo->info->strip == strip_all)
-       skip = TRUE;
-
-      /* We can skip resolved external references.  */
-      if (! skip
-         && isym.n_sclass == C_EXT
-         && smtyp == XTY_ER
-         && (*sym_hash)->root.type != bfd_link_hash_undefined)
-       skip = TRUE;
-
-      /* We can skip common symbols if they got defined somewhere
-        else.  */
-      if (! skip
-         && isym.n_sclass == C_EXT
-         && smtyp == XTY_CM
-         && ((*sym_hash)->root.type != bfd_link_hash_common
-             || (*sym_hash)->root.u.c.p->section != *csectpp)
-         && ((*sym_hash)->root.type != bfd_link_hash_defined
-             || (*sym_hash)->root.u.def.section != *csectpp))
-       skip = TRUE;
-
-      /* Skip local symbols if we are discarding them.  */
-      if (! skip
-         && finfo->info->discard == discard_all
-         && isym.n_sclass != C_EXT
-         && (isym.n_sclass != C_HIDEXT
-             || smtyp != XTY_SD))
-       skip = TRUE;
-
-      /* If we stripping debugging symbols, and this is a debugging
-        symbol, then skip it.  */
-      if (! skip
-         && finfo->info->strip == strip_debugger
-         && isym.n_scnum == N_DEBUG)
-       skip = TRUE;
-
-      /* If some symbols are stripped based on the name, work out the
-        name and decide whether to skip this symbol.  We don't handle
-        this correctly for symbols whose names are in the .debug
-        section; to get it right we would need a new bfd_strtab_hash
-        function to return the string given the index.  */
-      if (! skip
-         && (finfo->info->strip == strip_some
-             || finfo->info->discard == discard_l)
-         && (debug_index == NULL || *debug_index == (unsigned long) -1))
+      add = 1 + isymp->n_numaux;
+
+      if (*debug_index == -2)
+       /* We've decided to strip this symbol.  */
+       *indexp = -1;
+      else
        {
-         const char *name;
-         char buf[SYMNMLEN + 1];
+         /* Assign the next unused index to this symbol.  */
+         *indexp = output_index;
 
-         name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
+         if (isymp->n_sclass == C_EXT)
+           {
+             BFD_ASSERT (*sym_hash != NULL);
+             (*sym_hash)->indx = output_index;
+           }
 
-         if (name == NULL)
-           return FALSE;
+         /* If this is a symbol in the TOC which we may have merged
+            (class XMC_TC), remember the symbol index of the TOC
+            symbol.  */
+         if (isymp->n_sclass == C_HIDEXT
+             && aux.x_csect.x_smclas == XMC_TC
+             && *sym_hash != NULL)
+           {
+             BFD_ASSERT (((*sym_hash)->flags & XCOFF_SET_TOC) == 0);
+             BFD_ASSERT ((*sym_hash)->toc_section != NULL);
+             (*sym_hash)->u.toc_indx = output_index;
+           }
 
-         if ((finfo->info->strip == strip_some
-              && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE,
-                                   FALSE) == NULL))
-             || (finfo->info->discard == discard_l
-                 && (isym.n_sclass != C_EXT
-                     && (isym.n_sclass != C_HIDEXT
-                         || smtyp != XTY_SD))
-                 && bfd_is_local_label_name (input_bfd, name)))
-           skip = TRUE;
+         output_index += add;
        }
 
-      /* We now know whether we are to skip this symbol or not.  */
-      if (! skip)
+      esym += add * isymesz;
+      isymp += add;
+      csectpp += add;
+      sym_hash += add;
+      debug_index += add;
+      ++indexp;
+      for (--add; add > 0; --add)
+       *indexp++ = -1;
+    }
+
+  /* Now write out the symbols that we decided to keep.  */
+
+  esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
+  esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
+  isymp = finfo->internal_syms;
+  indexp = finfo->sym_indices;
+  csectpp = xcoff_data (input_bfd)->csects;
+  debug_index = xcoff_data (input_bfd)->debug_indices;
+  outsym = finfo->outsyms;
+  incls = 0;
+  oline = NULL;
+  while (esym < esym_end)
+    {
+      int add;
+
+      add = 1 + isymp->n_numaux;
+
+      if (*indexp < 0)
+       esym += add * isymesz;
+      else
        {
-         /* Adjust the symbol in order to output it.  */
+         struct internal_syment isym;
+         int i;
 
+         /* Adjust the symbol in order to output it.  */
+         isym = *isymp;
          if (isym._n._n_n._n_zeroes == 0
              && isym._n._n_n._n_offset != 0)
            {
              /* This symbol has a long name.  Enter it in the string
                 table we are building.  If *debug_index != -1, the
                 name has already been entered in the .debug section.  */
-             if (debug_index != NULL && *debug_index != (unsigned long) -1)
+             if (*debug_index >= 0)
                isym._n._n_n._n_offset = *debug_index;
              else
                {
@@ -3753,17 +3845,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
                }
            }
 
-         if (isym.n_sclass != C_BSTAT
-             && isym.n_sclass != C_ESTAT
-             && isym.n_sclass != C_DECL
-             && isym.n_scnum > 0)
-           {
-             isym.n_scnum = (*csectpp)->output_section->target_index;
-             isym.n_value += ((*csectpp)->output_section->vma
-                              + (*csectpp)->output_offset
-                              - (*csectpp)->vma);
-           }
-
          /* The value of a C_FILE symbol is the symbol index of the
             next C_FILE symbol.  The value of the last C_FILE symbol
             is -1.  We try to get this right, below, just before we
@@ -3772,10 +3853,10 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
          if (isym.n_sclass == C_FILE)
            {
              if (finfo->last_file_index != -1
-                 && finfo->last_file.n_value != (bfd_vma) output_index)
+                 && finfo->last_file.n_value != (bfd_vma) *indexp)
                {
                  /* We must correct the value of the last C_FILE entry.  */
-                 finfo->last_file.n_value = output_index;
+                 finfo->last_file.n_value = *indexp;
                  if ((bfd_size_type) finfo->last_file_index >= syment_base)
                    {
                      /* The last C_FILE symbol is in this input file.  */
@@ -3806,7 +3887,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
                    }
                }
 
-             finfo->last_file_index = output_index;
+             finfo->last_file_index = *indexp;
              finfo->last_file = isym;
            }
 
@@ -3819,84 +3900,12 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
              isym.n_value = finfo->line_filepos;
              ++incls;
            }
-
-         /* Output the symbol.  */
-
-         bfd_coff_swap_sym_out (output_bfd, (void *) &isym, (void *) outsym);
-
-         *indexp = output_index;
-
-         if (isym.n_sclass == C_EXT)
+         /* The value of a C_BSTAT symbol is the symbol table
+            index of the containing csect.  */
+         else if (isym.n_sclass == C_BSTAT)
            {
-             long indx;
-             struct xcoff_link_hash_entry *h;
-
-             indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd))
-                     / isymesz);
-             h = obj_xcoff_sym_hashes (input_bfd)[indx];
-             BFD_ASSERT (h != NULL);
-             h->indx = output_index;
-           }
-
-         /* If this is a symbol in the TOC which we may have merged
-            (class XMC_TC), remember the symbol index of the TOC
-            symbol.  */
-         if (isym.n_sclass == C_HIDEXT
-             && aux.x_csect.x_smclas == XMC_TC
-             && *sym_hash != NULL)
-           {
-             BFD_ASSERT (((*sym_hash)->flags & XCOFF_SET_TOC) == 0);
-             BFD_ASSERT ((*sym_hash)->toc_section != NULL);
-             (*sym_hash)->u.toc_indx = output_index;
-           }
-
-         output_index += add;
-         outsym += add * osymesz;
-       }
-
-      esym += add * isymesz;
-      isymp += add;
-      csectpp += add;
-      sym_hash += add;
-      if (debug_index != NULL)
-       debug_index += add;
-      ++indexp;
-      for (--add; add > 0; --add)
-       *indexp++ = -1;
-    }
-
-  /* Fix up the aux entries and the C_BSTAT symbols.  This must be
-     done in a separate pass, because we don't know the correct symbol
-     indices until we have already decided which symbols we are going
-     to keep.  */
-
-  esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
-  esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
-  isymp = finfo->internal_syms;
-  indexp = finfo->sym_indices;
-  csectpp = xcoff_data (input_bfd)->csects;
-  outsym = finfo->outsyms;
-  while (esym < esym_end)
-    {
-      int add;
-
-      add = 1 + isymp->n_numaux;
-
-      if (*indexp < 0)
-       esym += add * isymesz;
-      else
-       {
-         int i;
-
-         if (isymp->n_sclass == C_BSTAT)
-           {
-             struct internal_syment isym;
-
              bfd_vma indx;
 
-             /* The value of a C_BSTAT symbol is the symbol table
-                index of the containing csect.  */
-             bfd_coff_swap_sym_in (output_bfd, (void *) outsym, (void *) &isym);
              indx = isym.n_value;
              if (indx < obj_raw_syment_count (input_bfd))
                {
@@ -3907,10 +3916,20 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
                    isym.n_value = 0;
                  else
                    isym.n_value = symindx;
-                 bfd_coff_swap_sym_out (output_bfd, (void *) &isym,
-                                        (void *) outsym);
                }
            }
+         else if (isym.n_sclass != C_ESTAT
+                  && isym.n_sclass != C_DECL
+                  && isym.n_scnum > 0)
+           {
+             isym.n_scnum = (*csectpp)->output_section->target_index;
+             isym.n_value += ((*csectpp)->output_section->vma
+                              + (*csectpp)->output_offset
+                              - (*csectpp)->vma);
+           }
+
+         /* Output the symbol.  */
+         bfd_coff_swap_sym_out (output_bfd, (void *) &isym, (void *) outsym);
 
          esym += isymesz;
          outsym += osymesz;
@@ -4185,6 +4204,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
       indexp += add;
       isymp += add;
       csectpp += add;
+      debug_index += add;
     }
 
   /* If we swapped out a C_FILE symbol, guess that the next C_FILE