bfd/
[deliverable/binutils-gdb.git] / binutils / objcopy.c
index e577dd30160b55bed773cae29f09da23324542ab..b7c84d841771dca3d6560ecb20797f7c37017adf 100644 (file)
@@ -1,6 +1,6 @@
 /* objcopy.c -- copy object file from input to output, optionally massaging it.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 #include "elf-bfd.h"
 #include <sys/stat.h>
 #include "libbfd.h"
-
-/* A list of symbols to explicitly strip out, or to keep.  A linked
-   list is good enough for a small number from the command line, but
-   this will slow things down a lot if many symbols are being
-   deleted.  */
-
-struct symlist
+#include "coff/internal.h"
+#include "libcoff.h"
+
+/* FIXME: See bfd/peXXigen.c for why we include an architecture specific
+   header in generic PE code.  */
+#include "coff/i386.h"
+#include "coff/pe.h"
+
+static bfd_vma pe_file_alignment = (bfd_vma) -1;
+static bfd_vma pe_heap_commit = (bfd_vma) -1;
+static bfd_vma pe_heap_reserve = (bfd_vma) -1;
+static bfd_vma pe_image_base = (bfd_vma) -1;
+static bfd_vma pe_section_alignment = (bfd_vma) -1;
+static bfd_vma pe_stack_commit = (bfd_vma) -1;
+static bfd_vma pe_stack_reserve = (bfd_vma) -1;
+static short pe_subsystem = -1;
+static short pe_major_subsystem_version = -1;
+static short pe_minor_subsystem_version = -1;
+
+struct is_specified_symbol_predicate_data
 {
-  const char *name;
-  struct symlist *next;
+  const char   *name;
+  bfd_boolean  found;
 };
 
 /* A list to support redefine_sym.  */
@@ -64,8 +77,6 @@ section_rename;
 /* List of sections to be renamed.  */
 static section_rename *section_rename_list;
 
-#define RETURN_NONFATAL(s) {bfd_nonfatal (s); status = 1; return;}
-
 static asymbol **isympp = NULL;        /* Input symbols.  */
 static asymbol **osympp = NULL;        /* Output symbols that survive stripping.  */
 
@@ -196,13 +207,13 @@ static bfd_boolean localize_hidden = FALSE;
 
 /* List of symbols to strip, keep, localize, keep-global, weaken,
    or redefine.  */
-static struct symlist *strip_specific_list = NULL;
-static struct symlist *strip_unneeded_list = NULL;
-static struct symlist *keep_specific_list = NULL;
-static struct symlist *localize_specific_list = NULL;
-static struct symlist *globalize_specific_list = NULL;
-static struct symlist *keepglobal_specific_list = NULL;
-static struct symlist *weaken_specific_list = NULL;
+static htab_t strip_specific_htab = NULL;
+static htab_t strip_unneeded_htab = NULL;
+static htab_t keep_specific_htab = NULL;
+static htab_t localize_specific_htab = NULL;
+static htab_t globalize_specific_htab = NULL;
+static htab_t keepglobal_specific_htab = NULL;
+static htab_t weaken_specific_htab = NULL;
 static struct redefine_node *redefine_sym_list = NULL;
 
 /* If this is TRUE, we weaken global symbols (set BSF_WEAK).  */
@@ -223,6 +234,18 @@ static bfd_boolean extract_symbol = FALSE;
    of <reverse_bytes> bytes within each output section.  */
 static int reverse_bytes = 0;
 
+/* For Coff objects, we may want to allow or disallow long section names,
+   or preserve them where found in the inputs.  Debug info relies on them.  */
+enum long_section_name_handling
+  {
+    DISABLE,
+    ENABLE,
+    KEEP
+  };
+
+/* The default long section handling mode is to preserve them.
+   This is also the only behaviour for 'strip'.  */
+static enum long_section_name_handling long_section_names = KEEP;
 
 /* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
 enum command_line_switch
@@ -254,6 +277,7 @@ enum command_line_switch
     OPTION_KEEP_SYMBOLS,
     OPTION_LOCALIZE_HIDDEN,
     OPTION_LOCALIZE_SYMBOLS,
+    OPTION_LONG_SECTION_NAMES,
     OPTION_GLOBALIZE_SYMBOL,
     OPTION_GLOBALIZE_SYMBOLS,
     OPTION_KEEPGLOBAL_SYMBOLS,
@@ -272,7 +296,13 @@ enum command_line_switch
     OPTION_PURE,
     OPTION_IMPURE,
     OPTION_EXTRACT_SYMBOL,
-    OPTION_REVERSE_BYTES
+    OPTION_REVERSE_BYTES,
+    OPTION_FILE_ALIGNMENT,
+    OPTION_HEAP,
+    OPTION_IMAGE_BASE,
+    OPTION_SECTION_ALIGNMENT,
+    OPTION_STACK,
+    OPTION_SUBSYSTEM
   };
 
 /* Options to handle if running as "strip".  */
@@ -347,6 +377,7 @@ static struct option copy_options[] =
   {"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN},
   {"localize-symbol", required_argument, 0, 'L'},
   {"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
+  {"long-section-names", required_argument, 0, OPTION_LONG_SECTION_NAMES},
   {"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
   {"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
   {"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
@@ -385,6 +416,12 @@ static struct option copy_options[] =
   {"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS},
   {"wildcard", no_argument, 0, 'w'},
   {"writable-text", no_argument, 0, OPTION_WRITABLE_TEXT},
+  {"file-alignment", required_argument, 0, OPTION_FILE_ALIGNMENT},
+  {"heap", required_argument, 0, OPTION_HEAP},
+  {"image-base", required_argument, 0 , OPTION_IMAGE_BASE},
+  {"section-alignment", required_argument, 0, OPTION_SECTION_ALIGNMENT},
+  {"stack", required_argument, 0, OPTION_STACK},
+  {"subsystem", required_argument, 0, OPTION_SUBSYSTEM},
   {0, no_argument, 0, 0}
 };
 
@@ -477,6 +514,8 @@ copy_usage (FILE *stream, int exit_status)
                                    Set section <name>'s properties to <flags>\n\
      --add-section <name>=<file>   Add section <name> found in <file> to output\n\
      --rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\
+     --long-section-names {enable|disable|keep}\n\
+                                   Handle long section names in Coff objects.\n\
      --change-leading-char         Force output format's leading character style\n\
      --remove-leading-char         Remove leading character from global symbols\n\
      --reverse-bytes=<num>         Reverse <num> bytes at a time, in output sections with content\n\
@@ -504,6 +543,15 @@ copy_usage (FILE *stream, int exit_status)
      --prefix-alloc-sections <prefix>\n\
                                    Add <prefix> to start of every allocatable\n\
                                      section name\n\
+     --file-alignment <num>        Set PE file alignment to <num>\n\
+     --heap <reserve>[,<commit>]   Set PE reserve/commit heap to <reserve>/\n\
+                                   <commit>\n\
+     --image-base <address>        Set PE image base to <address>\n\
+     --section-alignment <num>     Set PE section alignment to <num>\n\
+     --stack <reserve>[,<commit>]  Set PE reserve/commit stack to <reserve>/\n\
+                                   <commit>\n\
+     --subsystem <name>[:<version>]\n\
+                                   Set PE subsystem to <name> [& <version>]\n]\
   -v --verbose                     List all object files modified\n\
   @<file>                          Read options from <file>\n\
   -V --version                     Display this program's version number\n\
@@ -639,17 +687,38 @@ find_section_list (const char *name, bfd_boolean add)
   return p;
 }
 
-/* Add a symbol to strip_specific_list.  */
+/* There is htab_hash_string but no htab_eq_string. Makes sense.  */
+
+static int
+eq_string (const void *s1, const void *s2)
+{
+  return strcmp (s1, s2) == 0;
+}
+
+static htab_t
+create_symbol_htab (void)
+{
+  return htab_create_alloc (16, htab_hash_string, eq_string, NULL, xcalloc, free);
+}
 
 static void
-add_specific_symbol (const char *name, struct symlist **list)
+create_symbol_htabs (void)
 {
-  struct symlist *tmp_list;
+  strip_specific_htab = create_symbol_htab ();
+  strip_unneeded_htab = create_symbol_htab ();
+  keep_specific_htab = create_symbol_htab ();
+  localize_specific_htab = create_symbol_htab ();
+  globalize_specific_htab = create_symbol_htab ();
+  keepglobal_specific_htab = create_symbol_htab ();
+  weaken_specific_htab = create_symbol_htab ();
+}
+
+/* Add a symbol to strip_specific_list.  */
 
-  tmp_list = xmalloc (sizeof (struct symlist));
-  tmp_list->name = name;
-  tmp_list->next = *list;
-  *list = tmp_list;
+static void
+add_specific_symbol (const char *name, htab_t htab)
+{
+  *htab_find_slot (htab, name, INSERT) = (char *) name;
 }
 
 /* Add symbols listed in `filename' to strip_specific_list.  */
@@ -658,7 +727,7 @@ add_specific_symbol (const char *name, struct symlist **list)
 #define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
 
 static void
-add_specific_symbols (const char *filename, struct symlist **list)
+add_specific_symbols (const char *filename, htab_t htab)
 {
   off_t  size;
   FILE * f;
@@ -759,7 +828,7 @@ add_specific_symbols (const char *filename, struct symlist **list)
       * name_end = '\0';
 
       if (name_end > name)
-       add_specific_symbol (name, list);
+       add_specific_symbol (name, htab);
 
       /* Advance line pointer to end of line.  The 'eol ++' in the for
         loop above will then advance us to the start of the next line.  */
@@ -768,36 +837,54 @@ add_specific_symbols (const char *filename, struct symlist **list)
     }
 }
 
-/* See whether a symbol should be stripped or kept based on
-   strip_specific_list and keep_symbols.  */
+/* See whether a symbol should be stripped or kept
+   based on strip_specific_list and keep_symbols.  */
 
-static bfd_boolean
-is_specified_symbol (const char *name, struct symlist *list)
+static int
+is_specified_symbol_predicate (void **slot, void *data)
 {
-  struct symlist *tmp_list;
+  struct is_specified_symbol_predicate_data *d = data;
+  const char *slot_name = *slot;
 
-  if (wildcard)
+  if (*slot_name != '!')
     {
-      for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
-       if (*(tmp_list->name) != '!')
-         {
-           if (!fnmatch (tmp_list->name, name, 0))
-             return TRUE;
-         }
-       else
-         {
-           if (fnmatch (tmp_list->name + 1, name, 0))
-             return TRUE;
-         }
+      if (! fnmatch (slot_name, d->name, 0))
+       {
+         d->found = TRUE;
+         /* Stop traversal.  */
+         return 0;
+       }
     }
   else
     {
-      for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
-       if (strcmp (name, tmp_list->name) == 0)
-         return TRUE;
+      if (fnmatch (slot_name + 1, d->name, 0))
+       {
+         d->found = TRUE;
+         /* Stop traversal.  */
+         return 0;
+       }
     }
 
-  return FALSE;
+  /* Continue traversal.  */
+  return 1;
+}
+
+static bfd_boolean
+is_specified_symbol (const char *name, htab_t htab)
+{
+  if (wildcard)
+    {
+      struct is_specified_symbol_predicate_data data;
+
+      data.name = name;
+      data.found = FALSE;
+
+      htab_traverse (htab, is_specified_symbol_predicate, &data);
+
+      return data.found;
+    }
+
+  return htab_find (htab, name) != NULL;
 }
 
 /* Return a pointer to the symbol used as a signature for GROUP.  */
@@ -874,8 +961,8 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
       else
        gname = sec->name;
       if ((strip_symbols == STRIP_ALL
-          && !is_specified_symbol (gname, keep_specific_list))
-         || is_specified_symbol (gname, strip_specific_list))
+          && !is_specified_symbol (gname, keep_specific_htab))
+         || is_specified_symbol (gname, strip_specific_htab))
        return TRUE;
     }
 
@@ -996,7 +1083,8 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
          used_in_reloc = TRUE;
        }
       else if (relocatable                     /* Relocatable file.  */
-              && (flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
+              && ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
+                  || bfd_is_com_section (bfd_get_section (sym))))
        keep = TRUE;
       else if (bfd_decode_symclass (sym) == 'I')
        /* Global symbols in $idata sections need to be retained
@@ -1023,7 +1111,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
                    && (discard_locals != LOCALS_START_L
                        || ! bfd_is_local_label (abfd, sym))));
 
-      if (keep && is_specified_symbol (name, strip_specific_list))
+      if (keep && is_specified_symbol (name, strip_specific_htab))
        {
          /* There are multiple ways to set 'keep' above, but if it
             was the relocatable symbol case, then that's an error.  */
@@ -1038,12 +1126,12 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
 
       if (keep
          && !(flags & BSF_KEEP)
-         && is_specified_symbol (name, strip_unneeded_list))
+         && is_specified_symbol (name, strip_unneeded_htab))
        keep = FALSE;
 
       if (!keep
          && ((keep_file_symbols && (flags & BSF_FILE))
-             || is_specified_symbol (name, keep_specific_list)))
+             || is_specified_symbol (name, keep_specific_htab)))
        keep = TRUE;
 
       if (keep && is_strip_section (abfd, bfd_get_section (sym)))
@@ -1052,7 +1140,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
       if (keep)
        {
          if ((flags & BSF_GLOBAL) != 0
-             && (weaken || is_specified_symbol (name, weaken_specific_list)))
+             && (weaken || is_specified_symbol (name, weaken_specific_htab)))
            {
              sym->flags &= ~ BSF_GLOBAL;
              sym->flags |= BSF_WEAK;
@@ -1060,9 +1148,9 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
 
          if (!undefined
              && (flags & (BSF_GLOBAL | BSF_WEAK))
-             && (is_specified_symbol (name, localize_specific_list)
-                 || (keepglobal_specific_list != NULL
-                     && ! is_specified_symbol (name, keepglobal_specific_list))
+             && (is_specified_symbol (name, localize_specific_htab)
+                 || (htab_elements (keepglobal_specific_htab) != 0
+                     && ! is_specified_symbol (name, keepglobal_specific_htab))
                  || (localize_hidden && is_hidden_symbol (sym))))
            {
              sym->flags &= ~ (BSF_GLOBAL | BSF_WEAK);
@@ -1071,7 +1159,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
 
          if (!undefined
              && (flags & BSF_LOCAL)
-             && is_specified_symbol (name, globalize_specific_list))
+             && is_specified_symbol (name, globalize_specific_htab))
            {
              sym->flags &= ~ BSF_LOCAL;
              sym->flags |= BSF_GLOBAL;
@@ -1254,7 +1342,7 @@ copy_unknown_object (bfd *ibfd, bfd *obfd)
 
   if (bfd_stat_arch_elt (ibfd, &buf) != 0)
     {
-      bfd_nonfatal (bfd_get_archive_filename (ibfd));
+      bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
       return FALSE;
     }
 
@@ -1287,7 +1375,7 @@ copy_unknown_object (bfd *ibfd, bfd *obfd)
       if (bfd_bread (cbuf, (bfd_size_type) tocopy, ibfd)
          != (bfd_size_type) tocopy)
        {
-         bfd_nonfatal (bfd_get_archive_filename (ibfd));
+         bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
          free (cbuf);
          return FALSE;
        }
@@ -1295,7 +1383,7 @@ copy_unknown_object (bfd *ibfd, bfd *obfd)
       if (bfd_bwrite (cbuf, (bfd_size_type) tocopy, obfd)
          != (bfd_size_type) tocopy)
        {
-         bfd_nonfatal (bfd_get_filename (obfd));
+         bfd_nonfatal_message (NULL, obfd, NULL, NULL);
          free (cbuf);
          return FALSE;
        }
@@ -1332,7 +1420,7 @@ copy_object (bfd *ibfd, bfd *obfd)
 
   if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
     {
-      bfd_nonfatal (bfd_get_filename (obfd));
+      bfd_nonfatal_message (NULL, obfd, NULL, NULL);
       return FALSE;
     }
 
@@ -1363,10 +1451,13 @@ copy_object (bfd *ibfd, bfd *obfd)
       flags &= ~bfd_flags_to_clear;
       flags &= bfd_applicable_file_flags (obfd);
 
+      if (strip_symbols == STRIP_ALL)
+       flags &= ~HAS_RELOC;
+
       if (!bfd_set_start_address (obfd, start)
          || !bfd_set_file_flags (obfd, flags))
        {
-         bfd_nonfatal (bfd_get_archive_filename (ibfd));
+         bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
          return FALSE;
        }
     }
@@ -1390,10 +1481,62 @@ copy_object (bfd *ibfd, bfd *obfd)
 
   if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
     {
-      bfd_nonfatal (bfd_get_archive_filename (ibfd));
+      bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
       return FALSE;
     }
 
+  if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
+      && bfd_pei_p (obfd))
+    {
+      /* Set up PE parameters.  */
+      pe_data_type *pe = pe_data (obfd);
+
+      if (pe_file_alignment != (bfd_vma) -1)
+       pe->pe_opthdr.FileAlignment = pe_file_alignment;
+      else
+       pe_file_alignment = PE_DEF_FILE_ALIGNMENT;
+
+      if (pe_heap_commit != (bfd_vma) -1)
+       pe->pe_opthdr.SizeOfHeapCommit = pe_heap_commit;
+
+      if (pe_heap_reserve != (bfd_vma) -1)
+       pe->pe_opthdr.SizeOfHeapCommit = pe_heap_reserve;
+
+      if (pe_image_base != (bfd_vma) -1)
+       pe->pe_opthdr.ImageBase = pe_image_base;
+
+      if (pe_section_alignment != (bfd_vma) -1)
+       pe->pe_opthdr.SectionAlignment = pe_section_alignment;
+      else
+       pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
+
+      if (pe_stack_commit != (bfd_vma) -1)
+       pe->pe_opthdr.SizeOfStackCommit = pe_stack_commit;
+
+      if (pe_stack_reserve != (bfd_vma) -1)
+       pe->pe_opthdr.SizeOfStackCommit = pe_stack_reserve;
+
+      if (pe_subsystem != -1)
+       pe->pe_opthdr.Subsystem = pe_subsystem;
+
+      if (pe_major_subsystem_version != -1)
+       pe->pe_opthdr.MajorSubsystemVersion = pe_major_subsystem_version;
+
+      if (pe_minor_subsystem_version != -1)
+       pe->pe_opthdr.MinorSubsystemVersion = pe_minor_subsystem_version;
+
+      if (pe_file_alignment > pe_section_alignment)
+       {
+         char file_alignment[20], section_alignment[20];
+
+         sprintf_vma (file_alignment, pe_file_alignment);
+         sprintf_vma (section_alignment, pe_section_alignment);
+         non_fatal (_("warning: file alignment (0x%s) > section alignment (0x%s)"),
+
+                    file_alignment, section_alignment);
+       }
+    }
+
   if (isympp)
     free (isympp);
 
@@ -1406,7 +1549,7 @@ copy_object (bfd *ibfd, bfd *obfd)
   symsize = bfd_get_symtab_upper_bound (ibfd);
   if (symsize < 0)
     {
-      bfd_nonfatal (bfd_get_archive_filename (ibfd));
+      bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
       return FALSE;
     }
 
@@ -1414,7 +1557,7 @@ copy_object (bfd *ibfd, bfd *obfd)
   symcount = bfd_canonicalize_symtab (ibfd, isympp);
   if (symcount < 0)
     {
-      bfd_nonfatal (bfd_get_filename (ibfd));
+      bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
       return FALSE;
     }
 
@@ -1422,7 +1565,8 @@ copy_object (bfd *ibfd, bfd *obfd)
      any output is done.  Thus, we traverse all sections multiple times.  */
   bfd_map_over_sections (ibfd, setup_section, obfd);
 
-  setup_bfd_headers (ibfd, obfd);
+  if (!extract_symbol)
+    setup_bfd_headers (ibfd, obfd);
 
   if (add_sections != NULL)
     {
@@ -1445,7 +1589,8 @@ copy_object (bfd *ibfd, bfd *obfd)
             error codes, so check for the most likely user error first.  */
          if (bfd_get_section_by_name (obfd, padd->name))
            {
-             non_fatal (_("can't add section '%s' - it already exists!"), padd->name);
+             bfd_nonfatal_message (NULL, obfd, NULL,
+                                _("can't add section '%s'"), padd->name);
              return FALSE;
            }
          else
@@ -1453,15 +1598,16 @@ copy_object (bfd *ibfd, bfd *obfd)
              padd->section = bfd_make_section_with_flags (obfd, padd->name, flags);
              if (padd->section == NULL)
                {
-                 non_fatal (_("can't create section `%s': %s"),
-                            padd->name, bfd_errmsg (bfd_get_error ()));
+                 bfd_nonfatal_message (NULL, obfd, NULL,
+                                       _("can't create section `%s'"),
+                                       padd->name);
                  return FALSE;
                }
            }
 
          if (! bfd_set_section_size (obfd, padd->section, padd->size))
            {
-             bfd_nonfatal (bfd_get_filename (obfd));
+             bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
              return FALSE;
            }
 
@@ -1471,7 +1617,7 @@ copy_object (bfd *ibfd, bfd *obfd)
                if (! bfd_set_section_vma (obfd, padd->section,
                                           pset->vma_val))
                  {
-                   bfd_nonfatal (bfd_get_filename (obfd));
+                   bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
                    return FALSE;
                  }
 
@@ -1483,7 +1629,7 @@ copy_object (bfd *ibfd, bfd *obfd)
                      (obfd, padd->section,
                       bfd_section_alignment (obfd, padd->section)))
                    {
-                     bfd_nonfatal (bfd_get_filename (obfd));
+                     bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
                      return FALSE;
                    }
                }
@@ -1498,7 +1644,9 @@ copy_object (bfd *ibfd, bfd *obfd)
 
       if (gnu_debuglink_section == NULL)
        {
-         bfd_nonfatal (gnu_debuglink_filename);
+         bfd_nonfatal_message (NULL, obfd, NULL,
+                               _("cannot create debug link section `%s'"),
+                               gnu_debuglink_filename);
          return FALSE;
        }
 
@@ -1589,9 +1737,8 @@ copy_object (bfd *ibfd, bfd *obfd)
                  if (! bfd_set_section_size (obfd, osections[i],
                                              size + (gap_stop - gap_start)))
                    {
-                     non_fatal (_("Can't fill gap after %s: %s"),
-                                bfd_get_section_name (obfd, osections[i]),
-                                bfd_errmsg (bfd_get_error ()));
+                     bfd_nonfatal_message (NULL, obfd, osections[i],
+                                           _("Can't fill gap after section"));
                      status = 1;
                      break;
                    }
@@ -1614,9 +1761,8 @@ copy_object (bfd *ibfd, bfd *obfd)
              if (! bfd_set_section_size (obfd, osections[c - 1],
                                          pad_to - lma))
                {
-                 non_fatal (_("Can't add padding to %s: %s"),
-                            bfd_get_section_name (obfd, osections[c - 1]),
-                            bfd_errmsg (bfd_get_error ()));
+                 bfd_nonfatal_message (NULL, obfd, osections[c - 1],
+                                       _("can't add padding"));
                  status = 1;
                }
              else
@@ -1633,7 +1779,7 @@ copy_object (bfd *ibfd, bfd *obfd)
      have been created, but before their contents are set.  */
   dhandle = NULL;
   if (convert_debugging)
-    dhandle = read_debugging_info (ibfd, isympp, symcount);
+    dhandle = read_debugging_info (ibfd, isympp, symcount, FALSE);
 
   if (strip_symbols == STRIP_DEBUG
       || strip_symbols == STRIP_ALL
@@ -1641,12 +1787,12 @@ copy_object (bfd *ibfd, bfd *obfd)
       || strip_symbols == STRIP_NONDEBUG
       || discard_locals != LOCALS_UNDEF
       || localize_hidden
-      || strip_specific_list != NULL
-      || keep_specific_list != NULL
-      || localize_specific_list != NULL
-      || globalize_specific_list != NULL
-      || keepglobal_specific_list != NULL
-      || weaken_specific_list != NULL
+      || htab_elements (strip_specific_htab) != 0
+      || htab_elements (keep_specific_htab) != 0
+      || htab_elements (localize_specific_htab) != 0
+      || htab_elements (globalize_specific_htab) != 0
+      || htab_elements (keepglobal_specific_htab) != 0
+      || htab_elements (weaken_specific_htab) != 0
       || prefix_symbols_string
       || sections_removed
       || sections_copied
@@ -1695,7 +1841,7 @@ copy_object (bfd *ibfd, bfd *obfd)
          if (! bfd_set_section_contents (obfd, padd->section, padd->contents,
                                          0, padd->size))
            {
-             bfd_nonfatal (bfd_get_filename (obfd));
+             bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
              return FALSE;
            }
        }
@@ -1706,7 +1852,9 @@ copy_object (bfd *ibfd, bfd *obfd)
       if (! bfd_fill_in_gnu_debuglink_section
          (obfd, gnu_debuglink_section, gnu_debuglink_filename))
        {
-         bfd_nonfatal (gnu_debuglink_filename);
+         bfd_nonfatal_message (NULL, obfd, NULL,
+                               _("cannot fill debug link section `%s'"),
+                               gnu_debuglink_filename);
          return FALSE;
        }
     }
@@ -1745,7 +1893,7 @@ copy_object (bfd *ibfd, bfd *obfd)
                  if (! bfd_set_section_contents (obfd, osections[i], buf,
                                                  off, now))
                    {
-                     bfd_nonfatal (bfd_get_filename (obfd));
+                     bfd_nonfatal_message (NULL, obfd, osections[i], NULL);
                      return FALSE;
                    }
 
@@ -1767,9 +1915,8 @@ copy_object (bfd *ibfd, bfd *obfd)
      important for the ECOFF code at least.  */
   if (! bfd_copy_private_bfd_data (ibfd, obfd))
     {
-      non_fatal (_("%s: error copying private BFD data: %s"),
-                bfd_get_filename (obfd),
-                bfd_errmsg (bfd_get_error ()));
+      bfd_nonfatal_message (NULL, obfd, NULL,
+                           _("error copying private BFD data"));
       return FALSE;
     }
 
@@ -1813,7 +1960,8 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
     } *list, *l;
   bfd **ptr = &obfd->archive_head;
   bfd *this_element;
-  char * dir;
+  char *dir;
+  const char *filename;
 
   /* Make a temp directory to hold the contents.  */
   dir = make_tempdir (bfd_get_filename (obfd));
@@ -1822,13 +1970,18 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
           strerror (errno));
 
   obfd->has_armap = ibfd->has_armap;
+  obfd->is_thin_archive = ibfd->is_thin_archive;
 
   list = NULL;
 
   this_element = bfd_openr_next_archived_file (ibfd, NULL);
 
   if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
-    RETURN_NONFATAL (bfd_get_filename (obfd));
+    {
+      status = 1;
+      bfd_nonfatal_message (NULL, obfd, NULL, NULL);
+      return;
+    }
 
   while (!status && this_element != NULL)
     {
@@ -1885,7 +2038,11 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
            output_bfd = bfd_openw (output_name, bfd_get_target (this_element));
 
          if (output_bfd == NULL)
-           RETURN_NONFATAL (output_name);
+           {
+             bfd_nonfatal_message (output_name, NULL, NULL, NULL);
+             status = 1;
+             return;
+           }
 
          delete = ! copy_object (this_element, output_bfd);
 
@@ -1894,7 +2051,7 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
            {
              if (!bfd_close (output_bfd))
                {
-                 bfd_nonfatal (bfd_get_filename (output_bfd));
+                 bfd_nonfatal_message (output_name, NULL, NULL, NULL);
                  /* Error in new object file. Don't change archive.  */
                  status = 1;
                }
@@ -1904,15 +2061,15 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
        }
       else
        {
-         non_fatal (_("Unable to recognise the format of the input file `%s'"),
-                    bfd_get_archive_filename (this_element));
+         bfd_nonfatal_message (NULL, this_element, NULL,
+                               _("Unable to recognise the format of file"));
 
          output_bfd = bfd_openw (output_name, output_target);
 copy_unknown_element:
          delete = !copy_unknown_object (this_element, output_bfd);
          if (!bfd_close_all_done (output_bfd))
            {
-             bfd_nonfatal (bfd_get_filename (output_bfd));
+             bfd_nonfatal_message (output_name, NULL, NULL, NULL);
              /* Error in new object file. Don't change archive.  */
              status = 1;
            }
@@ -1945,11 +2102,21 @@ copy_unknown_element:
     }
   *ptr = NULL;
 
+  filename = bfd_get_filename (obfd);
   if (!bfd_close (obfd))
-    RETURN_NONFATAL (bfd_get_filename (obfd));
+    {
+      status = 1;
+      bfd_nonfatal_message (filename, NULL, NULL, NULL);
+      return;
+    }
 
+  filename = bfd_get_filename (ibfd);
   if (!bfd_close (ibfd))
-    RETURN_NONFATAL (bfd_get_filename (ibfd));
+    {
+      status = 1;
+      bfd_nonfatal_message (filename, NULL, NULL, NULL);
+      return;
+    }
 
   /* Delete all the files that we opened.  */
   for (l = list; l != NULL; l = l->next)
@@ -1965,6 +2132,18 @@ copy_unknown_element:
   rmdir (dir);
 }
 
+static void
+set_long_section_mode (bfd *output_bfd, bfd *input_bfd, enum long_section_name_handling style)
+{
+  /* This is only relevant to Coff targets.  */
+  if (bfd_get_flavour (output_bfd) == bfd_target_coff_flavour)
+    {
+      if (style == KEEP)
+       style = bfd_coff_long_section_names (input_bfd) ? ENABLE : DISABLE;
+      bfd_coff_set_long_section_names (output_bfd, style != DISABLE);
+    }
+}
+
 /* The top-level control.  */
 
 static void
@@ -1985,7 +2164,11 @@ copy_file (const char *input_filename, const char *output_filename,
      non-object file, failures are nonfatal.  */
   ibfd = bfd_openr (input_filename, input_target);
   if (ibfd == NULL)
-    RETURN_NONFATAL (input_filename);
+    {
+      bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
+      status = 1;
+      return;
+    }
 
   if (bfd_check_format (ibfd, bfd_archive))
     {
@@ -2004,7 +2187,13 @@ copy_file (const char *input_filename, const char *output_filename,
 
       obfd = bfd_openw (output_filename, output_target);
       if (obfd == NULL)
-       RETURN_NONFATAL (output_filename);
+       {
+         bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
+         status = 1;
+         return;
+       }
+      /* This is a no-op on non-Coff targets.  */
+      set_long_section_mode (obfd, ibfd, long_section_names);
 
       copy_archive (ibfd, obfd, output_target, force_output_target);
     }
@@ -2020,17 +2209,30 @@ copy_file (const char *input_filename, const char *output_filename,
 
       obfd = bfd_openw (output_filename, output_target);
       if (obfd == NULL)
-       RETURN_NONFATAL (output_filename);
+       {
+         bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
+         status = 1;
+         return;
+       }
+      /* This is a no-op on non-Coff targets.  */
+      set_long_section_mode (obfd, ibfd, long_section_names);
 
       if (! copy_object (ibfd, obfd))
        status = 1;
 
       if (!bfd_close (obfd))
-       RETURN_NONFATAL (output_filename);
+       {
+         status = 1;
+         bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
+         return;
+       }
 
       if (!bfd_close (ibfd))
-       RETURN_NONFATAL (input_filename);
-
+       {
+         status = 1;
+         bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
+         return;
+       }
     }
   else
     {
@@ -2050,7 +2252,7 @@ copy_file (const char *input_filename, const char *output_filename,
       if (obj_error != core_error)
        bfd_set_error (obj_error);
 
-      bfd_nonfatal (input_filename);
+      bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
 
       if (obj_error == bfd_error_file_ambiguously_recognized)
        {
@@ -2129,24 +2331,18 @@ find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection,
 static void
 setup_bfd_headers (bfd *ibfd, bfd *obfd)
 {
-  const char *err;
-
   /* Allow the BFD backend to copy any private data it understands
      from the input section to the output section.  */
   if (! bfd_copy_private_header_data (ibfd, obfd))
     {
-      err = _("private header data");
-      goto loser;
+      status = 1;
+      bfd_nonfatal_message (NULL, ibfd, NULL,
+                           _("error in private header data"));
+      return;
     }
 
   /* All went well.  */
   return;
-
-loser:
-  non_fatal (_("%s: error in %s: %s"),
-            bfd_get_filename (ibfd),
-            err, bfd_errmsg (bfd_get_error ()));
-  status = 1;
 }
 
 /* Create a section in OBFD with the same
@@ -2219,7 +2415,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
 
   if (osection == NULL)
     {
-      err = _("making");
+      err = _("failed to create output section");
       goto loser;
     }
 
@@ -2233,7 +2429,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
     size = 0;
   if (! bfd_set_section_size (obfd, osection, size))
     {
-      err = _("size");
+      err = _("failed to set size");
       goto loser;
     }
 
@@ -2245,9 +2441,9 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   else
     vma += change_section_address;
 
-  if (! bfd_set_section_vma (obfd, osection, extract_symbol ? 0 : vma))
+  if (! bfd_set_section_vma (obfd, osection, vma))
     {
-      err = _("vma");
+      err = _("failed to set vma");
       goto loser;
     }
 
@@ -2264,7 +2460,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   else
     lma += change_section_address;
 
-  osection->lma = extract_symbol ? 0 : lma;
+  osection->lma = lma;
 
   /* FIXME: This is probably not enough.  If we change the LMA we
      may have to recompute the header for the file as well.  */
@@ -2272,7 +2468,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
                                  osection,
                                  bfd_section_alignment (ibfd, isection)))
     {
-      err = _("alignment");
+      err = _("failed to set alignment");
       goto loser;
     }
 
@@ -2283,37 +2479,39 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
      bfd_get_section_by_name since some formats allow multiple
      sections with the same name.  */
   isection->output_section = osection;
-  isection->output_offset = extract_symbol ? vma : 0;
+  isection->output_offset = 0;
 
   /* Do not copy backend data if --extract-symbol is passed; anything
      that needs to look at the section contents will fail.  */
   if (extract_symbol)
     return;
 
+  if ((isection->flags & SEC_GROUP) != 0)
+    {
+      asymbol *gsym = group_signature (isection);
+
+      if (gsym != NULL)
+       {
+         gsym->flags |= BSF_KEEP;
+         if (ibfd->xvec->flavour == bfd_target_elf_flavour)
+           elf_group_id (isection) = gsym;
+       }
+    }
+
   /* Allow the BFD backend to copy any private data it understands
      from the input section to the output section.  */
   if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
     {
-      err = _("private data");
+      err = _("failed to copy private data");
       goto loser;
     }
-  else if ((isection->flags & SEC_GROUP) != 0)
-    {
-      asymbol *gsym = group_signature (isection);
-
-      if (gsym != NULL)
-       gsym->flags |= BSF_KEEP;
-    }
 
   /* All went well.  */
   return;
 
 loser:
-  non_fatal (_("%s: section `%s': error in %s: %s"),
-            bfd_get_filename (ibfd),
-            bfd_section_name (ibfd, isection),
-            err, bfd_errmsg (bfd_get_error ()));
   status = 1;
+  bfd_nonfatal_message (NULL, obfd, osection, err);
 }
 
 /* Copy the data of input section ISECTION of IBFD
@@ -2350,6 +2548,9 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   if (size == 0 || osection == 0)
     return;
 
+  if (extract_symbol)
+    return;
+
   p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);
 
   /* Core files do not need to be relocated.  */
@@ -2365,7 +2566,11 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
          if (relsize == -1 && bfd_get_error () == bfd_error_invalid_operation)
            relsize = 0;
          else
-           RETURN_NONFATAL (bfd_get_filename (ibfd));
+           {
+             status = 1;
+             bfd_nonfatal_message (NULL, ibfd, isection, NULL);
+             return;
+           }
        }
     }
 
@@ -2376,7 +2581,12 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
       relpp = xmalloc (relsize);
       relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
       if (relcount < 0)
-       RETURN_NONFATAL (bfd_get_filename (ibfd));
+       {
+         status = 1;
+         bfd_nonfatal_message (NULL, ibfd, isection,
+                               _("relocation count is negative"));
+         return;
+       }
 
       if (strip_symbols == STRIP_ALL)
        {
@@ -2389,7 +2599,7 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
          temp_relpp = xmalloc (relsize);
          for (i = 0; i < relcount; i++)
            if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
-                                    keep_specific_list))
+                                    keep_specific_htab))
              temp_relpp [temp_relcount++] = relpp [i];
          relcount = temp_relcount;
          free (relpp);
@@ -2401,16 +2611,17 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
        free (relpp);
     }
 
-  if (extract_symbol)
-    return;
-
   if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
       && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
     {
       void *memhunk = xmalloc (size);
 
       if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size))
-       RETURN_NONFATAL (bfd_get_filename (ibfd));
+       {
+         status = 1;
+         bfd_nonfatal_message (NULL, ibfd, isection, NULL);
+         return;
+       }
 
       if (reverse_bytes)
        {
@@ -2453,8 +2664,11 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
        }
 
       if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
-       RETURN_NONFATAL (bfd_get_filename (obfd));
-
+       {
+         status = 1;
+         bfd_nonfatal_message (NULL, obfd, osection, NULL);
+         return;
+       }
       free (memhunk);
     }
   else if (p != NULL && p->set_flags && (p->flags & SEC_HAS_CONTENTS) != 0)
@@ -2469,7 +2683,11 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
 
       memset (memhunk, 0, size);
       if (! bfd_set_section_contents (obfd, osection, memhunk, 0, size))
-       RETURN_NONFATAL (bfd_get_filename (obfd));
+       {
+         status = 1;
+         bfd_nonfatal_message (NULL, obfd, osection, NULL);
+         return;
+       }
       free (memhunk);
     }
 }
@@ -2610,9 +2828,8 @@ write_debugging_info (bfd *obfd, void *dhandle,
          || ! bfd_set_section_alignment (obfd, stabsec, 2)
          || ! bfd_set_section_alignment (obfd, stabstrsec, 0))
        {
-         non_fatal (_("%s: can't create debugging section: %s"),
-                    bfd_get_filename (obfd),
-                    bfd_errmsg (bfd_get_error ()));
+         bfd_nonfatal_message (NULL, obfd, NULL,
+                               _("can't create debugging section"));
          return FALSE;
        }
 
@@ -2624,17 +2841,17 @@ write_debugging_info (bfd *obfd, void *dhandle,
          || ! bfd_set_section_contents (obfd, stabstrsec, strings, 0,
                                         stringsize))
        {
-         non_fatal (_("%s: can't set debugging section contents: %s"),
-                    bfd_get_filename (obfd),
-                    bfd_errmsg (bfd_get_error ()));
+         bfd_nonfatal_message (NULL, obfd, NULL,
+                               _("can't set debugging section contents"));
          return FALSE;
        }
 
       return TRUE;
     }
 
-  non_fatal (_("%s: don't know how to write debugging information for %s"),
-            bfd_get_filename (obfd), bfd_get_target (obfd));
+  bfd_nonfatal_message (NULL, obfd, NULL,
+                       _("don't know how to write debugging information for %s"),
+            bfd_get_target (obfd));
   return FALSE;
 }
 
@@ -2681,10 +2898,10 @@ strip_main (int argc, char *argv[])
          strip_symbols = STRIP_UNNEEDED;
          break;
        case 'K':
-         add_specific_symbol (optarg, &keep_specific_list);
+         add_specific_symbol (optarg, keep_specific_htab);
          break;
        case 'N':
-         add_specific_symbol (optarg, &strip_specific_list);
+         add_specific_symbol (optarg, strip_specific_htab);
          break;
        case 'o':
          output_file = optarg;
@@ -2739,7 +2956,7 @@ strip_main (int argc, char *argv[])
   /* Default is to strip all symbols.  */
   if (strip_symbols == STRIP_UNDEF
       && discard_locals == LOCALS_UNDEF
-      && strip_specific_list == NULL)
+      && htab_elements (strip_specific_htab) == 0)
     strip_symbols = STRIP_ALL;
 
   if (output_target == NULL)
@@ -2774,8 +2991,8 @@ strip_main (int argc, char *argv[])
 
       if (tmpname == NULL)
        {
-         non_fatal (_("could not create temporary file to hold stripped copy of '%s'"),
-                    argv[i]);
+         bfd_nonfatal_message (argv[i], NULL, NULL,
+                               _("could not create temporary file to hold stripped copy"));
          status = 1;
          continue;
        }
@@ -2800,6 +3017,117 @@ strip_main (int argc, char *argv[])
   return status;
 }
 
+/* Set up PE subsystem.  */
+
+static void
+set_pe_subsystem (const char *s)
+{
+  const char *version, *subsystem;
+  size_t i;
+  static const struct
+    {
+      const char *name;
+      const char set_def;
+      const short value;
+    }
+  v[] =
+    {
+      { "native", 0, IMAGE_SUBSYSTEM_NATIVE },  
+      { "windows", 0, IMAGE_SUBSYSTEM_WINDOWS_GUI },
+      { "console", 0, IMAGE_SUBSYSTEM_WINDOWS_CUI },
+      { "posix", 0, IMAGE_SUBSYSTEM_POSIX_CUI },
+      { "wince", 0, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI },
+      { "efi-app", 1, IMAGE_SUBSYSTEM_EFI_APPLICATION },
+      { "efi-bsd", 1, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER },
+      { "efi-rtd", 1, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER },
+      { "efi-rom", 1, IMAGE_SUBSYSTEM_EFI_ROM },
+      { "xbox", 0, IMAGE_SUBSYSTEM_XBOX }
+    };
+  short value;
+  char *copy;
+  int set_def = -1;
+
+  /* Check for the presence of a version number.  */
+  version = strchr (s, ':');
+  if (version == NULL)
+    subsystem = s;
+  else
+    {
+      int len = version - s;
+      copy = xstrdup (s);
+      subsystem = copy;
+      copy[len] = '\0';
+      version = copy + 1 + len;
+      pe_major_subsystem_version = strtoul (version, &copy, 0);
+      if (*copy == '.')
+       pe_minor_subsystem_version = strtoul (copy + 1, &copy, 0);
+      if (*copy != '\0')
+       non_fatal (_("%s: bad version in PE subsystem"), s);
+    }
+
+  /* Check for numeric subsystem.  */
+  value = (short) strtol (subsystem, &copy, 0);
+  if (*copy == '\0')
+    {
+      for (i = 0; i < ARRAY_SIZE (v); i++)
+       if (v[i].value == value)
+         {
+           pe_subsystem = value;
+           set_def = v[i].set_def;
+           break;
+         }
+    }
+  else
+    {
+      /* Search for subsystem by name.  */
+      for (i = 0; i < ARRAY_SIZE (v); i++)
+       if (strcmp (subsystem, v[i].name) == 0)
+         {
+           pe_subsystem = v[i].value;
+           set_def = v[i].set_def;
+           break;
+         }
+    }
+
+  switch (set_def)
+    {
+    case -1:
+      fatal (_("unknown PE subsystem: %s"), s);
+      break;
+    case 0:
+      break;
+    default:
+      if (pe_file_alignment == (bfd_vma) -1)
+       pe_file_alignment = PE_DEF_FILE_ALIGNMENT;
+      if (pe_section_alignment == (bfd_vma) -1)
+       pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
+      break;
+    }
+}
+
+/* Convert EFI target to PEI target.  */
+
+static void
+convert_efi_target (char *efi)
+{
+  efi[0] = 'p';
+  efi[1] = 'e';
+  efi[2] = 'i';
+
+  if (strcmp (efi + 4, "ia32") == 0)
+    {
+      /* Change ia32 to i386.  */
+      efi[5]= '3';
+      efi[6]= '8';
+      efi[7]= '6';
+    }
+  else if (strcmp (efi + 4, "x86_64") == 0)
+    {
+      /* Change x86_64 to x86-64.  */
+      efi[7] = '-';
+    }
+}
+
 static int
 copy_main (int argc, char *argv[])
 {
@@ -2892,31 +3220,31 @@ copy_main (int argc, char *argv[])
          break;
 
        case 'K':
-         add_specific_symbol (optarg, &keep_specific_list);
+         add_specific_symbol (optarg, keep_specific_htab);
          break;
 
        case 'N':
-         add_specific_symbol (optarg, &strip_specific_list);
+         add_specific_symbol (optarg, strip_specific_htab);
          break;
 
        case OPTION_STRIP_UNNEEDED_SYMBOL:
-         add_specific_symbol (optarg, &strip_unneeded_list);
+         add_specific_symbol (optarg, strip_unneeded_htab);
          break;
 
        case 'L':
-         add_specific_symbol (optarg, &localize_specific_list);
+         add_specific_symbol (optarg, localize_specific_htab);
          break;
 
        case OPTION_GLOBALIZE_SYMBOL:
-         add_specific_symbol (optarg, &globalize_specific_list);
+         add_specific_symbol (optarg, globalize_specific_htab);
          break;
 
        case 'G':
-         add_specific_symbol (optarg, &keepglobal_specific_list);
+         add_specific_symbol (optarg, keepglobal_specific_htab);
          break;
 
        case 'W':
-         add_specific_symbol (optarg, &weaken_specific_list);
+         add_specific_symbol (optarg, weaken_specific_htab);
          break;
 
        case 'p':
@@ -3240,15 +3568,15 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_STRIP_SYMBOLS:
-         add_specific_symbols (optarg, &strip_specific_list);
+         add_specific_symbols (optarg, strip_specific_htab);
          break;
 
        case OPTION_STRIP_UNNEEDED_SYMBOLS:
-         add_specific_symbols (optarg, &strip_unneeded_list);
+         add_specific_symbols (optarg, strip_unneeded_htab);
          break;
 
        case OPTION_KEEP_SYMBOLS:
-         add_specific_symbols (optarg, &keep_specific_list);
+         add_specific_symbols (optarg, keep_specific_htab);
          break;
 
        case OPTION_LOCALIZE_HIDDEN:
@@ -3256,19 +3584,30 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_LOCALIZE_SYMBOLS:
-         add_specific_symbols (optarg, &localize_specific_list);
+         add_specific_symbols (optarg, localize_specific_htab);
+         break;
+
+       case OPTION_LONG_SECTION_NAMES:
+         if (!strcmp ("enable", optarg))
+           long_section_names = ENABLE;
+         else if (!strcmp ("disable", optarg))
+           long_section_names = DISABLE;
+         else if (!strcmp ("keep", optarg))
+           long_section_names = KEEP;
+         else
+           fatal (_("unknown long section names option '%s'"), optarg);
          break;
 
        case OPTION_GLOBALIZE_SYMBOLS:
-         add_specific_symbols (optarg, &globalize_specific_list);
+         add_specific_symbols (optarg, globalize_specific_htab);
          break;
 
        case OPTION_KEEPGLOBAL_SYMBOLS:
-         add_specific_symbols (optarg, &keepglobal_specific_list);
+         add_specific_symbols (optarg, keepglobal_specific_htab);
          break;
 
        case OPTION_WEAKEN_SYMBOLS:
-         add_specific_symbols (optarg, &weaken_specific_list);
+         add_specific_symbols (optarg, weaken_specific_htab);
          break;
 
        case OPTION_ALT_MACH_CODE:
@@ -3327,6 +3666,59 @@ copy_main (int argc, char *argv[])
             break;
           }
 
+       case OPTION_FILE_ALIGNMENT:
+         pe_file_alignment = parse_vma (optarg, "--file-alignment");
+         break;
+       
+       case OPTION_HEAP:
+           {
+             char *end;
+             pe_heap_reserve = strtoul (optarg, &end, 0);
+             if (end == optarg
+                 || (*end != '.' && *end != '\0'))
+               non_fatal (_("%s: invalid reserve value for --heap"),
+                          optarg);
+             else if (*end != '\0')
+               {
+                 pe_heap_commit = strtoul (end + 1, &end, 0);
+                 if (*end != '\0')
+                   non_fatal (_("%s: invalid commit value for --heap"),
+                              optarg);
+               }
+           }
+         break;
+       
+       case OPTION_IMAGE_BASE:
+         pe_image_base = parse_vma (optarg, "--image-base");
+         break;
+       
+       case OPTION_SECTION_ALIGNMENT:
+         pe_section_alignment = parse_vma (optarg,
+                                           "--section-alignment");
+         break;
+       
+       case OPTION_SUBSYSTEM:
+         set_pe_subsystem (optarg);
+         break;
+       
+       case OPTION_STACK:
+           {
+             char *end;
+             pe_stack_reserve = strtoul (optarg, &end, 0);
+             if (end == optarg
+                 || (*end != '.' && *end != '\0'))
+               non_fatal (_("%s: invalid reserve value for --stack"),
+                          optarg);
+             else if (*end != '\0')
+               {
+                 pe_stack_commit = strtoul (end + 1, &end, 0);
+                 if (*end != '\0')
+                   non_fatal (_("%s: invalid commit value for --stack"),
+                              optarg);
+               }
+           }
+         break;
+       
        case 0:
          /* We've been given a long option.  */
          break;
@@ -3366,6 +3758,59 @@ copy_main (int argc, char *argv[])
   if (output_target == NULL)
     output_target = input_target;
 
+  /* Convert input EFI target to PEI target.  */
+  if (input_target != NULL
+      && strncmp (input_target, "efi-", 4) == 0)
+    {
+      char *efi;
+
+      efi = xstrdup (output_target + 4);
+      if (strncmp (efi, "bsdrv-", 6) == 0
+         || strncmp (efi, "rtdrv-", 6) == 0)
+       efi += 2;
+      else if (strncmp (efi, "app-", 4) != 0)
+       fatal (_("unknown input EFI target: %s"), input_target);
+
+      input_target = efi;
+      convert_efi_target (efi);
+    }
+
+  /* Convert output EFI target to PEI target.  */
+  if (output_target != NULL
+      && strncmp (output_target, "efi-", 4) == 0)
+    {
+      char *efi;
+
+      efi = xstrdup (output_target + 4);
+      if (strncmp (efi, "app-", 4) == 0)
+       {
+         if (pe_subsystem == -1)
+           pe_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
+       }
+      else if (strncmp (efi, "bsdrv-", 6) == 0)
+       {
+         if (pe_subsystem == -1)
+           pe_subsystem = IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
+         efi += 2;
+       }
+      else if (strncmp (efi, "rtdrv-", 6) == 0)
+       {
+         if (pe_subsystem == -1)
+           pe_subsystem = IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
+         efi += 2;
+       }
+      else
+       fatal (_("unknown output EFI target: %s"), output_target);
+
+      if (pe_file_alignment == (bfd_vma) -1)
+       pe_file_alignment = PE_DEF_FILE_ALIGNMENT;
+      if (pe_section_alignment == (bfd_vma) -1)
+       pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
+
+      output_target = efi;
+      convert_efi_target (efi);
+    }
+
   if (binary_architecture != NULL)
     {
       if (input_target && strcmp (input_target, "binary") == 0)
@@ -3495,6 +3940,8 @@ main (int argc, char *argv[])
       is_strip = (i >= 5 && FILENAME_CMP (program_name + i - 5, "strip") == 0);
     }
 
+  create_symbol_htabs ();
+
   if (is_strip)
     strip_main (argc, argv);
   else
This page took 0.04604 seconds and 4 git commands to generate.