/* 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
- Free Software Foundation, Inc.
+ Copyright (C) 1991-2014 Free Software Foundation, Inc.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
#include "filenames.h"
#include "fnmatch.h"
#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. */
/* 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. */
-/* If `copy_byte' >= 0, copy only that byte of every `interleave' bytes. */
+/* If `copy_byte' >= 0, copy 'copy_width' byte(s) of every `interleave' bytes. */
static int copy_byte = -1;
-static int interleave = 4;
+static int interleave = 0; /* Initialised to 4 in copy_main(). */
+static int copy_width = 1;
static bfd_boolean verbose; /* Print file and target names. */
static bfd_boolean preserve_dates; /* Preserve input file timestamp. */
+static int deterministic = -1; /* Enable deterministic archives. */
static int status = 0; /* Exit status. */
enum strip_action
STRIP_DEBUG, /* Strip all debugger symbols. */
STRIP_UNNEEDED, /* Strip unnecessary symbols. */
STRIP_NONDEBUG, /* Strip everything but debug info. */
+ STRIP_DWO, /* Strip all DWO info. */
+ STRIP_NONDWO, /* Strip everything but DWO info. */
STRIP_ALL /* Strip all symbols. */
};
/* Which symbols to remove. */
-static enum strip_action strip_symbols;
+static enum strip_action strip_symbols = STRIP_UNDEF;
enum locals_action
{
/* Which local symbols to remove. Overrides STRIP_ALL. */
static enum locals_action discard_locals;
-/* What kind of change to perform. */
-enum change_action
-{
- CHANGE_IGNORE,
- CHANGE_MODIFY,
- CHANGE_SET
-};
-
/* Structure used to hold lists of sections and actions to take. */
struct section_list
{
struct section_list * next; /* Next section to change. */
- const char * name; /* Section name. */
+ const char * pattern; /* Section name pattern. */
bfd_boolean used; /* Whether this entry was used. */
- bfd_boolean remove; /* Whether to remove this section. */
- bfd_boolean copy; /* Whether to copy this section. */
- enum change_action change_vma;/* Whether to change or set VMA. */
+
+ unsigned int context; /* What to do with matching sections. */
+ /* Flag bits used in the context field.
+ COPY and REMOVE are mutually exlusive. SET and ALTER are mutually exclusive. */
+#define SECTION_CONTEXT_REMOVE (1 << 0) /* Remove this section. */
+#define SECTION_CONTEXT_COPY (1 << 1) /* Copy this section, delete all non-copied section. */
+#define SECTION_CONTEXT_SET_VMA (1 << 2) /* Set the sections' VMA address. */
+#define SECTION_CONTEXT_ALTER_VMA (1 << 3) /* Increment or decrement the section's VMA address. */
+#define SECTION_CONTEXT_SET_LMA (1 << 4) /* Set the sections' LMA address. */
+#define SECTION_CONTEXT_ALTER_LMA (1 << 5) /* Increment or decrement the section's LMA address. */
+#define SECTION_CONTEXT_SET_FLAGS (1 << 6) /* Set the section's flags. */
+
bfd_vma vma_val; /* Amount to change by or set to. */
- enum change_action change_lma;/* Whether to change or set LMA. */
bfd_vma lma_val; /* Amount to change by or set to. */
- bfd_boolean set_flags; /* Whether to set the section flags. */
flagword flags; /* What to set the section flags to. */
};
/* List of sections to add to the output BFD. */
static struct section_add *add_sections;
+/* List of sections to dump from the output BFD. */
+static struct section_add *dump_sections;
+
/* If non-NULL the argument to --add-gnu-debuglink.
This should be the filename to store in the .gnu_debuglink section. */
static const char * gnu_debuglink_filename = NULL;
/* Whether to convert debugging information. */
static bfd_boolean convert_debugging = FALSE;
+/* Whether to compress/decompress DWARF debug sections. */
+static enum
+{
+ nothing,
+ compress,
+ decompress
+} do_debug_sections = nothing;
+
/* Whether to change the leading character in symbol names. */
static bfd_boolean change_leading_char = 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). */
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
{
OPTION_ADD_SECTION=150,
+ OPTION_DUMP_SECTION,
OPTION_CHANGE_ADDRESSES,
OPTION_CHANGE_LEADING_CHAR,
OPTION_CHANGE_START,
OPTION_CHANGE_SECTION_LMA,
OPTION_CHANGE_SECTION_VMA,
OPTION_CHANGE_WARNINGS,
+ OPTION_COMPRESS_DEBUG_SECTIONS,
OPTION_DEBUGGING,
+ OPTION_DECOMPRESS_DEBUG_SECTIONS,
OPTION_GAP_FILL,
OPTION_NO_CHANGE_WARNINGS,
OPTION_PAD_TO,
OPTION_KEEP_SYMBOLS,
OPTION_LOCALIZE_HIDDEN,
OPTION_LOCALIZE_SYMBOLS,
+ OPTION_LONG_SECTION_NAMES,
OPTION_GLOBALIZE_SYMBOL,
OPTION_GLOBALIZE_SYMBOLS,
OPTION_KEEPGLOBAL_SYMBOLS,
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_INTERLEAVE_WIDTH,
+ OPTION_SUBSYSTEM,
+ OPTION_EXTRACT_DWO,
+ OPTION_STRIP_DWO
};
/* Options to handle if running as "strip". */
static struct option strip_options[] =
{
+ {"disable-deterministic-archives", no_argument, 0, 'U'},
{"discard-all", no_argument, 0, 'x'},
{"discard-locals", no_argument, 0, 'X'},
+ {"enable-deterministic-archives", no_argument, 0, 'D'},
{"format", required_argument, 0, 'F'}, /* Obsolete */
{"help", no_argument, 0, 'h'},
{"info", no_argument, 0, OPTION_FORMATS_INFO},
{"remove-section", required_argument, 0, 'R'},
{"strip-all", no_argument, 0, 's'},
{"strip-debug", no_argument, 0, 'S'},
+ {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
{"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
{"strip-symbol", required_argument, 0, 'N'},
{"target", required_argument, 0, 'F'},
{"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA},
{"change-start", required_argument, 0, OPTION_CHANGE_START},
{"change-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
+ {"compress-debug-sections", no_argument, 0, OPTION_COMPRESS_DEBUG_SECTIONS},
{"debugging", no_argument, 0, OPTION_DEBUGGING},
+ {"decompress-debug-sections", no_argument, 0, OPTION_DECOMPRESS_DEBUG_SECTIONS},
+ {"disable-deterministic-archives", no_argument, 0, 'U'},
{"discard-all", no_argument, 0, 'x'},
{"discard-locals", no_argument, 0, 'X'},
+ {"dump-section", required_argument, 0, OPTION_DUMP_SECTION},
+ {"enable-deterministic-archives", no_argument, 0, 'D'},
+ {"extract-dwo", no_argument, 0, OPTION_EXTRACT_DWO},
{"extract-symbol", no_argument, 0, OPTION_EXTRACT_SYMBOL},
{"format", required_argument, 0, 'F'}, /* Obsolete */
{"gap-fill", required_argument, 0, OPTION_GAP_FILL},
{"info", no_argument, 0, OPTION_FORMATS_INFO},
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"input-target", required_argument, 0, 'I'},
- {"interleave", required_argument, 0, 'i'},
+ {"interleave", optional_argument, 0, 'i'},
+ {"interleave-width", required_argument, 0, OPTION_INTERLEAVE_WIDTH},
{"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
{"keep-global-symbol", required_argument, 0, 'G'},
{"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
{"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},
{"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3},
{"strip-all", no_argument, 0, 'S'},
{"strip-debug", no_argument, 0, 'g'},
+ {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
{"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
{"strip-unneeded-symbol", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOL},
{"strip-unneeded-symbols", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOLS},
{"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}
};
on by the --srec-forceS3 command line switch. */
extern bfd_boolean S3Forced;
-/* Defined in bfd/binary.c. Used to set architecture and machine of input
- binary files. */
-extern enum bfd_architecture bfd_external_binary_architecture;
-extern unsigned long bfd_external_machine;
-
/* Forward declarations. */
static void setup_section (bfd *, asection *, void *);
static void setup_bfd_headers (bfd *, bfd *);
+static void copy_relocations_in_section (bfd *, asection *, void *);
static void copy_section (bfd *, asection *, void *);
static void get_sections (bfd *, asection *, void *);
static int compare_section_lma (const void *, const void *);
fprintf (stream, _("\
-I --input-target <bfdname> Assume input file is in format <bfdname>\n\
-O --output-target <bfdname> Create an output file in format <bfdname>\n\
- -B --binary-architecture <arch> Set arch of output file, when input is binary\n\
+ -B --binary-architecture <arch> Set output arch, when input is arch-less\n\
-F --target <bfdname> Set both input and output format to <bfdname>\n\
--debugging Convert debugging information, if possible\n\
- -p --preserve-dates Copy modified/access timestamps to the output\n\
+ -p --preserve-dates Copy modified/access timestamps to the output\n"));
+ if (DEFAULT_AR_DETERMINISTIC)
+ fprintf (stream, _("\
+ -D --enable-deterministic-archives\n\
+ Produce deterministic output when stripping archives (default)\n\
+ -U --disable-deterministic-archives\n\
+ Disable -D behavior\n"));
+ else
+ fprintf (stream, _("\
+ -D --enable-deterministic-archives\n\
+ Produce deterministic output when stripping archives\n\
+ -U --disable-deterministic-archives\n\
+ Disable -D behavior (default)\n"));
+ fprintf (stream, _("\
-j --only-section <name> Only copy section <name> into the output\n\
--add-gnu-debuglink=<file> Add section .gnu_debuglink linking to <file>\n\
-R --remove-section <name> Remove section <name> from the output\n\
-S --strip-all Remove all symbol and relocation information\n\
-g --strip-debug Remove all debugging symbols & sections\n\
+ --strip-dwo Remove all DWO sections\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
-N --strip-symbol <name> Do not copy symbol <name>\n\
--strip-unneeded-symbol <name>\n\
Do not copy symbol <name> unless needed by\n\
relocations\n\
--only-keep-debug Strip everything but the debug information\n\
+ --extract-dwo Copy only DWO sections\n\
--extract-symbol Remove section contents but keep symbols\n\
-K --keep-symbol <name> Do not strip symbol <name>\n\
--keep-file-symbols Do not strip file symbol(s)\n\
-w --wildcard Permit wildcard in symbol comparison\n\
-x --discard-all Remove all non-global symbols\n\
-X --discard-locals Remove any compiler-generated symbols\n\
- -i --interleave <number> Only copy one out of every <number> bytes\n\
+ -i --interleave [<number>] Only copy N out of every <number> bytes\n\
+ --interleave-width <number> Set N for --interleave\n\
-b --byte <num> Select byte <num> in every interleaved block\n\
--gap-fill <val> Fill gaps between sections with <val>\n\
--pad-to <addr> Pad the last section up to address <addr>\n\
--set-section-flags <name>=<flags>\n\
Set section <name>'s properties to <flags>\n\
--add-section <name>=<file> Add section <name> found in <file> to output\n\
+ --dump-section <name>=<file> Dump the contents of section <name> into <file>\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\
--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\
+ --compress-debug-sections Compress DWARF debug sections using zlib\n\
+ --decompress-debug-sections Decompress DWARF debug sections using zlib\n\
-v --verbose List all object files modified\n\
@<file> Read options from <file>\n\
-V --version Display this program's version number\n\
-O --output-target=<bfdname> Create an output file in format <bfdname>\n\
-F --target=<bfdname> Set both input and output format to <bfdname>\n\
-p --preserve-dates Copy modified/access timestamps to the output\n\
+"));
+ if (DEFAULT_AR_DETERMINISTIC)
+ fprintf (stream, _("\
+ -D --enable-deterministic-archives\n\
+ Produce deterministic output when stripping archives (default)\n\
+ -U --disable-deterministic-archives\n\
+ Disable -D behavior\n"));
+ else
+ fprintf (stream, _("\
+ -D --enable-deterministic-archives\n\
+ Produce deterministic output when stripping archives\n\
+ -U --disable-deterministic-archives\n\
+ Disable -D behavior (default)\n"));
+ fprintf (stream, _("\
-R --remove-section=<name> Remove section <name> from the output\n\
-s --strip-all Remove all symbol and relocation information\n\
-g -S -d --strip-debug Remove all debugging symbols & sections\n\
+ --strip-dwo Remove all DWO sections\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
--only-keep-debug Strip everything but the debug information\n\
-N --strip-symbol=<name> Do not copy symbol <name>\n\
PARSE_FLAG ("rom", SEC_ROM);
PARSE_FLAG ("share", SEC_COFF_SHARED);
PARSE_FLAG ("contents", SEC_HAS_CONTENTS);
+ PARSE_FLAG ("merge", SEC_MERGE);
+ PARSE_FLAG ("strings", SEC_STRINGS);
#undef PARSE_FLAG
else
{
char *copy;
- copy = xmalloc (len + 1);
+ copy = (char *) xmalloc (len + 1);
strncpy (copy, s, len);
copy[len] = '\0';
non_fatal (_("unrecognized section flag `%s'"), copy);
fatal (_("supported flags: %s"),
- "alloc, load, noload, readonly, debug, code, data, rom, share, contents");
+ "alloc, load, noload, readonly, debug, code, data, rom, share, contents, merge, strings");
}
s = snext;
return ret;
}
-/* Find and optionally add an entry in the change_sections list. */
+/* Find and optionally add an entry in the change_sections list.
+
+ We need to be careful in how we match section names because of the support
+ for wildcard characters. For example suppose that the user has invoked
+ objcopy like this:
+
+ --set-section-flags .debug_*=debug
+ --set-section-flags .debug_str=readonly,debug
+ --change-section-address .debug_*ranges=0x1000
+
+ With the idea that all debug sections will receive the DEBUG flag, the
+ .debug_str section will also receive the READONLY flag and the
+ .debug_ranges and .debug_aranges sections will have their address set to
+ 0x1000. (This may not make much sense, but it is just an example).
+
+ When adding the section name patterns to the section list we need to make
+ sure that previous entries do not match with the new entry, unless the
+ match is exact. (In which case we assume that the user is overriding
+ the previous entry with the new context).
+
+ When matching real section names to the section list we make use of the
+ wildcard characters, but we must do so in context. Eg if we are setting
+ section addresses then we match for .debug_ranges but not for .debug_info.
+
+ Finally, if ADD is false and we do find a match, we mark the section list
+ entry as used. */
static struct section_list *
-find_section_list (const char *name, bfd_boolean add)
+find_section_list (const char *name, bfd_boolean add, unsigned int context)
{
struct section_list *p;
+ /* assert ((context & ((1 << 7) - 1)) != 0); */
+
for (p = change_sections; p != NULL; p = p->next)
- if (strcmp (p->name, name) == 0)
- return p;
+ {
+ if (add)
+ {
+ if (strcmp (p->pattern, name) == 0)
+ {
+ /* Check for context conflicts. */
+ if (((p->context & SECTION_CONTEXT_REMOVE)
+ && (context & SECTION_CONTEXT_COPY))
+ || ((context & SECTION_CONTEXT_REMOVE)
+ && (p->context & SECTION_CONTEXT_COPY)))
+ fatal (_("error: %s both copied and removed"), name);
+
+ if (((p->context & SECTION_CONTEXT_SET_VMA)
+ && (context & SECTION_CONTEXT_ALTER_VMA))
+ || ((context & SECTION_CONTEXT_SET_VMA)
+ && (context & SECTION_CONTEXT_ALTER_VMA)))
+ fatal (_("error: %s both sets and alters VMA"), name);
+
+ if (((p->context & SECTION_CONTEXT_SET_LMA)
+ && (context & SECTION_CONTEXT_ALTER_LMA))
+ || ((context & SECTION_CONTEXT_SET_LMA)
+ && (context & SECTION_CONTEXT_ALTER_LMA)))
+ fatal (_("error: %s both sets and alters LMA"), name);
+
+ /* Extend the context. */
+ p->context |= context;
+ return p;
+ }
+ }
+ /* If we are not adding a new name/pattern then
+ only check for a match if the context applies. */
+ else if ((p->context & context)
+ /* We could check for the presence of wildchar characters
+ first and choose between calling strcmp and fnmatch,
+ but is that really worth it ? */
+ && fnmatch (p->pattern, name, 0) == 0)
+ {
+ p->used = TRUE;
+ return p;
+ }
+ }
if (! add)
return NULL;
- p = xmalloc (sizeof (struct section_list));
- p->name = name;
+ p = (struct section_list *) xmalloc (sizeof (struct section_list));
+ p->pattern = name;
p->used = FALSE;
- p->remove = FALSE;
- p->copy = FALSE;
- p->change_vma = CHANGE_IGNORE;
- p->change_lma = CHANGE_IGNORE;
+ p->context = context;
p->vma_val = 0;
p->lma_val = 0;
- p->set_flags = FALSE;
p->flags = 0;
-
p->next = change_sections;
change_sections = p;
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 ((const char *) s1, (const char *) 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. */
#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;
return;
}
- buffer = xmalloc (size + 2);
+ buffer = (char *) xmalloc (size + 2);
f = fopen (filename, FOPEN_RT);
if (f == NULL)
fatal (_("cannot open '%s': %s"), filename, strerror (errno));
* 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. */
}
}
-/* 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 =
+ (struct is_specified_symbol_predicate_data *) data;
+ const char *slot_name = (char *) *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. */
return NULL;
}
-/* See if a section is being removed. */
+/* Return TRUE if the section is a DWO section. */
static bfd_boolean
-is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+is_dwo_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+{
+ const char *name = bfd_get_section_name (abfd, sec);
+ int len = strlen (name);
+
+ return strncmp (name + len - 4, ".dwo", 4) == 0;
+}
+
+/* See if a non-group section is being removed. */
+
+static bfd_boolean
+is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
if (sections_removed || sections_copied)
{
struct section_list *p;
+ struct section_list *q;
- p = find_section_list (bfd_get_section_name (abfd, sec), FALSE);
+ p = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
+ SECTION_CONTEXT_REMOVE);
+ q = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
+ SECTION_CONTEXT_COPY);
- if (sections_removed && p != NULL && p->remove)
+ if (p && q)
+ fatal (_("error: section %s matches both remove and copy options"),
+ bfd_get_section_name (abfd, sec));
+
+ if (p != NULL)
return TRUE;
- if (sections_copied && (p == NULL || ! p->copy))
+ if (sections_copied && q == NULL)
return TRUE;
}
|| strip_symbols == STRIP_ALL
|| discard_locals == LOCALS_ALL
|| convert_debugging)
- return TRUE;
+ {
+ /* By default we don't want to strip .reloc section.
+ This section has for pe-coff special meaning. See
+ pe-dll.c file in ld, and peXXigen.c in bfd for details. */
+ if (strcmp (bfd_get_section_name (abfd, sec), ".reloc") != 0)
+ return TRUE;
+ }
+
+ if (strip_symbols == STRIP_DWO)
+ return is_dwo_section (abfd, sec);
if (strip_symbols == STRIP_NONDEBUG)
return FALSE;
}
+ if (strip_symbols == STRIP_NONDWO)
+ return !is_dwo_section (abfd, sec);
+
+ return FALSE;
+}
+
+/* See if a section is being removed. */
+
+static bfd_boolean
+is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+{
+ if (is_strip_section_1 (abfd, sec))
+ return TRUE;
+
if ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0)
{
asymbol *gsym;
const char *gname;
-
- /* PR binutils/3166
- Group sections look like debugging sections but they are not.
- (They have a non-zero size but they are not ALLOCated). */
- if (strip_symbols == STRIP_NONDEBUG)
- return TRUE;
+ asection *elt, *first;
/* PR binutils/3181
If we are going to strip the group signature symbol, then
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;
+
+ /* Remove the group section if all members are removed. */
+ first = elt = elf_next_in_group (sec);
+ while (elt != NULL)
+ {
+ if (!is_strip_section_1 (abfd, elt))
+ return FALSE;
+ elt = elf_next_in_group (elt);
+ if (elt == first)
+ break;
+ }
+
+ return TRUE;
}
return FALSE;
}
+static bfd_boolean
+is_nondebug_keep_contents_section (bfd *ibfd, asection *isection)
+{
+ /* Always keep ELF note sections. */
+ if (ibfd->xvec->flavour == bfd_target_elf_flavour)
+ return (elf_section_type (isection) == SHT_NOTE);
+
+ /* Always keep the .build-id section for PE/COFF.
+
+ Strictly, this should be written "always keep the section storing the debug
+ directory", but that may be the .text section for objects produced by some
+ tools, which it is not sensible to keep. */
+ if (ibfd->xvec->flavour == bfd_target_coff_flavour)
+ return (strcmp (bfd_get_section_name (ibfd, isection), ".build-id") == 0);
+
+ return FALSE;
+}
+
/* Return true if SYM is a hidden symbol. */
static bfd_boolean
{
asymbol **from = isyms, **to = osyms;
long src_count = 0, dst_count = 0;
- int relocatable = (abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC))
- == HAS_RELOC;
+ int relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
for (; src_count < symcount; src_count++)
{
{
char *n, *ptr;
- ptr = n = xmalloc (1 + strlen (prefix_symbols_string)
- + strlen (name) + 1);
+ ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string)
+ + strlen (name) + 1);
if (add_leading_char)
*ptr++ = bfd_get_symbol_leading_char (obfd);
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
&& (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. */
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)))
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;
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);
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;
cause, target);
}
- new_node = xmalloc (sizeof (struct redefine_node));
+ new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
new_node->source = strdup (source);
new_node->target = strdup (target);
filename, strerror (errno));
bufsize = 100;
- buf = xmalloc (bufsize);
+ buf = (char *) xmalloc (bufsize + 1 /* For the terminating NUL. */);
lineno = 1;
c = getc (file);
if (len >= bufsize)
{
bufsize *= 2;
- buf = xrealloc (buf, bufsize);
+ buf = (char *) xrealloc (buf, bufsize + 1);
}
c = getc (file);
}
if (len >= bufsize)
{
bufsize *= 2;
- buf = xrealloc (buf, bufsize);
+ buf = (char *) xrealloc (buf, bufsize + 1);
}
c = getc (file);
}
if (bfd_stat_arch_elt (ibfd, &buf) != 0)
{
- bfd_nonfatal (bfd_get_archive_filename (ibfd));
+ bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
printf (_("copy from `%s' [unknown] to `%s' [unknown]\n"),
bfd_get_archive_filename (ibfd), bfd_get_filename (obfd));
- cbuf = xmalloc (BUFSIZE);
+ cbuf = (char *) xmalloc (BUFSIZE);
ncopied = 0;
while (ncopied < size)
{
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;
}
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;
}
ncopied += tocopy;
}
- chmod (bfd_get_filename (obfd), buf.st_mode);
+ /* We should at least to be able to read it back when copying an
+ unknown object in an archive. */
+ chmod (bfd_get_filename (obfd), buf.st_mode | S_IRUSR);
free (cbuf);
return TRUE;
}
Returns TRUE upon success, FALSE otherwise. */
static bfd_boolean
-copy_object (bfd *ibfd, bfd *obfd)
+copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
{
bfd_vma start;
long symcount;
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
{
- bfd_nonfatal (bfd_get_filename (obfd));
+ bfd_nonfatal_message (NULL, obfd, NULL, NULL);
+ return FALSE;
+ }
+
+ if (ibfd->sections == NULL)
+ {
+ non_fatal (_("error: the input file '%s' has no sections"),
+ bfd_get_archive_filename (ibfd));
return FALSE;
}
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;
}
}
/* Copy architecture of input file to output file. */
iarch = bfd_get_arch (ibfd);
imach = bfd_get_mach (ibfd);
+ if (input_arch)
+ {
+ if (bfd_get_arch_info (ibfd) == NULL
+ || bfd_get_arch_info (ibfd)->arch == bfd_arch_unknown)
+ {
+ iarch = input_arch->arch;
+ imach = input_arch->mach;
+ }
+ else
+ non_fatal (_("Input file `%s' ignores binary architecture parameter."),
+ bfd_get_archive_filename (ibfd));
+ }
if (!bfd_set_arch_mach (obfd, iarch, imach)
&& (ibfd->target_defaulted
|| bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
non_fatal (_("Unable to recognise the format of the input file `%s'"),
bfd_get_archive_filename (ibfd));
else
- non_fatal (_("Warning: Output file cannot represent architecture `%s'"),
+ non_fatal (_("Output file cannot represent architecture `%s'"),
bfd_printable_arch_mach (bfd_get_arch (ibfd),
bfd_get_mach (ibfd)));
return FALSE;
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);
+
+ /* Copy PE parameters before changing them. */
+ if (ibfd->xvec->flavour == bfd_target_coff_flavour
+ && bfd_pei_p (ibfd))
+ pe->pe_opthdr = pe_data (ibfd)->pe_opthdr;
+
+ 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);
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;
}
- osympp = isympp = xmalloc (symsize);
+ osympp = isympp = (asymbol **) xmalloc (symsize);
symcount = bfd_canonicalize_symtab (ibfd, isympp);
if (symcount < 0)
{
- bfd_nonfatal (bfd_get_filename (ibfd));
+ bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
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)
{
{
flagword flags;
- pset = find_section_list (padd->name, FALSE);
+ pset = find_section_list (padd->name, FALSE,
+ SECTION_CONTEXT_SET_FLAGS);
if (pset != NULL)
- pset->used = TRUE;
-
- flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
- if (pset != NULL && pset->set_flags)
flags = pset->flags | SEC_HAS_CONTENTS;
+ else
+ flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
/* bfd_make_section_with_flags() does not return very helpful
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
{
- padd->section = bfd_make_section_with_flags (obfd, padd->name, flags);
+ /* We use LINKER_CREATED here so that the backend hooks
+ will create any special section type information,
+ instead of presuming we know what we're doing merely
+ because we set the flags. */
+ padd->section = bfd_make_section_with_flags
+ (obfd, padd->name, flags | SEC_LINKER_CREATED);
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;
+ }
+
+ pset = find_section_list (padd->name, FALSE,
+ SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA);
+ if (pset != NULL
+ && ! bfd_set_section_vma (obfd, padd->section, pset->vma_val))
+ {
+ bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
}
+ pset = find_section_list (padd->name, FALSE,
+ SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_ALTER_LMA);
if (pset != NULL)
{
- if (pset->change_vma != CHANGE_IGNORE)
- if (! bfd_set_section_vma (obfd, padd->section,
- pset->vma_val))
- {
- bfd_nonfatal (bfd_get_filename (obfd));
- return FALSE;
- }
+ padd->section->lma = pset->lma_val;
- if (pset->change_lma != CHANGE_IGNORE)
+ if (! bfd_set_section_alignment
+ (obfd, padd->section,
+ bfd_section_alignment (obfd, padd->section)))
{
- padd->section->lma = pset->lma_val;
-
- if (! bfd_set_section_alignment
- (obfd, padd->section,
- bfd_section_alignment (obfd, padd->section)))
- {
- bfd_nonfatal (bfd_get_filename (obfd));
- return FALSE;
- }
+ bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
+ return FALSE;
}
}
}
}
- if (gnu_debuglink_filename != NULL)
+ if (dump_sections != NULL)
{
- gnu_debuglink_section = bfd_create_gnu_debuglink_section
- (obfd, gnu_debuglink_filename);
-
- if (gnu_debuglink_section == NULL)
- {
- bfd_nonfatal (gnu_debuglink_filename);
- return FALSE;
- }
+ struct section_add * pdump;
- /* Special processing for PE format files. We
- have no way to distinguish PE from COFF here. */
- if (bfd_get_flavour (obfd) == bfd_target_coff_flavour)
+ for (pdump = dump_sections; pdump != NULL; pdump = pdump->next)
{
- bfd_vma debuglink_vma;
- asection * highest_section;
asection * sec;
- /* The PE spec requires that all sections be adjacent and sorted
- in ascending order of VMA. It also specifies that debug
- sections should be last. This is despite the fact that debug
- sections are not loaded into memory and so in theory have no
- use for a VMA.
-
- This means that the debuglink section must be given a non-zero
- VMA which makes it contiguous with other debug sections. So
- walk the current section list, find the section with the
- highest VMA and start the debuglink section after that one. */
- for (sec = obfd->sections, highest_section = NULL;
- sec != NULL;
- sec = sec->next)
- if (sec->vma > 0
- && (highest_section == NULL
- || sec->vma > highest_section->vma))
- highest_section = sec;
-
- if (highest_section)
- debuglink_vma = BFD_ALIGN (highest_section->vma
- + highest_section->size,
- /* FIXME: We ought to be using
- COFF_PAGE_SIZE here or maybe
- bfd_get_section_alignment() (if it
- was set) but since this is for PE
- and we know the required alignment
- it is easier just to hard code it. */
- 0x1000);
+ sec = bfd_get_section_by_name (ibfd, pdump->name);
+ if (sec == NULL)
+ {
+ bfd_nonfatal_message (NULL, ibfd, NULL,
+ _("can't dump section '%s' - it does not exist"),
+ pdump->name);
+ continue;
+ }
+
+ if ((bfd_get_section_flags (ibfd, sec) & SEC_HAS_CONTENTS) == 0)
+ {
+ bfd_nonfatal_message (NULL, ibfd, sec,
+ _("can't dump section - it has no contents"));
+ continue;
+ }
+
+ bfd_size_type size = bfd_get_section_size (sec);
+ if (size == 0)
+ {
+ bfd_nonfatal_message (NULL, ibfd, sec,
+ _("can't dump section - it is empty"));
+ continue;
+ }
+
+ FILE * f;
+ f = fopen (pdump->filename, FOPEN_WB);
+ if (f == NULL)
+ {
+ bfd_nonfatal_message (pdump->filename, NULL, NULL,
+ _("could not open section dump file"));
+ continue;
+ }
+
+ bfd_byte * contents = xmalloc (size);
+ if (bfd_get_section_contents (ibfd, sec, contents, 0, size))
+ {
+ if (fwrite (contents, 1, size, f) != size)
+ fatal (_("error writing section contents to %s (error: %s)"),
+ pdump->filename,
+ strerror (errno));
+ }
else
- /* Umm, not sure what to do in this case. */
- debuglink_vma = 0x1000;
+ bfd_nonfatal_message (NULL, ibfd, sec,
+ _("could not retrieve section contents"));
+
+ fclose (f);
+ free (contents);
+ }
+ }
+
+ if (gnu_debuglink_filename != NULL)
+ {
+ /* PR 15125: Give a helpful warning message if
+ the debuglink section already exists, and
+ allow the rest of the copy to complete. */
+ if (bfd_get_section_by_name (obfd, ".gnu_debuglink"))
+ {
+ non_fatal (_("%s: debuglink section already exists"),
+ bfd_get_filename (obfd));
+ gnu_debuglink_filename = NULL;
+ }
+ else
+ {
+ gnu_debuglink_section = bfd_create_gnu_debuglink_section
+ (obfd, gnu_debuglink_filename);
+
+ if (gnu_debuglink_section == NULL)
+ {
+ bfd_nonfatal_message (NULL, obfd, NULL,
+ _("cannot create debug link section `%s'"),
+ gnu_debuglink_filename);
+ return FALSE;
+ }
+
+ /* Special processing for PE format files. We
+ have no way to distinguish PE from COFF here. */
+ if (bfd_get_flavour (obfd) == bfd_target_coff_flavour)
+ {
+ bfd_vma debuglink_vma;
+ asection * highest_section;
+ asection * sec;
+
+ /* The PE spec requires that all sections be adjacent and sorted
+ in ascending order of VMA. It also specifies that debug
+ sections should be last. This is despite the fact that debug
+ sections are not loaded into memory and so in theory have no
+ use for a VMA.
+
+ This means that the debuglink section must be given a non-zero
+ VMA which makes it contiguous with other debug sections. So
+ walk the current section list, find the section with the
+ highest VMA and start the debuglink section after that one. */
+ for (sec = obfd->sections, highest_section = NULL;
+ sec != NULL;
+ sec = sec->next)
+ if (sec->vma > 0
+ && (highest_section == NULL
+ || sec->vma > highest_section->vma))
+ highest_section = sec;
+
+ if (highest_section)
+ debuglink_vma = BFD_ALIGN (highest_section->vma
+ + highest_section->size,
+ /* FIXME: We ought to be using
+ COFF_PAGE_SIZE here or maybe
+ bfd_get_section_alignment() (if it
+ was set) but since this is for PE
+ and we know the required alignment
+ it is easier just to hard code it. */
+ 0x1000);
+ else
+ /* Umm, not sure what to do in this case. */
+ debuglink_vma = 0x1000;
- bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma);
+ bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma);
+ }
}
}
We write out the gap contents below. */
c = bfd_count_sections (obfd);
- osections = xmalloc (c * sizeof (asection *));
+ osections = (asection **) xmalloc (c * sizeof (asection *));
set = osections;
bfd_map_over_sections (obfd, get_sections, &set);
qsort (osections, c, sizeof (asection *), compare_section_lma);
- gaps = xmalloc (c * sizeof (bfd_size_type));
+ gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type));
memset (gaps, 0, c * sizeof (bfd_size_type));
if (gap_fill_set)
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;
}
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
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
|| strip_symbols == STRIP_UNNEEDED
|| strip_symbols == STRIP_NONDEBUG
+ || strip_symbols == STRIP_DWO
+ || strip_symbols == STRIP_NONDWO
|| 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
bfd_map_over_sections (ibfd,
mark_symbols_used_in_relocations,
isympp);
- osympp = xmalloc ((symcount + 1) * sizeof (asymbol *));
+ osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *));
symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
}
bfd_set_symtab (obfd, osympp, symcount);
+ /* This has to happen before section positions are set. */
+ bfd_map_over_sections (ibfd, copy_relocations_in_section, obfd);
+
/* This has to happen after the symbol table has been set. */
bfd_map_over_sections (ibfd, copy_section, 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;
}
}
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;
}
}
/* Fill in the gaps. */
if (max_gap > 8192)
max_gap = 8192;
- buf = xmalloc (max_gap);
+ buf = (bfd_byte *) xmalloc (max_gap);
memset (buf, gap_fill, max_gap);
c = bfd_count_sections (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;
}
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;
}
static void
copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
- bfd_boolean force_output_target)
+ bfd_boolean force_output_target,
+ const bfd_arch_info_type *input_arch)
{
struct name_list
{
} *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));
fatal (_("cannot create tempdir for archive copying (error: %s)"),
strerror (errno));
- obfd->has_armap = ibfd->has_armap;
+ if (strip_symbols == STRIP_ALL)
+ obfd->has_armap = FALSE;
+ else
+ obfd->has_armap = ibfd->has_armap;
+ obfd->is_thin_archive = ibfd->is_thin_archive;
+
+ if (deterministic)
+ obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
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)
{
bfd *last_element;
struct stat buf;
int stat_status = 0;
- bfd_boolean delete = TRUE;
+ bfd_boolean del = TRUE;
+ bfd_boolean ok_object;
/* Create an output file for this member. */
output_name = concat (dir, "/",
fatal (_("cannot create tempdir for archive copying (error: %s)"),
strerror (errno));
- l = xmalloc (sizeof (struct name_list));
+ l = (struct name_list *) xmalloc (sizeof (struct name_list));
l->name = output_name;
l->next = list;
l->obfd = NULL;
bfd_get_filename (this_element));
}
- l = xmalloc (sizeof (struct name_list));
+ l = (struct name_list *) xmalloc (sizeof (struct name_list));
l->name = output_name;
l->next = list;
l->obfd = NULL;
list = l;
- if (bfd_check_format (this_element, bfd_object))
- {
- /* PR binutils/3110: Cope with archives
- containing multiple target types. */
- if (force_output_target)
- output_bfd = bfd_openw (output_name, output_target);
- else
- output_bfd = bfd_openw (output_name, bfd_get_target (this_element));
+ ok_object = bfd_check_format (this_element, bfd_object);
+ if (!ok_object)
+ bfd_nonfatal_message (NULL, this_element, NULL,
+ _("Unable to recognise the format of file"));
+
+ /* PR binutils/3110: Cope with archives
+ containing multiple target types. */
+ if (force_output_target || !ok_object)
+ output_bfd = bfd_openw (output_name, output_target);
+ else
+ output_bfd = bfd_openw (output_name, bfd_get_target (this_element));
- if (output_bfd == NULL)
- RETURN_NONFATAL (output_name);
+ if (output_bfd == NULL)
+ {
+ bfd_nonfatal_message (output_name, NULL, NULL, NULL);
+ status = 1;
+ return;
+ }
- delete = ! copy_object (this_element, output_bfd);
+ if (ok_object)
+ {
+ del = !copy_object (this_element, output_bfd, input_arch);
- if (! delete
- || bfd_get_arch (this_element) != bfd_arch_unknown)
+ if (del && bfd_get_arch (this_element) == bfd_arch_unknown)
+ /* Try again as an unknown object file. */
+ ok_object = FALSE;
+ else if (!bfd_close (output_bfd))
{
- if (!bfd_close (output_bfd))
- {
- bfd_nonfatal (bfd_get_filename (output_bfd));
- /* Error in new object file. Don't change archive. */
- status = 1;
- }
+ bfd_nonfatal_message (output_name, NULL, NULL, NULL);
+ /* Error in new object file. Don't change archive. */
+ status = 1;
}
- else
- goto copy_unknown_element;
}
- else
- {
- non_fatal (_("Unable to recognise the format of the input file `%s'"),
- bfd_get_archive_filename (this_element));
- output_bfd = bfd_openw (output_name, output_target);
-copy_unknown_element:
- delete = !copy_unknown_object (this_element, output_bfd);
+ if (!ok_object)
+ {
+ del = !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;
}
}
- if (delete)
+ if (del)
{
unlink (output_name);
status = 1;
}
*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)
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
+ && bfd_get_flavour (input_bfd) == bfd_target_coff_flavour)
+ 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
copy_file (const char *input_filename, const char *output_filename,
- const char *input_target, const char *output_target)
+ const char *input_target, const char *output_target,
+ const bfd_arch_info_type *input_arch)
{
bfd *ibfd;
char **obj_matching;
char **core_matching;
+ off_t size = get_file_size (input_filename);
- if (get_file_size (input_filename) < 1)
+ if (size < 1)
{
+ if (size == 0)
+ non_fatal (_("error: the input file '%s' is empty"),
+ input_filename);
status = 1;
return;
}
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;
+ }
+
+ switch (do_debug_sections)
+ {
+ case compress:
+ ibfd->flags |= BFD_COMPRESS;
+ break;
+ case decompress:
+ ibfd->flags |= BFD_DECOMPRESS;
+ break;
+ default:
+ break;
+ }
if (bfd_check_format (ibfd, bfd_archive))
{
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);
+ copy_archive (ibfd, obfd, output_target, force_output_target, input_arch);
}
else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching))
{
obfd = bfd_openw (output_filename, output_target);
if (obfd == NULL)
- RETURN_NONFATAL (output_filename);
-
- if (! copy_object (ibfd, obfd))
+ {
+ 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, input_arch))
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
{
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)
{
add_section_rename (const char * old_name, const char * new_name,
flagword flags)
{
- section_rename * rename;
+ section_rename * srename;
/* Check for conflicts first. */
- for (rename = section_rename_list; rename != NULL; rename = rename->next)
- if (strcmp (rename->old_name, old_name) == 0)
+ for (srename = section_rename_list; srename != NULL; srename = srename->next)
+ if (strcmp (srename->old_name, old_name) == 0)
{
/* Silently ignore duplicate definitions. */
- if (strcmp (rename->new_name, new_name) == 0
- && rename->flags == flags)
+ if (strcmp (srename->new_name, new_name) == 0
+ && srename->flags == flags)
return;
fatal (_("Multiple renames of section %s"), old_name);
}
- rename = xmalloc (sizeof (* rename));
+ srename = (section_rename *) xmalloc (sizeof (* srename));
- rename->old_name = old_name;
- rename->new_name = new_name;
- rename->flags = flags;
- rename->next = section_rename_list;
+ srename->old_name = old_name;
+ srename->new_name = new_name;
+ srename->flags = flags;
+ srename->next = section_rename_list;
- section_rename_list = rename;
+ section_rename_list = srename;
}
/* Check the section rename list for a new name of the input section
flagword * returned_flags)
{
const char * old_name = bfd_section_name (ibfd, isection);
- section_rename * rename;
+ section_rename * srename;
/* Default to using the flags of the input section. */
* returned_flags = bfd_get_section_flags (ibfd, isection);
- for (rename = section_rename_list; rename != NULL; rename = rename->next)
- if (strcmp (rename->old_name, old_name) == 0)
+ for (srename = section_rename_list; srename != NULL; srename = srename->next)
+ if (strcmp (srename->old_name, old_name) == 0)
{
- if (rename->flags != (flagword) -1)
- * returned_flags = rename->flags;
+ if (srename->flags != (flagword) -1)
+ * returned_flags = srename->flags;
- return rename->new_name;
+ return srename->new_name;
}
return old_name;
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
static void
setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
{
- bfd *obfd = obfdarg;
+ bfd *obfd = (bfd *) obfdarg;
struct section_list *p;
sec_ptr osection;
bfd_size_type size;
const char *err;
const char * name;
char *prefix = NULL;
+ bfd_boolean make_nobits;
if (is_strip_section (ibfd, isection))
return;
- p = find_section_list (bfd_section_name (ibfd, isection), FALSE);
- if (p != NULL)
- p->used = TRUE;
-
/* Get the, possibly new, name of the output section. */
name = find_section_rename (ibfd, isection, & flags);
{
char *n;
- n = xmalloc (strlen (prefix) + strlen (name) + 1);
+ n = (char *) xmalloc (strlen (prefix) + strlen (name) + 1);
strcpy (n, prefix);
strcat (n, name);
name = n;
}
- if (p != NULL && p->set_flags)
+ make_nobits = FALSE;
+
+ p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ SECTION_CONTEXT_SET_FLAGS);
+ if (p != NULL)
flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
else if (strip_symbols == STRIP_NONDEBUG
- && obfd->xvec->flavour != bfd_target_elf_flavour
- && (flags & SEC_ALLOC) != 0)
- flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD);
+ && (flags & (SEC_ALLOC | SEC_GROUP)) != 0
+ && !is_nondebug_keep_contents_section (ibfd, isection))
+ {
+ flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
+ if (obfd->xvec->flavour == bfd_target_elf_flavour)
+ {
+ make_nobits = TRUE;
+
+ /* Twiddle the input section flags so that it seems to
+ elf.c:copy_private_bfd_data that section flags have not
+ changed between input and output sections. This hack
+ prevents wholesale rewriting of the program headers. */
+ isection->flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
+ }
+ }
osection = bfd_make_section_anyway_with_flags (obfd, name, flags);
if (osection == NULL)
{
- err = _("making");
+ err = _("failed to create output section");
goto loser;
}
- if (strip_symbols == STRIP_NONDEBUG
- && obfd->xvec->flavour == bfd_target_elf_flavour
- && (flags & SEC_ALLOC) != 0
- && elf_section_type (osection) != SHT_NOTE
- && (ibfd->xvec->flavour != bfd_target_elf_flavour
- || elf_section_type (isection) != SHT_NOTE)
- && (p == NULL || !p->set_flags))
+ if (make_nobits)
elf_section_type (osection) = SHT_NOBITS;
size = bfd_section_size (ibfd, isection);
if (copy_byte >= 0)
- size = (size + interleave - 1) / interleave;
+ size = (size + interleave - 1) / interleave * copy_width;
else if (extract_symbol)
size = 0;
if (! bfd_set_section_size (obfd, osection, size))
{
- err = _("size");
+ err = _("failed to set size");
goto loser;
}
vma = bfd_section_vma (ibfd, isection);
- if (p != NULL && p->change_vma == CHANGE_MODIFY)
- vma += p->vma_val;
- else if (p != NULL && p->change_vma == CHANGE_SET)
- vma = p->vma_val;
+ p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ SECTION_CONTEXT_ALTER_VMA | SECTION_CONTEXT_SET_VMA);
+ if (p != NULL)
+ {
+ if (p->context & SECTION_CONTEXT_SET_VMA)
+ vma = p->vma_val;
+ else
+ vma += p->vma_val;
+ }
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;
}
lma = isection->lma;
- if ((p != NULL) && p->change_lma != CHANGE_IGNORE)
+ p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_SET_LMA);
+ if (p != NULL)
{
- if (p->change_lma == CHANGE_MODIFY)
+ if (p->context & SECTION_CONTEXT_ALTER_LMA)
lma += p->lma_val;
- else if (p->change_lma == CHANGE_SET)
- lma = p->lma_val;
else
- abort ();
+ lma = p->lma_val;
}
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. */
osection,
bfd_section_alignment (ibfd, isection)))
{
- err = _("alignment");
+ err = _("failed to set alignment");
goto loser;
}
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
- to an output section with the same name in OBFD.
- If stripping then don't copy any relocation info. */
+/* Return TRUE if input section ISECTION should be skipped. */
-static void
-copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+static bfd_boolean
+skip_section (bfd *ibfd, sec_ptr isection)
{
- bfd *obfd = obfdarg;
- struct section_list *p;
- arelent **relpp;
- long relcount;
sec_ptr osection;
bfd_size_type size;
- long relsize;
flagword flags;
/* If we have already failed earlier on,
do not keep on generating complaints now. */
if (status != 0)
- return;
+ return TRUE;
+
+ if (extract_symbol)
+ return TRUE;
if (is_strip_section (ibfd, isection))
- return;
+ return TRUE;
flags = bfd_get_section_flags (ibfd, isection);
if ((flags & SEC_GROUP) != 0)
- return;
+ return TRUE;
osection = isection->output_section;
size = bfd_get_section_size (isection);
if (size == 0 || osection == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Copy relocations in input section ISECTION of IBFD to an output
+ section with the same name in OBFDARG. If stripping then don't
+ copy any relocation info. */
+
+static void
+copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+{
+ bfd *obfd = (bfd *) obfdarg;
+ long relsize;
+ arelent **relpp;
+ long relcount;
+ sec_ptr osection;
+
+ if (skip_section (ibfd, isection))
return;
- p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);
+ osection = isection->output_section;
- /* Core files do not need to be relocated. */
- if (bfd_get_format (obfd) == bfd_core)
+ /* Core files and DWO files do not need to be relocated. */
+ if (bfd_get_format (obfd) == bfd_core || strip_symbols == STRIP_NONDWO)
relsize = 0;
else
{
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;
+ }
}
}
if (relsize == 0)
- bfd_set_reloc (obfd, osection, NULL, 0);
+ {
+ bfd_set_reloc (obfd, osection, NULL, 0);
+ osection->flags &= ~SEC_RELOC;
+ }
else
{
- relpp = xmalloc (relsize);
+ relpp = (arelent **) 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)
{
long temp_relcount = 0;
long i;
- temp_relpp = xmalloc (relsize);
+ temp_relpp = (arelent **) 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);
bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
if (relcount == 0)
- free (relpp);
+ {
+ osection->flags &= ~SEC_RELOC;
+ free (relpp);
+ }
}
+}
- if (extract_symbol)
+/* Copy the data of input section ISECTION of IBFD
+ to an output section with the same name in OBFD. */
+
+static void
+copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+{
+ bfd *obfd = (bfd *) obfdarg;
+ struct section_list *p;
+ sec_ptr osection;
+ bfd_size_type size;
+
+ if (skip_section (ibfd, isection))
return;
+ osection = isection->output_section;
+ size = bfd_get_section_size (isection);
+
if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
&& bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
{
- void *memhunk = xmalloc (size);
+ bfd_byte *memhunk = NULL;
- if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size))
- RETURN_NONFATAL (bfd_get_filename (ibfd));
+ if (!bfd_get_full_section_contents (ibfd, isection, &memhunk))
+ {
+ status = 1;
+ bfd_nonfatal_message (NULL, ibfd, isection, NULL);
+ return;
+ }
if (reverse_bytes)
{
{
/* Keep only every `copy_byte'th byte in MEMHUNK. */
char *from = (char *) memhunk + copy_byte;
- char *to = memhunk;
+ char *to = (char *) memhunk;
char *end = (char *) memhunk + size;
+ int i;
for (; from < end; from += interleave)
- *to++ = *from;
+ for (i = 0; i < copy_width; i++)
+ {
+ if (&from[i] >= end)
+ break;
+ *to++ = from[i];
+ }
- size = (size + interleave - 1 - copy_byte) / interleave;
+ size = (size + interleave - 1 - copy_byte) / interleave * copy_width;
osection->lma /= interleave;
}
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)
+ else if ((p = find_section_list (bfd_get_section_name (ibfd, isection),
+ FALSE, SECTION_CONTEXT_SET_FLAGS)) != NULL
+ && (p->flags & SEC_HAS_CONTENTS) != 0)
{
void *memhunk = xmalloc (size);
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);
}
}
static void
get_sections (bfd *obfd ATTRIBUTE_UNUSED, asection *osection, void *secppparg)
{
- asection ***secppp = secppparg;
+ asection ***secppp = (asection ***) secppparg;
**secppp = osection;
++(*secppp);
static int
compare_section_lma (const void *arg1, const void *arg2)
{
- const asection *const *sec1 = arg1;
- const asection *const *sec2 = arg2;
+ const asection *const *sec1 = (const asection * const *) arg1;
+ const asection *const *sec2 = (const asection * const *) arg2;
flagword flags1, flags2;
/* Sort non loadable sections to the front. */
static void
mark_symbols_used_in_relocations (bfd *ibfd, sec_ptr isection, void *symbolsarg)
{
- asymbol **symbols = symbolsarg;
+ asymbol **symbols = (asymbol **) symbolsarg;
long relsize;
arelent **relpp;
long relcount, i;
if (relsize == 0)
return;
- relpp = xmalloc (relsize);
+ relpp = (arelent **) xmalloc (relsize);
relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, symbols);
if (relcount < 0)
bfd_fatal (bfd_get_filename (ibfd));
|| ! 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;
}
|| ! 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;
}
+/* If neither -D nor -U was specified explicitly,
+ then use the configured default. */
+static void
+default_deterministic (void)
+{
+ if (deterministic < 0)
+ deterministic = DEFAULT_AR_DETERMINISTIC;
+}
+
static int
strip_main (int argc, char *argv[])
{
bfd_boolean formats_info = FALSE;
int c;
int i;
- struct section_list *p;
char *output_file = NULL;
while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvw",
input_target = output_target = optarg;
break;
case 'R':
- p = find_section_list (optarg, TRUE);
- p->remove = TRUE;
+ find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
sections_removed = TRUE;
break;
case 's':
case 'd': /* Historic BSD alias for -g. Used by early NetBSD. */
strip_symbols = STRIP_DEBUG;
break;
+ case OPTION_STRIP_DWO:
+ strip_symbols = STRIP_DWO;
+ break;
case OPTION_STRIP_UNNEEDED:
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;
case 'p':
preserve_dates = TRUE;
break;
+ case 'D':
+ deterministic = TRUE;
+ break;
+ case 'U':
+ deterministic = FALSE;
+ break;
case 'x':
discard_locals = LOCALS_ALL;
break;
if (show_version)
print_version ("strip");
+ default_deterministic ();
+
/* 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)
It has already been checked in get_file_size(). */
stat (argv[i], &statbuf);
- if (output_file == NULL || strcmp (argv[i], output_file) == 0)
+ if (output_file == NULL
+ || filename_cmp (argv[i], output_file) == 0)
tmpname = make_tempname (argv[i]);
else
tmpname = output_file;
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;
}
status = 0;
- copy_file (argv[i], tmpname, input_target, output_target);
+ copy_file (argv[i], tmpname, input_target, output_target, NULL);
if (status == 0)
{
if (preserve_dates)
set_times (tmpname, &statbuf);
if (output_file != tmpname)
- smart_rename (tmpname, output_file ? output_file : argv[i],
- preserve_dates);
- status = hold_status;
+ status = (smart_rename (tmpname,
+ output_file ? output_file : argv[i],
+ preserve_dates) != 0);
+ if (status == 0)
+ status = hold_status;
}
else
unlink_if_ordinary (tmpname);
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 },
+ { "sal-rtd", 1, IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER },
+ { "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, ©, 0);
+ if (*copy == '.')
+ pe_minor_subsystem_version = strtoul (copy + 1, ©, 0);
+ if (*copy != '\0')
+ non_fatal (_("%s: bad version in PE subsystem"), s);
+ }
+
+ /* Check for numeric subsystem. */
+ value = (short) strtol (subsystem, ©, 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;
+ }
+ if (s != subsystem)
+ free ((char *) subsystem);
+}
+
+/* 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[])
{
- char * binary_architecture = NULL;
char *input_filename = NULL;
char *output_filename = NULL;
char *tmpname;
bfd_boolean change_warn = TRUE;
bfd_boolean formats_info = FALSE;
int c;
- struct section_list *p;
struct stat statbuf;
+ const bfd_arch_info_type *input_arch = NULL;
while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:w",
copy_options, (int *) 0)) != EOF)
break;
case 'B':
- binary_architecture = optarg;
+ input_arch = bfd_scan_arch (optarg);
+ if (input_arch == NULL)
+ fatal (_("architecture %s unknown"), optarg);
break;
case 'i':
- interleave = atoi (optarg);
- if (interleave < 1)
- fatal (_("interleave must be positive"));
+ if (optarg)
+ {
+ interleave = atoi (optarg);
+ if (interleave < 1)
+ fatal (_("interleave must be positive"));
+ }
+ else
+ interleave = 4;
+ break;
+
+ case OPTION_INTERLEAVE_WIDTH:
+ copy_width = atoi (optarg);
+ if (copy_width < 1)
+ fatal(_("interleave width must be positive"));
break;
case 'I':
break;
case 'j':
- p = find_section_list (optarg, TRUE);
- if (p->remove)
- fatal (_("%s both copied and removed"), optarg);
- p->copy = TRUE;
+ find_section_list (optarg, TRUE, SECTION_CONTEXT_COPY);
sections_copied = TRUE;
break;
case 'R':
- p = find_section_list (optarg, TRUE);
- if (p->copy)
- fatal (_("%s both copied and removed"), optarg);
- p->remove = TRUE;
+ find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
sections_removed = TRUE;
break;
strip_symbols = STRIP_DEBUG;
break;
+ case OPTION_STRIP_DWO:
+ strip_symbols = STRIP_DWO;
+ break;
+
case OPTION_STRIP_UNNEEDED:
strip_symbols = STRIP_UNNEEDED;
break;
break;
case OPTION_ADD_GNU_DEBUGLINK:
+ long_section_names = ENABLE ;
gnu_debuglink_filename = optarg;
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':
preserve_dates = TRUE;
break;
+ case 'D':
+ deterministic = TRUE;
+ break;
+
+ case 'U':
+ deterministic = FALSE;
+ break;
+
case 'w':
wildcard = TRUE;
break;
case OPTION_ADD_SECTION:
{
const char *s;
- off_t size;
+ size_t off, alloc;
struct section_add *pa;
- int len;
- char *name;
FILE *f;
s = strchr (optarg, '=');
if (s == NULL)
fatal (_("bad format for %s"), "--add-section");
- size = get_file_size (s + 1);
- if (size < 1)
- {
- status = 1;
- break;
- }
-
- pa = xmalloc (sizeof (struct section_add));
-
- len = s - optarg;
- name = xmalloc (len + 1);
- strncpy (name, optarg, len);
- name[len] = '\0';
- pa->name = name;
-
+ pa = (struct section_add *) xmalloc (sizeof (struct section_add));
+ pa->name = xstrndup (optarg, s - optarg);
pa->filename = s + 1;
- pa->size = size;
- pa->contents = xmalloc (size);
- f = fopen (pa->filename, FOPEN_RB);
+ /* We don't use get_file_size so that we can do
+ --add-section .note.GNU_stack=/dev/null
+ get_file_size doesn't work on /dev/null. */
+ f = fopen (pa->filename, FOPEN_RB);
if (f == NULL)
fatal (_("cannot open: %s: %s"),
pa->filename, strerror (errno));
- if (fread (pa->contents, 1, pa->size, f) == 0
- || ferror (f))
- fatal (_("%s: fread failed"), pa->filename);
+ off = 0;
+ alloc = 4096;
+ pa->contents = (bfd_byte *) xmalloc (alloc);
+ while (!feof (f))
+ {
+ off_t got;
+
+ if (off == alloc)
+ {
+ alloc <<= 1;
+ pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
+ }
+
+ got = fread (pa->contents + off, 1, alloc - off, f);
+ if (ferror (f))
+ fatal (_("%s: fread failed"), pa->filename);
+
+ off += got;
+ }
+
+ pa->size = off;
fclose (f);
}
break;
+ case OPTION_DUMP_SECTION:
+ {
+ const char *s;
+ struct section_add *pa;
+
+ s = strchr (optarg, '=');
+
+ if (s == NULL)
+ fatal (_("bad format for %s"), "--dump-section");
+
+ pa = (struct section_add *) xmalloc (sizeof * pa);
+ pa->name = xstrndup (optarg, s - optarg);
+ pa->filename = s + 1;
+ pa->next = dump_sections;
+ pa->contents = NULL;
+ dump_sections = pa;
+ }
+ break;
+
case OPTION_CHANGE_START:
change_start = parse_vma (optarg, "--change-start");
break;
case OPTION_CHANGE_SECTION_LMA:
case OPTION_CHANGE_SECTION_VMA:
{
+ struct section_list * p;
+ unsigned int context = 0;
const char *s;
int len;
char *name;
char *option = NULL;
bfd_vma val;
- enum change_action what = CHANGE_IGNORE;
switch (c)
{
case OPTION_CHANGE_SECTION_ADDRESS:
option = "--change-section-address";
+ context = SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_ALTER_VMA;
break;
case OPTION_CHANGE_SECTION_LMA:
option = "--change-section-lma";
+ context = SECTION_CONTEXT_ALTER_LMA;
break;
case OPTION_CHANGE_SECTION_VMA:
option = "--change-section-vma";
+ context = SECTION_CONTEXT_ALTER_VMA;
break;
}
fatal (_("bad format for %s"), option);
}
}
+ else
+ {
+ /* Correct the context. */
+ switch (c)
+ {
+ case OPTION_CHANGE_SECTION_ADDRESS:
+ context = SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_SET_VMA;
+ break;
+ case OPTION_CHANGE_SECTION_LMA:
+ context = SECTION_CONTEXT_SET_LMA;
+ break;
+ case OPTION_CHANGE_SECTION_VMA:
+ context = SECTION_CONTEXT_SET_VMA;
+ break;
+ }
+ }
len = s - optarg;
- name = xmalloc (len + 1);
+ name = (char *) xmalloc (len + 1);
strncpy (name, optarg, len);
name[len] = '\0';
- p = find_section_list (name, TRUE);
+ p = find_section_list (name, TRUE, context);
val = parse_vma (s + 1, option);
-
- switch (*s)
- {
- case '=': what = CHANGE_SET; break;
- case '-': val = - val; /* Drop through. */
- case '+': what = CHANGE_MODIFY; break;
- }
+ if (*s == '-')
+ val = - val;
switch (c)
{
case OPTION_CHANGE_SECTION_ADDRESS:
- p->change_vma = what;
- p->vma_val = val;
+ p->vma_val = val;
/* Drop through. */
case OPTION_CHANGE_SECTION_LMA:
- p->change_lma = what;
- p->lma_val = val;
+ p->lma_val = val;
break;
case OPTION_CHANGE_SECTION_VMA:
- p->change_vma = what;
- p->vma_val = val;
+ p->vma_val = val;
break;
}
}
change_leading_char = TRUE;
break;
+ case OPTION_COMPRESS_DEBUG_SECTIONS:
+ do_debug_sections = compress;
+ break;
+
case OPTION_DEBUGGING:
convert_debugging = TRUE;
break;
+ case OPTION_DECOMPRESS_DEBUG_SECTIONS:
+ do_debug_sections = decompress;
+ break;
+
case OPTION_GAP_FILL:
{
bfd_vma gap_fill_vma;
fatal (_("bad format for %s"), "--redefine-sym");
len = s - optarg;
- source = xmalloc (len + 1);
+ source = (char *) xmalloc (len + 1);
strncpy (source, optarg, len);
source[len] = '\0';
nextarg = s + 1;
len = strlen (nextarg);
- target = xmalloc (len + 1);
+ target = (char *) xmalloc (len + 1);
strcpy (target, nextarg);
redefine_list_append ("--redefine-sym", source, target);
case OPTION_SET_SECTION_FLAGS:
{
+ struct section_list *p;
const char *s;
int len;
char *name;
fatal (_("bad format for %s"), "--set-section-flags");
len = s - optarg;
- name = xmalloc (len + 1);
+ name = (char *) xmalloc (len + 1);
strncpy (name, optarg, len);
name[len] = '\0';
- p = find_section_list (name, TRUE);
+ p = find_section_list (name, TRUE, SECTION_CONTEXT_SET_FLAGS);
- p->set_flags = TRUE;
p->flags = parse_flags (s + 1);
}
break;
if (len == 0)
fatal (_("bad format for %s"), "--rename-section");
- old_name = xmalloc (len + 1);
+ old_name = (char *) xmalloc (len + 1);
strncpy (old_name, optarg, len);
old_name[len] = 0;
if (len == 0)
fatal (_("bad format for %s"), "--rename-section");
- new_name = xmalloc (len + 1);
+ new_name = (char *) xmalloc (len + 1);
strncpy (new_name, eq, len);
new_name[len] = 0;
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:
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:
bfd_flags_to_set &= ~D_PAGED;
break;
+ case OPTION_EXTRACT_DWO:
+ strip_symbols = STRIP_NONDWO;
+ break;
+
case OPTION_EXTRACT_SYMBOL:
extract_symbol = TRUE;
break;
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;
if (show_version)
print_version ("objcopy");
+ if (interleave && copy_byte == -1)
+ fatal (_("interleave start byte must be set with --byte"));
+
if (copy_byte >= interleave)
fatal (_("byte number must be less than interleave"));
+ if (copy_width > interleave - copy_byte)
+ fatal (_("interleave width must be less than or equal to interleave - byte`"));
+
if (optind == argc || optind + 2 < argc)
copy_usage (stderr, 1);
if (optind + 1 < argc)
output_filename = argv[optind + 1];
+ default_deterministic ();
+
/* Default is to strip no symbols. */
if (strip_symbols == STRIP_UNDEF && discard_locals == LOCALS_UNDEF)
strip_symbols = STRIP_NONE;
if (output_target == NULL)
output_target = input_target;
- if (binary_architecture != NULL)
+ /* Convert input EFI target to PEI target. */
+ if (input_target != NULL
+ && strncmp (input_target, "efi-", 4) == 0)
{
- if (input_target && strcmp (input_target, "binary") == 0)
- {
- const bfd_arch_info_type * temp_arch_info;
+ char *efi;
- temp_arch_info = bfd_scan_arch (binary_architecture);
+ 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);
- if (temp_arch_info != NULL)
- {
- bfd_external_binary_architecture = temp_arch_info->arch;
- bfd_external_machine = temp_arch_info->mach;
- }
- else
- fatal (_("architecture %s unknown"), binary_architecture);
+ 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
+ else if (strncmp (efi, "bsdrv-", 6) == 0)
{
- non_fatal (_("Warning: input target 'binary' required for binary architecture parameter."));
- non_fatal (_(" Argument %s ignored"), binary_architecture);
+ 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 (preserve_dates)
/* If there is no destination file, or the source and destination files
are the same, then create a temp and rename the result into the input. */
- if (output_filename == NULL || strcmp (input_filename, output_filename) == 0)
+ if (output_filename == NULL
+ || filename_cmp (input_filename, output_filename) == 0)
tmpname = make_tempname (input_filename);
else
tmpname = output_filename;
fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"),
input_filename, strerror (errno));
- copy_file (input_filename, tmpname, input_target, output_target);
+ copy_file (input_filename, tmpname, input_target, output_target, input_arch);
if (status == 0)
{
if (preserve_dates)
set_times (tmpname, &statbuf);
if (tmpname != output_filename)
- smart_rename (tmpname, input_filename, preserve_dates);
+ status = (smart_rename (tmpname, input_filename,
+ preserve_dates) != 0);
}
else
unlink_if_ordinary (tmpname);
if (change_warn)
{
+ struct section_list *p;
+
for (p = change_sections; p != NULL; p = p->next)
{
if (! p->used)
{
- if (p->change_vma != CHANGE_IGNORE)
+ if (p->context & (SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA))
{
char buff [20];
/* xgettext:c-format */
non_fatal (_("%s %s%c0x%s never used"),
"--change-section-vma",
- p->name,
- p->change_vma == CHANGE_SET ? '=' : '+',
+ p->pattern,
+ p->context & SECTION_CONTEXT_SET_VMA ? '=' : '+',
buff);
}
- if (p->change_lma != CHANGE_IGNORE)
+ if (p->context & (SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_ALTER_LMA))
{
char buff [20];
/* xgettext:c-format */
non_fatal (_("%s %s%c0x%s never used"),
"--change-section-lma",
- p->name,
- p->change_lma == CHANGE_SET ? '=' : '+',
+ p->pattern,
+ p->context & SECTION_CONTEXT_SET_LMA ? '=' : '+',
buff);
}
}
is_strip = (i >= 5 && FILENAME_CMP (program_name + i - 5, "strip") == 0);
}
+ create_symbol_htabs ();
+
if (is_strip)
strip_main (argc, argv);
else