/* 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, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 1991-2019 Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "filenames.h"
#include "fnmatch.h"
#include "elf-bfd.h"
-#include <sys/stat.h>
-#include "libbfd.h"
#include "coff/internal.h"
#include "libcoff.h"
+#include "safe-ctype.h"
/* FIXME: See bfd/peXXigen.c for why we include an architecture specific
header in generic PE code. */
struct is_specified_symbol_predicate_data
{
- const char *name;
+ const char * name;
bfd_boolean found;
};
-/* A list to support redefine_sym. */
+/* A node includes symbol name mapping to support redefine_sym. */
struct redefine_node
{
char *source;
char *target;
- struct redefine_node *next;
+};
+
+struct addsym_node
+{
+ struct addsym_node *next;
+ char * symdef;
+ long symval;
+ flagword flags;
+ char * section;
+ char * othersym;
};
typedef struct section_rename
static bfd_boolean verbose; /* Print file and target names. */
static bfd_boolean preserve_dates; /* Preserve input file timestamp. */
-static int status = 0; /* Exit status. */
+static int deterministic = -1; /* Enable deterministic archives. */
+static int status = 0; /* Exit status. */
+
+static bfd_boolean merge_notes = FALSE; /* Merge note sections. */
+static bfd_byte * merged_notes = NULL; /* Contents on note section undergoing a merge. */
+static bfd_size_type merged_size = 0; /* New, smaller size of the merged note section. */
enum strip_action
- {
- STRIP_UNDEF,
- STRIP_NONE, /* Don't strip. */
- STRIP_DEBUG, /* Strip all debugger symbols. */
- STRIP_UNNEEDED, /* Strip unnecessary symbols. */
- STRIP_NONDEBUG, /* Strip everything but debug info. */
- STRIP_ALL /* Strip all symbols. */
- };
+{
+ STRIP_UNDEF,
+ STRIP_NONE, /* Don't strip. */
+ 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
- {
- LOCALS_UNDEF,
- LOCALS_START_L, /* Discard locals starting with L. */
- LOCALS_ALL /* Discard all locals. */
- };
+{
+ LOCALS_UNDEF,
+ LOCALS_START_L, /* Discard locals starting with L. */
+ LOCALS_ALL /* Discard all locals. */
+};
/* 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. */
+#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 7) /* Remove relocations for this section. */
+
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 update in the output BFD. */
+static struct section_add *update_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 compress/decompress DWARF debug sections. */
static enum
{
- nothing,
- compress,
- decompress
+ nothing = 0,
+ compress = 1 << 0,
+ compress_zlib = compress | 1 << 1,
+ compress_gnu_zlib = compress | 1 << 2,
+ compress_gabi_zlib = compress | 1 << 3,
+ decompress = 1 << 4
} do_debug_sections = nothing;
+/* Whether to generate ELF common symbols with the STT_COMMON type. */
+static enum bfd_link_elf_stt_common do_elf_stt_common = unchanged;
+
/* Whether to change the leading character in symbol names. */
static bfd_boolean change_leading_char = FALSE;
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;
+static htab_t redefine_specific_htab = NULL;
+static htab_t redefine_specific_reverse_htab = NULL;
+static struct addsym_node *add_sym_list = NULL, **add_sym_tail = &add_sym_list;
+static int add_symbols = 0;
+
+static char *strip_specific_buffer = NULL;
+static char *strip_unneeded_buffer = NULL;
+static char *keep_specific_buffer = NULL;
+static char *localize_specific_buffer = NULL;
+static char *globalize_specific_buffer = NULL;
+static char *keepglobal_specific_buffer = NULL;
+static char *weaken_specific_buffer = NULL;
/* If this is TRUE, we weaken global symbols (set BSF_WEAK). */
static bfd_boolean weaken = FALSE;
/* 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
- };
+{
+ DISABLE,
+ ENABLE,
+ KEEP
+};
/* The default long section handling mode is to preserve them.
This is also the only behaviour for 'strip'. */
/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
enum command_line_switch
- {
- OPTION_ADD_SECTION=150,
- OPTION_CHANGE_ADDRESSES,
- OPTION_CHANGE_LEADING_CHAR,
- OPTION_CHANGE_START,
- OPTION_CHANGE_SECTION_ADDRESS,
- 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_REMOVE_LEADING_CHAR,
- OPTION_SET_SECTION_FLAGS,
- OPTION_SET_START,
- OPTION_STRIP_UNNEEDED,
- OPTION_WEAKEN,
- OPTION_REDEFINE_SYM,
- OPTION_REDEFINE_SYMS,
- OPTION_SREC_LEN,
- OPTION_SREC_FORCES3,
- OPTION_STRIP_SYMBOLS,
- OPTION_STRIP_UNNEEDED_SYMBOL,
- OPTION_STRIP_UNNEEDED_SYMBOLS,
- OPTION_KEEP_SYMBOLS,
- OPTION_LOCALIZE_HIDDEN,
- OPTION_LOCALIZE_SYMBOLS,
- OPTION_LONG_SECTION_NAMES,
- OPTION_GLOBALIZE_SYMBOL,
- OPTION_GLOBALIZE_SYMBOLS,
- OPTION_KEEPGLOBAL_SYMBOLS,
- OPTION_WEAKEN_SYMBOLS,
- OPTION_RENAME_SECTION,
- OPTION_ALT_MACH_CODE,
- OPTION_PREFIX_SYMBOLS,
- OPTION_PREFIX_SECTIONS,
- OPTION_PREFIX_ALLOC_SECTIONS,
- OPTION_FORMATS_INFO,
- OPTION_ADD_GNU_DEBUGLINK,
- OPTION_ONLY_KEEP_DEBUG,
- OPTION_KEEP_FILE_SYMBOLS,
- OPTION_READONLY_TEXT,
- OPTION_WRITABLE_TEXT,
- OPTION_PURE,
- OPTION_IMPURE,
- OPTION_EXTRACT_SYMBOL,
- OPTION_REVERSE_BYTES,
- OPTION_FILE_ALIGNMENT,
- OPTION_HEAP,
- OPTION_IMAGE_BASE,
- OPTION_SECTION_ALIGNMENT,
- OPTION_STACK,
- OPTION_INTERLEAVE_WIDTH,
- OPTION_SUBSYSTEM
- };
+{
+ OPTION_ADD_SECTION=150,
+ OPTION_ADD_GNU_DEBUGLINK,
+ OPTION_ADD_SYMBOL,
+ OPTION_ALT_MACH_CODE,
+ OPTION_CHANGE_ADDRESSES,
+ OPTION_CHANGE_LEADING_CHAR,
+ OPTION_CHANGE_SECTION_ADDRESS,
+ OPTION_CHANGE_SECTION_LMA,
+ OPTION_CHANGE_SECTION_VMA,
+ OPTION_CHANGE_START,
+ OPTION_CHANGE_WARNINGS,
+ OPTION_COMPRESS_DEBUG_SECTIONS,
+ OPTION_DEBUGGING,
+ OPTION_DECOMPRESS_DEBUG_SECTIONS,
+ OPTION_DUMP_SECTION,
+ OPTION_ELF_STT_COMMON,
+ OPTION_EXTRACT_DWO,
+ OPTION_EXTRACT_SYMBOL,
+ OPTION_FILE_ALIGNMENT,
+ OPTION_FORMATS_INFO,
+ OPTION_GAP_FILL,
+ OPTION_GLOBALIZE_SYMBOL,
+ OPTION_GLOBALIZE_SYMBOLS,
+ OPTION_HEAP,
+ OPTION_IMAGE_BASE,
+ OPTION_IMPURE,
+ OPTION_INTERLEAVE_WIDTH,
+ OPTION_KEEPGLOBAL_SYMBOLS,
+ OPTION_KEEP_FILE_SYMBOLS,
+ OPTION_KEEP_SYMBOLS,
+ OPTION_LOCALIZE_HIDDEN,
+ OPTION_LOCALIZE_SYMBOLS,
+ OPTION_LONG_SECTION_NAMES,
+ OPTION_MERGE_NOTES,
+ OPTION_NO_MERGE_NOTES,
+ OPTION_NO_CHANGE_WARNINGS,
+ OPTION_ONLY_KEEP_DEBUG,
+ OPTION_PAD_TO,
+ OPTION_PREFIX_ALLOC_SECTIONS,
+ OPTION_PREFIX_SECTIONS,
+ OPTION_PREFIX_SYMBOLS,
+ OPTION_PURE,
+ OPTION_READONLY_TEXT,
+ OPTION_REDEFINE_SYM,
+ OPTION_REDEFINE_SYMS,
+ OPTION_REMOVE_LEADING_CHAR,
+ OPTION_REMOVE_RELOCS,
+ OPTION_RENAME_SECTION,
+ OPTION_REVERSE_BYTES,
+ OPTION_SECTION_ALIGNMENT,
+ OPTION_SET_SECTION_FLAGS,
+ OPTION_SET_START,
+ OPTION_SREC_FORCES3,
+ OPTION_SREC_LEN,
+ OPTION_STACK,
+ OPTION_STRIP_DWO,
+ OPTION_STRIP_SYMBOLS,
+ OPTION_STRIP_UNNEEDED,
+ OPTION_STRIP_UNNEEDED_SYMBOL,
+ OPTION_STRIP_UNNEEDED_SYMBOLS,
+ OPTION_SUBSYSTEM,
+ OPTION_UPDATE_SECTION,
+ OPTION_WEAKEN,
+ OPTION_WEAKEN_SYMBOLS,
+ OPTION_WRITABLE_TEXT
+};
/* 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},
{"input-target", required_argument, 0, 'I'},
{"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
{"keep-symbol", required_argument, 0, 'K'},
+ {"merge-notes", no_argument, 0, 'M'},
+ {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
{"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
+ {"output-file", required_argument, 0, 'o'},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
- {"output-file", required_argument, 0, 'o'},
{"preserve-dates", no_argument, 0, 'p'},
{"remove-section", required_argument, 0, 'R'},
+ {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
{"strip-all", no_argument, 0, 's'},
{"strip-debug", no_argument, 0, 'S'},
- {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
+ {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
{"strip-symbol", required_argument, 0, 'N'},
+ {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
{"target", required_argument, 0, 'F'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{
{"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK},
{"add-section", required_argument, 0, OPTION_ADD_SECTION},
+ {"add-symbol", required_argument, 0, OPTION_ADD_SYMBOL},
+ {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
{"adjust-start", required_argument, 0, OPTION_CHANGE_START},
{"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES},
- {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
{"adjust-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
{"alt-machine-code", required_argument, 0, OPTION_ALT_MACH_CODE},
{"binary-architecture", required_argument, 0, 'B'},
{"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},
+ {"compress-debug-sections", optional_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},
+ {"elf-stt-common", required_argument, 0, OPTION_ELF_STT_COMMON},
+ {"enable-deterministic-archives", no_argument, 0, 'D'},
+ {"extract-dwo", no_argument, 0, OPTION_EXTRACT_DWO},
{"extract-symbol", no_argument, 0, OPTION_EXTRACT_SYMBOL},
+ {"file-alignment", required_argument, 0, OPTION_FILE_ALIGNMENT},
{"format", required_argument, 0, 'F'}, /* Obsolete */
{"gap-fill", required_argument, 0, OPTION_GAP_FILL},
{"globalize-symbol", required_argument, 0, OPTION_GLOBALIZE_SYMBOL},
{"globalize-symbols", required_argument, 0, OPTION_GLOBALIZE_SYMBOLS},
+ {"heap", required_argument, 0, OPTION_HEAP},
{"help", no_argument, 0, 'h'},
+ {"image-base", required_argument, 0 , OPTION_IMAGE_BASE},
{"impure", no_argument, 0, OPTION_IMPURE},
{"info", no_argument, 0, OPTION_FORMATS_INFO},
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"localize-symbol", required_argument, 0, 'L'},
{"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
{"long-section-names", required_argument, 0, OPTION_LONG_SECTION_NAMES},
+ {"merge-notes", no_argument, 0, 'M'},
+ {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
{"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},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
{"pad-to", required_argument, 0, OPTION_PAD_TO},
- {"prefix-symbols", required_argument, 0, OPTION_PREFIX_SYMBOLS},
- {"prefix-sections", required_argument, 0, OPTION_PREFIX_SECTIONS},
{"prefix-alloc-sections", required_argument, 0, OPTION_PREFIX_ALLOC_SECTIONS},
+ {"prefix-sections", required_argument, 0, OPTION_PREFIX_SECTIONS},
+ {"prefix-symbols", required_argument, 0, OPTION_PREFIX_SYMBOLS},
{"preserve-dates", no_argument, 0, 'p'},
{"pure", no_argument, 0, OPTION_PURE},
{"readonly-text", no_argument, 0, OPTION_READONLY_TEXT},
{"redefine-syms", required_argument, 0, OPTION_REDEFINE_SYMS},
{"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
{"remove-section", required_argument, 0, 'R'},
+ {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
{"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
{"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
+ {"section-alignment", required_argument, 0, OPTION_SECTION_ALIGNMENT},
{"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS},
{"set-start", required_argument, 0, OPTION_SET_START},
- {"srec-len", required_argument, 0, OPTION_SREC_LEN},
{"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3},
+ {"srec-len", required_argument, 0, OPTION_SREC_LEN},
+ {"stack", required_argument, 0, OPTION_STACK},
{"strip-all", no_argument, 0, 'S'},
{"strip-debug", no_argument, 0, 'g'},
+ {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
+ {"strip-symbol", required_argument, 0, 'N'},
+ {"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS},
{"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},
- {"strip-symbol", required_argument, 0, 'N'},
- {"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS},
+ {"subsystem", required_argument, 0, OPTION_SUBSYSTEM},
{"target", required_argument, 0, 'F'},
+ {"update-section", required_argument, 0, OPTION_UPDATE_SECTION},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"weaken", no_argument, 0, OPTION_WEAKEN},
{"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}
};
-1 means if we should use argv[0] to decide. */
extern int is_strip;
-/* The maximum length of an S record. This variable is declared in srec.c
+/* The maximum length of an S record. This variable is defined in srec.c
and can be modified by the --srec-len parameter. */
-extern unsigned int Chunk;
+extern unsigned int _bfd_srec_len;
/* Restrict the generation of Srecords to type S3 only.
- This variable is declare in bfd/srec.c and can be toggled
+ This variable is defined in bfd/srec.c and can be toggled
on by the --srec-forceS3 command line switch. */
-extern bfd_boolean S3Forced;
+extern bfd_boolean _bfd_srec_forceS3;
/* 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 *);
static void mark_symbols_used_in_relocations (bfd *, asection *, void *);
static bfd_boolean write_debugging_info (bfd *, void *, long *, asymbol ***);
static const char *lookup_sym_redefinition (const char *);
+static const char *find_section_rename (const char *, flagword *);
\f
-static void
+ATTRIBUTE_NORETURN static void
copy_usage (FILE *stream, int exit_status)
{
fprintf (stream, _("Usage: %s [option(s)] in-file [out-file]\n"), program_name);
-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\
+ --remove-relocations <name> Remove relocations from section <name>\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 N 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\
--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\
+ --update-section <name>=<file>\n\
+ Update contents of section <name> with\n\
+ contents found in <file>\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\
--globalize-symbols <file> --globalize-symbol for all in <file>\n\
--keep-global-symbols <file> -G for all symbols listed in <file>\n\
--weaken-symbols <file> -W for all symbols listed in <file>\n\
+ --add-symbol <name>=[<section>:]<value>[,<flags>] Add a symbol\n\
--alt-machine-code <index> Use the target's <index>'th alternative machine\n\
--writable-text Mark the output text as writable\n\
--readonly-text Make the output text write protected\n\
<commit>\n\
--subsystem <name>[:<version>]\n\
Set PE subsystem to <name> [& <version>]\n\
- --compress-debug-sections Compress DWARF debug sections using zlib\n\
+ --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+ Compress DWARF debug sections using zlib\n\
--decompress-debug-sections Decompress DWARF debug sections using zlib\n\
+ --elf-stt-common=[yes|no] Generate ELF common symbols with STT_COMMON\n\
+ type\n\
+ -M --merge-notes Remove redundant entries in note sections\n\
+ --no-merge-notes Do not attempt to remove redundant notes (default)\n\
-v --verbose List all object files modified\n\
@<file> Read options from <file>\n\
-V --version Display this program's version number\n\
exit (exit_status);
}
-static void
+ATTRIBUTE_NORETURN static void
strip_usage (FILE *stream, int exit_status)
{
fprintf (stream, _("Usage: %s <option(s)> in-file(s)\n"), program_name);
-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\
- -R --remove-section=<name> Remove section <name> from 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> Also remove section <name> from the output\n\
+ --remove-relocations <name> Remove relocations from section <name>\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\
+ -M --merge-notes Remove redundant entries in note sections (default)\n\
+ --no-merge-notes Do not attempt to remove redundant notes\n\
-N --strip-symbol=<name> Do not copy symbol <name>\n\
-K --keep-symbol=<name> Do not strip symbol <name>\n\
--keep-file-symbols Do not strip file symbol(s)\n\
}
if (0) ;
-#define PARSE_FLAG(fname,fval) \
- else if (strncasecmp (fname, s, len) == 0) ret |= fval
+#define PARSE_FLAG(fname,fval) \
+ else if (strncasecmp (fname, s, len) == 0) ret |= fval
PARSE_FLAG ("alloc", SEC_ALLOC);
PARSE_FLAG ("load", SEC_LOAD);
PARSE_FLAG ("noload", SEC_NEVER_LOAD);
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
{
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;
+ }
+ while (s != NULL);
+
+ return ret;
+}
+
+/* Parse symbol flags into a flagword, with a fatal error if the
+ string can't be parsed. */
+
+static flagword
+parse_symflags (const char *s, char **other)
+{
+ flagword ret;
+ const char *snext;
+ size_t len;
+
+ ret = BSF_NO_FLAGS;
+
+ do
+ {
+ snext = strchr (s, ',');
+ if (snext == NULL)
+ len = strlen (s);
+ else
+ {
+ len = snext - s;
+ ++snext;
+ }
+
+#define PARSE_FLAG(fname, fval) \
+ else if (len == sizeof fname - 1 \
+ && strncasecmp (fname, s, len) == 0) \
+ ret |= fval
+
+#define PARSE_OTHER(fname, fval) \
+ else if (len >= sizeof fname \
+ && strncasecmp (fname, s, sizeof fname - 1) == 0) \
+ fval = xstrndup (s + sizeof fname - 1, len - sizeof fname + 1)
+
+ if (0) ;
+ PARSE_FLAG ("local", BSF_LOCAL);
+ PARSE_FLAG ("global", BSF_GLOBAL);
+ PARSE_FLAG ("export", BSF_EXPORT);
+ PARSE_FLAG ("debug", BSF_DEBUGGING);
+ PARSE_FLAG ("function", BSF_FUNCTION);
+ PARSE_FLAG ("weak", BSF_WEAK);
+ PARSE_FLAG ("section", BSF_SECTION_SYM);
+ PARSE_FLAG ("constructor", BSF_CONSTRUCTOR);
+ PARSE_FLAG ("warning", BSF_WARNING);
+ PARSE_FLAG ("indirect", BSF_INDIRECT);
+ PARSE_FLAG ("file", BSF_FILE);
+ PARSE_FLAG ("object", BSF_OBJECT);
+ PARSE_FLAG ("synthetic", BSF_SYNTHETIC);
+ PARSE_FLAG ("indirect-function", BSF_GNU_INDIRECT_FUNCTION | BSF_FUNCTION);
+ PARSE_FLAG ("unique-object", BSF_GNU_UNIQUE | BSF_OBJECT);
+ PARSE_OTHER ("before=", *other);
+
+#undef PARSE_FLAG
+#undef PARSE_OTHER
+ else
+ {
+ char *copy;
+
+ copy = (char *) xmalloc (len + 1);
+ strncpy (copy, s, len);
+ copy[len] = '\0';
+ non_fatal (_("unrecognized symbol flag `%s'"), copy);
+ fatal (_("supported flags: %s"),
+ "local, global, export, debug, function, weak, section, "
+ "constructor, warning, indirect, file, object, synthetic, "
+ "indirect-function, unique-object, before=<othersym>");
}
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;
+ struct section_list *p, *match = NULL;
+
+ /* 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 ? */
+ if (p->pattern [0] == '!')
+ {
+ if (fnmatch (p->pattern + 1, name, 0) == 0)
+ {
+ p->used = TRUE;
+ return NULL;
+ }
+ }
+ else
+ {
+ if (fnmatch (p->pattern, name, 0) == 0)
+ {
+ if (match == NULL)
+ match = p;
+ }
+ }
+ }
+ }
if (! add)
- return NULL;
+ {
+ if (match != NULL)
+ match->used = TRUE;
+ return match;
+ }
p = (struct section_list *) xmalloc (sizeof (struct section_list));
- p->name = name;
+ 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;
}
+/* S1 is the entry node already in the table, S2 is the key node. */
+
+static int
+eq_string_redefnode (const void *s1, const void *s2)
+{
+ struct redefine_node *node1 = (struct redefine_node *) s1;
+ struct redefine_node *node2 = (struct redefine_node *) s2;
+ return !strcmp ((const char *) node1->source, (const char *) node2->source);
+}
+
+/* P is redefine node. Hash value is generated from its "source" filed. */
+
+static hashval_t
+htab_hash_redefnode (const void *p)
+{
+ struct redefine_node *redefnode = (struct redefine_node *) p;
+ return htab_hash_string (redefnode->source);
+}
+
+/* Create hashtab used for redefine node. */
+
+static htab_t
+create_symbol2redef_htab (void)
+{
+ return htab_create_alloc (16, htab_hash_redefnode, eq_string_redefnode, NULL,
+ xcalloc, free);
+}
+
/* There is htab_hash_string but no htab_eq_string. Makes sense. */
static int
globalize_specific_htab = create_symbol_htab ();
keepglobal_specific_htab = create_symbol_htab ();
weaken_specific_htab = create_symbol_htab ();
+ redefine_specific_htab = create_symbol2redef_htab ();
+ /* As there is no bidirectional hash table in libiberty, need a reverse table
+ to check duplicated target string. */
+ redefine_specific_reverse_htab = create_symbol_htab ();
}
/* Add a symbol to strip_specific_list. */
*htab_find_slot (htab, name, INSERT) = (char *) name;
}
+/* Like add_specific_symbol, but the element type is void *. */
+
+static void
+add_specific_symbol_node (const void *node, htab_t htab)
+{
+ *htab_find_slot (htab, node, INSERT) = (void *) node;
+}
+
/* Add symbols listed in `filename' to strip_specific_list. */
#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t')
#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
static void
-add_specific_symbols (const char *filename, htab_t htab)
+add_specific_symbols (const char *filename, htab_t htab, char **buffer_p)
{
off_t size;
FILE * f;
line = eol;
line_count ++;
}
+
+ /* Do not free the buffer. Parts of it will have been referenced
+ in the calls to add_specific_symbol. */
+ *buffer_p = buffer;
}
/* See whether a symbol should be stripped or kept
if (! fnmatch (slot_name, d->name, 0))
{
d->found = TRUE;
- /* Stop traversal. */
- return 0;
+ /* Continue traversal, there might be a non-match rule. */
+ return 1;
}
}
else
{
- if (fnmatch (slot_name + 1, d->name, 0))
+ if (! fnmatch (slot_name + 1, d->name, 0))
{
- d->found = TRUE;
+ d->found = FALSE;
/* Stop traversal. */
return 0;
}
bfd *abfd = group->owner;
Elf_Internal_Shdr *ghdr;
+ /* PR 20089: An earlier error may have prevented us from loading the symbol table. */
+ if (isympp == NULL)
+ return NULL;
+
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
return NULL;
ghdr = &elf_section_data (group)->this_hdr;
- if (ghdr->sh_link < elf_numsections (abfd))
+ if (ghdr->sh_link == elf_onesymtab (abfd))
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
+ Elf_Internal_Shdr *symhdr = &elf_symtab_hdr (abfd);
- if (symhdr->sh_type == SHT_SYMTAB
+ if (ghdr->sh_info > 0
&& ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
return isympp[ghdr->sh_info - 1];
}
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;
+}
+
+/* Return TRUE if section SEC is in the update list. */
+
+static bfd_boolean
+is_update_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+{
+ if (update_sections != NULL)
+ {
+ struct section_add *pupdate;
+
+ for (pupdate = update_sections;
+ pupdate != NULL;
+ pupdate = pupdate->next)
+ {
+ if (strcmp (sec->name, pupdate->name) == 0)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static bfd_boolean
+is_merged_note_section (bfd * abfd, asection * sec)
+{
+ if (merge_notes
+ && bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && elf_section_data (sec)->this_hdr.sh_type == SHT_NOTE
+ /* FIXME: We currently only support merging GNU_BUILD_NOTEs.
+ We should add support for more note types. */
+ && ((elf_section_data (sec)->this_hdr.sh_flags & SHF_GNU_BUILD_NOTE) != 0
+ /* Old versions of GAS (prior to 2.27) could not set the section
+ flags to OS-specific values, so we also accept sections with the
+ expected name. */
+ || (strcmp (sec->name, GNU_BUILD_ATTRS_SECTION_NAME) == 0)))
+ return TRUE;
+
+ return FALSE;
+}
+
+/* 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 && is_update_section (abfd, sec))
+ fatal (_("error: section %s matches both update and remove 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;
+ asection *elt, *first;
+
+ gsym = group_signature (sec);
+ /* Strip groups without a valid signature. */
+ if (gsym == NULL)
+ return TRUE;
/* PR binutils/3181
If we are going to strip the group signature symbol, then
strip the group section too. */
- gsym = group_signature (sec);
- if (gsym != NULL)
- gname = gsym->name;
- else
- gname = sec->name;
+ gname = gsym->name;
if ((strip_symbols == STRIP_ALL
&& !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 .buildid 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), ".buildid") == 0);
+
+ return FALSE;
+}
+
/* Return true if SYM is a hidden symbol. */
static bfd_boolean
return FALSE;
}
+static bfd_boolean
+need_sym_before (struct addsym_node **node, const char *sym)
+{
+ int count;
+ struct addsym_node *ptr = add_sym_list;
+
+ /* 'othersym' symbols are at the front of the list. */
+ for (count = 0; count < add_symbols; count++)
+ {
+ if (!ptr->othersym)
+ break;
+ else if (strcmp (ptr->othersym, sym) == 0)
+ {
+ free (ptr->othersym);
+ ptr->othersym = ""; /* Empty name is hopefully never a valid symbol name. */
+ *node = ptr;
+ return TRUE;
+ }
+ ptr = ptr->next;
+ }
+ return FALSE;
+}
+
+static asymbol *
+create_new_symbol (struct addsym_node *ptr, bfd *obfd)
+{
+ asymbol *sym = bfd_make_empty_symbol (obfd);
+
+ bfd_asymbol_name (sym) = ptr->symdef;
+ sym->value = ptr->symval;
+ sym->flags = ptr->flags;
+ if (ptr->section)
+ {
+ asection *sec = bfd_get_section_by_name (obfd, ptr->section);
+ if (!sec)
+ fatal (_("Section %s not found"), ptr->section);
+ sym->section = sec;
+ }
+ else
+ sym->section = bfd_abs_section_ptr;
+ return sym;
+}
+
/* Choose which symbol entries to copy; put the result in OSYMS.
We don't copy in place, because that confuses the relocs.
Return the number of symbols to print. */
undefined = bfd_is_und_section (bfd_get_section (sym));
- if (redefine_sym_list)
+ if (add_sym_list)
+ {
+ struct addsym_node *ptr;
+
+ if (need_sym_before (&ptr, name))
+ to[dst_count++] = create_new_symbol (ptr, obfd);
+ }
+
+ if (htab_elements (redefine_specific_htab) || section_rename_list)
{
- char *old_name, *new_name;
+ char *new_name;
- old_name = (char *) bfd_asymbol_name (sym);
- new_name = (char *) lookup_sym_redefinition (old_name);
+ new_name = (char *) lookup_sym_redefinition (name);
+ if (new_name == name
+ && (flags & BSF_SECTION_SYM) != 0)
+ new_name = (char *) find_section_rename (name, NULL);
bfd_asymbol_name (sym) = new_name;
name = new_name;
}
/* Short circuit for change_leading_char if we can do it in-place. */
if (rem_leading_char && add_leading_char && !prefix_symbols_string)
- {
+ {
name[0] = bfd_get_symbol_leading_char (obfd);
bfd_asymbol_name (sym) = name;
rem_leading_char = FALSE;
add_leading_char = FALSE;
- }
+ }
/* Remove leading char. */
if (rem_leading_char)
/* Add new leading char and/or prefix. */
if (add_leading_char || prefix_symbols_string)
- {
- char *n, *ptr;
+ {
+ char *n, *ptr;
- ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string)
- + strlen (name) + 1);
- if (add_leading_char)
+ ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string)
+ + strlen (name) + 1);
+ if (add_leading_char)
*ptr++ = bfd_get_symbol_leading_char (obfd);
- if (prefix_symbols_string)
- {
- strcpy (ptr, prefix_symbols_string);
- ptr += strlen (prefix_symbols_string);
- }
+ if (prefix_symbols_string)
+ {
+ strcpy (ptr, prefix_symbols_string);
+ ptr += strlen (prefix_symbols_string);
+ }
- strcpy (ptr, name);
- bfd_asymbol_name (sym) = n;
- name = n;
+ strcpy (ptr, name);
+ bfd_asymbol_name (sym) = n;
+ name = n;
}
if (strip_symbols == STRIP_ALL)
to[dst_count++] = sym;
}
}
+ if (add_sym_list)
+ {
+ struct addsym_node *ptr = add_sym_list;
+
+ for (src_count = 0; src_count < add_symbols; src_count++)
+ {
+ if (ptr->othersym)
+ {
+ if (strcmp (ptr->othersym, ""))
+ fatal (_("'before=%s' not found"), ptr->othersym);
+ }
+ else
+ to[dst_count++] = create_new_symbol (ptr, obfd);
+
+ ptr = ptr->next;
+ }
+ }
to[dst_count] = NULL;
static const char *
lookup_sym_redefinition (const char *source)
{
- struct redefine_node *list;
-
- for (list = redefine_sym_list; list != NULL; list = list->next)
- if (strcmp (source, list->source) == 0)
- return list->target;
+ struct redefine_node key_node = {(char *) source, NULL};
+ struct redefine_node *redef_node
+ = (struct redefine_node *) htab_find (redefine_specific_htab, &key_node);
- return source;
+ return redef_node == NULL ? source : redef_node->target;
}
-/* Add a node to a symbol redefine list. */
+/* Insert a node into symbol redefine hash tabel. */
static void
-redefine_list_append (const char *cause, const char *source, const char *target)
+add_redefine_and_check (const char *cause, const char *source,
+ const char *target)
{
- struct redefine_node **p;
- struct redefine_node *list;
- struct redefine_node *new_node;
-
- for (p = &redefine_sym_list; (list = *p) != NULL; p = &list->next)
- {
- if (strcmp (source, list->source) == 0)
- fatal (_("%s: Multiple redefinition of symbol \"%s\""),
- cause, source);
-
- if (strcmp (target, list->target) == 0)
- fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
- cause, target);
- }
-
- new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
+ struct redefine_node *new_node
+ = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
new_node->source = strdup (source);
new_node->target = strdup (target);
- new_node->next = NULL;
- *p = new_node;
+ if (htab_find (redefine_specific_htab, new_node) != HTAB_EMPTY_ENTRY)
+ fatal (_("%s: Multiple redefinition of symbol \"%s\""),
+ cause, source);
+
+ if (htab_find (redefine_specific_reverse_htab, target) != HTAB_EMPTY_ENTRY)
+ fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
+ cause, target);
+
+ /* Insert the NEW_NODE into hash table for quick search. */
+ add_specific_symbol_node (new_node, redefine_specific_htab);
+
+ /* Insert the target string into the reverse hash table, this is needed for
+ duplicated target string check. */
+ add_specific_symbol (new_node->target, redefine_specific_reverse_htab);
+
}
/* Handle the --redefine-syms option. Read lines containing "old new"
if ((c == '\r' && (c = getc (file)) == '\n')
|| c == '\n' || c == EOF)
{
- end_of_line:
+ end_of_line:
/* Append the redefinition to the list. */
if (buf[0] != '\0')
- redefine_list_append (filename, &buf[0], &buf[outsym_off]);
+ add_redefine_and_check (filename, &buf[0], &buf[outsym_off]);
lineno++;
len = 0;
}
else
fatal (_("%s:%d: garbage found at end of line"), filename, lineno);
- comment:
+ comment:
if (len != 0 && (outsym_off == 0 || outsym_off == len))
fatal (_("%s:%d: missing new symbol name"), filename, lineno);
buf[len++] = '\0';
fatal (_("%s:%d: premature end of file"), filename, lineno);
free (buf);
+ fclose (file);
}
-/* Copy unkown object file IBFD onto OBFD.
+/* Copy unknown object file IBFD onto OBFD.
Returns TRUE upon success, FALSE otherwise. */
static bfd_boolean
return TRUE;
}
+/* Returns the number of bytes needed to store VAL. */
+
+static inline unsigned int
+num_bytes (unsigned long val)
+{
+ unsigned int count = 0;
+
+ /* FIXME: There must be a faster way to do this. */
+ while (val)
+ {
+ count ++;
+ val >>= 8;
+ }
+ return count;
+}
+
+typedef struct objcopy_internal_note
+{
+ Elf_Internal_Note note;
+ bfd_vma start;
+ bfd_vma end;
+ bfd_boolean modified;
+} objcopy_internal_note;
+
+/* Returns TRUE if a gap does, or could, exist between the address range
+ covered by PNOTE1 and PNOTE2. */
+
+static bfd_boolean
+gap_exists (objcopy_internal_note * pnote1,
+ objcopy_internal_note * pnote2)
+{
+ /* Without range end notes, we assume that a gap might exist. */
+ if (pnote1->end == 0 || pnote2->end == 0)
+ return TRUE;
+
+ /* FIXME: Alignment of 16 bytes taken from x86_64 binaries.
+ Really we should extract the alignment of the section covered by the notes. */
+ return BFD_ALIGN (pnote1->end, 16) < pnote2->start;
+}
+
+static bfd_boolean
+is_open_note (objcopy_internal_note * pnote)
+{
+ return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_OPEN);
+}
+
+static bfd_boolean
+is_func_note (objcopy_internal_note * pnote)
+{
+ return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_FUNC);
+}
+
+static bfd_boolean
+is_64bit (bfd * abfd)
+{
+ /* Should never happen, but let's be paranoid. */
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ return FALSE;
+
+ return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64;
+}
+
+/* Merge the notes on SEC, removing redundant entries.
+ Returns the new, smaller size of the section upon success. */
+
+static bfd_size_type
+merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte * contents)
+{
+ objcopy_internal_note * pnotes_end;
+ objcopy_internal_note * pnotes = NULL;
+ objcopy_internal_note * pnote;
+ bfd_size_type remain = size;
+ unsigned version_1_seen = 0;
+ unsigned version_2_seen = 0;
+ unsigned version_3_seen = 0;
+ bfd_boolean duplicate_found = FALSE;
+ const char * err = NULL;
+ bfd_byte * in = contents;
+ int attribute_type_byte;
+ int val_start;
+ unsigned long previous_func_start = 0;
+ unsigned long previous_open_start = 0;
+ unsigned long previous_func_end = 0;
+ unsigned long previous_open_end = 0;
+ long relsize;
+
+
+ relsize = bfd_get_reloc_upper_bound (abfd, sec);
+ if (relsize > 0)
+ {
+ arelent ** relpp;
+ long relcount;
+
+ /* If there are relocs associated with this section then we
+ cannot safely merge it. */
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
+ free (relpp);
+ if (relcount != 0)
+ goto done;
+ }
+
+ /* Make a copy of the notes and convert to our internal format.
+ Minimum size of a note is 12 bytes. */
+ pnote = pnotes = (objcopy_internal_note *) xcalloc ((size / 12), sizeof (* pnote));
+ while (remain >= 12)
+ {
+ bfd_vma start, end;
+
+ pnote->note.namesz = (bfd_get_32 (abfd, in ) + 3) & ~3;
+ pnote->note.descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
+ pnote->note.type = bfd_get_32 (abfd, in + 8);
+
+ if (pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_OPEN
+ && pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
+ {
+ err = _("corrupt GNU build attribute note: wrong note type");
+ goto done;
+ }
+
+ if (pnote->note.namesz + pnote->note.descsz + 12 > remain)
+ {
+ err = _("corrupt GNU build attribute note: note too big");
+ goto done;
+ }
+
+ if (pnote->note.namesz < 2)
+ {
+ err = _("corrupt GNU build attribute note: name too small");
+ goto done;
+ }
+
+ pnote->note.namedata = (char *)(in + 12);
+ pnote->note.descdata = (char *)(in + 12 + pnote->note.namesz);
+
+ remain -= 12 + pnote->note.namesz + pnote->note.descsz;
+ in += 12 + pnote->note.namesz + pnote->note.descsz;
+
+ if (pnote->note.namesz > 2
+ && pnote->note.namedata[0] == '$'
+ && pnote->note.namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION
+ && pnote->note.namedata[2] == '1')
+ ++ version_1_seen;
+ else if (pnote->note.namesz > 4
+ && pnote->note.namedata[0] == 'G'
+ && pnote->note.namedata[1] == 'A'
+ && pnote->note.namedata[2] == '$'
+ && pnote->note.namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION)
+ {
+ if (pnote->note.namedata[4] == '2')
+ ++ version_2_seen;
+ else if (pnote->note.namedata[4] == '3')
+ ++ version_3_seen;
+ else
+ {
+ err = _("corrupt GNU build attribute note: unsupported version");
+ goto done;
+ }
+ }
+
+ switch (pnote->note.descsz)
+ {
+ case 0:
+ start = end = 0;
+ break;
+
+ case 4:
+ start = bfd_get_32 (abfd, pnote->note.descdata);
+ /* FIXME: For version 1 and 2 notes we should try to
+ calculate the end address by finding a symbol whose
+ value is START, and then adding in its size.
+
+ For now though, since v1 and v2 was not intended to
+ handle gaps, we chose an artificially large end
+ address. */
+ end = (bfd_vma) -1;
+ break;
+
+ case 8:
+ if (! is_64bit (abfd))
+ {
+ start = bfd_get_32 (abfd, pnote->note.descdata);
+ end = bfd_get_32 (abfd, pnote->note.descdata + 4);
+ }
+ else
+ {
+ start = bfd_get_64 (abfd, pnote->note.descdata);
+ /* FIXME: For version 1 and 2 notes we should try to
+ calculate the end address by finding a symbol whose
+ value is START, and then adding in its size.
+
+ For now though, since v1 and v2 was not intended to
+ handle gaps, we chose an artificially large end
+ address. */
+ end = (bfd_vma) -1;
+ }
+ break;
+
+ case 16:
+ start = bfd_get_64 (abfd, pnote->note.descdata);
+ end = bfd_get_64 (abfd, pnote->note.descdata + 8);
+ break;
+
+ default:
+ err = _("corrupt GNU build attribute note: bad description size");
+ goto done;
+ }
+
+ if (is_open_note (pnote))
+ {
+ if (start)
+ previous_open_start = start;
+
+ pnote->start = previous_open_start;
+
+ if (end)
+ previous_open_end = end;
+
+ pnote->end = previous_open_end;
+ }
+ else
+ {
+ if (start)
+ previous_func_start = start;
+
+ pnote->start = previous_func_start;
+
+ if (end)
+ previous_func_end = end;
+
+ pnote->end = previous_func_end;
+ }
+
+ if (pnote->note.namedata[pnote->note.namesz - 1] != 0)
+ {
+ err = _("corrupt GNU build attribute note: name not NUL terminated");
+ goto done;
+ }
+
+ pnote ++;
+ }
+
+ pnotes_end = pnote;
+
+ /* Check that the notes are valid. */
+ if (remain != 0)
+ {
+ err = _("corrupt GNU build attribute notes: excess data at end");
+ goto done;
+ }
+
+ if (version_1_seen == 0 && version_2_seen == 0 && version_3_seen == 0)
+ {
+ err = _("bad GNU build attribute notes: no known versions detected");
+ goto done;
+ }
+
+ if ((version_1_seen > 0 && version_2_seen > 0)
+ || (version_1_seen > 0 && version_3_seen > 0)
+ || (version_2_seen > 0 && version_3_seen > 0))
+ {
+ err = _("bad GNU build attribute notes: multiple different versions");
+ goto done;
+ }
+
+ /* Merging is only needed if there is more than one version note... */
+ if (version_1_seen == 1 || version_2_seen == 1 || version_3_seen == 1)
+ goto done;
+
+ attribute_type_byte = version_1_seen ? 1 : 3;
+ val_start = attribute_type_byte + 1;
+
+ /* The first note should be the first version note. */
+ if (pnotes[0].note.namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION)
+ {
+ err = _("bad GNU build attribute notes: first note not version note");
+ goto done;
+ }
+
+ /* Now merge the notes. The rules are:
+ 1. Preserve the ordering of the notes.
+ 2. Preserve any NT_GNU_BUILD_ATTRIBUTE_FUNC notes.
+ 3. Eliminate any NT_GNU_BUILD_ATTRIBUTE_OPEN notes that have the same
+ full name field as the immediately preceeding note with the same type
+ of name and whose address ranges coincide.
+ IE - if there are gaps in the coverage of the notes, then these gaps
+ must be preserved.
+ 4. Combine the numeric value of any NT_GNU_BUILD_ATTRIBUTE_OPEN notes
+ of type GNU_BUILD_ATTRIBUTE_STACK_SIZE.
+ 5. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
+ its description field is empty then the nearest preceeding OPEN note
+ with a non-empty description field must also be preserved *OR* the
+ description field of the note must be changed to contain the starting
+ address to which it refers.
+ 6. Notes with the same start and end address can be deleted. */
+ for (pnote = pnotes + 1; pnote < pnotes_end; pnote ++)
+ {
+ int note_type;
+ objcopy_internal_note * back;
+ objcopy_internal_note * prev_open_with_range = NULL;
+
+ /* Rule 6 - delete 0-range notes. */
+ if (pnote->start == pnote->end)
+ {
+ duplicate_found = TRUE;
+ pnote->note.type = 0;
+ continue;
+ }
+
+ /* Rule 2 - preserve function notes. */
+ if (! is_open_note (pnote))
+ {
+ int iter;
+
+ /* Check to see if there is an identical previous function note.
+ This can happen with overlays for example. */
+ for (iter = 0, back = pnote -1; back >= pnotes; back --)
+ {
+ if (back->start == pnote->start
+ && back->end == pnote->end
+ && back->note.namesz == pnote->note.namesz
+ && memcmp (back->note.namedata, pnote->note.namedata, pnote->note.namesz) == 0)
+ {
+ fprintf (stderr, "DUP FUNXC\n");
+ duplicate_found = TRUE;
+ pnote->note.type = 0;
+ break;
+ }
+
+ /* Don't scan too far back however. */
+ if (iter ++ > 16)
+ break;
+ }
+ continue;
+ }
+
+ note_type = pnote->note.namedata[attribute_type_byte];
+
+ /* Scan backwards from pnote, looking for duplicates.
+ Clear the type field of any found - but do not delete them just yet. */
+ for (back = pnote - 1; back >= pnotes; back --)
+ {
+ int back_type = back->note.namedata[attribute_type_byte];
+
+ /* If this is the first open note with an address
+ range that we have encountered then record it. */
+ if (prev_open_with_range == NULL
+ && back->note.descsz > 0
+ && ! is_func_note (back))
+ prev_open_with_range = back;
+
+ if (! is_open_note (back))
+ continue;
+
+ /* If the two notes are different then keep on searching. */
+ if (back_type != note_type)
+ continue;
+
+ /* Rule 4 - combine stack size notes. */
+ if (back_type == GNU_BUILD_ATTRIBUTE_STACK_SIZE)
+ {
+ unsigned char * name;
+ unsigned long note_val;
+ unsigned long back_val;
+ unsigned int shift;
+ unsigned int bytes;
+ unsigned long byte;
+
+ for (shift = 0, note_val = 0,
+ bytes = pnote->note.namesz - val_start,
+ name = (unsigned char *) pnote->note.namedata + val_start;
+ bytes--;)
+ {
+ byte = (* name ++) & 0xff;
+ note_val |= byte << shift;
+ shift += 8;
+ }
+
+ for (shift = 0, back_val = 0,
+ bytes = back->note.namesz - val_start,
+ name = (unsigned char *) back->note.namedata + val_start;
+ bytes--;)
+ {
+ byte = (* name ++) & 0xff;
+ back_val |= byte << shift;
+ shift += 8;
+ }
+
+ back_val += note_val;
+ if (num_bytes (back_val) >= back->note.namesz - val_start)
+ {
+ /* We have a problem - the new value requires more bytes of
+ storage in the name field than are available. Currently
+ we have no way of fixing this, so we just preserve both
+ notes. */
+ continue;
+ }
+
+ /* Write the new val into back. */
+ name = (unsigned char *) back->note.namedata + val_start;
+ while (name < (unsigned char *) back->note.namedata
+ + back->note.namesz)
+ {
+ byte = back_val & 0xff;
+ * name ++ = byte;
+ if (back_val == 0)
+ break;
+ back_val >>= 8;
+ }
+
+ duplicate_found = TRUE;
+ pnote->note.type = 0;
+ break;
+ }
+
+ /* Rule 3 - combine identical open notes. */
+ if (back->note.namesz == pnote->note.namesz
+ && memcmp (back->note.namedata,
+ pnote->note.namedata, back->note.namesz) == 0
+ && ! gap_exists (back, pnote))
+ {
+ duplicate_found = TRUE;
+ pnote->note.type = 0;
+
+ if (pnote->end > back->end)
+ back->end = pnote->end;
+
+ if (version_3_seen)
+ back->modified = TRUE;
+ break;
+ }
+
+ /* Rule 5 - Since we are keeping this note we must check to see
+ if its description refers back to an earlier OPEN version
+ note that has been scheduled for deletion. If so then we
+ must make sure that version note is also preserved. */
+ if (version_3_seen)
+ {
+ /* As of version 3 we can just
+ move the range into the note. */
+ pnote->modified = TRUE;
+ pnote->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+ back->modified = TRUE;
+ back->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+ }
+ else
+ {
+ if (pnote->note.descsz == 0
+ && prev_open_with_range != NULL
+ && prev_open_with_range->note.type == 0)
+ prev_open_with_range->note.type = NT_GNU_BUILD_ATTRIBUTE_OPEN;
+ }
+
+ /* We have found a similar attribute but the details do not match.
+ Stop searching backwards. */
+ break;
+ }
+ }
+
+ if (duplicate_found)
+ {
+ bfd_byte * new_contents;
+ bfd_byte * old;
+ bfd_byte * new;
+ bfd_size_type new_size;
+ bfd_vma prev_start = 0;
+ bfd_vma prev_end = 0;
+
+ /* Eliminate the duplicates. */
+ new = new_contents = xmalloc (size);
+ for (pnote = pnotes, old = contents;
+ pnote < pnotes_end;
+ pnote ++)
+ {
+ bfd_size_type note_size = 12 + pnote->note.namesz + pnote->note.descsz;
+
+ if (pnote->note.type != 0)
+ {
+ if (pnote->modified)
+ {
+ /* If the note has been modified then we must copy it by
+ hand, potentially adding in a new description field. */
+ if (pnote->start == prev_start && pnote->end == prev_end)
+ {
+ bfd_put_32 (abfd, pnote->note.namesz, new);
+ bfd_put_32 (abfd, 0, new + 4);
+ bfd_put_32 (abfd, pnote->note.type, new + 8);
+ new += 12;
+ memcpy (new, pnote->note.namedata, pnote->note.namesz);
+ new += pnote->note.namesz;
+ }
+ else
+ {
+ bfd_put_32 (abfd, pnote->note.namesz, new);
+ bfd_put_32 (abfd, is_64bit (abfd) ? 16 : 8, new + 4);
+ bfd_put_32 (abfd, pnote->note.type, new + 8);
+ new += 12;
+ memcpy (new, pnote->note.namedata, pnote->note.namesz);
+ new += pnote->note.namesz;
+ if (is_64bit (abfd))
+ {
+ bfd_put_64 (abfd, pnote->start, new);
+ bfd_put_64 (abfd, pnote->end, new + 8);
+ new += 16;
+ }
+ else
+ {
+ bfd_put_32 (abfd, pnote->start, new);
+ bfd_put_32 (abfd, pnote->end, new + 4);
+ new += 8;
+ }
+ }
+ }
+ else
+ {
+ memcpy (new, old, note_size);
+ new += note_size;
+ }
+ prev_start = pnote->start;
+ prev_end = pnote->end;
+ }
+
+ old += note_size;
+ }
+
+ new_size = new - new_contents;
+ memcpy (contents, new_contents, new_size);
+ size = new_size;
+ free (new_contents);
+ }
+
+ done:
+ if (err)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ bfd_nonfatal_message (NULL, abfd, sec, err);
+ status = 1;
+ }
+
+ free (pnotes);
+ return size;
+}
+
/* Copy object file IBFD onto OBFD.
Returns TRUE upon success, FALSE otherwise. */
bfd_vma start;
long symcount;
asection **osections = NULL;
+ asection *osec;
asection *gnu_debuglink_section = NULL;
bfd_size_type *gaps = NULL;
bfd_size_type max_gap = 0;
void *dhandle;
enum bfd_architecture iarch;
unsigned int imach;
+ unsigned int c, i;
if (ibfd->xvec->byteorder != obfd->xvec->byteorder
&& ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
&& obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
- fatal (_("Unable to change endianness of input file(s)"));
+ {
+ /* PR 17636: Call non-fatal so that we return to our parent who
+ may need to tidy temporary files. */
+ non_fatal (_("Unable to change endianness of input file(s)"));
+ return FALSE;
+ }
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
{
return FALSE;
}
+ if (ibfd->sections == NULL)
+ {
+ non_fatal (_("error: the input file '%s' has no sections"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
+ if (ibfd->xvec->flavour != bfd_target_elf_flavour)
+ {
+ if ((do_debug_sections & compress) != 0
+ && do_debug_sections != compress)
+ {
+ non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
+ if (do_elf_stt_common)
+ {
+ non_fatal (_("--elf-stt-common=[yes|no] is unsupported on `%s'"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+ }
+
if (verbose)
printf (_("copy from `%s' [%s] to `%s' [%s]\n"),
bfd_get_archive_filename (ibfd), bfd_get_target (ibfd),
bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
+ /* PR 17512: file: d6323821
+ If the symbol table could not be loaded do not pretend that we have
+ any symbols. This trips us up later on when we load the relocs. */
+ if (symcount == 0)
+ {
+ free (isympp);
+ osympp = isympp = NULL;
+ }
/* BFD mandates that all output sections be created and sizes set before
any output is done. Thus, we traverse all sections multiple times. */
{
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))
{
bfd_nonfatal_message (NULL, obfd, NULL,
- _("can't add section '%s'"), padd->name);
+ _("can't add section '%s'"), padd->name);
return FALSE;
}
else
{
/* 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. */
+ 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)
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_message (NULL, obfd, padd->section, NULL);
- 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;
+ bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ if (update_sections != NULL)
+ {
+ struct section_add *pupdate;
- if (! bfd_set_section_alignment
- (obfd, padd->section,
- bfd_section_alignment (obfd, padd->section)))
+ for (pupdate = update_sections;
+ pupdate != NULL;
+ pupdate = pupdate->next)
+ {
+ pupdate->section = bfd_get_section_by_name (ibfd, pupdate->name);
+ if (pupdate->section == NULL)
+ {
+ non_fatal (_("error: %s not found, can't be updated"), pupdate->name);
+ return FALSE;
+ }
+
+ osec = pupdate->section->output_section;
+ if (! bfd_set_section_size (obfd, osec, pupdate->size))
+ {
+ bfd_nonfatal_message (NULL, obfd, osec, NULL);
+ return FALSE;
+ }
+ }
+ }
+
+ if (merge_notes)
+ {
+ /* This palaver is necessary because we must set the output
+ section size first, before its contents are ready. */
+ osec = bfd_get_section_by_name (ibfd, GNU_BUILD_ATTRS_SECTION_NAME);
+ if (osec && is_merged_note_section (ibfd, osec))
+ {
+ bfd_size_type size;
+
+ size = bfd_get_section_size (osec);
+ if (size == 0)
+ {
+ bfd_nonfatal_message (NULL, ibfd, osec, _("warning: note section is empty"));
+ merge_notes = FALSE;
+ }
+ else if (! bfd_get_full_section_contents (ibfd, osec, & merged_notes))
+ {
+ bfd_nonfatal_message (NULL, ibfd, osec, _("warning: could not load note section"));
+ free (merged_notes);
+ merged_notes = NULL;
+ merge_notes = FALSE;
+ }
+ else
+ {
+ merged_size = merge_gnu_build_notes (ibfd, osec, size, merged_notes);
+ if (merged_size == size)
+ {
+ /* Merging achieves nothing. */
+ free (merged_notes);
+ merged_notes = NULL;
+ merge_notes = FALSE;
+ merged_size = 0;
+ }
+ else
+ {
+ if (osec->output_section == NULL
+ || ! bfd_set_section_size (obfd, osec->output_section, merged_size))
{
- bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
- return FALSE;
+ bfd_nonfatal_message (NULL, obfd, osec, _("warning: failed to set merged notes size"));
+ free (merged_notes);
+ merged_notes = NULL;
+ merge_notes = FALSE;
+ merged_size = 0;
}
}
}
}
}
- if (gnu_debuglink_filename != NULL)
+ if (dump_sections != NULL)
{
- gnu_debuglink_section = bfd_create_gnu_debuglink_section
- (obfd, gnu_debuglink_filename);
+ struct section_add * pdump;
- if (gnu_debuglink_section == NULL)
+ for (pdump = dump_sections; pdump != NULL; pdump = pdump->next)
{
- bfd_nonfatal_message (NULL, obfd, NULL,
- _("cannot create debug link section `%s'"),
- gnu_debuglink_filename);
- return FALSE;
- }
+ osec = bfd_get_section_by_name (ibfd, pdump->name);
+ if (osec == 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, osec) & SEC_HAS_CONTENTS) == 0)
+ {
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("can't dump section - it has no contents"));
+ continue;
+ }
+
+ bfd_size_type size = bfd_get_section_size (osec);
+ if (size == 0)
+ {
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("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;
+ }
- /* 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);
+ bfd_byte *contents;
+ if (bfd_malloc_and_get_section (ibfd, osec, &contents))
+ {
+ if (fwrite (contents, 1, size, f) != size)
+ {
+ non_fatal (_("error writing section contents to %s (error: %s)"),
+ pdump->filename,
+ strerror (errno));
+ free (contents);
+ fclose (f);
+ return FALSE;
+ }
+ }
else
- /* Umm, not sure what to do in this case. */
- debuglink_vma = 0x1000;
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("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;
+
+ /* 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 (osec = obfd->sections, highest_section = NULL;
+ osec != NULL;
+ osec = osec->next)
+ if (osec->vma > 0
+ && (highest_section == NULL
+ || osec->vma > highest_section->vma))
+ highest_section = osec;
+
+ 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);
+ }
}
}
- if (bfd_count_sections (obfd) != 0
+ c = bfd_count_sections (obfd);
+ if (c != 0
&& (gap_fill_set || pad_to_set))
{
asection **set;
- unsigned int c, i;
/* We must fill in gaps between the sections and/or we must pad
the last section to a specified address. We do this by
increasing the section sizes as required to fill the gaps.
We write out the gap contents below. */
- c = bfd_count_sections (obfd);
osections = (asection **) xmalloc (c * sizeof (asection *));
set = osections;
bfd_map_over_sections (obfd, get_sections, &set);
|| 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
|| htab_elements (strip_specific_htab) != 0
|| htab_elements (globalize_specific_htab) != 0
|| htab_elements (keepglobal_specific_htab) != 0
|| htab_elements (weaken_specific_htab) != 0
+ || htab_elements (redefine_specific_htab) != 0
|| prefix_symbols_string
|| sections_removed
|| sections_copied
|| convert_debugging
|| change_leading_char
|| remove_leading_char
- || redefine_sym_list
- || weaken)
+ || section_rename_list
+ || weaken
+ || add_symbols)
{
/* Mark symbols used in output relocations so that they
are kept, even if they are local labels or static symbols.
ignore input sections which have no corresponding output
section. */
if (strip_symbols != STRIP_ALL)
- bfd_map_over_sections (ibfd,
- mark_symbols_used_in_relocations,
- isympp);
- osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *));
+ {
+ bfd_set_error (bfd_error_no_error);
+ bfd_map_over_sections (ibfd,
+ mark_symbols_used_in_relocations,
+ isympp);
+ if (bfd_get_error () != bfd_error_no_error)
+ {
+ status = 1;
+ return FALSE;
+ }
+ }
+
+ osympp = (asymbol **) xmalloc ((symcount + add_symbols + 1) * sizeof (asymbol *));
symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
}
if (convert_debugging && dhandle != NULL)
{
- if (! write_debugging_info (obfd, dhandle, &symcount, &osympp))
+ bfd_boolean res;
+
+ res = write_debugging_info (obfd, dhandle, &symcount, &osympp);
+
+ free (dhandle);
+ dhandle = NULL; /* Paranoia... */
+
+ if (! res)
{
status = 1;
return FALSE;
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 (update_sections != NULL)
+ {
+ struct section_add *pupdate;
+
+ for (pupdate = update_sections;
+ pupdate != NULL;
+ pupdate = pupdate->next)
+ {
+ osec = pupdate->section->output_section;
+ if (! bfd_set_section_contents (obfd, osec, pupdate->contents,
+ 0, pupdate->size))
+ {
+ bfd_nonfatal_message (NULL, obfd, osec, NULL);
+ return FALSE;
+ }
+ }
+ }
+
+ if (merge_notes)
+ {
+ osec = bfd_get_section_by_name (obfd, GNU_BUILD_ATTRS_SECTION_NAME);
+ if (osec && is_merged_note_section (obfd, osec))
+ {
+ if (! bfd_set_section_contents (obfd, osec, merged_notes, 0, merged_size))
+ {
+ bfd_nonfatal_message (NULL, obfd, osec, _("error: failed to copy merged notes into output"));
+ return FALSE;
+ }
+ }
+ else if (! is_strip)
+ bfd_nonfatal_message (NULL, obfd, osec, _("could not find any mergeable note sections"));
+ free (merged_notes);
+ merged_notes = NULL;
+ merge_notes = FALSE;
+ }
+
if (gnu_debuglink_filename != NULL)
{
if (! bfd_fill_in_gnu_debuglink_section
if (gap_fill_set || pad_to_set)
{
bfd_byte *buf;
- int c, i;
/* Fill in the gaps. */
if (max_gap > 8192)
off, now))
{
bfd_nonfatal_message (NULL, obfd, osections[i], NULL);
+ free (buf);
return FALSE;
}
}
}
}
- }
- /* 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 TRUE;
+ free (buf);
+ free (gaps);
+ gaps = NULL;
+ }
/* Allow the BFD backend to copy any private data it understands
from the input BFD to the output BFD. This is done last to
char *dir;
const char *filename;
+ /* PR 24281: It is not clear what should happen when copying a thin archive.
+ One part is straight forward - if the output archive is in a different
+ directory from the input archive then any relative paths in the library
+ should be adjusted to the new location. But if any transformation
+ options are active (eg strip, rename, add, etc) then the implication is
+ that these should be applied to the files pointed to by the archive.
+ But since objcopy is not destructive, this means that new files must be
+ created, and there is no guidance for the names of the new files. (Plus
+ this conflicts with one of the goals of thin libraries - only taking up
+ a minimal amount of space in the file system).
+
+ So for now we fail if an attempt is made to copy such libraries. */
+ if (ibfd->is_thin_archive)
+ {
+ status = 1;
+ bfd_set_error (bfd_error_invalid_operation);
+ bfd_nonfatal_message (NULL, ibfd, NULL,
+ _("sorry: copying thin archives is not currently supported"));
+ return;
+ }
+
/* Make a temp directory to hold the contents. */
dir = make_tempdir (bfd_get_filename (obfd));
if (dir == NULL)
- fatal (_("cannot create tempdir for archive copying (error: %s)"),
+ 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);
{
status = 1;
bfd_nonfatal_message (NULL, obfd, NULL, NULL);
- return;
+ goto cleanup_and_exit;
}
while (!status && this_element != NULL)
struct stat buf;
int stat_status = 0;
bfd_boolean del = TRUE;
+ bfd_boolean ok_object;
+
+ /* PR binutils/17533: Do not allow directory traversal
+ outside of the current directory tree by archive members. */
+ if (! is_valid_archive_path (bfd_get_filename (this_element)))
+ {
+ non_fatal (_("illegal pathname found in archive member: %s"),
+ bfd_get_filename (this_element));
+ status = 1;
+ goto cleanup_and_exit;
+ }
/* Create an output file for this member. */
output_name = concat (dir, "/",
/* If the file already exists, make another temp dir. */
if (stat (output_name, &buf) >= 0)
{
- output_name = make_tempdir (output_name);
- if (output_name == NULL)
- fatal (_("cannot create tempdir for archive copying (error: %s)"),
- strerror (errno));
+ char * tmpdir = make_tempdir (output_name);
+
+ free (output_name);
+ if (tmpdir == NULL)
+ {
+ non_fatal (_("cannot create tempdir for archive copying (error: %s)"),
+ strerror (errno));
+ status = 1;
+ goto cleanup_and_exit;
+ }
l = (struct name_list *) xmalloc (sizeof (struct name_list));
- l->name = output_name;
+ l->name = tmpdir;
l->next = list;
l->obfd = NULL;
list = l;
- output_name = concat (output_name, "/",
+ output_name = concat (tmpdir, "/",
bfd_get_filename (this_element), (char *) 0);
}
l->obfd = NULL;
list = l;
- if (bfd_check_format (this_element, bfd_object))
+ 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)
{
- /* 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));
+ bfd_nonfatal_message (output_name, NULL, NULL, NULL);
+ status = 1;
+ goto cleanup_and_exit;
+ }
+
+ if (ok_object)
+ {
+ del = !copy_object (this_element, output_bfd, input_arch);
- if (output_bfd == NULL)
+ 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))
{
bfd_nonfatal_message (output_name, NULL, NULL, NULL);
+ /* Error in new object file. Don't change archive. */
status = 1;
- return;
- }
-
- del = ! copy_object (this_element, output_bfd, input_arch);
-
- if (! del
- || bfd_get_arch (this_element) != bfd_arch_unknown)
- {
- if (!bfd_close (output_bfd))
- {
- 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
- {
- 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:
+ if (!ok_object)
+ {
del = !copy_unknown_object (this_element, output_bfd);
if (!bfd_close_all_done (output_bfd))
{
{
status = 1;
bfd_nonfatal_message (filename, NULL, NULL, NULL);
- return;
}
filename = bfd_get_filename (ibfd);
{
status = 1;
bfd_nonfatal_message (filename, NULL, NULL, NULL);
- return;
}
+ cleanup_and_exit:
/* Delete all the files that we opened. */
- for (l = list; l != NULL; l = l->next)
- {
- if (l->obfd == NULL)
- rmdir (l->name);
- else
- {
- bfd_close (l->obfd);
- unlink (l->name);
- }
- }
+ {
+ struct name_list * next;
+
+ for (l = list; l != NULL; l = next)
+ {
+ if (l->obfd == NULL)
+ rmdir (l->name);
+ else
+ {
+ bfd_close (l->obfd);
+ unlink (l->name);
+ }
+ next = l->next;
+ free (l);
+ }
+ }
+
rmdir (dir);
}
switch (do_debug_sections)
{
case compress:
+ case compress_zlib:
+ case compress_gnu_zlib:
+ case compress_gabi_zlib:
ibfd->flags |= BFD_COMPRESS;
+ /* Don't check if input is ELF here since this information is
+ only available after bfd_check_format_matches is called. */
+ if (do_debug_sections != compress_gnu_zlib)
+ ibfd->flags |= BFD_COMPRESS_GABI;
break;
case decompress:
ibfd->flags |= BFD_DECOMPRESS;
break;
}
+ switch (do_elf_stt_common)
+ {
+ case elf_stt_common:
+ ibfd->flags |= BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON;
+ break;
+ break;
+ case no_elf_stt_common:
+ ibfd->flags |= BFD_CONVERT_ELF_COMMON;
+ break;
+ default:
+ break;
+ }
+
if (bfd_check_format (ibfd, bfd_archive))
{
bfd_boolean force_output_target;
bfd *obfd;
/* bfd_get_target does not return the correct value until
- bfd_check_format succeeds. */
+ bfd_check_format succeeds. */
if (output_target == NULL)
{
output_target = bfd_get_target (ibfd);
do_copy:
/* bfd_get_target does not return the correct value until
- bfd_check_format succeeds. */
+ bfd_check_format succeeds. */
if (output_target == NULL)
output_target = bfd_get_target (ibfd);
if (! copy_object (ibfd, obfd, input_arch))
status = 1;
- if (!bfd_close (obfd))
+ /* PR 17512: file: 0f15796a.
+ If the file could not be copied it may not be in a writeable
+ state. So use bfd_close_all_done to avoid the possibility of
+ writing uninitialised data into the file. */
+ if (! (status ? bfd_close_all_done (obfd) : bfd_close (obfd)))
{
status = 1;
bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
}
/* Check the section rename list for a new name of the input section
- ISECTION. Return the new name if one is found.
- Also set RETURNED_FLAGS to the flags to be used for this section. */
+ called OLD_NAME. Returns the new name if one is found and sets
+ RETURNED_FLAGS if non-NULL to the flags to be used for this section. */
static const char *
-find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection,
- flagword * returned_flags)
+find_section_rename (const char *old_name, flagword *returned_flags)
{
- const char * old_name = bfd_section_name (ibfd, isection);
- section_rename * srename;
-
- /* Default to using the flags of the input section. */
- * returned_flags = bfd_get_section_flags (ibfd, isection);
+ const section_rename *srename;
for (srename = section_rename_list; srename != NULL; srename = srename->next)
if (strcmp (srename->old_name, old_name) == 0)
{
- if (srename->flags != (flagword) -1)
- * returned_flags = srename->flags;
+ if (returned_flags != NULL && srename->flags != (flagword) -1)
+ *returned_flags = srename->flags;
return srename->new_name;
}
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);
+ name = bfd_section_name (ibfd, isection);
+ flags = bfd_get_section_flags (ibfd, isection);
+ name = find_section_rename (name, &flags);
/* Prefix sections. */
if ((prefix_alloc_sections_string)
}
make_nobits = FALSE;
- if (p != NULL && p->set_flags)
+
+ 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
&& (flags & (SEC_ALLOC | SEC_GROUP)) != 0
- && !(ibfd->xvec->flavour == bfd_target_elf_flavour
- && elf_section_type (isection) == SHT_NOTE))
+ && !is_nondebug_keep_contents_section (ibfd, isection))
{
flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
if (obfd->xvec->flavour == bfd_target_elf_flavour)
elf_section_type (osection) = SHT_NOBITS;
size = bfd_section_size (ibfd, isection);
+ size = bfd_convert_section_size (ibfd, isection, obfd, size);
if (copy_byte >= 0)
size = (size + interleave - 1) / interleave * copy_width;
else if (extract_symbol)
}
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;
}
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;
/* Copy merge entity size. */
osection->entsize = isection->entsize;
+ /* Copy compress status. */
+ osection->compress_status = isection->compress_status;
+
/* This used to be mangle_section; we do here to avoid using
bfd_get_section_by_name since some formats allow multiple
sections with the same name. */
isection->output_section = osection;
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);
/* All went well. */
return;
-loser:
+ loser:
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_boolean skip_copy)
{
- bfd *obfd = (bfd *) 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;
+
+ if (is_update_section (ibfd, isection))
+ return TRUE;
+
+ /* When merging a note section we skip the copying of the contents,
+ but not the copying of the relocs associated with the contents. */
+ if (skip_copy && is_merged_note_section (ibfd, isection))
+ 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;
+ return TRUE;
- if (extract_symbol)
+ return FALSE;
+}
+
+/* Add section SECTION_PATTERN to the list of sections that will have their
+ relocations removed. */
+
+static void
+handle_remove_relocations_option (const char *section_pattern)
+{
+ find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE_RELOCS);
+}
+
+/* Return TRUE if ISECTION from IBFD should have its relocations removed,
+ otherwise return FALSE. If the user has requested that relocations be
+ removed from a section that does not have relocations then this
+ function will still return TRUE. */
+
+static bfd_boolean
+discard_relocations (bfd *ibfd ATTRIBUTE_UNUSED, asection *isection)
+{
+ return (find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ SECTION_CONTEXT_REMOVE_RELOCS) != NULL);
+}
+
+/* Wrapper for dealing with --remove-section (-R) command line arguments.
+ A special case is detected here, if the user asks to remove a relocation
+ section (one starting with ".rela" or ".rel") then this removal must
+ be done using a different technique in a relocatable object. */
+
+static void
+handle_remove_section_option (const char *section_pattern)
+{
+ find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE);
+ if (strncmp (section_pattern, ".rel", 4) == 0)
+ {
+ section_pattern += 4;
+ if (*section_pattern == 'a')
+ section_pattern++;
+ if (*section_pattern)
+ handle_remove_relocations_option (section_pattern);
+ }
+ sections_removed = TRUE;
+}
+
+/* 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, FALSE))
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
+ || discard_relocations (ibfd, isection))
relsize = 0;
else
{
}
if (relsize == 0)
- bfd_set_reloc (obfd, osection, NULL, 0);
+ {
+ bfd_set_reloc (obfd, osection, NULL, 0);
+ osection->flags &= ~SEC_RELOC;
+ }
else
{
- relpp = (arelent **) xmalloc (relsize);
- relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
- if (relcount < 0)
+ if (isection->orelocation != NULL)
{
- status = 1;
- bfd_nonfatal_message (NULL, ibfd, isection,
- _("relocation count is negative"));
- return;
+ /* Some other function has already set up the output relocs
+ for us, so scan those instead of the default relocs. */
+ relcount = isection->reloc_count;
+ relpp = isection->orelocation;
+ }
+ else
+ {
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
+ if (relcount < 0)
+ {
+ status = 1;
+ bfd_nonfatal_message (NULL, ibfd, isection,
+ _("relocation count is negative"));
+ return;
+ }
}
if (strip_symbols == STRIP_ALL)
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_htab))
- temp_relpp [temp_relcount++] = relpp [i];
+ {
+ /* PR 17512: file: 9e907e0c. */
+ if (relpp[i]->sym_ptr_ptr
+ /* PR 20096 */
+ && * relpp[i]->sym_ptr_ptr)
+ if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
+ keep_specific_htab))
+ temp_relpp [temp_relcount++] = relpp [i];
+ }
relcount = temp_relcount;
- free (relpp);
+ if (isection->orelocation == NULL)
+ free (relpp);
relpp = temp_relpp;
}
bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
if (relcount == 0)
- free (relpp);
+ {
+ osection->flags &= ~SEC_RELOC;
+ free (relpp);
+ }
}
+}
+
+/* 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, TRUE))
+ return;
+
+ osection = isection->output_section;
+ /* The output SHF_COMPRESSED section size is different from input if
+ ELF classes of input and output aren't the same. We can't use
+ the output section size since --interleave will shrink the output
+ section. Size will be updated if the section is converted. */
+ 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)
{
bfd_byte *memhunk = NULL;
- if (!bfd_get_full_section_contents (ibfd, isection, &memhunk))
+ if (!bfd_get_full_section_contents (ibfd, isection, &memhunk)
+ || !bfd_convert_section_contents (ibfd, isection, obfd,
+ &memhunk, &size))
{
status = 1;
bfd_nonfatal_message (NULL, ibfd, isection, NULL);
+ free (memhunk);
return;
}
char *end = (char *) memhunk + size;
int i;
+ /* If the section address is not exactly divisible by the interleave,
+ then we must bias the from address. If the copy_byte is less than
+ the bias, then we must skip forward one interleave, and increment
+ the final lma. */
+ int extra = isection->lma % interleave;
+ from -= extra;
+ if (copy_byte < extra)
+ from += interleave;
+
for (; from < end; from += interleave)
for (i = 0; i < copy_width; i++)
- *to++ = from[i];
+ {
+ if (&from[i] >= end)
+ break;
+ *to++ = from[i];
+ }
size = (size + interleave - 1 - copy_byte) / interleave * copy_width;
osection->lma /= interleave;
+ if (copy_byte < extra)
+ osection->lma++;
}
if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
{
status = 1;
bfd_nonfatal_message (NULL, obfd, osection, NULL);
+ free (memhunk);
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);
{
status = 1;
bfd_nonfatal_message (NULL, obfd, osection, NULL);
+ free (memhunk);
return;
}
free (memhunk);
special bfd section symbols, then mark it with BSF_KEEP. */
for (i = 0; i < relcount; i++)
{
- if (*relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
+ /* See PRs 20923 and 20930 for reproducers for the NULL tests. */
+ if (relpp[i]->sym_ptr_ptr != NULL
+ && * relpp[i]->sym_ptr_ptr != NULL
+ && *relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
&& *relpp[i]->sym_ptr_ptr != bfd_abs_section_ptr->symbol
&& *relpp[i]->sym_ptr_ptr != bfd_und_section_ptr->symbol)
(*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP;
long *symcountp ATTRIBUTE_UNUSED,
asymbol ***symppp ATTRIBUTE_UNUSED)
{
- if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour)
- return write_ieee_debugging_info (obfd, dhandle);
-
if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
|| bfd_get_flavour (obfd) == bfd_target_elf_flavour)
{
- bfd_byte *syms, *strings;
+ bfd_byte *syms, *strings = NULL;
bfd_size_type symsize, stringsize;
asection *stabsec, *stabstrsec;
flagword flags;
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't create debugging section"));
+ free (strings);
return FALSE;
}
/* We can get away with setting the section contents now because
- the next thing the caller is going to do is copy over the
- real sections. We may someday have to split the contents
- setting out of this function. */
+ the next thing the caller is going to do is copy over the
+ real sections. We may someday have to split the contents
+ setting out of this function. */
if (! bfd_set_section_contents (obfd, stabsec, syms, 0, symsize)
|| ! bfd_set_section_contents (obfd, stabstrsec, strings, 0,
stringsize))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't set debugging section contents"));
+ free (strings);
return FALSE;
}
bfd_nonfatal_message (NULL, obfd, NULL,
_("don't know how to write debugging information for %s"),
- bfd_get_target (obfd));
+ 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",
+ merge_notes = TRUE;
+
+ while ((c = getopt_long (argc, argv, "I:O:F:K:MN:R:o:sSpdgxXHhVvwDU",
strip_options, (int *) 0)) != EOF)
{
switch (c)
input_target = output_target = optarg;
break;
case 'R':
- p = find_section_list (optarg, TRUE);
- p->remove = TRUE;
- sections_removed = TRUE;
+ handle_remove_section_option (optarg);
+ break;
+ case OPTION_REMOVE_RELOCS:
+ handle_remove_relocations_option (optarg);
break;
case 's':
strip_symbols = STRIP_ALL;
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_htab);
break;
+ case 'M':
+ merge_notes = TRUE;
+ break;
+ case OPTION_NO_MERGE_NOTES:
+ merge_notes = FALSE;
+ break;
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
break;
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
}
v[] =
{
- { "native", 0, IMAGE_SUBSYSTEM_NATIVE },
+ { "native", 0, IMAGE_SUBSYSTEM_NATIVE },
{ "windows", 0, IMAGE_SUBSYSTEM_WINDOWS_GUI },
{ "console", 0, IMAGE_SUBSYSTEM_WINDOWS_CUI },
{ "posix", 0, IMAGE_SUBSYSTEM_POSIX_CUI },
}
}
+/* Allocate and return a pointer to a struct section_add, initializing the
+ structure using ARG, a string in the format "sectionname=filename".
+ The returned structure will have its next pointer set to NEXT. The
+ OPTION field is the name of the command line option currently being
+ parsed, and is only used if an error needs to be reported. */
+
+static struct section_add *
+init_section_add (const char *arg,
+ struct section_add *next,
+ const char *option)
+{
+ struct section_add *pa;
+ const char *s;
+
+ s = strchr (arg, '=');
+ if (s == NULL)
+ fatal (_("bad format for %s"), option);
+
+ pa = (struct section_add *) xmalloc (sizeof (struct section_add));
+ pa->name = xstrndup (arg, s - arg);
+ pa->filename = s + 1;
+ pa->next = next;
+ pa->contents = NULL;
+ pa->size = 0;
+
+ return pa;
+}
+
+/* Load the file specified in PA, allocating memory to hold the file
+ contents, and store a pointer to the allocated memory in the contents
+ field of PA. The size field of PA is also updated. All errors call
+ FATAL. */
+
+static void
+section_add_load_file (struct section_add *pa)
+{
+ size_t off, alloc;
+ FILE *f;
+
+ /* 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));
+
+ 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);
+}
+
static int
copy_main (int argc, char *argv[])
{
bfd_boolean show_version = FALSE;
bfd_boolean change_warn = TRUE;
bfd_boolean formats_info = FALSE;
+ bfd_boolean use_globalize = FALSE;
+ bfd_boolean use_keep_global = 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",
+ while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:MN:s:O:d:F:L:G:R:SpgxXHhVvW:wDU",
copy_options, (int *) 0)) != EOF)
{
switch (c)
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;
- sections_removed = TRUE;
+ handle_remove_section_option (optarg);
+ break;
+
+ case OPTION_REMOVE_RELOCS:
+ handle_remove_relocations_option (optarg);
break;
case 'S':
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;
add_specific_symbol (optarg, keep_specific_htab);
break;
+ case 'M':
+ merge_notes = TRUE;
+ break;
+ case OPTION_NO_MERGE_NOTES:
+ merge_notes = FALSE;
+ break;
+
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
break;
break;
case OPTION_GLOBALIZE_SYMBOL:
+ use_globalize = TRUE;
add_specific_symbol (optarg, globalize_specific_htab);
break;
case 'G':
+ use_keep_global = TRUE;
add_specific_symbol (optarg, keepglobal_specific_htab);
break;
preserve_dates = TRUE;
break;
+ case 'D':
+ deterministic = TRUE;
+ break;
+
+ case 'U':
+ deterministic = FALSE;
+ break;
+
case 'w':
wildcard = TRUE;
break;
break;
case OPTION_ADD_SECTION:
- {
- const char *s;
- size_t off, alloc;
- struct section_add *pa;
- FILE *f;
-
- s = strchr (optarg, '=');
+ add_sections = init_section_add (optarg, add_sections,
+ "--add-section");
+ section_add_load_file (add_sections);
+ break;
- if (s == NULL)
- fatal (_("bad format for %s"), "--add-section");
+ case OPTION_UPDATE_SECTION:
+ update_sections = init_section_add (optarg, update_sections,
+ "--update-section");
+ section_add_load_file (update_sections);
+ break;
- pa = (struct section_add *) xmalloc (sizeof (struct section_add));
- pa->name = xstrndup (optarg, s - optarg);
- pa->filename = s + 1;
+ case OPTION_DUMP_SECTION:
+ dump_sections = init_section_add (optarg, dump_sections,
+ "--dump-section");
+ break;
- /* 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. */
+ case OPTION_ADD_SYMBOL:
+ {
+ char *s, *t;
+ struct addsym_node *newsym = xmalloc (sizeof *newsym);
- f = fopen (pa->filename, FOPEN_RB);
- if (f == NULL)
- fatal (_("cannot open: %s: %s"),
- pa->filename, strerror (errno));
+ newsym->next = NULL;
+ s = strchr (optarg, '=');
+ if (s == NULL)
+ fatal (_("bad format for %s"), "--add-symbol");
+ t = strchr (s + 1, ':');
- off = 0;
- alloc = 4096;
- pa->contents = (bfd_byte *) xmalloc (alloc);
- while (!feof (f))
+ newsym->symdef = xstrndup (optarg, s - optarg);
+ if (t)
{
- 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;
+ newsym->section = xstrndup (s + 1, t - (s + 1));
+ newsym->symval = strtol (t + 1, NULL, 0);
+ }
+ else
+ {
+ newsym->section = NULL;
+ newsym->symval = strtol (s + 1, NULL, 0);
+ t = s;
}
- pa->size = off;
-
- fclose (f);
+ t = strchr (t + 1, ',');
+ newsym->othersym = NULL;
+ if (t)
+ newsym->flags = parse_symflags (t+1, &newsym->othersym);
+ else
+ newsym->flags = BSF_GLOBAL;
- pa->next = add_sections;
- add_sections = pa;
+ /* Keep 'othersym' symbols at the front of the list. */
+ if (newsym->othersym)
+ {
+ newsym->next = add_sym_list;
+ if (!add_sym_list)
+ add_sym_tail = &newsym->next;
+ add_sym_list = newsym;
+ }
+ else
+ {
+ *add_sym_tail = newsym;
+ add_sym_tail = &newsym->next;
+ }
+ add_symbols++;
}
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 = (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;
- /* Drop through. */
+ p->vma_val = val;
+ /* Fall 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;
}
}
break;
case OPTION_COMPRESS_DEBUG_SECTIONS:
- do_debug_sections = compress;
+ if (optarg)
+ {
+ if (strcasecmp (optarg, "none") == 0)
+ do_debug_sections = decompress;
+ else if (strcasecmp (optarg, "zlib") == 0)
+ do_debug_sections = compress_zlib;
+ else if (strcasecmp (optarg, "zlib-gnu") == 0)
+ do_debug_sections = compress_gnu_zlib;
+ else if (strcasecmp (optarg, "zlib-gabi") == 0)
+ do_debug_sections = compress_gabi_zlib;
+ else
+ fatal (_("unrecognized --compress-debug-sections type `%s'"),
+ optarg);
+ }
+ else
+ do_debug_sections = compress;
break;
case OPTION_DEBUGGING:
do_debug_sections = decompress;
break;
+ case OPTION_ELF_STT_COMMON:
+ if (strcasecmp (optarg, "yes") == 0)
+ do_elf_stt_common = elf_stt_common;
+ else if (strcasecmp (optarg, "no") == 0)
+ do_elf_stt_common = no_elf_stt_common;
+ else
+ fatal (_("unrecognized --elf-stt-common= option `%s'"),
+ optarg);
+ break;
+
case OPTION_GAP_FILL:
{
bfd_vma gap_fill_vma;
case OPTION_REDEFINE_SYM:
{
- /* Push this redefinition onto redefine_symbol_list. */
+ /* Insert this redefinition onto redefine_specific_htab. */
int len;
const char *s;
target = (char *) xmalloc (len + 1);
strcpy (target, nextarg);
- redefine_list_append ("--redefine-sym", source, target);
+ add_redefine_and_check ("--redefine-sym", source, target);
free (source);
free (target);
case OPTION_SET_SECTION_FLAGS:
{
+ struct section_list *p;
const char *s;
int len;
char *name;
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;
break;
case OPTION_SREC_LEN:
- Chunk = parse_vma (optarg, "--srec-len");
+ _bfd_srec_len = parse_vma (optarg, "--srec-len");
break;
case OPTION_SREC_FORCES3:
- S3Forced = TRUE;
+ _bfd_srec_forceS3 = TRUE;
break;
case OPTION_STRIP_SYMBOLS:
- add_specific_symbols (optarg, strip_specific_htab);
+ add_specific_symbols (optarg, strip_specific_htab,
+ &strip_specific_buffer);
break;
case OPTION_STRIP_UNNEEDED_SYMBOLS:
- add_specific_symbols (optarg, strip_unneeded_htab);
+ add_specific_symbols (optarg, strip_unneeded_htab,
+ &strip_unneeded_buffer);
break;
case OPTION_KEEP_SYMBOLS:
- add_specific_symbols (optarg, keep_specific_htab);
+ add_specific_symbols (optarg, keep_specific_htab,
+ &keep_specific_buffer);
break;
case OPTION_LOCALIZE_HIDDEN:
break;
case OPTION_LOCALIZE_SYMBOLS:
- add_specific_symbols (optarg, localize_specific_htab);
+ add_specific_symbols (optarg, localize_specific_htab,
+ &localize_specific_buffer);
break;
case OPTION_LONG_SECTION_NAMES:
break;
case OPTION_GLOBALIZE_SYMBOLS:
- add_specific_symbols (optarg, globalize_specific_htab);
+ use_globalize = TRUE;
+ add_specific_symbols (optarg, globalize_specific_htab,
+ &globalize_specific_buffer);
break;
case OPTION_KEEPGLOBAL_SYMBOLS:
- add_specific_symbols (optarg, keepglobal_specific_htab);
+ use_keep_global = TRUE;
+ add_specific_symbols (optarg, keepglobal_specific_htab,
+ &keepglobal_specific_buffer);
break;
case OPTION_WEAKEN_SYMBOLS:
- add_specific_symbols (optarg, weaken_specific_htab);
+ add_specific_symbols (optarg, weaken_specific_htab,
+ &weaken_specific_buffer);
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;
case OPTION_REVERSE_BYTES:
- {
- int prev = reverse_bytes;
+ {
+ int prev = reverse_bytes;
- reverse_bytes = atoi (optarg);
- if ((reverse_bytes <= 0) || ((reverse_bytes % 2) != 0))
- fatal (_("number of bytes to reverse must be positive and even"));
+ reverse_bytes = atoi (optarg);
+ if ((reverse_bytes <= 0) || ((reverse_bytes % 2) != 0))
+ fatal (_("number of bytes to reverse must be positive and even"));
- if (prev && prev != reverse_bytes)
- non_fatal (_("Warning: ignoring previous --reverse-bytes value of %d"),
- prev);
- break;
- }
+ if (prev && prev != reverse_bytes)
+ non_fatal (_("Warning: ignoring previous --reverse-bytes value of %d"),
+ prev);
+ 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);
- }
- }
+ {
+ 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);
- }
- }
+ {
+ 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 (use_globalize && use_keep_global)
+ fatal(_("--globalize-symbol(s) is incompatible with -G/--keep-global-symbol(s)"));
+
if (formats_info)
{
display_info ();
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;
else
unlink_if_ordinary (tmpname);
+ if (tmpname != output_filename)
+ free (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);
}
}
}
}
+ if (strip_specific_buffer)
+ free (strip_specific_buffer);
+
+ if (strip_unneeded_buffer)
+ free (strip_unneeded_buffer);
+
+ if (keep_specific_buffer)
+ free (keep_specific_buffer);
+
+ if (localize_specific_buffer)
+ free (globalize_specific_buffer);
+
+ if (globalize_specific_buffer)
+ free (globalize_specific_buffer);
+
+ if (keepglobal_specific_buffer)
+ free (keepglobal_specific_buffer);
+
+ if (weaken_specific_buffer)
+ free (weaken_specific_buffer);
+
return 0;
}
strip_symbols = STRIP_UNDEF;
discard_locals = LOCALS_UNDEF;
- bfd_init ();
+ if (bfd_init () != BFD_INIT_MAGIC)
+ fatal (_("fatal error: libbfd ABI mismatch"));
set_default_bfd_target ();
if (is_strip < 0)
create_symbol_htabs ();
+ if (argv != NULL)
+ bfd_set_error_program_name (argv[0]);
+
if (is_strip)
strip_main (argc, argv);
else