]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/cofflink.c
[PATCH] fix windmc typedef bug
[thirdparty/binutils-gdb.git] / bfd / cofflink.c
index 12a693e0edad2006252900cab3015d6af188a59b..27ac20e80da814065c61f250c0eac5072e7615f5 100644 (file)
@@ -1,6 +1,5 @@
 /* COFF specific linker code.
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1994-2020 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
 #include "libcoff.h"
 #include "safe-ctype.h"
 
-static bfd_boolean coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info);
-static bfd_boolean coff_link_check_archive_element (bfd *abfd, struct bfd_link_info *info, bfd_boolean *pneeded);
-static bfd_boolean coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info);
+static bfd_boolean coff_link_add_object_symbols (bfd *, struct bfd_link_info *);
+static bfd_boolean coff_link_check_archive_element
+  (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
+   bfd_boolean *);
+static bfd_boolean coff_link_add_symbols (bfd *, struct bfd_link_info *);
 
 /* Return TRUE if SYM is a weak, external symbol.  */
 #define IS_WEAK_EXTERNAL(abfd, sym)                    \
@@ -108,7 +109,7 @@ struct bfd_link_hash_table *
 _bfd_coff_link_hash_table_create (bfd *abfd)
 {
   struct coff_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct coff_link_hash_table);
+  size_t amt = sizeof (struct coff_link_hash_table);
 
   ret = (struct coff_link_hash_table *) bfd_malloc (amt);
   if (ret == NULL)
@@ -191,72 +192,6 @@ coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 
-/* Look through the symbols to see if this object file should be
-   included in the link.  */
-
-static bfd_boolean
-coff_link_check_ar_symbols (bfd *abfd,
-                           struct bfd_link_info *info,
-                           bfd_boolean *pneeded)
-{
-  bfd_size_type symesz;
-  bfd_byte *esym;
-  bfd_byte *esym_end;
-
-  *pneeded = FALSE;
-
-  symesz = bfd_coff_symesz (abfd);
-  esym = (bfd_byte *) obj_coff_external_syms (abfd);
-  esym_end = esym + obj_raw_syment_count (abfd) * symesz;
-  while (esym < esym_end)
-    {
-      struct internal_syment sym;
-      enum coff_symbol_classification classification;
-
-      bfd_coff_swap_sym_in (abfd, esym, &sym);
-
-      classification = bfd_coff_classify_symbol (abfd, &sym);
-      if (classification == COFF_SYMBOL_GLOBAL
-         || classification == COFF_SYMBOL_COMMON)
-       {
-         const char *name;
-         char buf[SYMNMLEN + 1];
-         struct bfd_link_hash_entry *h;
-
-         /* This symbol is externally visible, and is defined by this
-             object file.  */
-         name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
-         if (name == NULL)
-           return FALSE;
-         h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
-
-         /* Auto import.  */
-         if (!h
-             && info->pei386_auto_import
-             && CONST_STRNEQ (name, "__imp_"))
-           h = bfd_link_hash_lookup (info->hash, name + 6, FALSE, FALSE, TRUE);
-
-         /* We are only interested in symbols that are currently
-            undefined.  If a symbol is currently known to be common,
-            COFF linkers do not bring in an object file which defines
-            it.  */
-         if (h != (struct bfd_link_hash_entry *) NULL
-             && h->type == bfd_link_hash_undefined)
-           {
-             if (! (*info->callbacks->add_archive_element) (info, abfd, name))
-               return FALSE;
-             *pneeded = TRUE;
-             return TRUE;
-           }
-       }
-
-      esym += (sym.n_numaux + 1) * symesz;
-    }
-
-  /* We do not need this object file.  */
-  return TRUE;
-}
-
 /* Check a single archive element to see if we need to include it in
    the link.  *PNEEDED is set according to whether this element is
    needed in the link or not.  This is called via
@@ -265,23 +200,28 @@ coff_link_check_ar_symbols (bfd *abfd,
 static bfd_boolean
 coff_link_check_archive_element (bfd *abfd,
                                 struct bfd_link_info *info,
+                                struct bfd_link_hash_entry *h,
+                                const char *name,
                                 bfd_boolean *pneeded)
 {
-  if (! _bfd_coff_get_external_symbols (abfd))
-    return FALSE;
+  *pneeded = FALSE;
 
-  if (! coff_link_check_ar_symbols (abfd, info, pneeded))
-    return FALSE;
+  /* We are only interested in symbols that are currently undefined.
+     If a symbol is currently known to be common, COFF linkers do not
+     bring in an object file which defines it.  */
+  if (h->type != bfd_link_hash_undefined)
+    return TRUE;
 
-  if (*pneeded
-      && ! coff_link_add_symbols (abfd, info))
-    return FALSE;
+  /* PR 22369 - Skip non COFF objects in the archive.  */
+  if (! bfd_family_coff (abfd))
+    return TRUE;
 
-  if ((! info->keep_memory || ! *pneeded)
-      && ! _bfd_coff_free_symbols (abfd))
-    return FALSE;
+  /* Include this element?  */
+  if (!(*info->callbacks->add_archive_element) (info, abfd, name, &abfd))
+    return TRUE;
+  *pneeded = TRUE;
 
-  return TRUE;
+  return bfd_link_add_symbols (abfd, info);
 }
 
 /* Add all the symbols from an object file to the hash table.  */
@@ -354,7 +294,7 @@ coff_link_add_symbols (bfd *abfd,
            goto error_return;
 
          /* We must copy the name into memory if we got it from the
-             syment itself, rather than the string table.  */
+            syment itself, rather than the string table.  */
          copy = default_copy;
          if (sym._n._n_n._n_zeroes != 0
              || sym._n._n_n._n_offset == 0)
@@ -370,7 +310,9 @@ coff_link_add_symbols (bfd *abfd,
            case COFF_SYMBOL_GLOBAL:
              flags = BSF_EXPORT | BSF_GLOBAL;
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
-             if (! obj_pe (abfd))
+             if (discarded_section (section))
+               section = bfd_und_section_ptr;
+             else if (! obj_pe (abfd))
                value -= section->vma;
              break;
 
@@ -387,6 +329,8 @@ coff_link_add_symbols (bfd *abfd,
            case COFF_SYMBOL_PE_SECTION:
              flags = BSF_SECTION_SYM | BSF_GLOBAL;
              section = coff_section_from_bfd_index (abfd, sym.n_scnum);
+             if (discarded_section (section))
+               section = bfd_und_section_ptr;
              break;
            }
 
@@ -396,8 +340,8 @@ coff_link_add_symbols (bfd *abfd,
          addit = TRUE;
 
          /* In the PE format, section symbols actually refer to the
-             start of the output section.  We handle them specially
-             here.  */
+            start of the output section.  We handle them specially
+            here.  */
          if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0)
            {
              *sym_hash = coff_link_hash_lookup (coff_hash_table (info),
@@ -408,8 +352,8 @@ coff_link_add_symbols (bfd *abfd,
                       & COFF_LINK_HASH_PE_SECTION_SYMBOL) == 0
                      && (*sym_hash)->root.type != bfd_link_hash_undefined
                      && (*sym_hash)->root.type != bfd_link_hash_undefweak)
-                   (*_bfd_error_handler)
-                     ("Warning: symbol `%s' is both section and non-section",
+                   _bfd_error_handler
+                     (_("warning: symbol `%s' is both section and non-section"),
                       name);
 
                  addit = FALSE;
@@ -471,10 +415,10 @@ coff_link_add_symbols (bfd *abfd,
              COFF_LINK_HASH_PE_SECTION_SYMBOL;
 
          /* Limit the alignment of a common symbol to the possible
-             alignment of a section.  There is no point to permitting
-             a higher alignment for a common symbol: we can not
-             guarantee it, and it may cause us to allocate extra space
-             in the common section.  */
+            alignment of a section.  There is no point to permitting
+            a higher alignment for a common symbol: we can not
+            guarantee it, and it may cause us to allocate extra space
+            in the common section.  */
          if (section == bfd_com_section_ptr
              && (*sym_hash)->root.type == bfd_link_hash_common
              && ((*sym_hash)->root.u.c.p->alignment_power
@@ -485,42 +429,44 @@ coff_link_add_symbols (bfd *abfd,
          if (bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd))
            {
              /* If we don't have any symbol information currently in
-                 the hash table, or if we are looking at a symbol
-                 definition, then update the symbol class and type in
-                 the hash table.  */
-             if (((*sym_hash)->symbol_class == C_NULL
-                  && (*sym_hash)->type == T_NULL)
-                 || sym.n_scnum != 0
-                 || (sym.n_value != 0
-                     && (*sym_hash)->root.type != bfd_link_hash_defined
-                     && (*sym_hash)->root.type != bfd_link_hash_defweak))
-               {
-                 (*sym_hash)->symbol_class = sym.n_sclass;
-                 if (sym.n_type != T_NULL)
-                   {
-                     /* We want to warn if the type changed, but not
-                        if it changed from an unspecified type.
-                        Testing the whole type byte may work, but the
-                        change from (e.g.) a function of unspecified
-                        type to function of known type also wants to
-                        skip the warning.  */
-                     if ((*sym_hash)->type != T_NULL
-                         && (*sym_hash)->type != sym.n_type
-                         && !(DTYPE ((*sym_hash)->type) == DTYPE (sym.n_type)
-                              && (BTYPE ((*sym_hash)->type) == T_NULL
-                                  || BTYPE (sym.n_type) == T_NULL)))
-                       (*_bfd_error_handler)
-                         (_("Warning: type of symbol `%s' changed from %d to %d in %B"),
-                          abfd, name, (*sym_hash)->type, sym.n_type);
-
-                     /* We don't want to change from a meaningful
-                        base type to a null one, but if we know
-                        nothing, take what little we might now know.  */
-                     if (BTYPE (sym.n_type) != T_NULL
-                         || (*sym_hash)->type == T_NULL)
+                the hash table, or if we are looking at a symbol
+                definition, then update the symbol class and type in
+                the hash table.  */
+             if (((*sym_hash)->symbol_class == C_NULL
+                  && (*sym_hash)->type == T_NULL)
+                 || sym.n_scnum != 0
+                 || (sym.n_value != 0
+                     && (*sym_hash)->root.type != bfd_link_hash_defined
+                     && (*sym_hash)->root.type != bfd_link_hash_defweak))
+               {
+                 (*sym_hash)->symbol_class = sym.n_sclass;
+                 if (sym.n_type != T_NULL)
+                   {
+                     /* We want to warn if the type changed, but not
+                        if it changed from an unspecified type.
+                        Testing the whole type byte may work, but the
+                        change from (e.g.) a function of unspecified
+                        type to function of known type also wants to
+                        skip the warning.  */
+                     if ((*sym_hash)->type != T_NULL
+                         && (*sym_hash)->type != sym.n_type
+                         && !(DTYPE ((*sym_hash)->type) == DTYPE (sym.n_type)
+                              && (BTYPE ((*sym_hash)->type) == T_NULL
+                                  || BTYPE (sym.n_type) == T_NULL)))
+                       _bfd_error_handler
+                         /* xgettext: c-format */
+                         (_("warning: type of symbol `%s' changed"
+                            " from %d to %d in %pB"),
+                          name, (*sym_hash)->type, sym.n_type, abfd);
+
+                     /* We don't want to change from a meaningful
+                        base type to a null one, but if we know
+                        nothing, take what little we might now know.  */
+                     if (BTYPE (sym.n_type) != T_NULL
+                         || (*sym_hash)->type == T_NULL)
                        (*sym_hash)->type = sym.n_type;
-                   }
-                 (*sym_hash)->auxbfd = abfd;
+                   }
+                 (*sym_hash)->auxbfd = abfd;
                  if (sym.n_numaux != 0)
                    {
                      union internal_auxent *alloc;
@@ -550,8 +496,8 @@ coff_link_add_symbols (bfd *abfd,
              && (*sym_hash)->numaux != 0)
            {
              /* Some PE sections (such as .bss) have a zero size in
-                 the section header, but a non-zero size in the AUX
-                 record.  Correct that here.
+                the section header, but a non-zero size in the AUX
+                record.  Correct that here.
 
                 FIXME: This is not at all the right place to do this.
                 For example, it won't help objdump.  This needs to be
@@ -561,8 +507,8 @@ coff_link_add_symbols (bfd *abfd,
                section->size = (*sym_hash)->aux[0].x_scn.x_scnlen;
 
              /* FIXME: We could test whether the section sizes
-                 matches the size in the aux entry, but apparently
-                 that sometimes fails unexpectedly.  */
+                matches the size in the aux entry, but apparently
+                that sometimes fails unexpectedly.  */
            }
        }
 
@@ -572,7 +518,7 @@ coff_link_add_symbols (bfd *abfd,
 
   /* If this is a non-traditional, non-relocatable link, try to
      optimize the handling of any .stab/.stabstr sections.  */
-  if (! info->relocatable
+  if (! bfd_link_relocatable (info)
       && ! info->traditional_format
       && bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd)
       && (info->strip != strip_all && info->strip != strip_debugger))
@@ -585,7 +531,7 @@ coff_link_add_symbols (bfd *abfd,
        {
          bfd_size_type string_offset = 0;
          asection *stab;
-         
+
          for (stab = abfd->sections; stab; stab = stab->next)
            if (CONST_STRNEQ (stab->name, ".stab")
                && (!stab->name[5]
@@ -594,7 +540,7 @@ coff_link_add_symbols (bfd *abfd,
              struct coff_link_hash_table *table;
              struct coff_section_tdata *secdata
                = coff_section_data (abfd, stab);
-             
+
              if (secdata == NULL)
                {
                  amt = sizeof (struct coff_section_tdata);
@@ -631,7 +577,7 @@ _bfd_coff_final_link (bfd *abfd,
                      struct bfd_link_info *info)
 {
   bfd_size_type symesz;
-  struct coff_final_link_info finfo;
+  struct coff_final_link_info flaginfo;
   bfd_boolean debug_merge_allocated;
   bfd_boolean long_section_names;
   asection *o;
@@ -652,30 +598,30 @@ _bfd_coff_final_link (bfd *abfd,
 
   symesz = bfd_coff_symesz (abfd);
 
-  finfo.info = info;
-  finfo.output_bfd = abfd;
-  finfo.strtab = NULL;
-  finfo.section_info = NULL;
-  finfo.last_file_index = -1;
-  finfo.last_bf_index = -1;
-  finfo.internal_syms = NULL;
-  finfo.sec_ptrs = NULL;
-  finfo.sym_indices = NULL;
-  finfo.outsyms = NULL;
-  finfo.linenos = NULL;
-  finfo.contents = NULL;
-  finfo.external_relocs = NULL;
-  finfo.internal_relocs = NULL;
-  finfo.global_to_static = FALSE;
+  flaginfo.info = info;
+  flaginfo.output_bfd = abfd;
+  flaginfo.strtab = NULL;
+  flaginfo.section_info = NULL;
+  flaginfo.last_file_index = -1;
+  flaginfo.last_bf_index = -1;
+  flaginfo.internal_syms = NULL;
+  flaginfo.sec_ptrs = NULL;
+  flaginfo.sym_indices = NULL;
+  flaginfo.outsyms = NULL;
+  flaginfo.linenos = NULL;
+  flaginfo.contents = NULL;
+  flaginfo.external_relocs = NULL;
+  flaginfo.internal_relocs = NULL;
+  flaginfo.global_to_static = FALSE;
   debug_merge_allocated = FALSE;
 
   coff_data (abfd)->link_info = info;
 
-  finfo.strtab = _bfd_stringtab_init ();
-  if (finfo.strtab == NULL)
+  flaginfo.strtab = _bfd_stringtab_init ();
+  if (flaginfo.strtab == NULL)
     goto error_return;
 
-  if (! coff_debug_merge_hash_table_init (&finfo.debug_merge))
+  if (! coff_debug_merge_hash_table_init (&flaginfo.debug_merge))
     goto error_return;
   debug_merge_allocated = TRUE;
 
@@ -717,7 +663,7 @@ _bfd_coff_final_link (bfd *abfd,
                  || info->strip == strip_some)
                o->lineno_count += sec->lineno_count;
 
-             if (info->relocatable)
+             if (bfd_link_relocatable (info))
                o->reloc_count += sec->reloc_count;
 
              if (sec->rawsize > max_contents_size)
@@ -729,7 +675,7 @@ _bfd_coff_final_link (bfd *abfd,
              if (sec->reloc_count > max_reloc_count)
                max_reloc_count = sec->reloc_count;
            }
-         else if (info->relocatable
+         else if (bfd_link_relocatable (info)
                   && (p->type == bfd_section_reloc_link_order
                       || p->type == bfd_symbol_reloc_link_order))
            ++o->reloc_count;
@@ -743,7 +689,7 @@ _bfd_coff_final_link (bfd *abfd,
          rel_filepos += o->reloc_count * relsz;
          /* In PE COFF, if there are at least 0xffff relocations an
             extra relocation will be written out to encode the count.  */
-         if (obj_pe (abfd) && o->reloc_count >= 0xffff)
+         if ((obj_pe (abfd) || obj_go32 (abfd)) && o->reloc_count >= 0xffff)
            rel_filepos += relsz;
        }
 
@@ -751,11 +697,11 @@ _bfd_coff_final_link (bfd *abfd,
          && strlen (o->name) > SCNNMLEN)
        {
          /* This section has a long name which must go in the string
-             table.  This must correspond to the code in
-             coff_write_object_contents which puts the string index
-             into the s_name field of the section header.  That is why
-             we pass hash as FALSE.  */
-         if (_bfd_stringtab_add (finfo.strtab, o->name, FALSE, FALSE)
+            table.  This must correspond to the code in
+            coff_write_object_contents which puts the string index
+            into the s_name field of the section header.  That is why
+            we pass hash as FALSE.  */
+         if (_bfd_stringtab_add (flaginfo.strtab, o->name, FALSE, FALSE)
              == (bfd_size_type) -1)
            goto error_return;
          long_section_names = TRUE;
@@ -764,21 +710,21 @@ _bfd_coff_final_link (bfd *abfd,
 
   /* If doing a relocatable link, allocate space for the pointers we
      need to keep.  */
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     {
       unsigned int i;
 
       /* We use section_count + 1, rather than section_count, because
-         the target_index fields are 1 based.  */
+        the target_index fields are 1 based.  */
       amt = abfd->section_count + 1;
       amt *= sizeof (struct coff_link_section_info);
-      finfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt);
-      if (finfo.section_info == NULL)
+      flaginfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt);
+      if (flaginfo.section_info == NULL)
        goto error_return;
       for (i = 0; i <= abfd->section_count; i++)
        {
-         finfo.section_info[i].relocs = NULL;
-         finfo.section_info[i].rel_hashes = NULL;
+         flaginfo.section_info[i].relocs = NULL;
+         flaginfo.section_info[i].rel_hashes = NULL;
        }
     }
 
@@ -800,29 +746,29 @@ _bfd_coff_final_link (bfd *abfd,
       if (o->reloc_count != 0)
        {
          /* We don't know the indices of global symbols until we have
-             written out all the local symbols.  For each section in
-             the output file, we keep an array of pointers to hash
-             table entries.  Each entry in the array corresponds to a
-             reloc.  When we find a reloc against a global symbol, we
-             set the corresponding entry in this array so that we can
-             fix up the symbol index after we have written out all the
-             local symbols.
+            written out all the local symbols.  For each section in
+            the output file, we keep an array of pointers to hash
+            table entries.  Each entry in the array corresponds to a
+            reloc.  When we find a reloc against a global symbol, we
+            set the corresponding entry in this array so that we can
+            fix up the symbol index after we have written out all the
+            local symbols.
 
             Because of this problem, we also keep the relocs in
             memory until the end of the link.  This wastes memory,
             but only when doing a relocatable link, which is not the
             common case.  */
-         BFD_ASSERT (info->relocatable);
+         BFD_ASSERT (bfd_link_relocatable (info));
          amt = o->reloc_count;
          amt *= sizeof (struct internal_reloc);
-         finfo.section_info[o->target_index].relocs =
-              (struct internal_reloc *) bfd_malloc (amt);
+         flaginfo.section_info[o->target_index].relocs =
+             (struct internal_reloc *) bfd_malloc (amt);
          amt = o->reloc_count;
          amt *= sizeof (struct coff_link_hash_entry *);
-         finfo.section_info[o->target_index].rel_hashes =
-              (struct coff_link_hash_entry **) bfd_malloc (amt);
-         if (finfo.section_info[o->target_index].relocs == NULL
-             || finfo.section_info[o->target_index].rel_hashes == NULL)
+         flaginfo.section_info[o->target_index].rel_hashes =
+             (struct coff_link_hash_entry **) bfd_malloc (amt);
+         if (flaginfo.section_info[o->target_index].relocs == NULL
+             || flaginfo.section_info[o->target_index].rel_hashes == NULL)
            goto error_return;
 
          if (o->reloc_count > max_output_reloc_count)
@@ -841,43 +787,43 @@ _bfd_coff_final_link (bfd *abfd,
      the opportunity to clear the output_has_begun fields of all the
      input BFD's.  */
   max_sym_count = 0;
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     {
       size_t sz;
 
       sub->output_has_begun = FALSE;
-      sz = obj_raw_syment_count (sub);
+      sz = bfd_family_coff (sub) ? obj_raw_syment_count (sub) : 2;
       if (sz > max_sym_count)
        max_sym_count = sz;
     }
 
   /* Allocate some buffers used while linking.  */
   amt = max_sym_count * sizeof (struct internal_syment);
-  finfo.internal_syms = (struct internal_syment *) bfd_malloc (amt);
+  flaginfo.internal_syms = (struct internal_syment *) bfd_malloc (amt);
   amt = max_sym_count * sizeof (asection *);
-  finfo.sec_ptrs = (asection **) bfd_malloc (amt);
+  flaginfo.sec_ptrs = (asection **) bfd_malloc (amt);
   amt = max_sym_count * sizeof (long);
-  finfo.sym_indices = (long int *) bfd_malloc (amt);
-  finfo.outsyms = (bfd_byte *) bfd_malloc ((max_sym_count + 1) * symesz);
+  flaginfo.sym_indices = (long int *) bfd_malloc (amt);
+  flaginfo.outsyms = (bfd_byte *) bfd_malloc ((max_sym_count + 1) * symesz);
   amt = max_lineno_count * bfd_coff_linesz (abfd);
-  finfo.linenos = (bfd_byte *) bfd_malloc (amt);
-  finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+  flaginfo.linenos = (bfd_byte *) bfd_malloc (amt);
+  flaginfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
   amt = max_reloc_count * relsz;
-  finfo.external_relocs = (bfd_byte *) bfd_malloc (amt);
-  if (! info->relocatable)
+  flaginfo.external_relocs = (bfd_byte *) bfd_malloc (amt);
+  if (! bfd_link_relocatable (info))
     {
       amt = max_reloc_count * sizeof (struct internal_reloc);
-      finfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt);
+      flaginfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt);
     }
-  if ((finfo.internal_syms == NULL && max_sym_count > 0)
-      || (finfo.sec_ptrs == NULL && max_sym_count > 0)
-      || (finfo.sym_indices == NULL && max_sym_count > 0)
-      || finfo.outsyms == NULL
-      || (finfo.linenos == NULL && max_lineno_count > 0)
-      || (finfo.contents == NULL && max_contents_size > 0)
-      || (finfo.external_relocs == NULL && max_reloc_count > 0)
-      || (! info->relocatable
-         && finfo.internal_relocs == NULL
+  if ((flaginfo.internal_syms == NULL && max_sym_count > 0)
+      || (flaginfo.sec_ptrs == NULL && max_sym_count > 0)
+      || (flaginfo.sym_indices == NULL && max_sym_count > 0)
+      || flaginfo.outsyms == NULL
+      || (flaginfo.linenos == NULL && max_lineno_count > 0)
+      || (flaginfo.contents == NULL && max_contents_size > 0)
+      || (flaginfo.external_relocs == NULL && max_reloc_count > 0)
+      || (! bfd_link_relocatable (info)
+         && flaginfo.internal_relocs == NULL
          && max_reloc_count > 0))
     goto error_return;
 
@@ -902,9 +848,9 @@ _bfd_coff_final_link (bfd *abfd,
              && bfd_family_coff (p->u.indirect.section->owner))
            {
              sub = p->u.indirect.section->owner;
-             if (! bfd_coff_link_output_has_begun (sub, & finfo))
+             if (! bfd_coff_link_output_has_begun (sub, & flaginfo))
                {
-                 if (! _bfd_coff_link_input_bfd (&finfo, sub))
+                 if (! _bfd_coff_link_input_bfd (&flaginfo, sub))
                    goto error_return;
                  sub->output_has_begun = TRUE;
                }
@@ -912,7 +858,7 @@ _bfd_coff_final_link (bfd *abfd,
          else if (p->type == bfd_section_reloc_link_order
                   || p->type == bfd_symbol_reloc_link_order)
            {
-             if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p))
+             if (! _bfd_coff_reloc_link_order (abfd, &flaginfo, o, p))
                goto error_return;
            }
          else
@@ -923,65 +869,160 @@ _bfd_coff_final_link (bfd *abfd,
        }
     }
 
-  if (! bfd_coff_final_link_postscript (abfd, & finfo))
+  if (flaginfo.info->strip != strip_all && flaginfo.info->discard != discard_all)
+    {
+      /* Add local symbols from foreign inputs.  */
+      for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
+       {
+         unsigned int i;
+
+         if (bfd_family_coff (sub) || ! bfd_get_outsymbols (sub))
+           continue;
+         for (i = 0; i < bfd_get_symcount (sub); ++i)
+           {
+             asymbol *sym = bfd_get_outsymbols (sub) [i];
+             file_ptr pos;
+             struct internal_syment isym;
+             union internal_auxent iaux;
+             bfd_size_type string_size = 0, indx;
+             bfd_vma written = 0;
+             bfd_boolean rewrite = FALSE, hash;
+
+             if (! (sym->flags & BSF_LOCAL)
+                 || (sym->flags & (BSF_SECTION_SYM | BSF_DEBUGGING_RELOC
+                                   | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC
+                                   | BSF_SYNTHETIC))
+                 || ((sym->flags & BSF_DEBUGGING)
+                     && ! (sym->flags & BSF_FILE)))
+               continue;
+
+             /* See if we are discarding symbols with this name.  */
+             if ((flaginfo.info->strip == strip_some
+                  && (bfd_hash_lookup (flaginfo.info->keep_hash,
+                                       bfd_asymbol_name(sym), FALSE, FALSE)
+                      == NULL))
+                 || (((flaginfo.info->discard == discard_sec_merge
+                       && (bfd_asymbol_section (sym)->flags & SEC_MERGE)
+                       && ! bfd_link_relocatable (flaginfo.info))
+                      || flaginfo.info->discard == discard_l)
+                     && bfd_is_local_label_name (sub, bfd_asymbol_name(sym))))
+               continue;
+
+             pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd)
+                                            * symesz;
+             if (bfd_seek (abfd, pos, SEEK_SET) != 0)
+               goto error_return;
+             if (! coff_write_alien_symbol(abfd, sym, &isym, &iaux, &written,
+                                           &string_size, NULL, NULL))
+               goto error_return;
+
+             hash = !flaginfo.info->traditional_format;
+
+             if (string_size >= 6 && isym.n_sclass == C_FILE
+                 && ! isym._n._n_n._n_zeroes && isym.n_numaux)
+               {
+                 indx = _bfd_stringtab_add (flaginfo.strtab, ".file", hash,
+                                            FALSE);
+                 if (indx == (bfd_size_type) -1)
+                   goto error_return;
+                 isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
+                 bfd_coff_swap_sym_out (abfd, &isym, flaginfo.outsyms);
+                 if (bfd_seek (abfd, pos, SEEK_SET) != 0
+                     || bfd_bwrite (flaginfo.outsyms, symesz,
+                                    abfd) != symesz)
+                   goto error_return;
+                 string_size -= 6;
+               }
+
+             if (string_size)
+               {
+                 indx = _bfd_stringtab_add (flaginfo.strtab,
+                                            bfd_asymbol_name (sym), hash,
+                                            FALSE);
+                 if (indx == (bfd_size_type) -1)
+                   goto error_return;
+                 if (isym.n_sclass != C_FILE)
+                   {
+                     isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
+                     bfd_coff_swap_sym_out (abfd, &isym, flaginfo.outsyms);
+                     rewrite = TRUE;
+                   }
+                 else
+                   {
+                     BFD_ASSERT (isym.n_numaux == 1);
+                     iaux.x_file.x_n.x_offset = STRING_SIZE_SIZE + indx;
+                     bfd_coff_swap_aux_out (abfd, &iaux, isym.n_type, C_FILE,
+                                            0, 1, flaginfo.outsyms + symesz);
+                     if (bfd_seek (abfd, pos + symesz, SEEK_SET) != 0
+                         || bfd_bwrite (flaginfo.outsyms + symesz, symesz,
+                                        abfd) != symesz)
+                       goto error_return;
+                   }
+               }
+
+             if (isym.n_sclass == C_FILE)
+               {
+                 if (flaginfo.last_file_index != -1)
+                   {
+                     flaginfo.last_file.n_value = obj_raw_syment_count (abfd);
+                     bfd_coff_swap_sym_out (abfd, &flaginfo.last_file,
+                                            flaginfo.outsyms);
+                     pos = obj_sym_filepos (abfd) + flaginfo.last_file_index
+                                                    * symesz;
+                     rewrite = TRUE;
+                   }
+                 flaginfo.last_file_index = obj_raw_syment_count (abfd);
+                 flaginfo.last_file = isym;
+               }
+
+             if (rewrite
+                 && (bfd_seek (abfd, pos, SEEK_SET) != 0
+                     || bfd_bwrite (flaginfo.outsyms, symesz, abfd) != symesz))
+               goto error_return;
+
+             obj_raw_syment_count (abfd) += written;
+           }
+       }
+    }
+
+  if (! bfd_coff_final_link_postscript (abfd, & flaginfo))
     goto error_return;
 
   /* Free up the buffers used by _bfd_coff_link_input_bfd.  */
 
-  coff_debug_merge_hash_table_free (&finfo.debug_merge);
+  coff_debug_merge_hash_table_free (&flaginfo.debug_merge);
   debug_merge_allocated = FALSE;
 
-  if (finfo.internal_syms != NULL)
-    {
-      free (finfo.internal_syms);
-      finfo.internal_syms = NULL;
-    }
-  if (finfo.sec_ptrs != NULL)
-    {
-      free (finfo.sec_ptrs);
-      finfo.sec_ptrs = NULL;
-    }
-  if (finfo.sym_indices != NULL)
-    {
-      free (finfo.sym_indices);
-      finfo.sym_indices = NULL;
-    }
-  if (finfo.linenos != NULL)
-    {
-      free (finfo.linenos);
-      finfo.linenos = NULL;
-    }
-  if (finfo.contents != NULL)
-    {
-      free (finfo.contents);
-      finfo.contents = NULL;
-    }
-  if (finfo.external_relocs != NULL)
-    {
-      free (finfo.external_relocs);
-      finfo.external_relocs = NULL;
-    }
-  if (finfo.internal_relocs != NULL)
-    {
-      free (finfo.internal_relocs);
-      finfo.internal_relocs = NULL;
-    }
+  free (flaginfo.internal_syms);
+  flaginfo.internal_syms = NULL;
+  free (flaginfo.sec_ptrs);
+  flaginfo.sec_ptrs = NULL;
+  free (flaginfo.sym_indices);
+  flaginfo.sym_indices = NULL;
+  free (flaginfo.linenos);
+  flaginfo.linenos = NULL;
+  free (flaginfo.contents);
+  flaginfo.contents = NULL;
+  free (flaginfo.external_relocs);
+  flaginfo.external_relocs = NULL;
+  free (flaginfo.internal_relocs);
+  flaginfo.internal_relocs = NULL;
 
   /* The value of the last C_FILE symbol is supposed to be the symbol
      index of the first external symbol.  Write it out again if
      necessary.  */
-  if (finfo.last_file_index != -1
-      && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd))
+  if (flaginfo.last_file_index != -1
+      && (unsigned int) flaginfo.last_file.n_value != obj_raw_syment_count (abfd))
     {
       file_ptr pos;
 
-      finfo.last_file.n_value = obj_raw_syment_count (abfd);
-      bfd_coff_swap_sym_out (abfd, &finfo.last_file,
-                            finfo.outsyms);
+      flaginfo.last_file.n_value = obj_raw_syment_count (abfd);
+      bfd_coff_swap_sym_out (abfd, &flaginfo.last_file,
+                            flaginfo.outsyms);
 
-      pos = obj_sym_filepos (abfd) + finfo.last_file_index * symesz;
+      pos = obj_sym_filepos (abfd) + flaginfo.last_file_index * symesz;
       if (bfd_seek (abfd, pos, SEEK_SET) != 0
-         || bfd_bwrite (finfo.outsyms, symesz, abfd) != symesz)
+         || bfd_bwrite (flaginfo.outsyms, symesz, abfd) != symesz)
        return FALSE;
     }
 
@@ -990,28 +1031,24 @@ _bfd_coff_final_link (bfd *abfd,
      static.  */
   if (info->task_link)
     {
-      finfo.failed = FALSE;
+      flaginfo.failed = FALSE;
       coff_link_hash_traverse (coff_hash_table (info),
-                              _bfd_coff_write_task_globals, &finfo);
-      if (finfo.failed)
+                              _bfd_coff_write_task_globals, &flaginfo);
+      if (flaginfo.failed)
        goto error_return;
     }
 
   /* Write out the global symbols.  */
-  finfo.failed = FALSE;
-  coff_link_hash_traverse (coff_hash_table (info),
-                          _bfd_coff_write_global_sym, &finfo);
-  if (finfo.failed)
+  flaginfo.failed = FALSE;
+  bfd_hash_traverse (&info->hash->table, _bfd_coff_write_global_sym, &flaginfo);
+  if (flaginfo.failed)
     goto error_return;
 
   /* The outsyms buffer is used by _bfd_coff_write_global_sym.  */
-  if (finfo.outsyms != NULL)
-    {
-      free (finfo.outsyms);
-      finfo.outsyms = NULL;
-    }
+  free (flaginfo.outsyms);
+  flaginfo.outsyms = NULL;
 
-  if (info->relocatable && max_output_reloc_count > 0)
+  if (bfd_link_relocatable (info) && max_output_reloc_count > 0)
     {
       /* Now that we have written out all the global symbols, we know
         the symbol indices to use for relocs against them, and we can
@@ -1031,9 +1068,9 @@ _bfd_coff_final_link (bfd *abfd,
          if (o->reloc_count == 0)
            continue;
 
-         irel = finfo.section_info[o->target_index].relocs;
+         irel = flaginfo.section_info[o->target_index].relocs;
          irelend = irel + o->reloc_count;
-         rel_hash = finfo.section_info[o->target_index].rel_hashes;
+         rel_hash = flaginfo.section_info[o->target_index].rel_hashes;
          erel = external_relocs;
          for (; irel < irelend; irel++, rel_hash++, erel += relsz)
            {
@@ -1047,17 +1084,17 @@ _bfd_coff_final_link (bfd *abfd,
 
          if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0)
            goto error_return;
-         if (obj_pe (abfd) && o->reloc_count >= 0xffff)
+         if ((obj_pe (abfd) || obj_go32 (abfd)) && o->reloc_count >= 0xffff)
            {
              /* In PE COFF, write the count of relocs as the first
                 reloc.  The header overflow bit will be set
                 elsewhere. */
              struct internal_reloc incount;
              bfd_byte *excount = (bfd_byte *)bfd_malloc (relsz);
-             
+
              memset (&incount, 0, sizeof (incount));
              incount.r_vaddr = o->reloc_count + 1;
-             bfd_coff_swap_reloc_out (abfd, (PTR) &incount, (PTR) excount);
+             bfd_coff_swap_reloc_out (abfd, &incount, excount);
              if (bfd_bwrite (excount, relsz, abfd) != relsz)
                /* We'll leak, but it's an error anyway. */
                goto error_return;
@@ -1074,19 +1111,17 @@ _bfd_coff_final_link (bfd *abfd,
     }
 
   /* Free up the section information.  */
-  if (finfo.section_info != NULL)
+  if (flaginfo.section_info != NULL)
     {
       unsigned int i;
 
       for (i = 0; i < abfd->section_count; i++)
        {
-         if (finfo.section_info[i].relocs != NULL)
-           free (finfo.section_info[i].relocs);
-         if (finfo.section_info[i].rel_hashes != NULL)
-           free (finfo.section_info[i].rel_hashes);
+         free (flaginfo.section_info[i].relocs);
+         free (flaginfo.section_info[i].rel_hashes);
        }
-      free (finfo.section_info);
-      finfo.section_info = NULL;
+      free (flaginfo.section_info);
+      flaginfo.section_info = NULL;
     }
 
   /* If we have optimized stabs strings, output them.  */
@@ -1107,7 +1142,7 @@ _bfd_coff_final_link (bfd *abfd,
 
 #if STRING_SIZE_SIZE == 4
       H_PUT_32 (abfd,
-               _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
+               _bfd_stringtab_size (flaginfo.strtab) + STRING_SIZE_SIZE,
                strbuf);
 #else
  #error Change H_PUT_32 above
@@ -1117,56 +1152,45 @@ _bfd_coff_final_link (bfd *abfd,
          != STRING_SIZE_SIZE)
        return FALSE;
 
-      if (! _bfd_stringtab_emit (abfd, finfo.strtab))
+      if (! _bfd_stringtab_emit (abfd, flaginfo.strtab))
        return FALSE;
 
       obj_coff_strings_written (abfd) = TRUE;
     }
 
-  _bfd_stringtab_free (finfo.strtab);
+  _bfd_stringtab_free (flaginfo.strtab);
 
-  /* Setting bfd_get_symcount to 0 will cause write_object_contents to
+  /* Setting symcount to 0 will cause write_object_contents to
      not try to write out the symbols.  */
-  bfd_get_symcount (abfd) = 0;
+  abfd->symcount = 0;
 
   return TRUE;
 
  error_return:
   if (debug_merge_allocated)
-    coff_debug_merge_hash_table_free (&finfo.debug_merge);
-  if (finfo.strtab != NULL)
-    _bfd_stringtab_free (finfo.strtab);
-  if (finfo.section_info != NULL)
+    coff_debug_merge_hash_table_free (&flaginfo.debug_merge);
+  if (flaginfo.strtab != NULL)
+    _bfd_stringtab_free (flaginfo.strtab);
+  if (flaginfo.section_info != NULL)
     {
       unsigned int i;
 
       for (i = 0; i < abfd->section_count; i++)
        {
-         if (finfo.section_info[i].relocs != NULL)
-           free (finfo.section_info[i].relocs);
-         if (finfo.section_info[i].rel_hashes != NULL)
-           free (finfo.section_info[i].rel_hashes);
+         free (flaginfo.section_info[i].relocs);
+         free (flaginfo.section_info[i].rel_hashes);
        }
-      free (finfo.section_info);
+      free (flaginfo.section_info);
     }
-  if (finfo.internal_syms != NULL)
-    free (finfo.internal_syms);
-  if (finfo.sec_ptrs != NULL)
-    free (finfo.sec_ptrs);
-  if (finfo.sym_indices != NULL)
-    free (finfo.sym_indices);
-  if (finfo.outsyms != NULL)
-    free (finfo.outsyms);
-  if (finfo.linenos != NULL)
-    free (finfo.linenos);
-  if (finfo.contents != NULL)
-    free (finfo.contents);
-  if (finfo.external_relocs != NULL)
-    free (finfo.external_relocs);
-  if (finfo.internal_relocs != NULL)
-    free (finfo.internal_relocs);
-  if (external_relocs != NULL)
-    free (external_relocs);
+  free (flaginfo.internal_syms);
+  free (flaginfo.sec_ptrs);
+  free (flaginfo.sym_indices);
+  free (flaginfo.outsyms);
+  free (flaginfo.linenos);
+  free (flaginfo.contents);
+  free (flaginfo.external_relocs);
+  free (flaginfo.internal_relocs);
+  free (external_relocs);
   return FALSE;
 }
 
@@ -1225,8 +1249,7 @@ process_embedded_commands (bfd *output_bfd,
 
   if (!bfd_malloc_and_get_section (abfd, sec, &copy))
     {
-      if (copy != NULL)
-       free (copy);
+      free (copy);
       return 0;
     }
   e = (char *) copy + sec->size;
@@ -1306,7 +1329,7 @@ process_embedded_commands (bfd *output_bfd,
    that symbol.  */
 
 static void
-mark_relocs (struct coff_final_link_info *finfo, bfd *input_bfd)
+mark_relocs (struct coff_final_link_info *flaginfo, bfd *input_bfd)
 {
   asection * a;
 
@@ -1319,7 +1342,8 @@ mark_relocs (struct coff_final_link_info *finfo, bfd *input_bfd)
       struct internal_reloc *  irel;
       struct internal_reloc *  irelend;
 
-      if ((a->flags & SEC_RELOC) == 0 || a->reloc_count  < 1)
+      if ((a->flags & SEC_RELOC) == 0 || a->reloc_count  < 1
+         || a->linker_mark == 0)
        continue;
       /* Don't mark relocs in excluded sections.  */
       if (a->output_section == bfd_abs_section_ptr)
@@ -1328,11 +1352,11 @@ mark_relocs (struct coff_final_link_info *finfo, bfd *input_bfd)
       /* Read in the relocs.  */
       internal_relocs = _bfd_coff_read_internal_relocs
        (input_bfd, a, FALSE,
-        finfo->external_relocs,
-        finfo->info->relocatable,
-        (finfo->info->relocatable
-         ? (finfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count)
-         : finfo->internal_relocs)
+        flaginfo->external_relocs,
+        bfd_link_relocatable (flaginfo->info),
+        (bfd_link_relocatable (flaginfo->info)
+         ? (flaginfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count)
+         : flaginfo->internal_relocs)
        );
 
       if (internal_relocs == NULL)
@@ -1346,7 +1370,8 @@ mark_relocs (struct coff_final_link_info *finfo, bfd *input_bfd)
         in the relocation table.  This will then be picked up in the
         skip/don't-skip pass.  */
       for (; irel < irelend; irel++)
-       finfo->sym_indices[ irel->r_symndx ] = -1;
+       if ((unsigned long) irel->r_symndx < obj_raw_syment_count (input_bfd))
+         flaginfo->sym_indices[irel->r_symndx] = -1;
     }
 }
 
@@ -1354,7 +1379,7 @@ mark_relocs (struct coff_final_link_info *finfo, bfd *input_bfd)
    handles all the sections and relocations of the input file at once.  */
 
 bfd_boolean
-_bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
+_bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd)
 {
   unsigned int n_tmask = coff_data (input_bfd)->local_n_tmask;
   unsigned int n_btshft = coff_data (input_bfd)->local_n_btshft;
@@ -1380,7 +1405,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
 
   /* Move all the symbols to the output file.  */
 
-  output_bfd = finfo->output_bfd;
+  output_bfd = flaginfo->output_bfd;
   strings = NULL;
   syment_base = obj_raw_syment_count (output_bfd);
   isymesz = bfd_coff_symesz (input_bfd);
@@ -1389,10 +1414,10 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
   BFD_ASSERT (linesz == bfd_coff_linesz (output_bfd));
 
   copy = FALSE;
-  if (! finfo->info->keep_memory)
+  if (! flaginfo->info->keep_memory)
     copy = TRUE;
   hash = TRUE;
-  if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
+  if (flaginfo->info->traditional_format)
     hash = FALSE;
 
   if (! _bfd_coff_get_external_symbols (input_bfd))
@@ -1400,27 +1425,27 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
 
   esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
   esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
-  isymp = finfo->internal_syms;
-  secpp = finfo->sec_ptrs;
-  indexp = finfo->sym_indices;
+  isymp = flaginfo->internal_syms;
+  secpp = flaginfo->sec_ptrs;
+  indexp = flaginfo->sym_indices;
   output_index = syment_base;
-  outsym = finfo->outsyms;
+  outsym = flaginfo->outsyms;
 
   if (coff_data (output_bfd)->pe
-      && ! process_embedded_commands (output_bfd, finfo->info, input_bfd))
+      && ! process_embedded_commands (output_bfd, flaginfo->info, input_bfd))
     return FALSE;
 
   /* If we are going to perform relocations and also strip/discard some
      symbols then we must make sure that we do not strip/discard those
      symbols that are going to be involved in the relocations.  */
-  if ((   finfo->info->strip   != strip_none
-       || finfo->info->discard != discard_none)
-      && finfo->info->relocatable)
+  if ((   flaginfo->info->strip   != strip_none
+       || flaginfo->info->discard != discard_none)
+      && bfd_link_relocatable (flaginfo->info))
     {
       /* Mark the symbol array as 'not-used'.  */
       memset (indexp, 0, obj_raw_syment_count (input_bfd) * sizeof * indexp);
 
-      mark_relocs (finfo, input_bfd);
+      mark_relocs (flaginfo, input_bfd);
     }
 
   while (esym < esym_end)
@@ -1459,10 +1484,10 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
        }
 
       /* Extract the flag indicating if this symbol is used by a
-         relocation.  */
-      if ((finfo->info->strip != strip_none
-          || finfo->info->discard != discard_none)
-         && finfo->info->relocatable)
+        relocation.  */
+      if ((flaginfo->info->strip != strip_none
+          || flaginfo->info->discard != discard_none)
+         && bfd_link_relocatable (flaginfo->info))
        dont_skip_symbol = *indexp;
       else
        dont_skip_symbol = FALSE;
@@ -1474,7 +1499,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
       add = 1 + isym.n_numaux;
 
       /* If we are stripping all symbols, we want to skip this one.  */
-      if (finfo->info->strip == strip_all && ! dont_skip_symbol)
+      if (flaginfo->info->strip == strip_all && ! dont_skip_symbol)
        skip = TRUE;
 
       if (! skip)
@@ -1503,8 +1528,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
 
            case COFF_SYMBOL_LOCAL:
              /* This is a local symbol.  Skip it if we are discarding
-                 local symbols.  */
-             if (finfo->info->discard == discard_all && ! dont_skip_symbol)
+                local symbols.  */
+             if (flaginfo->info->discard == discard_all && ! dont_skip_symbol)
                skip = TRUE;
              break;
            }
@@ -1514,20 +1539,22 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
       /* Skip section symbols for sections which are not going to be
         emitted.  */
       if (!skip
-         && dont_skip_symbol == 0
+         && !dont_skip_symbol
          && isym.n_sclass == C_STAT
          && isym.n_type == T_NULL
-          && isym.n_numaux > 0
-         && (*secpp)->output_section == bfd_abs_section_ptr)
+         && isym.n_numaux > 0
+         && ((*secpp)->output_section == bfd_abs_section_ptr
+             || bfd_section_removed_from_list (output_bfd,
+                                               (*secpp)->output_section)))
        skip = TRUE;
 #endif
 
       /* If we stripping debugging symbols, and this is a debugging
-         symbol, then skip it.  FIXME: gas sets the section to N_ABS
-         for some types of debugging symbols; I don't know if this is
-         a bug or not.  In any case, we handle it here.  */
+        symbol, then skip it.  FIXME: gas sets the section to N_ABS
+        for some types of debugging symbols; I don't know if this is
+        a bug or not.  In any case, we handle it here.  */
       if (! skip
-         && finfo->info->strip == strip_debugger
+         && flaginfo->info->strip == strip_debugger
          && ! dont_skip_symbol
          && (isym.n_scnum == N_DEBUG
              || (isym.n_scnum == N_ABS
@@ -1545,8 +1572,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
       /* If some symbols are stripped based on the name, work out the
         name and decide whether to skip this symbol.  */
       if (! skip
-         && (finfo->info->strip == strip_some
-             || finfo->info->discard == discard_l))
+         && (flaginfo->info->strip == strip_some
+             || flaginfo->info->discard == discard_l))
        {
          const char *name;
          char buf[SYMNMLEN + 1];
@@ -1556,19 +1583,19 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
            return FALSE;
 
          if (! dont_skip_symbol
-             && ((finfo->info->strip == strip_some
-                  && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE,
+             && ((flaginfo->info->strip == strip_some
+                  && (bfd_hash_lookup (flaginfo->info->keep_hash, name, FALSE,
                                    FALSE) == NULL))
                   || (! global
-                      && finfo->info->discard == discard_l
+                      && flaginfo->info->discard == discard_l
                       && bfd_is_local_label_name (input_bfd, name))))
            skip = TRUE;
        }
 
       /* If this is an enum, struct, or union tag, see if we have
-         already output an identical type.  */
+        already output an identical type.  */
       if (! skip
-         && (finfo->output_bfd->flags & BFD_TRADITIONAL_FORMAT) == 0
+         && !flaginfo->info->traditional_format
          && (isym.n_sclass == C_ENTAG
              || isym.n_sclass == C_STRTAG
              || isym.n_sclass == C_UNTAG)
@@ -1582,27 +1609,27 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
          struct coff_debug_merge_element **epp;
          bfd_byte *esl, *eslend;
          struct internal_syment *islp;
-         bfd_size_type amt;
+         size_t amt;
 
          name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
          if (name == NULL)
            return FALSE;
 
          /* Ignore fake names invented by compiler; treat them all as
-             the same name.  */
+            the same name.  */
          if (*name == '~' || *name == '.' || *name == '$'
              || (*name == bfd_get_symbol_leading_char (input_bfd)
                  && (name[1] == '~' || name[1] == '.' || name[1] == '$')))
            name = "";
 
-         mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name,
+         mh = coff_debug_merge_hash_lookup (&flaginfo->debug_merge, name,
                                             TRUE, TRUE);
          if (mh == NULL)
            return FALSE;
 
          /* Allocate memory to hold type information.  If this turns
-             out to be a duplicate, we pass this address to
-             bfd_release.  */
+            out to be a duplicate, we pass this address to
+            bfd_release.  */
          amt = sizeof (struct coff_debug_merge_type);
          mt = (struct coff_debug_merge_type *) bfd_alloc (input_bfd, amt);
          if (mt == NULL)
@@ -1610,7 +1637,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
          mt->type_class = isym.n_sclass;
 
          /* Pick up the aux entry, which points to the end of the tag
-             entries.  */
+            entries.  */
          bfd_coff_swap_aux_in (input_bfd, (esym + isymesz),
                                isym.n_type, isym.n_sclass, 0, isym.n_numaux,
                                &aux);
@@ -1632,7 +1659,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
 
              amt = sizeof (struct coff_debug_merge_element);
              *epp = (struct coff_debug_merge_element *)
-                  bfd_alloc (input_bfd, amt);
+                 bfd_alloc (input_bfd, amt);
              if (*epp == NULL)
                return FALSE;
 
@@ -1672,7 +1699,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                              (bfd_byte *) obj_coff_external_syms (input_bfd))
                             / (long) isymesz)))
                    {
-                     (*epp)->tagndx = finfo->sym_indices[indx];
+                     (*epp)->tagndx = flaginfo->sym_indices[indx];
                      if ((*epp)->tagndx < 0)
                        (*epp)->tagndx = 0;
                    }
@@ -1685,8 +1712,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
            }
 
          /* See if we already have a definition which matches this
-             type.  We always output the type if it has no elements,
-             for simplicity.  */
+            type.  We always output the type if it has no elements,
+            for simplicity.  */
          if (mt->elements == NULL)
            bfd_release (input_bfd, mt);
          else
@@ -1751,7 +1778,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
              name = _bfd_coff_internal_syment_name (input_bfd, &isym, NULL);
              if (name == NULL)
                return FALSE;
-             indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy);
+             indx = _bfd_stringtab_add (flaginfo->strtab, name, hash, copy);
              if (indx == (bfd_size_type) -1)
                return FALSE;
              isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
@@ -1778,7 +1805,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
 
            case C_FCN:
              if (obj_pe (input_bfd)
-                 && strcmp (isym.n_name, ".bf") != 0
+                 && memcmp (isym.n_name, ".bf", sizeof ".bf") != 0
                  && isym.n_scnum > 0)
                {
                  /* For PE, .lf and .ef get their value left alone,
@@ -1806,7 +1833,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                isym.n_value += (*secpp)->output_offset;
                if (! obj_pe (input_bfd))
                  isym.n_value -= (*secpp)->vma;
-               if (! obj_pe (finfo->output_bfd))
+               if (! obj_pe (flaginfo->output_bfd))
                  isym.n_value += (*secpp)->output_section->vma;
              }
            break;
@@ -1821,19 +1848,19 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                 it).  We try to get this right, below, just before we
                 write the symbols out, but in the general case we may
                 have to write the symbol out twice.  */
-             if (finfo->last_file_index != -1
-                 && finfo->last_file.n_value != (bfd_vma) output_index)
+             if (flaginfo->last_file_index != -1
+                 && flaginfo->last_file.n_value != (bfd_vma) output_index)
                {
                  /* We must correct the value of the last C_FILE
-                     entry.  */
-                 finfo->last_file.n_value = output_index;
-                 if ((bfd_size_type) finfo->last_file_index >= syment_base)
+                    entry.  */
+                 flaginfo->last_file.n_value = output_index;
+                 if ((bfd_size_type) flaginfo->last_file_index >= syment_base)
                    {
                      /* The last C_FILE symbol is in this input file.  */
                      bfd_coff_swap_sym_out (output_bfd,
-                                            &finfo->last_file,
-                                            (finfo->outsyms
-                                             + ((finfo->last_file_index
+                                            &flaginfo->last_file,
+                                            (flaginfo->outsyms
+                                             + ((flaginfo->last_file_index
                                                  - syment_base)
                                                 * osymesz)));
                    }
@@ -1845,23 +1872,23 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                         symbol.  We need to write it out again.  We
                         borrow *outsym temporarily.  */
                      bfd_coff_swap_sym_out (output_bfd,
-                                            &finfo->last_file, outsym);
+                                            &flaginfo->last_file, outsym);
                      pos = obj_sym_filepos (output_bfd);
-                     pos += finfo->last_file_index * osymesz;
+                     pos += flaginfo->last_file_index * osymesz;
                      if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
                          || bfd_bwrite (outsym, osymesz, output_bfd) != osymesz)
                        return FALSE;
                    }
                }
 
-             finfo->last_file_index = output_index;
-             finfo->last_file = isym;
+             flaginfo->last_file_index = output_index;
+             flaginfo->last_file = isym;
              break;
            }
 
          /* If doing task linking, convert normal global function symbols to
             static functions.  */
-         if (finfo->info->task_link && IS_EXTERNAL (input_bfd, isym))
+         if (flaginfo->info->task_link && IS_EXTERNAL (input_bfd, isym))
            isym.n_sclass = C_STAT;
 
          /* Output the symbol.  */
@@ -1880,7 +1907,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
              if (h == NULL)
                {
                  /* This can happen if there were errors earlier in
-                     the link.  */
+                    the link.  */
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                }
@@ -1907,10 +1934,10 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
      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;
+  isymp = flaginfo->internal_syms;
+  indexp = flaginfo->sym_indices;
   sym_hash = obj_coff_sym_hashes (input_bfd);
-  outsym = finfo->outsyms;
+  outsym = flaginfo->outsyms;
 
   while (esym < esym_end)
     {
@@ -1934,8 +1961,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
              h = *sym_hash;
 
              /* The m68k-motorola-sysv assembler will sometimes
-                 generate two symbols with the same name, but only one
-                 will have aux entries.  */
+                generate two symbols with the same name, but only one
+                will have aux entries.  */
              BFD_ASSERT (isymp->n_numaux == 0
                          || h->numaux == 0
                          || h->numaux == isymp->n_numaux);
@@ -1980,8 +2007,11 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                          if (strings == NULL)
                            return FALSE;
                        }
-                     filename = strings + auxp->x_file.x_n.x_offset;
-                     indx = _bfd_stringtab_add (finfo->strtab, filename,
+                     if ((bfd_size_type) auxp->x_file.x_n.x_offset >= obj_coff_strings_len (input_bfd))
+                       filename = _("<corrupt>");
+                     else
+                       filename = strings + auxp->x_file.x_n.x_offset;
+                     indx = _bfd_stringtab_add (flaginfo->strtab, filename,
                                                 hash, copy);
                      if (indx == (bfd_size_type) -1)
                        return FALSE;
@@ -2003,18 +2033,18 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                          && indx < obj_raw_syment_count (input_bfd))
                        {
                          /* We look forward through the symbol for
-                             the index of the next symbol we are going
-                             to include.  I don't know if this is
-                             entirely right.  */
-                         while ((finfo->sym_indices[indx] < 0
-                                 || ((bfd_size_type) finfo->sym_indices[indx]
+                            the index of the next symbol we are going
+                            to include.  I don't know if this is
+                            entirely right.  */
+                         while ((flaginfo->sym_indices[indx] < 0
+                                 || ((bfd_size_type) flaginfo->sym_indices[indx]
                                      < syment_base))
                                 && indx < obj_raw_syment_count (input_bfd))
                            ++indx;
                          if (indx >= obj_raw_syment_count (input_bfd))
                            indx = output_index;
                          else
-                           indx = finfo->sym_indices[indx];
+                           indx = flaginfo->sym_indices[indx];
                          auxp->x_sym.x_fcnary.x_fcn.x_endndx.l = indx;
                        }
                    }
@@ -2024,7 +2054,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                    {
                      long symindx;
 
-                     symindx = finfo->sym_indices[indx];
+                     symindx = flaginfo->sym_indices[indx];
                      if (symindx < 0)
                        auxp->x_sym.x_tagndx.l = 0;
                      else
@@ -2044,12 +2074,12 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                      && isymp->_n._n_name[2] == 'f'
                      && isymp->_n._n_name[3] == '\0')
                    {
-                     if (finfo->last_bf_index != -1)
+                     if (flaginfo->last_bf_index != -1)
                        {
-                         finfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l =
+                         flaginfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l =
                            *indexp;
 
-                         if ((bfd_size_type) finfo->last_bf_index
+                         if ((bfd_size_type) flaginfo->last_bf_index
                              >= syment_base)
                            {
                              void *auxout;
@@ -2058,13 +2088,13 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                                 file.  This will only happen if the
                                 assembler did not set up the .bf
                                 endndx symbols correctly.  */
-                             auxout = (finfo->outsyms
-                                       + ((finfo->last_bf_index
+                             auxout = (flaginfo->outsyms
+                                       + ((flaginfo->last_bf_index
                                            - syment_base)
                                           * osymesz));
 
                              bfd_coff_swap_aux_out (output_bfd,
-                                                    &finfo->last_bf,
+                                                    &flaginfo->last_bf,
                                                     isymp->n_type,
                                                     isymp->n_sclass,
                                                     0, isymp->n_numaux,
@@ -2075,18 +2105,18 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                              file_ptr pos;
 
                              /* We have already written out the last
-                                 .bf aux entry.  We need to write it
-                                 out again.  We borrow *outsym
-                                 temporarily.  FIXME: This case should
-                                 be made faster.  */
+                                .bf aux entry.  We need to write it
+                                out again.  We borrow *outsym
+                                temporarily.  FIXME: This case should
+                                be made faster.  */
                              bfd_coff_swap_aux_out (output_bfd,
-                                                    &finfo->last_bf,
+                                                    &flaginfo->last_bf,
                                                     isymp->n_type,
                                                     isymp->n_sclass,
                                                     0, isymp->n_numaux,
                                                     outsym);
                              pos = obj_sym_filepos (output_bfd);
-                             pos += finfo->last_bf_index * osymesz;
+                             pos += flaginfo->last_bf_index * osymesz;
                              if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
                                  || (bfd_bwrite (outsym, osymesz, output_bfd)
                                      != osymesz))
@@ -2095,14 +2125,14 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                        }
 
                      if (auxp->x_sym.x_fcnary.x_fcn.x_endndx.l != 0)
-                       finfo->last_bf_index = -1;
+                       flaginfo->last_bf_index = -1;
                      else
                        {
                          /* The endndx field of this aux entry must
-                             be updated with the symbol number of the
-                             next .bf symbol.  */
-                         finfo->last_bf = *auxp;
-                         finfo->last_bf_index = (((outsym - finfo->outsyms)
+                            be updated with the symbol number of the
+                            next .bf symbol.  */
+                         flaginfo->last_bf = *auxp;
+                         flaginfo->last_bf_index = (((outsym - flaginfo->outsyms)
                                                   / osymesz)
                                                  + syment_base);
                        }
@@ -2127,8 +2157,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
     }
 
   /* Relocate the line numbers, unless we are stripping them.  */
-  if (finfo->info->strip == strip_none
-      || finfo->info->strip == strip_some)
+  if (flaginfo->info->strip == strip_none
+      || flaginfo->info->strip == strip_some)
     {
       for (o = input_bfd->sections; o != NULL; o = o->next)
        {
@@ -2154,13 +2184,13 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
            continue;
 
          if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0
-             || bfd_bread (finfo->linenos, linesz * o->lineno_count,
+             || bfd_bread (flaginfo->linenos, linesz * o->lineno_count,
                           input_bfd) != linesz * o->lineno_count)
            return FALSE;
 
          offset = o->output_section->vma + o->output_offset - o->vma;
-         eline = finfo->linenos;
-         oeline = finfo->linenos;
+         eline = flaginfo->linenos;
+         oeline = flaginfo->linenos;
          elineend = eline + linesz * o->lineno_count;
          skipping = FALSE;
          for (; eline < elineend; eline += linesz)
@@ -2177,7 +2207,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                {
                  long indx;
 
-                 indx = finfo->sym_indices[iline.l_addr.l_symndx];
+                 indx = flaginfo->sym_indices[iline.l_addr.l_symndx];
 
                  if (indx < 0)
                    {
@@ -2203,7 +2233,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                         of the line numbers rather than an absolute
                         file index.  */
                      bfd_coff_swap_sym_in (output_bfd,
-                                           (finfo->outsyms
+                                           (flaginfo->outsyms
                                             + ((indx - syment_base)
                                                * osymesz)), &is);
                      if ((ISFCN (is.n_type)
@@ -2212,7 +2242,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                        {
                          void *auxptr;
 
-                         auxptr = (finfo->outsyms
+                         auxptr = (flaginfo->outsyms
                                    + ((indx - syment_base + 1)
                                       * osymesz));
                          bfd_coff_swap_aux_in (output_bfd, auxptr,
@@ -2221,7 +2251,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                          ia.x_sym.x_fcnary.x_fcn.x_lnnoptr =
                            (o->output_section->line_filepos
                             + o->output_section->lineno_count * linesz
-                            + eline - finfo->linenos);
+                            + eline - flaginfo->linenos);
                          bfd_coff_swap_aux_out (output_bfd, &ia,
                                                 is.n_type, is.n_sclass, 0,
                                                 is.n_numaux, auxptr);
@@ -2234,7 +2264,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                }
 
              if (!skipping)
-               {
+               {
                  bfd_coff_swap_lineno_out (output_bfd, &iline, oeline);
                  oeline += linesz;
                }
@@ -2242,9 +2272,9 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
 
          pos = o->output_section->line_filepos;
          pos += o->output_section->lineno_count * linesz;
-         amt = oeline - finfo->linenos;
+         amt = oeline - flaginfo->linenos;
          if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
-             || bfd_bwrite (finfo->linenos, amt, output_bfd) != amt)
+             || bfd_bwrite (flaginfo->linenos, amt, output_bfd) != amt)
            return FALSE;
 
          o->output_section->lineno_count += amt / linesz;
@@ -2255,30 +2285,30 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
      symbol will be the first symbol in the next input file.  In the
      normal case, this will save us from writing out the C_FILE symbol
      again.  */
-  if (finfo->last_file_index != -1
-      && (bfd_size_type) finfo->last_file_index >= syment_base)
+  if (flaginfo->last_file_index != -1
+      && (bfd_size_type) flaginfo->last_file_index >= syment_base)
     {
-      finfo->last_file.n_value = output_index;
-      bfd_coff_swap_sym_out (output_bfd, &finfo->last_file,
-                            (finfo->outsyms
-                             + ((finfo->last_file_index - syment_base)
+      flaginfo->last_file.n_value = output_index;
+      bfd_coff_swap_sym_out (output_bfd, &flaginfo->last_file,
+                            (flaginfo->outsyms
+                             + ((flaginfo->last_file_index - syment_base)
                                 * osymesz)));
     }
 
   /* Write the modified symbols to the output file.  */
-  if (outsym > finfo->outsyms)
+  if (outsym > flaginfo->outsyms)
     {
       file_ptr pos;
       bfd_size_type amt;
 
       pos = obj_sym_filepos (output_bfd) + syment_base * osymesz;
-      amt = outsym - finfo->outsyms;
+      amt = outsym - flaginfo->outsyms;
       if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
-         || bfd_bwrite (finfo->outsyms, amt, output_bfd) != amt)
+         || bfd_bwrite (flaginfo->outsyms, amt, output_bfd) != amt)
        return FALSE;
 
       BFD_ASSERT ((obj_raw_syment_count (output_bfd)
-                  + (outsym - finfo->outsyms) / osymesz)
+                  + (outsym - flaginfo->outsyms) / osymesz)
                  == output_index);
 
       obj_raw_syment_count (output_bfd) = output_index;
@@ -2304,8 +2334,9 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
          if ((o->flags & SEC_RELOC) != 0
              && o->reloc_count != 0)
            {
-             (*_bfd_error_handler)
-               (_("%B: relocs in section `%A', but it has no contents"),
+             _bfd_error_handler
+               /* xgettext: c-format */
+               (_("%pB: relocs in section `%pA', but it has no contents"),
                 input_bfd, o);
              bfd_set_error (bfd_error_no_contents);
              return FALSE;
@@ -2319,10 +2350,9 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
        contents = secdata->contents;
       else
        {
-         bfd_size_type x = o->rawsize ? o->rawsize : o->size;
-         if (! bfd_get_section_contents (input_bfd, o, finfo->contents, 0, x))
+         contents = flaginfo->contents;
+         if (! bfd_get_full_section_contents (input_bfd, o, &contents))
            return FALSE;
-         contents = finfo->contents;
        }
 
       if ((o->flags & SEC_RELOC) != 0)
@@ -2334,26 +2364,57 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
          /* Read in the relocs.  */
          target_index = o->output_section->target_index;
          internal_relocs = (_bfd_coff_read_internal_relocs
-                            (input_bfd, o, FALSE, finfo->external_relocs,
-                             finfo->info->relocatable,
-                             (finfo->info->relocatable
-                              ? (finfo->section_info[target_index].relocs
+                            (input_bfd, o, FALSE, flaginfo->external_relocs,
+                             bfd_link_relocatable (flaginfo->info),
+                             (bfd_link_relocatable (flaginfo->info)
+                              ? (flaginfo->section_info[target_index].relocs
                                  + o->output_section->reloc_count)
-                              : finfo->internal_relocs)));
-         if (internal_relocs == NULL)
+                              : flaginfo->internal_relocs)));
+         if (internal_relocs == NULL
+             && o->reloc_count > 0)
            return FALSE;
 
+         /* Run through the relocs looking for relocs against symbols
+            coming from discarded sections and complain about them.  */
+         irel = internal_relocs;
+         for (; irel < &internal_relocs[o->reloc_count]; irel++)
+           {
+             struct coff_link_hash_entry *h;
+             asection *ps = NULL;
+             long symndx = irel->r_symndx;
+             if (symndx < 0)
+               continue;
+             h = obj_coff_sym_hashes (input_bfd)[symndx];
+             if (h == NULL)
+               continue;
+             while (h->root.type == bfd_link_hash_indirect
+                    || h->root.type == bfd_link_hash_warning)
+               h = (struct coff_link_hash_entry *) h->root.u.i.link;
+             if (h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak)
+               ps = h->root.u.def.section;
+             if (ps == NULL)
+               continue;
+             /* Complain if definition comes from an excluded section.  */
+             if (ps->flags & SEC_EXCLUDE)
+               (*flaginfo->info->callbacks->einfo)
+                 /* xgettext: c-format */
+                 (_("%X`%s' referenced in section `%pA' of %pB: "
+                    "defined in discarded section `%pA' of %pB\n"),
+                  h->root.root.string, o, input_bfd, ps, ps->owner);
+           }
+
          /* Call processor specific code to relocate the section
-             contents.  */
-         if (! bfd_coff_relocate_section (output_bfd, finfo->info,
+            contents.  */
+         if (! bfd_coff_relocate_section (output_bfd, flaginfo->info,
                                           input_bfd, o,
                                           contents,
                                           internal_relocs,
-                                          finfo->internal_syms,
-                                          finfo->sec_ptrs))
+                                          flaginfo->internal_syms,
+                                          flaginfo->sec_ptrs))
            return FALSE;
 
-         if (finfo->info->relocatable)
+         if (bfd_link_relocatable (flaginfo->info))
            {
              bfd_vma offset;
              struct internal_reloc *irelend;
@@ -2362,7 +2423,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
              offset = o->output_section->vma + o->output_offset - o->vma;
              irel = internal_relocs;
              irelend = irel + o->reloc_count;
-             rel_hash = (finfo->section_info[target_index].rel_hashes
+             rel_hash = (flaginfo->section_info[target_index].rel_hashes
                          + o->output_section->reloc_count);
              for (; irel < irelend; irel++, rel_hash++)
                {
@@ -2379,7 +2440,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
 
                  if (adjust_symndx)
                    {
-                     if (! (*adjust_symndx) (output_bfd, finfo->info,
+                     if (! (*adjust_symndx) (output_bfd, flaginfo->info,
                                              input_bfd, o, irel,
                                              &adjusted))
                        return FALSE;
@@ -2409,7 +2470,7 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                    {
                      long indx;
 
-                     indx = finfo->sym_indices[irel->r_symndx];
+                     indx = flaginfo->sym_indices[irel->r_symndx];
                      if (indx != -1)
                        irel->r_symndx = indx;
                      else
@@ -2419,20 +2480,18 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                          char buf[SYMNMLEN + 1];
 
                          /* This reloc is against a symbol we are
-                             stripping.  This should have been handled
+                            stripping.  This should have been handled
                             by the 'dont_skip_symbol' code in the while
                             loop at the top of this function.  */
-                         is = finfo->internal_syms + irel->r_symndx;
+                         is = flaginfo->internal_syms + irel->r_symndx;
 
                          name = (_bfd_coff_internal_syment_name
                                  (input_bfd, is, buf));
                          if (name == NULL)
                            return FALSE;
 
-                         if (! ((*finfo->info->callbacks->unattached_reloc)
-                                (finfo->info, name, input_bfd, o,
-                                 irel->r_vaddr)))
-                           return FALSE;
+                         (*flaginfo->info->callbacks->unattached_reloc)
+                           (flaginfo->info, name, input_bfd, o, irel->r_vaddr);
                        }
                    }
                }
@@ -2444,7 +2503,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
       /* Write out the modified section contents.  */
       if (secdata == NULL || secdata->stab_info == NULL)
        {
-         file_ptr loc = o->output_offset * bfd_octets_per_byte (output_bfd);
+         file_ptr loc = (o->output_offset
+                         * bfd_octets_per_byte (output_bfd, o));
          if (! bfd_set_section_contents (output_bfd, o->output_section,
                                          contents, loc, o->size))
            return FALSE;
@@ -2452,32 +2512,33 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
       else
        {
          if (! (_bfd_write_section_stabs
-                (output_bfd, &coff_hash_table (finfo->info)->stab_info,
+                (output_bfd, &coff_hash_table (flaginfo->info)->stab_info,
                  o, &secdata->stab_info, contents)))
            return FALSE;
        }
     }
 
-  if (! finfo->info->keep_memory
+  if (! flaginfo->info->keep_memory
       && ! _bfd_coff_free_symbols (input_bfd))
     return FALSE;
 
   return TRUE;
 }
 
-/* Write out a global symbol.  Called via coff_link_hash_traverse.  */
+/* Write out a global symbol.  Called via bfd_hash_traverse.  */
 
 bfd_boolean
-_bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
+_bfd_coff_write_global_sym (struct bfd_hash_entry *bh, void *data)
 {
-  struct coff_final_link_info *finfo = (struct coff_final_link_info *) data;
+  struct coff_link_hash_entry *h = (struct coff_link_hash_entry *) bh;
+  struct coff_final_link_info *flaginfo = (struct coff_final_link_info *) data;
   bfd *output_bfd;
   struct internal_syment isym;
   bfd_size_type symesz;
   unsigned int i;
   file_ptr pos;
 
-  output_bfd = finfo->output_bfd;
+  output_bfd = flaginfo->output_bfd;
 
   if (h->root.type == bfd_link_hash_warning)
     {
@@ -2490,9 +2551,9 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
     return TRUE;
 
   if (h->indx != -2
-      && (finfo->info->strip == strip_all
-         || (finfo->info->strip == strip_some
-             && (bfd_hash_lookup (finfo->info->keep_hash,
+      && (flaginfo->info->strip == strip_all
+         || (flaginfo->info->strip == strip_some
+             && (bfd_hash_lookup (flaginfo->info->keep_hash,
                                   h->root.root.string, FALSE, FALSE)
                  == NULL))))
     return TRUE;
@@ -2523,7 +2584,7 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
          isym.n_scnum = sec->target_index;
        isym.n_value = (h->root.u.def.value
                        + h->root.u.def.section->output_offset);
-       if (! obj_pe (finfo->output_bfd))
+       if (! obj_pe (flaginfo->output_bfd))
          isym.n_value += sec->vma;
       }
       break;
@@ -2546,13 +2607,13 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
       bfd_size_type indx;
 
       hash = TRUE;
-      if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
+      if (flaginfo->info->traditional_format)
        hash = FALSE;
-      indx = _bfd_stringtab_add (finfo->strtab, h->root.root.string, hash,
+      indx = _bfd_stringtab_add (flaginfo->strtab, h->root.root.string, hash,
                                 FALSE);
       if (indx == (bfd_size_type) -1)
        {
-         finfo->failed = TRUE;
+         flaginfo->failed = TRUE;
          return FALSE;
        }
       isym._n._n_n._n_zeroes = 0;
@@ -2569,7 +2630,7 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
      defined globals to statics, then do that conversion now.  If the
      symbol is not being converted, just ignore it and it will be
      output during a later pass.  */
-  if (finfo->global_to_static)
+  if (flaginfo->global_to_static)
     {
       if (! IS_EXTERNAL (output_bfd, isym))
        return TRUE;
@@ -2580,23 +2641,23 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
   /* When a weak symbol is not overridden by a strong one,
      turn it into an external symbol when not building a
      shared or relocatable object.  */
-  if (! finfo->info->shared
-      && ! finfo->info->relocatable
-      && IS_WEAK_EXTERNAL (finfo->output_bfd, isym))
+  if (! bfd_link_pic (flaginfo->info)
+      && ! bfd_link_relocatable (flaginfo->info)
+      && IS_WEAK_EXTERNAL (flaginfo->output_bfd, isym))
     isym.n_sclass = C_EXT;
 
   isym.n_numaux = h->numaux;
 
-  bfd_coff_swap_sym_out (output_bfd, &isym, finfo->outsyms);
+  bfd_coff_swap_sym_out (output_bfd, &isym, flaginfo->outsyms);
 
   symesz = bfd_coff_symesz (output_bfd);
 
   pos = obj_sym_filepos (output_bfd);
   pos += obj_raw_syment_count (output_bfd) * symesz;
   if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
-      || bfd_bwrite (finfo->outsyms, symesz, output_bfd) != symesz)
+      || bfd_bwrite (flaginfo->outsyms, symesz, output_bfd) != symesz)
     {
-      finfo->failed = TRUE;
+      flaginfo->failed = TRUE;
       return FALSE;
     }
 
@@ -2615,7 +2676,7 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
       auxp = h->aux + i;
 
       /* Look for a section aux entry here using the same tests that
-         coff_swap_aux_out uses.  */
+        coff_swap_aux_out uses.  */
       if (i == 0
          && (isym.n_sclass == C_STAT
              || isym.n_sclass == C_HIDDEN)
@@ -2631,24 +2692,22 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
              auxp->x_scn.x_scnlen = sec->size;
 
              /* For PE, an overflow on the final link reportedly does
-                 not matter.  FIXME: Why not?  */
+                not matter.  FIXME: Why not?  */
              if (sec->reloc_count > 0xffff
                  && (! obj_pe (output_bfd)
-                     || finfo->info->relocatable))
-               (*_bfd_error_handler)
-                 (_("%s: %s: reloc overflow: 0x%lx > 0xffff"),
-                  bfd_get_filename (output_bfd),
-                  bfd_get_section_name (output_bfd, sec),
-                  sec->reloc_count);
+                     || bfd_link_relocatable (flaginfo->info)))
+               _bfd_error_handler
+                 /* xgettext: c-format */
+                 (_("%pB: %pA: reloc overflow: %#x > 0xffff"),
+                  output_bfd, sec, sec->reloc_count);
 
              if (sec->lineno_count > 0xffff
                  && (! obj_pe (output_bfd)
-                     || finfo->info->relocatable))
-               (*_bfd_error_handler)
-                 (_("%s: warning: %s: line number overflow: 0x%lx > 0xffff"),
-                  bfd_get_filename (output_bfd),
-                  bfd_get_section_name (output_bfd, sec),
-                  sec->lineno_count);
+                     || bfd_link_relocatable (flaginfo->info)))
+               _bfd_error_handler
+                 /* xgettext: c-format */
+                 (_("%pB: warning: %pA: line number overflow: %#x > 0xffff"),
+                  output_bfd, sec, sec->lineno_count);
 
              auxp->x_scn.x_nreloc = sec->reloc_count;
              auxp->x_scn.x_nlinno = sec->lineno_count;
@@ -2660,10 +2719,10 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
 
       bfd_coff_swap_aux_out (output_bfd, auxp, isym.n_type,
                             isym.n_sclass, (int) i, isym.n_numaux,
-                            finfo->outsyms);
-      if (bfd_bwrite (finfo->outsyms, symesz, output_bfd) != symesz)
+                            flaginfo->outsyms);
+      if (bfd_bwrite (flaginfo->outsyms, symesz, output_bfd) != symesz)
        {
-         finfo->failed = TRUE;
+         flaginfo->failed = TRUE;
          return FALSE;
        }
       ++obj_raw_syment_count (output_bfd);
@@ -2679,7 +2738,7 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
 bfd_boolean
 _bfd_coff_write_task_globals (struct coff_link_hash_entry *h, void *data)
 {
-  struct coff_final_link_info *finfo = (struct coff_final_link_info *) data;
+  struct coff_final_link_info *flaginfo = (struct coff_final_link_info *) data;
   bfd_boolean rtnval = TRUE;
   bfd_boolean save_global_to_static;
 
@@ -2692,10 +2751,10 @@ _bfd_coff_write_task_globals (struct coff_link_hash_entry *h, void *data)
        {
        case bfd_link_hash_defined:
        case bfd_link_hash_defweak:
-         save_global_to_static = finfo->global_to_static;
-         finfo->global_to_static = TRUE;
-         rtnval = _bfd_coff_write_global_sym (h, data);
-         finfo->global_to_static = save_global_to_static;
+         save_global_to_static = flaginfo->global_to_static;
+         flaginfo->global_to_static = TRUE;
+         rtnval = _bfd_coff_write_global_sym (&h->root.root, data);
+         flaginfo->global_to_static = save_global_to_static;
          break;
        default:
          break;
@@ -2708,7 +2767,7 @@ _bfd_coff_write_task_globals (struct coff_link_hash_entry *h, void *data)
 
 bfd_boolean
 _bfd_coff_reloc_link_order (bfd *output_bfd,
-                           struct coff_final_link_info *finfo,
+                           struct coff_final_link_info *flaginfo,
                            asection *output_section,
                            struct bfd_link_order *link_order)
 {
@@ -2733,11 +2792,11 @@ _bfd_coff_reloc_link_order (bfd *output_bfd,
 
       size = bfd_get_reloc_size (howto);
       buf = (bfd_byte *) bfd_zmalloc (size);
-      if (buf == NULL)
+      if (buf == NULL && size != 0)
        return FALSE;
 
       rstat = _bfd_relocate_contents (howto, output_bfd,
-                                     (bfd_vma) link_order->u.reloc.p->addend,\
+                                     (bfd_vma) link_order->u.reloc.p->addend,
                                      buf);
       switch (rstat)
        {
@@ -2747,23 +2806,19 @@ _bfd_coff_reloc_link_order (bfd *output_bfd,
        case bfd_reloc_outofrange:
          abort ();
        case bfd_reloc_overflow:
-         if (! ((*finfo->info->callbacks->reloc_overflow)
-                (finfo->info, NULL,
-                 (link_order->type == bfd_section_reloc_link_order
-                  ? bfd_section_name (output_bfd,
-                                      link_order->u.reloc.p->u.section)
-                  : link_order->u.reloc.p->u.name),
-                 howto->name, link_order->u.reloc.p->addend,
-                 (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
-           {
-             free (buf);
-             return FALSE;
-           }
+         (*flaginfo->info->callbacks->reloc_overflow)
+           (flaginfo->info, NULL,
+            (link_order->type == bfd_section_reloc_link_order
+             ? bfd_section_name (link_order->u.reloc.p->u.section)
+             : link_order->u.reloc.p->u.name),
+            howto->name, link_order->u.reloc.p->addend,
+            (bfd *) NULL, (asection *) NULL, (bfd_vma) 0);
          break;
        }
-      loc = link_order->offset * bfd_octets_per_byte (output_bfd);
+      loc = link_order->offset * bfd_octets_per_byte (output_bfd,
+                                                     output_section);
       ok = bfd_set_section_contents (output_bfd, output_section, buf,
-                                     loc, size);
+                                    loc, size);
       free (buf);
       if (! ok)
        return FALSE;
@@ -2771,9 +2826,9 @@ _bfd_coff_reloc_link_order (bfd *output_bfd,
 
   /* Store the reloc information in the right place.  It will get
      swapped and written out at the end of the final_link routine.  */
-  irel = (finfo->section_info[output_section->target_index].relocs
+  irel = (flaginfo->section_info[output_section->target_index].relocs
          + output_section->reloc_count);
-  rel_hash_ptr = (finfo->section_info[output_section->target_index].rel_hashes
+  rel_hash_ptr = (flaginfo->section_info[output_section->target_index].rel_hashes
                  + output_section->reloc_count);
 
   memset (irel, 0, sizeof (struct internal_reloc));
@@ -2784,9 +2839,9 @@ _bfd_coff_reloc_link_order (bfd *output_bfd,
   if (link_order->type == bfd_section_reloc_link_order)
     {
       /* We need to somehow locate a symbol in the right section.  The
-         symbol must either have a value of zero, or we must adjust
-         the addend by the value of the symbol.  FIXME: Write this
-         when we need it.  The old linker couldn't handle this anyhow.  */
+        symbol must either have a value of zero, or we must adjust
+        the addend by the value of the symbol.  FIXME: Write this
+        when we need it.  The old linker couldn't handle this anyhow.  */
       abort ();
       *rel_hash_ptr = NULL;
       irel->r_symndx = 0;
@@ -2796,7 +2851,7 @@ _bfd_coff_reloc_link_order (bfd *output_bfd,
       struct coff_link_hash_entry *h;
 
       h = ((struct coff_link_hash_entry *)
-          bfd_wrapped_link_hash_lookup (output_bfd, finfo->info,
+          bfd_wrapped_link_hash_lookup (output_bfd, flaginfo->info,
                                         link_order->u.reloc.p->u.name,
                                         FALSE, FALSE, TRUE));
       if (h != NULL)
@@ -2814,10 +2869,9 @@ _bfd_coff_reloc_link_order (bfd *output_bfd,
        }
       else
        {
-         if (! ((*finfo->info->callbacks->unattached_reloc)
-                (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL,
-                 (asection *) NULL, (bfd_vma) 0)))
-           return FALSE;
+         (*flaginfo->info->callbacks->unattached_reloc)
+           (flaginfo->info, link_order->u.reloc.p->u.name,
+            (bfd *) NULL, (asection *) NULL, (bfd_vma) 0);
          irel->r_symndx = 0;
        }
     }
@@ -2859,6 +2913,7 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
       struct internal_syment *sym;
       bfd_vma addend;
       bfd_vma val;
+      asection *sec;
       reloc_howto_type *howto;
       bfd_reloc_status_type rstat;
 
@@ -2872,8 +2927,9 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
       else if (symndx < 0
               || (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
        {
-         (*_bfd_error_handler)
-           ("%B: illegal symbol index %ld in relocs", input_bfd, symndx);
+         _bfd_error_handler
+           /* xgettext: c-format */
+           (_("%pB: illegal symbol index %ld in relocs"), input_bfd, symndx);
          return FALSE;
        }
       else
@@ -2883,9 +2939,9 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
        }
 
       /* COFF treats common symbols in one of two ways.  Either the
-         size of the symbol is included in the section contents, or it
-         is not.  We assume that the size is not included, and force
-         the rtype_to_howto function to adjust the addend as needed.  */
+        size of the symbol is included in the section contents, or it
+        is not.  We assume that the size is not included, and force
+        the rtype_to_howto function to adjust the addend as needed.  */
       if (sym != NULL && sym->n_scnum != 0)
        addend = - sym->n_value;
       else
@@ -2897,23 +2953,21 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
        return FALSE;
 
       /* If we are doing a relocatable link, then we can just ignore
-         a PC relative reloc that is pcrel_offset.  It will already
-         have the correct value.  If this is not a relocatable link,
-         then we should ignore the symbol value.  */
+        a PC relative reloc that is pcrel_offset.  It will already
+        have the correct value.  If this is not a relocatable link,
+        then we should ignore the symbol value.  */
       if (howto->pc_relative && howto->pcrel_offset)
        {
-         if (info->relocatable)
+         if (bfd_link_relocatable (info))
            continue;
          if (sym != NULL && sym->n_scnum != 0)
            addend += sym->n_value;
        }
 
       val = 0;
-
+      sec = NULL;
       if (h == NULL)
        {
-         asection *sec;
-
          if (symndx == -1)
            {
              sec = bfd_abs_section_ptr;
@@ -2922,7 +2976,13 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
          else
            {
              sec = sections[symndx];
-              val = (sec->output_section->vma
+
+             /* PR 19623: Relocations against symbols in
+                the absolute sections should ignored.  */
+             if (bfd_is_abs_section (sec))
+               continue;
+
+             val = (sec->output_section->vma
                     + sec->output_offset
                     + sym->n_value);
              if (! obj_pe (input_bfd))
@@ -2935,8 +2995,6 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
              || h->root.type == bfd_link_hash_defweak)
            {
              /* Defined weak symbols are a GNU extension. */
-             asection *sec;
-
              sec = h->root.u.def.section;
              val = (h->root.u.def.value
                     + sec->output_section->vma
@@ -2945,10 +3003,10 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
 
          else if (h->root.type == bfd_link_hash_undefweak)
            {
-              if (h->symbol_class == C_NT_WEAK && h->numaux == 1)
+             if (h->symbol_class == C_NT_WEAK && h->numaux == 1)
                {
                  /* See _Microsoft Portable Executable and Common Object
-                     File Format Specification_, section 5.5.3.
+                    File Format Specification_, section 5.5.3.
                     Note that weak symbols without aux records are a GNU
                     extension.
                     FIXME: All weak externals are treated as having
@@ -2957,9 +3015,8 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
                     will resolve a weak external only if a normal
                     external causes the library member to be linked.
                     See also linker.c: generic_link_check_archive_element. */
-                 asection *sec;
                  struct coff_link_hash_entry *h2 =
-                   input_bfd->tdata.coff_obj_data->sym_hashes[
+                   h->auxbfd->tdata.coff_obj_data->sym_hashes[
                    h->aux->x_sym.x_tagndx.l];
 
                  if (!h2 || h2->root.type == bfd_link_hash_undefined)
@@ -2975,17 +3032,23 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
                    }
                }
              else
-                /* This is a GNU extension.  */
+               /* This is a GNU extension.  */
                val = 0;
            }
 
-         else if (! info->relocatable)
-           {
-             if (! ((*info->callbacks->undefined_symbol)
-                    (info, h->root.root.string, input_bfd, input_section,
-                     rel->r_vaddr - input_section->vma, TRUE)))
-               return FALSE;
-           }
+         else if (! bfd_link_relocatable (info))
+           (*info->callbacks->undefined_symbol)
+             (info, h->root.root.string, input_bfd, input_section,
+              rel->r_vaddr - input_section->vma, TRUE);
+       }
+
+      /* If the input section defining the symbol has been discarded
+        then zero this reloc field.  */
+      if (sec != NULL && discarded_section (sec))
+       {
+         _bfd_clear_contents (howto, input_bfd, input_section,
+                              contents, rel->r_vaddr - input_section->vma);
+         continue;
        }
 
       if (info->base_file)
@@ -3026,9 +3089,10 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
        case bfd_reloc_ok:
          break;
        case bfd_reloc_outofrange:
-         (*_bfd_error_handler)
-           (_("%B: bad reloc address 0x%lx in section `%A'"),
-            input_bfd, input_section, (unsigned long) rel->r_vaddr);
+         _bfd_error_handler
+           /* xgettext: c-format */
+           (_("%pB: bad reloc address %#" PRIx64 " in section `%pA'"),
+            input_bfd, (uint64_t) rel->r_vaddr, input_section);
          return FALSE;
        case bfd_reloc_overflow:
          {
@@ -3046,11 +3110,10 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
                  return FALSE;
              }
 
-           if (! ((*info->callbacks->reloc_overflow)
-                  (info, (h ? &h->root : NULL), name, howto->name,
-                   (bfd_vma) 0, input_bfd, input_section,
-                   rel->r_vaddr - input_section->vma)))
-             return FALSE;
+           (*info->callbacks->reloc_overflow)
+             (info, (h ? &h->root : NULL), name, howto->name,
+              (bfd_vma) 0, input_bfd, input_section,
+              rel->r_vaddr - input_section->vma);
          }
        }
     }