X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Fobjcopy.c;h=873908c688d3d6b450dfe6f6e4faf147b3d45848;hb=5063a42103f83b921b0b6899acdd5d4d920fdc36;hp=deff1697e9b221de9009a21727dec2770d0a3218;hpb=237dcb538fb06d94108754e4812e49b5b25d4926;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objcopy.c b/binutils/objcopy.c index deff1697e9..873908c688 100644 --- a/binutils/objcopy.c +++ b/binutils/objcopy.c @@ -1,7 +1,5 @@ /* 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 - Free Software Foundation, Inc. + Copyright (C) 1991-2014 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -30,8 +28,25 @@ #include "filenames.h" #include "fnmatch.h" #include "elf-bfd.h" -#include #include "libbfd.h" +#include "coff/internal.h" +#include "libcoff.h" + +/* FIXME: See bfd/peXXigen.c for why we include an architecture specific + header in generic PE code. */ +#include "coff/i386.h" +#include "coff/pe.h" + +static bfd_vma pe_file_alignment = (bfd_vma) -1; +static bfd_vma pe_heap_commit = (bfd_vma) -1; +static bfd_vma pe_heap_reserve = (bfd_vma) -1; +static bfd_vma pe_image_base = (bfd_vma) -1; +static bfd_vma pe_section_alignment = (bfd_vma) -1; +static bfd_vma pe_stack_commit = (bfd_vma) -1; +static bfd_vma pe_stack_reserve = (bfd_vma) -1; +static short pe_subsystem = -1; +static short pe_major_subsystem_version = -1; +static short pe_minor_subsystem_version = -1; struct is_specified_symbol_predicate_data { @@ -59,20 +74,17 @@ section_rename; /* List of sections to be renamed. */ static section_rename *section_rename_list; -#define RETURN_NONFATAL(bfd) \ - do { \ - status = 1; bfd_nonfatal_message (NULL, bfd, NULL, NULL); return; \ - } while (0) - static asymbol **isympp = NULL; /* Input symbols. */ static asymbol **osympp = NULL; /* Output symbols that survive stripping. */ -/* If `copy_byte' >= 0, copy only that byte of every `interleave' bytes. */ +/* If `copy_byte' >= 0, copy 'copy_width' byte(s) of every `interleave' bytes. */ static int copy_byte = -1; -static int interleave = 4; +static int interleave = 0; /* Initialised to 4 in copy_main(). */ +static int copy_width = 1; static bfd_boolean verbose; /* Print file and target names. */ static bfd_boolean preserve_dates; /* Preserve input file timestamp. */ +static int deterministic = -1; /* Enable deterministic archives. */ static int status = 0; /* Exit status. */ enum strip_action @@ -82,11 +94,13 @@ enum strip_action STRIP_DEBUG, /* Strip all debugger symbols. */ STRIP_UNNEEDED, /* Strip unnecessary symbols. */ STRIP_NONDEBUG, /* Strip everything but debug info. */ + STRIP_DWO, /* Strip all DWO info. */ + STRIP_NONDWO, /* Strip everything but DWO info. */ STRIP_ALL /* Strip all symbols. */ }; /* Which symbols to remove. */ -static enum strip_action strip_symbols; +static enum strip_action strip_symbols = STRIP_UNDEF; enum locals_action { @@ -98,27 +112,26 @@ enum locals_action /* Which local symbols to remove. Overrides STRIP_ALL. */ static enum locals_action discard_locals; -/* What kind of change to perform. */ -enum change_action -{ - CHANGE_IGNORE, - CHANGE_MODIFY, - CHANGE_SET -}; - /* Structure used to hold lists of sections and actions to take. */ struct section_list { struct section_list * next; /* Next section to change. */ - const char * name; /* Section name. */ + const char * pattern; /* Section name pattern. */ bfd_boolean used; /* Whether this entry was used. */ - bfd_boolean remove; /* Whether to remove this section. */ - bfd_boolean copy; /* Whether to copy this section. */ - enum change_action change_vma;/* Whether to change or set VMA. */ + + unsigned int context; /* What to do with matching sections. */ + /* Flag bits used in the context field. + COPY and REMOVE are mutually exlusive. SET and ALTER are mutually exclusive. */ +#define SECTION_CONTEXT_REMOVE (1 << 0) /* Remove this section. */ +#define SECTION_CONTEXT_COPY (1 << 1) /* Copy this section, delete all non-copied section. */ +#define SECTION_CONTEXT_SET_VMA (1 << 2) /* Set the sections' VMA address. */ +#define SECTION_CONTEXT_ALTER_VMA (1 << 3) /* Increment or decrement the section's VMA address. */ +#define SECTION_CONTEXT_SET_LMA (1 << 4) /* Set the sections' LMA address. */ +#define SECTION_CONTEXT_ALTER_LMA (1 << 5) /* Increment or decrement the section's LMA address. */ +#define SECTION_CONTEXT_SET_FLAGS (1 << 6) /* Set the section's flags. */ + bfd_vma vma_val; /* Amount to change by or set to. */ - enum change_action change_lma;/* Whether to change or set LMA. */ bfd_vma lma_val; /* Amount to change by or set to. */ - bfd_boolean set_flags; /* Whether to set the section flags. */ flagword flags; /* What to set the section flags to. */ }; @@ -173,6 +186,9 @@ struct section_add /* List of sections to add to the output BFD. */ static struct section_add *add_sections; +/* List of sections to dump from the output BFD. */ +static struct section_add *dump_sections; + /* If non-NULL the argument to --add-gnu-debuglink. This should be the filename to store in the .gnu_debuglink section. */ static const char * gnu_debuglink_filename = NULL; @@ -180,6 +196,14 @@ static const char * gnu_debuglink_filename = NULL; /* Whether to convert debugging information. */ static bfd_boolean convert_debugging = FALSE; +/* Whether to compress/decompress DWARF debug sections. */ +static enum +{ + nothing, + compress, + decompress +} do_debug_sections = nothing; + /* Whether to change the leading character in symbol names. */ static bfd_boolean change_leading_char = FALSE; @@ -221,11 +245,24 @@ static bfd_boolean extract_symbol = FALSE; of bytes within each output section. */ static int reverse_bytes = 0; +/* For Coff objects, we may want to allow or disallow long section names, + or preserve them where found in the inputs. Debug info relies on them. */ +enum long_section_name_handling + { + DISABLE, + ENABLE, + KEEP + }; + +/* The default long section handling mode is to preserve them. + This is also the only behaviour for 'strip'. */ +static enum long_section_name_handling long_section_names = KEEP; /* 150 isn't special; it's just an arbitrary non-ASCII char value. */ enum command_line_switch { OPTION_ADD_SECTION=150, + OPTION_DUMP_SECTION, OPTION_CHANGE_ADDRESSES, OPTION_CHANGE_LEADING_CHAR, OPTION_CHANGE_START, @@ -233,7 +270,9 @@ enum command_line_switch 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, @@ -252,6 +291,7 @@ enum command_line_switch OPTION_KEEP_SYMBOLS, OPTION_LOCALIZE_HIDDEN, OPTION_LOCALIZE_SYMBOLS, + OPTION_LONG_SECTION_NAMES, OPTION_GLOBALIZE_SYMBOL, OPTION_GLOBALIZE_SYMBOLS, OPTION_KEEPGLOBAL_SYMBOLS, @@ -270,15 +310,26 @@ enum command_line_switch OPTION_PURE, OPTION_IMPURE, OPTION_EXTRACT_SYMBOL, - OPTION_REVERSE_BYTES + OPTION_REVERSE_BYTES, + OPTION_FILE_ALIGNMENT, + OPTION_HEAP, + OPTION_IMAGE_BASE, + OPTION_SECTION_ALIGNMENT, + OPTION_STACK, + OPTION_INTERLEAVE_WIDTH, + OPTION_SUBSYSTEM, + OPTION_EXTRACT_DWO, + OPTION_STRIP_DWO }; /* Options to handle if running as "strip". */ static struct option strip_options[] = { + {"disable-deterministic-archives", no_argument, 0, 'U'}, {"discard-all", no_argument, 0, 'x'}, {"discard-locals", no_argument, 0, 'X'}, + {"enable-deterministic-archives", no_argument, 0, 'D'}, {"format", required_argument, 0, 'F'}, /* Obsolete */ {"help", no_argument, 0, 'h'}, {"info", no_argument, 0, OPTION_FORMATS_INFO}, @@ -294,6 +345,7 @@ static struct option strip_options[] = {"remove-section", required_argument, 0, 'R'}, {"strip-all", no_argument, 0, 's'}, {"strip-debug", no_argument, 0, 'S'}, + {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO}, {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, {"strip-symbol", required_argument, 0, 'N'}, {"target", required_argument, 0, 'F'}, @@ -323,9 +375,15 @@ static struct option copy_options[] = {"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA}, {"change-start", required_argument, 0, OPTION_CHANGE_START}, {"change-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS}, + {"compress-debug-sections", no_argument, 0, OPTION_COMPRESS_DEBUG_SECTIONS}, {"debugging", no_argument, 0, OPTION_DEBUGGING}, + {"decompress-debug-sections", no_argument, 0, OPTION_DECOMPRESS_DEBUG_SECTIONS}, + {"disable-deterministic-archives", no_argument, 0, 'U'}, {"discard-all", no_argument, 0, 'x'}, {"discard-locals", no_argument, 0, 'X'}, + {"dump-section", required_argument, 0, OPTION_DUMP_SECTION}, + {"enable-deterministic-archives", no_argument, 0, 'D'}, + {"extract-dwo", no_argument, 0, OPTION_EXTRACT_DWO}, {"extract-symbol", no_argument, 0, OPTION_EXTRACT_SYMBOL}, {"format", required_argument, 0, 'F'}, /* Obsolete */ {"gap-fill", required_argument, 0, OPTION_GAP_FILL}, @@ -336,7 +394,8 @@ static struct option copy_options[] = {"info", no_argument, 0, OPTION_FORMATS_INFO}, {"input-format", required_argument, 0, 'I'}, /* Obsolete */ {"input-target", required_argument, 0, 'I'}, - {"interleave", required_argument, 0, 'i'}, + {"interleave", optional_argument, 0, 'i'}, + {"interleave-width", required_argument, 0, OPTION_INTERLEAVE_WIDTH}, {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS}, {"keep-global-symbol", required_argument, 0, 'G'}, {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS}, @@ -345,6 +404,7 @@ static struct option copy_options[] = {"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN}, {"localize-symbol", required_argument, 0, 'L'}, {"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS}, + {"long-section-names", required_argument, 0, OPTION_LONG_SECTION_NAMES}, {"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS}, {"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS}, {"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG}, @@ -370,6 +430,7 @@ static struct option copy_options[] = {"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3}, {"strip-all", no_argument, 0, 'S'}, {"strip-debug", no_argument, 0, 'g'}, + {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO}, {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, {"strip-unneeded-symbol", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOL}, {"strip-unneeded-symbols", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOLS}, @@ -383,6 +444,12 @@ static struct option copy_options[] = {"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS}, {"wildcard", no_argument, 0, 'w'}, {"writable-text", no_argument, 0, OPTION_WRITABLE_TEXT}, + {"file-alignment", required_argument, 0, OPTION_FILE_ALIGNMENT}, + {"heap", required_argument, 0, OPTION_HEAP}, + {"image-base", required_argument, 0 , OPTION_IMAGE_BASE}, + {"section-alignment", required_argument, 0, OPTION_SECTION_ALIGNMENT}, + {"stack", required_argument, 0, OPTION_STACK}, + {"subsystem", required_argument, 0, OPTION_SUBSYSTEM}, {0, no_argument, 0, 0} }; @@ -403,14 +470,10 @@ extern unsigned int Chunk; on by the --srec-forceS3 command line switch. */ extern bfd_boolean S3Forced; -/* Defined in bfd/binary.c. Used to set architecture and machine of input - binary files. */ -extern enum bfd_architecture bfd_external_binary_architecture; -extern unsigned long bfd_external_machine; - /* Forward declarations. */ static void setup_section (bfd *, asection *, void *); static void setup_bfd_headers (bfd *, bfd *); +static void copy_relocations_in_section (bfd *, asection *, void *); static void copy_section (bfd *, asection *, void *); static void get_sections (bfd *, asection *, void *); static int compare_section_lma (const void *, const void *); @@ -427,21 +490,36 @@ copy_usage (FILE *stream, int exit_status) fprintf (stream, _("\ -I --input-target Assume input file is in format \n\ -O --output-target Create an output file in format \n\ - -B --binary-architecture Set arch of output file, when input is binary\n\ + -B --binary-architecture Set output arch, when input is arch-less\n\ -F --target Set both input and output format to \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 Only copy section into the output\n\ --add-gnu-debuglink= Add section .gnu_debuglink linking to \n\ -R --remove-section Remove section from the output\n\ -S --strip-all Remove all symbol and relocation information\n\ -g --strip-debug Remove all debugging symbols & sections\n\ + --strip-dwo Remove all DWO sections\n\ --strip-unneeded Remove all symbols not needed by relocations\n\ -N --strip-symbol Do not copy symbol \n\ --strip-unneeded-symbol \n\ Do not copy symbol 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 Do not strip symbol \n\ --keep-file-symbols Do not strip file symbol(s)\n\ @@ -454,7 +532,8 @@ copy_usage (FILE *stream, int exit_status) -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 Only copy one out of every bytes\n\ + -i --interleave [] Only copy N out of every bytes\n\ + --interleave-width Set N for --interleave\n\ -b --byte Select byte in every interleaved block\n\ --gap-fill Fill gaps between sections with \n\ --pad-to Pad the last section up to address \n\ @@ -474,7 +553,10 @@ copy_usage (FILE *stream, int exit_status) --set-section-flags =\n\ Set section 's properties to \n\ --add-section = Add section found in to output\n\ + --dump-section = Dump the contents of section into \n\ --rename-section =[,] Rename section to \n\ + --long-section-names {enable|disable|keep}\n\ + Handle long section names in Coff objects.\n\ --change-leading-char Force output format's leading character style\n\ --remove-leading-char Remove leading character from global symbols\n\ --reverse-bytes= Reverse bytes at a time, in output sections with content\n\ @@ -502,6 +584,17 @@ copy_usage (FILE *stream, int exit_status) --prefix-alloc-sections \n\ Add to start of every allocatable\n\ section name\n\ + --file-alignment Set PE file alignment to \n\ + --heap [,] Set PE reserve/commit heap to /\n\ + \n\ + --image-base
Set PE image base to
\n\ + --section-alignment Set PE section alignment to \n\ + --stack [,] Set PE reserve/commit stack to /\n\ + \n\ + --subsystem [:]\n\ + Set PE subsystem to [& ]\n\ + --compress-debug-sections Compress DWARF debug sections using zlib\n\ + --decompress-debug-sections Decompress DWARF debug sections using zlib\n\ -v --verbose List all object files modified\n\ @ Read options from \n\ -V --version Display this program's version number\n\ @@ -525,9 +618,24 @@ strip_usage (FILE *stream, int exit_status) -O --output-target= Create an output file in format \n\ -F --target= Set both input and output format to \n\ -p --preserve-dates Copy modified/access timestamps to the output\n\ +")); + if (DEFAULT_AR_DETERMINISTIC) + fprintf (stream, _("\ + -D --enable-deterministic-archives\n\ + Produce deterministic output when stripping archives (default)\n\ + -U --disable-deterministic-archives\n\ + Disable -D behavior\n")); + else + fprintf (stream, _("\ + -D --enable-deterministic-archives\n\ + Produce deterministic output when stripping archives\n\ + -U --disable-deterministic-archives\n\ + Disable -D behavior (default)\n")); + fprintf (stream, _("\ -R --remove-section= Remove section from the output\n\ -s --strip-all Remove all symbol and relocation information\n\ -g -S -d --strip-debug Remove all debugging symbols & sections\n\ + --strip-dwo Remove all DWO sections\n\ --strip-unneeded Remove all symbols not needed by relocations\n\ --only-keep-debug Strip everything but the debug information\n\ -N --strip-symbol= Do not copy symbol \n\ @@ -585,17 +693,19 @@ parse_flags (const char *s) PARSE_FLAG ("rom", SEC_ROM); PARSE_FLAG ("share", SEC_COFF_SHARED); PARSE_FLAG ("contents", SEC_HAS_CONTENTS); + PARSE_FLAG ("merge", SEC_MERGE); + PARSE_FLAG ("strings", SEC_STRINGS); #undef PARSE_FLAG else { char *copy; - copy = xmalloc (len + 1); + copy = (char *) xmalloc (len + 1); strncpy (copy, s, len); copy[len] = '\0'; non_fatal (_("unrecognized section flag `%s'"), copy); fatal (_("supported flags: %s"), - "alloc, load, noload, readonly, debug, code, data, rom, share, contents"); + "alloc, load, noload, readonly, debug, code, data, rom, share, contents, merge, strings"); } s = snext; @@ -605,32 +715,93 @@ parse_flags (const char *s) return ret; } -/* Find and optionally add an entry in the change_sections list. */ +/* Find and optionally add an entry in the change_sections list. + + We need to be careful in how we match section names because of the support + for wildcard characters. For example suppose that the user has invoked + objcopy like this: + + --set-section-flags .debug_*=debug + --set-section-flags .debug_str=readonly,debug + --change-section-address .debug_*ranges=0x1000 + + With the idea that all debug sections will receive the DEBUG flag, the + .debug_str section will also receive the READONLY flag and the + .debug_ranges and .debug_aranges sections will have their address set to + 0x1000. (This may not make much sense, but it is just an example). + + When adding the section name patterns to the section list we need to make + sure that previous entries do not match with the new entry, unless the + match is exact. (In which case we assume that the user is overriding + the previous entry with the new context). + + When matching real section names to the section list we make use of the + wildcard characters, but we must do so in context. Eg if we are setting + section addresses then we match for .debug_ranges but not for .debug_info. + + Finally, if ADD is false and we do find a match, we mark the section list + entry as used. */ static struct section_list * -find_section_list (const char *name, bfd_boolean add) +find_section_list (const char *name, bfd_boolean add, unsigned int context) { struct section_list *p; + /* assert ((context & ((1 << 7) - 1)) != 0); */ + for (p = change_sections; p != NULL; p = p->next) - if (strcmp (p->name, name) == 0) - return p; + { + if (add) + { + if (strcmp (p->pattern, name) == 0) + { + /* Check for context conflicts. */ + if (((p->context & SECTION_CONTEXT_REMOVE) + && (context & SECTION_CONTEXT_COPY)) + || ((context & SECTION_CONTEXT_REMOVE) + && (p->context & SECTION_CONTEXT_COPY))) + fatal (_("error: %s both copied and removed"), name); + + if (((p->context & SECTION_CONTEXT_SET_VMA) + && (context & SECTION_CONTEXT_ALTER_VMA)) + || ((context & SECTION_CONTEXT_SET_VMA) + && (context & SECTION_CONTEXT_ALTER_VMA))) + fatal (_("error: %s both sets and alters VMA"), name); + + if (((p->context & SECTION_CONTEXT_SET_LMA) + && (context & SECTION_CONTEXT_ALTER_LMA)) + || ((context & SECTION_CONTEXT_SET_LMA) + && (context & SECTION_CONTEXT_ALTER_LMA))) + fatal (_("error: %s both sets and alters LMA"), name); + + /* Extend the context. */ + p->context |= context; + return p; + } + } + /* If we are not adding a new name/pattern then + only check for a match if the context applies. */ + else if ((p->context & context) + /* We could check for the presence of wildchar characters + first and choose between calling strcmp and fnmatch, + but is that really worth it ? */ + && fnmatch (p->pattern, name, 0) == 0) + { + p->used = TRUE; + return p; + } + } if (! add) return NULL; - p = xmalloc (sizeof (struct section_list)); - p->name = name; + p = (struct section_list *) xmalloc (sizeof (struct section_list)); + p->pattern = name; p->used = FALSE; - p->remove = FALSE; - p->copy = FALSE; - p->change_vma = CHANGE_IGNORE; - p->change_lma = CHANGE_IGNORE; + p->context = context; p->vma_val = 0; p->lma_val = 0; - p->set_flags = FALSE; p->flags = 0; - p->next = change_sections; change_sections = p; @@ -642,7 +813,7 @@ find_section_list (const char *name, bfd_boolean add) static int eq_string (const void *s1, const void *s2) { - return strcmp (s1, s2) == 0; + return strcmp ((const char *) s1, (const char *) s2) == 0; } static htab_t @@ -692,7 +863,7 @@ add_specific_symbols (const char *filename, htab_t htab) return; } - buffer = xmalloc (size + 2); + buffer = (char *) xmalloc (size + 2); f = fopen (filename, FOPEN_RT); if (f == NULL) fatal (_("cannot open '%s': %s"), filename, strerror (errno)); @@ -793,8 +964,9 @@ add_specific_symbols (const char *filename, htab_t htab) static int is_specified_symbol_predicate (void **slot, void *data) { - struct is_specified_symbol_predicate_data *d = data; - const char *slot_name = *slot; + struct is_specified_symbol_predicate_data *d = + (struct is_specified_symbol_predicate_data *) data; + const char *slot_name = (char *) *slot; if (*slot_name != '!') { @@ -861,20 +1033,39 @@ group_signature (asection *group) return NULL; } -/* See if a section is being removed. */ +/* Return TRUE if the section is a DWO section. */ static bfd_boolean -is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) +is_dwo_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) +{ + const char *name = bfd_get_section_name (abfd, sec); + int len = strlen (name); + + return strncmp (name + len - 4, ".dwo", 4) == 0; +} + +/* See if a non-group section is being removed. */ + +static bfd_boolean +is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) { if (sections_removed || sections_copied) { struct section_list *p; + struct section_list *q; + + p = find_section_list (bfd_get_section_name (abfd, sec), FALSE, + SECTION_CONTEXT_REMOVE); + q = find_section_list (bfd_get_section_name (abfd, sec), FALSE, + SECTION_CONTEXT_COPY); - p = find_section_list (bfd_get_section_name (abfd, sec), FALSE); + if (p && q) + fatal (_("error: section %s matches both remove and copy options"), + bfd_get_section_name (abfd, sec)); - if (sections_removed && p != NULL && p->remove) + if (p != NULL) return TRUE; - if (sections_copied && (p == NULL || ! p->copy)) + if (sections_copied && q == NULL) return TRUE; } @@ -885,22 +1076,40 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) || strip_symbols == STRIP_ALL || discard_locals == LOCALS_ALL || convert_debugging) - return TRUE; + { + /* By default we don't want to strip .reloc section. + This section has for pe-coff special meaning. See + pe-dll.c file in ld, and peXXigen.c in bfd for details. */ + if (strcmp (bfd_get_section_name (abfd, sec), ".reloc") != 0) + return TRUE; + } + + if (strip_symbols == STRIP_DWO) + return is_dwo_section (abfd, sec); if (strip_symbols == STRIP_NONDEBUG) return FALSE; } + if (strip_symbols == STRIP_NONDWO) + return !is_dwo_section (abfd, sec); + + return FALSE; +} + +/* See if a section is being removed. */ + +static bfd_boolean +is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) +{ + if (is_strip_section_1 (abfd, sec)) + return TRUE; + if ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0) { asymbol *gsym; const char *gname; - - /* PR binutils/3166 - Group sections look like debugging sections but they are not. - (They have a non-zero size but they are not ALLOCated). */ - if (strip_symbols == STRIP_NONDEBUG) - return TRUE; + asection *elt, *first; /* PR binutils/3181 If we are going to strip the group signature symbol, then @@ -914,6 +1123,19 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) && !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; @@ -1006,8 +1228,8 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, { char *n, *ptr; - ptr = n = xmalloc (1 + strlen (prefix_symbols_string) - + strlen (name) + 1); + ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string) + + strlen (name) + 1); if (add_leading_char) *ptr++ = bfd_get_symbol_leading_char (obfd); @@ -1033,7 +1255,8 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, used_in_reloc = TRUE; } else if (relocatable /* Relocatable file. */ - && (flags & (BSF_GLOBAL | BSF_WEAK)) != 0) + && ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0 + || bfd_is_com_section (bfd_get_section (sym)))) keep = TRUE; else if (bfd_decode_symclass (sym) == 'I') /* Global symbols in $idata sections need to be retained @@ -1157,7 +1380,7 @@ redefine_list_append (const char *cause, const char *source, const char *target) cause, target); } - new_node = xmalloc (sizeof (struct redefine_node)); + new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node)); new_node->source = strdup (source); new_node->target = strdup (target); @@ -1185,7 +1408,7 @@ add_redefine_syms_file (const char *filename) filename, strerror (errno)); bufsize = 100; - buf = xmalloc (bufsize); + buf = (char *) xmalloc (bufsize + 1 /* For the terminating NUL. */); lineno = 1; c = getc (file); @@ -1202,7 +1425,7 @@ add_redefine_syms_file (const char *filename) if (len >= bufsize) { bufsize *= 2; - buf = xrealloc (buf, bufsize); + buf = (char *) xrealloc (buf, bufsize + 1); } c = getc (file); } @@ -1228,7 +1451,7 @@ add_redefine_syms_file (const char *filename) if (len >= bufsize) { bufsize *= 2; - buf = xrealloc (buf, bufsize); + buf = (char *) xrealloc (buf, bufsize + 1); } c = getc (file); } @@ -1291,7 +1514,7 @@ copy_unknown_object (bfd *ibfd, bfd *obfd) if (bfd_stat_arch_elt (ibfd, &buf) != 0) { - bfd_nonfatal_message (bfd_get_archive_filename (ibfd), NULL, NULL, NULL); + bfd_nonfatal_message (NULL, ibfd, NULL, NULL); return FALSE; } @@ -1313,7 +1536,7 @@ copy_unknown_object (bfd *ibfd, bfd *obfd) printf (_("copy from `%s' [unknown] to `%s' [unknown]\n"), bfd_get_archive_filename (ibfd), bfd_get_filename (obfd)); - cbuf = xmalloc (BUFSIZE); + cbuf = (char *) xmalloc (BUFSIZE); ncopied = 0; while (ncopied < size) { @@ -1324,8 +1547,7 @@ copy_unknown_object (bfd *ibfd, bfd *obfd) if (bfd_bread (cbuf, (bfd_size_type) tocopy, ibfd) != (bfd_size_type) tocopy) { - bfd_nonfatal_message (bfd_get_archive_filename (ibfd), - NULL, NULL, NULL); + bfd_nonfatal_message (NULL, ibfd, NULL, NULL); free (cbuf); return FALSE; } @@ -1341,7 +1563,9 @@ copy_unknown_object (bfd *ibfd, bfd *obfd) ncopied += tocopy; } - chmod (bfd_get_filename (obfd), buf.st_mode); + /* We should at least to be able to read it back when copying an + unknown object in an archive. */ + chmod (bfd_get_filename (obfd), buf.st_mode | S_IRUSR); free (cbuf); return TRUE; } @@ -1350,7 +1574,7 @@ copy_unknown_object (bfd *ibfd, bfd *obfd) Returns TRUE upon success, FALSE otherwise. */ static bfd_boolean -copy_object (bfd *ibfd, bfd *obfd) +copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) { bfd_vma start; long symcount; @@ -1374,6 +1598,13 @@ copy_object (bfd *ibfd, bfd *obfd) return FALSE; } + if (ibfd->sections == NULL) + { + non_fatal (_("error: the input file '%s' has no sections"), + 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), @@ -1401,11 +1632,13 @@ copy_object (bfd *ibfd, bfd *obfd) flags &= ~bfd_flags_to_clear; flags &= bfd_applicable_file_flags (obfd); + if (strip_symbols == STRIP_ALL) + flags &= ~HAS_RELOC; + if (!bfd_set_start_address (obfd, start) || !bfd_set_file_flags (obfd, flags)) { - bfd_nonfatal_message (bfd_get_archive_filename (ibfd), - NULL, NULL, NULL); + bfd_nonfatal_message (NULL, ibfd, NULL, NULL); return FALSE; } } @@ -1413,6 +1646,18 @@ copy_object (bfd *ibfd, bfd *obfd) /* Copy architecture of input file to output file. */ iarch = bfd_get_arch (ibfd); imach = bfd_get_mach (ibfd); + if (input_arch) + { + if (bfd_get_arch_info (ibfd) == NULL + || bfd_get_arch_info (ibfd)->arch == bfd_arch_unknown) + { + iarch = input_arch->arch; + imach = input_arch->mach; + } + else + non_fatal (_("Input file `%s' ignores binary architecture parameter."), + bfd_get_archive_filename (ibfd)); + } if (!bfd_set_arch_mach (obfd, iarch, imach) && (ibfd->target_defaulted || bfd_get_arch (ibfd) != bfd_get_arch (obfd))) @@ -1421,7 +1666,7 @@ copy_object (bfd *ibfd, bfd *obfd) non_fatal (_("Unable to recognise the format of the input file `%s'"), bfd_get_archive_filename (ibfd)); else - non_fatal (_("Warning: Output file cannot represent architecture `%s'"), + non_fatal (_("Output file cannot represent architecture `%s'"), bfd_printable_arch_mach (bfd_get_arch (ibfd), bfd_get_mach (ibfd))); return FALSE; @@ -1429,10 +1674,67 @@ copy_object (bfd *ibfd, bfd *obfd) if (!bfd_set_format (obfd, bfd_get_format (ibfd))) { - bfd_nonfatal_message (bfd_get_archive_filename (ibfd), NULL, NULL, NULL); + bfd_nonfatal_message (NULL, ibfd, NULL, NULL); return FALSE; } + if (bfd_get_flavour (obfd) == bfd_target_coff_flavour + && bfd_pei_p (obfd)) + { + /* Set up PE parameters. */ + pe_data_type *pe = pe_data (obfd); + + /* Copy PE parameters before changing them. */ + if (ibfd->xvec->flavour == bfd_target_coff_flavour + && bfd_pei_p (ibfd)) + pe->pe_opthdr = pe_data (ibfd)->pe_opthdr; + + if (pe_file_alignment != (bfd_vma) -1) + pe->pe_opthdr.FileAlignment = pe_file_alignment; + else + pe_file_alignment = PE_DEF_FILE_ALIGNMENT; + + if (pe_heap_commit != (bfd_vma) -1) + pe->pe_opthdr.SizeOfHeapCommit = pe_heap_commit; + + if (pe_heap_reserve != (bfd_vma) -1) + pe->pe_opthdr.SizeOfHeapCommit = pe_heap_reserve; + + if (pe_image_base != (bfd_vma) -1) + pe->pe_opthdr.ImageBase = pe_image_base; + + if (pe_section_alignment != (bfd_vma) -1) + pe->pe_opthdr.SectionAlignment = pe_section_alignment; + else + pe_section_alignment = PE_DEF_SECTION_ALIGNMENT; + + if (pe_stack_commit != (bfd_vma) -1) + pe->pe_opthdr.SizeOfStackCommit = pe_stack_commit; + + if (pe_stack_reserve != (bfd_vma) -1) + pe->pe_opthdr.SizeOfStackCommit = pe_stack_reserve; + + if (pe_subsystem != -1) + pe->pe_opthdr.Subsystem = pe_subsystem; + + if (pe_major_subsystem_version != -1) + pe->pe_opthdr.MajorSubsystemVersion = pe_major_subsystem_version; + + if (pe_minor_subsystem_version != -1) + pe->pe_opthdr.MinorSubsystemVersion = pe_minor_subsystem_version; + + if (pe_file_alignment > pe_section_alignment) + { + char file_alignment[20], section_alignment[20]; + + sprintf_vma (file_alignment, pe_file_alignment); + sprintf_vma (section_alignment, pe_section_alignment); + non_fatal (_("warning: file alignment (0x%s) > section alignment (0x%s)"), + + file_alignment, section_alignment); + } + } + if (isympp) free (isympp); @@ -1445,11 +1747,11 @@ copy_object (bfd *ibfd, bfd *obfd) symsize = bfd_get_symtab_upper_bound (ibfd); if (symsize < 0) { - bfd_nonfatal_message (bfd_get_archive_filename (ibfd), NULL, NULL, NULL); + bfd_nonfatal_message (NULL, ibfd, NULL, NULL); return FALSE; } - osympp = isympp = xmalloc (symsize); + osympp = isympp = (asymbol **) xmalloc (symsize); symcount = bfd_canonicalize_symtab (ibfd, isympp); if (symcount < 0) { @@ -1473,13 +1775,12 @@ copy_object (bfd *ibfd, bfd *obfd) { 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. */ @@ -1491,7 +1792,12 @@ copy_object (bfd *ibfd, bfd *obfd) } else { - padd->section = bfd_make_section_with_flags (obfd, padd->name, flags); + /* We use LINKER_CREATED here so that the backend hooks + will create any special section type information, + instead of presuming we know what we're doing merely + because we set the flags. */ + padd->section = bfd_make_section_with_flags + (obfd, padd->name, flags | SEC_LINKER_CREATED); if (padd->section == NULL) { bfd_nonfatal_message (NULL, obfd, NULL, @@ -1507,86 +1813,156 @@ copy_object (bfd *ibfd, bfd *obfd) 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; - - if (! bfd_set_section_alignment - (obfd, padd->section, - bfd_section_alignment (obfd, padd->section))) - { - bfd_nonfatal_message (NULL, obfd, padd->section, NULL); - return FALSE; - } + bfd_nonfatal_message (NULL, obfd, padd->section, NULL); + return FALSE; } } } } - if (gnu_debuglink_filename != NULL) + if (dump_sections != NULL) { - gnu_debuglink_section = bfd_create_gnu_debuglink_section - (obfd, gnu_debuglink_filename); - - if (gnu_debuglink_section == NULL) - { - bfd_nonfatal_message (NULL, obfd, NULL, - _("cannot create debug link section `%s'"), - gnu_debuglink_filename); - return FALSE; - } + struct section_add * pdump; - /* Special processing for PE format files. We - have no way to distinguish PE from COFF here. */ - if (bfd_get_flavour (obfd) == bfd_target_coff_flavour) + for (pdump = dump_sections; pdump != NULL; pdump = pdump->next) { - bfd_vma debuglink_vma; - asection * highest_section; asection * sec; - /* The PE spec requires that all sections be adjacent and sorted - in ascending order of VMA. It also specifies that debug - sections should be last. This is despite the fact that debug - sections are not loaded into memory and so in theory have no - use for a VMA. - - This means that the debuglink section must be given a non-zero - VMA which makes it contiguous with other debug sections. So - walk the current section list, find the section with the - highest VMA and start the debuglink section after that one. */ - for (sec = obfd->sections, highest_section = NULL; - sec != NULL; - sec = sec->next) - if (sec->vma > 0 - && (highest_section == NULL - || sec->vma > highest_section->vma)) - highest_section = sec; - - if (highest_section) - debuglink_vma = BFD_ALIGN (highest_section->vma - + highest_section->size, - /* FIXME: We ought to be using - COFF_PAGE_SIZE here or maybe - bfd_get_section_alignment() (if it - was set) but since this is for PE - and we know the required alignment - it is easier just to hard code it. */ - 0x1000); + sec = bfd_get_section_by_name (ibfd, pdump->name); + if (sec == NULL) + { + bfd_nonfatal_message (NULL, ibfd, NULL, + _("can't dump section '%s' - it does not exist"), + pdump->name); + continue; + } + + if ((bfd_get_section_flags (ibfd, sec) & SEC_HAS_CONTENTS) == 0) + { + bfd_nonfatal_message (NULL, ibfd, sec, + _("can't dump section - it has no contents")); + continue; + } + + bfd_size_type size = bfd_get_section_size (sec); + if (size == 0) + { + bfd_nonfatal_message (NULL, ibfd, sec, + _("can't dump section - it is empty")); + continue; + } + + FILE * f; + f = fopen (pdump->filename, FOPEN_WB); + if (f == NULL) + { + bfd_nonfatal_message (pdump->filename, NULL, NULL, + _("could not open section dump file")); + continue; + } + + bfd_byte * contents = xmalloc (size); + if (bfd_get_section_contents (ibfd, sec, contents, 0, size)) + { + if (fwrite (contents, 1, size, f) != size) + fatal (_("error writing section contents to %s (error: %s)"), + pdump->filename, + strerror (errno)); + } else - /* Umm, not sure what to do in this case. */ - debuglink_vma = 0x1000; + bfd_nonfatal_message (NULL, ibfd, sec, + _("could not retrieve section contents")); - bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma); + fclose (f); + free (contents); + } + } + + if (gnu_debuglink_filename != NULL) + { + /* PR 15125: Give a helpful warning message if + the debuglink section already exists, and + allow the rest of the copy to complete. */ + if (bfd_get_section_by_name (obfd, ".gnu_debuglink")) + { + non_fatal (_("%s: debuglink section already exists"), + bfd_get_filename (obfd)); + gnu_debuglink_filename = NULL; + } + else + { + gnu_debuglink_section = bfd_create_gnu_debuglink_section + (obfd, gnu_debuglink_filename); + + if (gnu_debuglink_section == NULL) + { + bfd_nonfatal_message (NULL, obfd, NULL, + _("cannot create debug link section `%s'"), + gnu_debuglink_filename); + return FALSE; + } + + /* Special processing for PE format files. We + have no way to distinguish PE from COFF here. */ + if (bfd_get_flavour (obfd) == bfd_target_coff_flavour) + { + bfd_vma debuglink_vma; + asection * highest_section; + asection * sec; + + /* The PE spec requires that all sections be adjacent and sorted + in ascending order of VMA. It also specifies that debug + sections should be last. This is despite the fact that debug + sections are not loaded into memory and so in theory have no + use for a VMA. + + This means that the debuglink section must be given a non-zero + VMA which makes it contiguous with other debug sections. So + walk the current section list, find the section with the + highest VMA and start the debuglink section after that one. */ + for (sec = obfd->sections, highest_section = NULL; + sec != NULL; + sec = sec->next) + if (sec->vma > 0 + && (highest_section == NULL + || sec->vma > highest_section->vma)) + highest_section = sec; + + if (highest_section) + debuglink_vma = BFD_ALIGN (highest_section->vma + + highest_section->size, + /* FIXME: We ought to be using + COFF_PAGE_SIZE here or maybe + bfd_get_section_alignment() (if it + was set) but since this is for PE + and we know the required alignment + it is easier just to hard code it. */ + 0x1000); + else + /* Umm, not sure what to do in this case. */ + debuglink_vma = 0x1000; + + bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma); + } } } @@ -1603,13 +1979,13 @@ copy_object (bfd *ibfd, bfd *obfd) We write out the gap contents below. */ c = bfd_count_sections (obfd); - osections = xmalloc (c * sizeof (asection *)); + osections = (asection **) xmalloc (c * sizeof (asection *)); set = osections; bfd_map_over_sections (obfd, get_sections, &set); qsort (osections, c, sizeof (asection *), compare_section_lma); - gaps = xmalloc (c * sizeof (bfd_size_type)); + gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type)); memset (gaps, 0, c * sizeof (bfd_size_type)); if (gap_fill_set) @@ -1681,6 +2057,8 @@ copy_object (bfd *ibfd, bfd *obfd) || 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 @@ -1710,7 +2088,7 @@ copy_object (bfd *ibfd, bfd *obfd) bfd_map_over_sections (ibfd, mark_symbols_used_in_relocations, isympp); - osympp = xmalloc ((symcount + 1) * sizeof (asymbol *)); + osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *)); symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount); } @@ -1725,6 +2103,9 @@ copy_object (bfd *ibfd, bfd *obfd) 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); @@ -1763,7 +2144,7 @@ copy_object (bfd *ibfd, bfd *obfd) /* Fill in the gaps. */ if (max_gap > 8192) max_gap = 8192; - buf = xmalloc (max_gap); + buf = (bfd_byte *) xmalloc (max_gap); memset (buf, gap_fill, max_gap); c = bfd_count_sections (obfd); @@ -1846,7 +2227,8 @@ copy_object (bfd *ibfd, bfd *obfd) static void copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, - bfd_boolean force_output_target) + bfd_boolean force_output_target, + const bfd_arch_info_type *input_arch) { struct name_list { @@ -1856,7 +2238,8 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, } *list, *l; bfd **ptr = &obfd->archive_head; bfd *this_element; - char * dir; + char *dir; + const char *filename; /* Make a temp directory to hold the contents. */ dir = make_tempdir (bfd_get_filename (obfd)); @@ -1864,15 +2247,25 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, fatal (_("cannot create tempdir for archive copying (error: %s)"), strerror (errno)); - obfd->has_armap = ibfd->has_armap; + if (strip_symbols == STRIP_ALL) + obfd->has_armap = FALSE; + else + obfd->has_armap = ibfd->has_armap; obfd->is_thin_archive = ibfd->is_thin_archive; + if (deterministic) + obfd->flags |= BFD_DETERMINISTIC_OUTPUT; + list = NULL; this_element = bfd_openr_next_archived_file (ibfd, NULL); if (!bfd_set_format (obfd, bfd_get_format (ibfd))) - RETURN_NONFATAL (obfd); + { + status = 1; + bfd_nonfatal_message (NULL, obfd, NULL, NULL); + return; + } while (!status && this_element != NULL) { @@ -1881,7 +2274,8 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, bfd *last_element; struct stat buf; int stat_status = 0; - bfd_boolean delete = TRUE; + bfd_boolean del = TRUE; + bfd_boolean ok_object; /* Create an output file for this member. */ output_name = concat (dir, "/", @@ -1895,7 +2289,7 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, fatal (_("cannot create tempdir for archive copying (error: %s)"), strerror (errno)); - l = xmalloc (sizeof (struct name_list)); + l = (struct name_list *) xmalloc (sizeof (struct name_list)); l->name = output_name; l->next = list; l->obfd = NULL; @@ -1913,61 +2307,58 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, bfd_get_filename (this_element)); } - l = xmalloc (sizeof (struct name_list)); + l = (struct name_list *) xmalloc (sizeof (struct name_list)); l->name = output_name; l->next = list; l->obfd = NULL; list = l; - if (bfd_check_format (this_element, bfd_object)) + 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; + return; + } - if (output_bfd == NULL) + if (ok_object) + { + del = !copy_object (this_element, output_bfd, input_arch); + + 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; - } - - delete = ! copy_object (this_element, output_bfd); - - if (! delete - || bfd_get_arch (this_element) != bfd_arch_unknown) - { - if (!bfd_close (output_bfd)) - { - bfd_nonfatal_message (NULL, output_bfd, NULL, NULL); - /* Error in new object file. Don't change archive. */ - status = 1; - } } - else - goto copy_unknown_element; } - else - { - bfd_nonfatal_message (bfd_get_archive_filename (this_element), - NULL, NULL, - _("Unable to recognise the format of file")); - output_bfd = bfd_openw (output_name, output_target); -copy_unknown_element: - delete = !copy_unknown_object (this_element, output_bfd); + if (!ok_object) + { + del = !copy_unknown_object (this_element, output_bfd); if (!bfd_close_all_done (output_bfd)) { - bfd_nonfatal_message (NULL, output_bfd, NULL, NULL); + bfd_nonfatal_message (output_name, NULL, NULL, NULL); /* Error in new object file. Don't change archive. */ status = 1; } } - if (delete) + if (del) { unlink (output_name); status = 1; @@ -1994,11 +2385,21 @@ copy_unknown_element: } *ptr = NULL; + filename = bfd_get_filename (obfd); if (!bfd_close (obfd)) - RETURN_NONFATAL (obfd); + { + status = 1; + bfd_nonfatal_message (filename, NULL, NULL, NULL); + return; + } + filename = bfd_get_filename (ibfd); if (!bfd_close (ibfd)) - RETURN_NONFATAL (obfd); + { + status = 1; + bfd_nonfatal_message (filename, NULL, NULL, NULL); + return; + } /* Delete all the files that we opened. */ for (l = list; l != NULL; l = l->next) @@ -2014,18 +2415,36 @@ copy_unknown_element: rmdir (dir); } +static void +set_long_section_mode (bfd *output_bfd, bfd *input_bfd, enum long_section_name_handling style) +{ + /* This is only relevant to Coff targets. */ + if (bfd_get_flavour (output_bfd) == bfd_target_coff_flavour) + { + if (style == KEEP + && bfd_get_flavour (input_bfd) == bfd_target_coff_flavour) + style = bfd_coff_long_section_names (input_bfd) ? ENABLE : DISABLE; + bfd_coff_set_long_section_names (output_bfd, style != DISABLE); + } +} + /* The top-level control. */ static void copy_file (const char *input_filename, const char *output_filename, - const char *input_target, const char *output_target) + const char *input_target, const char *output_target, + const bfd_arch_info_type *input_arch) { bfd *ibfd; char **obj_matching; char **core_matching; + off_t size = get_file_size (input_filename); - if (get_file_size (input_filename) < 1) + if (size < 1) { + if (size == 0) + non_fatal (_("error: the input file '%s' is empty"), + input_filename); status = 1; return; } @@ -2040,6 +2459,18 @@ copy_file (const char *input_filename, const char *output_filename, return; } + switch (do_debug_sections) + { + case compress: + ibfd->flags |= BFD_COMPRESS; + break; + case decompress: + ibfd->flags |= BFD_DECOMPRESS; + break; + default: + break; + } + if (bfd_check_format (ibfd, bfd_archive)) { bfd_boolean force_output_target; @@ -2062,8 +2493,10 @@ copy_file (const char *input_filename, const char *output_filename, status = 1; return; } + /* This is a no-op on non-Coff targets. */ + set_long_section_mode (obfd, ibfd, long_section_names); - copy_archive (ibfd, obfd, output_target, force_output_target); + copy_archive (ibfd, obfd, output_target, force_output_target, input_arch); } else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching)) { @@ -2082,15 +2515,25 @@ copy_file (const char *input_filename, const char *output_filename, status = 1; return; } + /* This is a no-op on non-Coff targets. */ + set_long_section_mode (obfd, ibfd, long_section_names); - if (! copy_object (ibfd, obfd)) + if (! copy_object (ibfd, obfd, input_arch)) status = 1; if (!bfd_close (obfd)) - RETURN_NONFATAL (obfd); + { + status = 1; + bfd_nonfatal_message (output_filename, NULL, NULL, NULL); + return; + } if (!bfd_close (ibfd)) - RETURN_NONFATAL (ibfd); + { + status = 1; + bfd_nonfatal_message (input_filename, NULL, NULL, NULL); + return; + } } else { @@ -2133,28 +2576,28 @@ static void add_section_rename (const char * old_name, const char * new_name, flagword flags) { - section_rename * rename; + section_rename * srename; /* Check for conflicts first. */ - for (rename = section_rename_list; rename != NULL; rename = rename->next) - if (strcmp (rename->old_name, old_name) == 0) + for (srename = section_rename_list; srename != NULL; srename = srename->next) + if (strcmp (srename->old_name, old_name) == 0) { /* Silently ignore duplicate definitions. */ - if (strcmp (rename->new_name, new_name) == 0 - && rename->flags == flags) + if (strcmp (srename->new_name, new_name) == 0 + && srename->flags == flags) return; fatal (_("Multiple renames of section %s"), old_name); } - rename = xmalloc (sizeof (* rename)); + srename = (section_rename *) xmalloc (sizeof (* srename)); - rename->old_name = old_name; - rename->new_name = new_name; - rename->flags = flags; - rename->next = section_rename_list; + srename->old_name = old_name; + srename->new_name = new_name; + srename->flags = flags; + srename->next = section_rename_list; - section_rename_list = rename; + section_rename_list = srename; } /* Check the section rename list for a new name of the input section @@ -2166,18 +2609,18 @@ find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection, flagword * returned_flags) { const char * old_name = bfd_section_name (ibfd, isection); - section_rename * rename; + section_rename * srename; /* Default to using the flags of the input section. */ * returned_flags = bfd_get_section_flags (ibfd, isection); - for (rename = section_rename_list; rename != NULL; rename = rename->next) - if (strcmp (rename->old_name, old_name) == 0) + for (srename = section_rename_list; srename != NULL; srename = srename->next) + if (strcmp (srename->old_name, old_name) == 0) { - if (rename->flags != (flagword) -1) - * returned_flags = rename->flags; + if (srename->flags != (flagword) -1) + * returned_flags = srename->flags; - return rename->new_name; + return srename->new_name; } return old_name; @@ -2195,7 +2638,7 @@ setup_bfd_headers (bfd *ibfd, bfd *obfd) { status = 1; bfd_nonfatal_message (NULL, ibfd, NULL, - _("error in private h eader data")); + _("error in private header data")); return; } @@ -2209,7 +2652,7 @@ setup_bfd_headers (bfd *ibfd, bfd *obfd) static void setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) { - bfd *obfd = obfdarg; + bfd *obfd = (bfd *) obfdarg; struct section_list *p; sec_ptr osection; bfd_size_type size; @@ -2224,10 +2667,6 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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); @@ -2242,21 +2681,24 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) { char *n; - n = xmalloc (strlen (prefix) + strlen (name) + 1); + n = (char *) xmalloc (strlen (prefix) + strlen (name) + 1); strcpy (n, prefix); strcat (n, name); name = n; } 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) != 0 - && (ibfd->xvec->flavour != bfd_target_elf_flavour - || elf_section_type (isection) != SHT_NOTE)) + && (flags & (SEC_ALLOC | SEC_GROUP)) != 0 + && !(ibfd->xvec->flavour == bfd_target_elf_flavour + && elf_section_type (isection) == SHT_NOTE)) { - flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD); + flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP); if (obfd->xvec->flavour == bfd_target_elf_flavour) { make_nobits = TRUE; @@ -2265,7 +2707,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) elf.c:copy_private_bfd_data that section flags have not changed between input and output sections. This hack prevents wholesale rewriting of the program headers. */ - isection->flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD); + isection->flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP); } } @@ -2282,7 +2724,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) size = bfd_section_size (ibfd, isection); if (copy_byte >= 0) - size = (size + interleave - 1) / interleave; + size = (size + interleave - 1) / interleave * copy_width; else if (extract_symbol) size = 0; if (! bfd_set_section_size (obfd, osection, size)) @@ -2292,10 +2734,15 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) } 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; @@ -2306,14 +2753,14 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) } 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; @@ -2344,6 +2791,18 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) if (extract_symbol) return; + if ((isection->flags & SEC_GROUP) != 0) + { + asymbol *gsym = group_signature (isection); + + if (gsym != NULL) + { + gsym->flags |= BSF_KEEP; + if (ibfd->xvec->flavour == bfd_target_elf_flavour) + elf_group_id (isection) = gsym; + } + } + /* Allow the BFD backend to copy any private data it understands from the input section to the output section. */ if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection)) @@ -2351,13 +2810,6 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) err = _("failed to copy private data"); goto loser; } - else if ((isection->flags & SEC_GROUP) != 0) - { - asymbol *gsym = group_signature (isection); - - if (gsym != NULL) - gsym->flags |= BSF_KEEP; - } /* All went well. */ return; @@ -2367,47 +2819,59 @@ loser: bfd_nonfatal_message (NULL, obfd, osection, err); } -/* Copy the data of input section ISECTION of IBFD - to an output section with the same name in OBFD. - If stripping then don't copy any relocation info. */ +/* Return TRUE if input section ISECTION should be skipped. */ -static void -copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) +static bfd_boolean +skip_section (bfd *ibfd, sec_ptr isection) { - bfd *obfd = obfdarg; - struct section_list *p; - arelent **relpp; - long relcount; sec_ptr osection; bfd_size_type size; - long relsize; flagword flags; /* If we have already failed earlier on, do not keep on generating complaints now. */ if (status != 0) - return; + return TRUE; + + if (extract_symbol) + return TRUE; if (is_strip_section (ibfd, isection)) - return; + return TRUE; flags = bfd_get_section_flags (ibfd, isection); if ((flags & SEC_GROUP) != 0) - return; + return TRUE; osection = isection->output_section; size = bfd_get_section_size (isection); if (size == 0 || osection == 0) - return; + return TRUE; - if (extract_symbol) + return FALSE; +} + +/* Copy relocations in input section ISECTION of IBFD to an output + section with the same name in OBFDARG. If stripping then don't + copy any relocation info. */ + +static void +copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg) +{ + bfd *obfd = (bfd *) obfdarg; + long relsize; + arelent **relpp; + long relcount; + sec_ptr osection; + + if (skip_section (ibfd, isection)) return; - p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE); + osection = isection->output_section; - /* Core files do not need to be relocated. */ - if (bfd_get_format (obfd) == bfd_core) + /* Core files and DWO files do not need to be relocated. */ + if (bfd_get_format (obfd) == bfd_core || strip_symbols == STRIP_NONDWO) relsize = 0; else { @@ -2428,10 +2892,13 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) } if (relsize == 0) - bfd_set_reloc (obfd, osection, NULL, 0); + { + bfd_set_reloc (obfd, osection, NULL, 0); + osection->flags &= ~SEC_RELOC; + } else { - relpp = xmalloc (relsize); + relpp = (arelent **) xmalloc (relsize); relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp); if (relcount < 0) { @@ -2449,7 +2916,7 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) long temp_relcount = 0; long i; - temp_relpp = xmalloc (relsize); + temp_relpp = (arelent **) xmalloc (relsize); for (i = 0; i < relcount; i++) if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr), keep_specific_htab)) @@ -2461,15 +2928,36 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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)) + return; + + osection = isection->output_section; + size = bfd_get_section_size (isection); if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS) { - void *memhunk = xmalloc (size); + bfd_byte *memhunk = NULL; - if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size)) + if (!bfd_get_full_section_contents (ibfd, isection, &memhunk)) { status = 1; bfd_nonfatal_message (NULL, ibfd, isection, NULL); @@ -2506,13 +2994,19 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) { /* Keep only every `copy_byte'th byte in MEMHUNK. */ char *from = (char *) memhunk + copy_byte; - char *to = memhunk; + char *to = (char *) memhunk; char *end = (char *) memhunk + size; + int i; for (; from < end; from += interleave) - *to++ = *from; + for (i = 0; i < copy_width; i++) + { + if (&from[i] >= end) + break; + *to++ = from[i]; + } - size = (size + interleave - 1 - copy_byte) / interleave; + size = (size + interleave - 1 - copy_byte) / interleave * copy_width; osection->lma /= interleave; } @@ -2524,7 +3018,9 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) } 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); @@ -2551,7 +3047,7 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) static void get_sections (bfd *obfd ATTRIBUTE_UNUSED, asection *osection, void *secppparg) { - asection ***secppp = secppparg; + asection ***secppp = (asection ***) secppparg; **secppp = osection; ++(*secppp); @@ -2564,8 +3060,8 @@ get_sections (bfd *obfd ATTRIBUTE_UNUSED, asection *osection, void *secppparg) static int compare_section_lma (const void *arg1, const void *arg2) { - const asection *const *sec1 = arg1; - const asection *const *sec2 = arg2; + const asection *const *sec1 = (const asection * const *) arg1; + const asection *const *sec2 = (const asection * const *) arg2; flagword flags1, flags2; /* Sort non loadable sections to the front. */ @@ -2608,7 +3104,7 @@ compare_section_lma (const void *arg1, const void *arg2) static void mark_symbols_used_in_relocations (bfd *ibfd, sec_ptr isection, void *symbolsarg) { - asymbol **symbols = symbolsarg; + asymbol **symbols = (asymbol **) symbolsarg; long relsize; arelent **relpp; long relcount, i; @@ -2629,7 +3125,7 @@ mark_symbols_used_in_relocations (bfd *ibfd, sec_ptr isection, void *symbolsarg) if (relsize == 0) return; - relpp = xmalloc (relsize); + relpp = (arelent **) xmalloc (relsize); relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, symbols); if (relcount < 0) bfd_fatal (bfd_get_filename (ibfd)); @@ -2708,6 +3204,15 @@ write_debugging_info (bfd *obfd, void *dhandle, 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[]) { @@ -2717,7 +3222,6 @@ 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", @@ -2735,8 +3239,7 @@ strip_main (int argc, char *argv[]) input_target = output_target = optarg; break; case 'R': - p = find_section_list (optarg, TRUE); - p->remove = TRUE; + find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE); sections_removed = TRUE; break; case 's': @@ -2747,6 +3250,9 @@ strip_main (int argc, char *argv[]) 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; @@ -2762,6 +3268,12 @@ strip_main (int argc, char *argv[]) case 'p': preserve_dates = TRUE; break; + case 'D': + deterministic = TRUE; + break; + case 'U': + deterministic = FALSE; + break; case 'x': discard_locals = LOCALS_ALL; break; @@ -2806,6 +3318,8 @@ strip_main (int argc, char *argv[]) if (show_version) print_version ("strip"); + default_deterministic (); + /* Default is to strip all symbols. */ if (strip_symbols == STRIP_UNDEF && discard_locals == LOCALS_UNDEF @@ -2837,7 +3351,8 @@ strip_main (int argc, char *argv[]) It has already been checked in get_file_size(). */ stat (argv[i], &statbuf); - if (output_file == NULL || strcmp (argv[i], output_file) == 0) + if (output_file == NULL + || filename_cmp (argv[i], output_file) == 0) tmpname = make_tempname (argv[i]); else tmpname = output_file; @@ -2851,15 +3366,17 @@ strip_main (int argc, char *argv[]) } status = 0; - copy_file (argv[i], tmpname, input_target, output_target); + copy_file (argv[i], tmpname, input_target, output_target, NULL); if (status == 0) { if (preserve_dates) set_times (tmpname, &statbuf); if (output_file != tmpname) - smart_rename (tmpname, output_file ? output_file : argv[i], - preserve_dates); - status = hold_status; + status = (smart_rename (tmpname, + output_file ? output_file : argv[i], + preserve_dates) != 0); + if (status == 0) + status = hold_status; } else unlink_if_ordinary (tmpname); @@ -2870,10 +3387,122 @@ strip_main (int argc, char *argv[]) return status; } +/* Set up PE subsystem. */ + +static void +set_pe_subsystem (const char *s) +{ + const char *version, *subsystem; + size_t i; + static const struct + { + const char *name; + const char set_def; + const short value; + } + v[] = + { + { "native", 0, IMAGE_SUBSYSTEM_NATIVE }, + { "windows", 0, IMAGE_SUBSYSTEM_WINDOWS_GUI }, + { "console", 0, IMAGE_SUBSYSTEM_WINDOWS_CUI }, + { "posix", 0, IMAGE_SUBSYSTEM_POSIX_CUI }, + { "wince", 0, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI }, + { "efi-app", 1, IMAGE_SUBSYSTEM_EFI_APPLICATION }, + { "efi-bsd", 1, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER }, + { "efi-rtd", 1, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER }, + { "sal-rtd", 1, IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER }, + { "xbox", 0, IMAGE_SUBSYSTEM_XBOX } + }; + short value; + char *copy; + int set_def = -1; + + /* Check for the presence of a version number. */ + version = strchr (s, ':'); + if (version == NULL) + subsystem = s; + else + { + int len = version - s; + copy = xstrdup (s); + subsystem = copy; + copy[len] = '\0'; + version = copy + 1 + len; + pe_major_subsystem_version = strtoul (version, ©, 0); + if (*copy == '.') + pe_minor_subsystem_version = strtoul (copy + 1, ©, 0); + if (*copy != '\0') + non_fatal (_("%s: bad version in PE subsystem"), s); + } + + /* Check for numeric subsystem. */ + value = (short) strtol (subsystem, ©, 0); + if (*copy == '\0') + { + for (i = 0; i < ARRAY_SIZE (v); i++) + if (v[i].value == value) + { + pe_subsystem = value; + set_def = v[i].set_def; + break; + } + } + else + { + /* Search for subsystem by name. */ + for (i = 0; i < ARRAY_SIZE (v); i++) + if (strcmp (subsystem, v[i].name) == 0) + { + pe_subsystem = v[i].value; + set_def = v[i].set_def; + break; + } + } + + switch (set_def) + { + case -1: + fatal (_("unknown PE subsystem: %s"), s); + break; + case 0: + break; + default: + if (pe_file_alignment == (bfd_vma) -1) + pe_file_alignment = PE_DEF_FILE_ALIGNMENT; + if (pe_section_alignment == (bfd_vma) -1) + pe_section_alignment = PE_DEF_SECTION_ALIGNMENT; + break; + } + if (s != subsystem) + free ((char *) subsystem); +} + +/* Convert EFI target to PEI target. */ + +static void +convert_efi_target (char *efi) +{ + efi[0] = 'p'; + efi[1] = 'e'; + efi[2] = 'i'; + + if (strcmp (efi + 4, "ia32") == 0) + { + /* Change ia32 to i386. */ + efi[5]= '3'; + efi[6]= '8'; + efi[7]= '6'; + } + else if (strcmp (efi + 4, "x86_64") == 0) + { + /* Change x86_64 to x86-64. */ + efi[7] = '-'; + } +} + static int copy_main (int argc, char *argv[]) { - char * binary_architecture = NULL; char *input_filename = NULL; char *output_filename = NULL; char *tmpname; @@ -2883,8 +3512,8 @@ copy_main (int argc, char *argv[]) bfd_boolean change_warn = TRUE; bfd_boolean formats_info = FALSE; int c; - struct section_list *p; struct stat statbuf; + const bfd_arch_info_type *input_arch = NULL; while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:w", copy_options, (int *) 0)) != EOF) @@ -2898,13 +3527,26 @@ copy_main (int argc, char *argv[]) break; case 'B': - binary_architecture = optarg; + input_arch = bfd_scan_arch (optarg); + if (input_arch == NULL) + fatal (_("architecture %s unknown"), optarg); break; case 'i': - interleave = atoi (optarg); - if (interleave < 1) - fatal (_("interleave must be positive")); + if (optarg) + { + interleave = atoi (optarg); + if (interleave < 1) + fatal (_("interleave must be positive")); + } + else + interleave = 4; + break; + + case OPTION_INTERLEAVE_WIDTH: + copy_width = atoi (optarg); + if (copy_width < 1) + fatal(_("interleave width must be positive")); break; case 'I': @@ -2922,18 +3564,12 @@ copy_main (int argc, char *argv[]) break; case 'j': - p = find_section_list (optarg, TRUE); - if (p->remove) - fatal (_("%s both copied and removed"), optarg); - p->copy = TRUE; + find_section_list (optarg, TRUE, SECTION_CONTEXT_COPY); sections_copied = TRUE; break; case 'R': - p = find_section_list (optarg, TRUE); - if (p->copy) - fatal (_("%s both copied and removed"), optarg); - p->remove = TRUE; + find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE); sections_removed = TRUE; break; @@ -2945,6 +3581,10 @@ copy_main (int argc, char *argv[]) strip_symbols = STRIP_DEBUG; break; + case OPTION_STRIP_DWO: + strip_symbols = STRIP_DWO; + break; + case OPTION_STRIP_UNNEEDED: strip_symbols = STRIP_UNNEEDED; break; @@ -2958,6 +3598,7 @@ copy_main (int argc, char *argv[]) break; case OPTION_ADD_GNU_DEBUGLINK: + long_section_names = ENABLE ; gnu_debuglink_filename = optarg; break; @@ -2993,6 +3634,14 @@ copy_main (int argc, char *argv[]) preserve_dates = TRUE; break; + case 'D': + deterministic = TRUE; + break; + + case 'U': + deterministic = FALSE; + break; + case 'w': wildcard = TRUE; break; @@ -3024,10 +3673,8 @@ copy_main (int argc, char *argv[]) case OPTION_ADD_SECTION: { const char *s; - off_t size; + size_t off, alloc; struct section_add *pa; - int len; - char *name; FILE *f; s = strchr (optarg, '='); @@ -3035,34 +3682,40 @@ copy_main (int argc, char *argv[]) if (s == NULL) fatal (_("bad format for %s"), "--add-section"); - size = get_file_size (s + 1); - if (size < 1) - { - status = 1; - break; - } - - pa = xmalloc (sizeof (struct section_add)); - - len = s - optarg; - name = xmalloc (len + 1); - strncpy (name, optarg, len); - name[len] = '\0'; - pa->name = name; - + pa = (struct section_add *) xmalloc (sizeof (struct section_add)); + pa->name = xstrndup (optarg, s - optarg); pa->filename = s + 1; - pa->size = size; - pa->contents = xmalloc (size); - f = fopen (pa->filename, FOPEN_RB); + /* We don't use get_file_size so that we can do + --add-section .note.GNU_stack=/dev/null + get_file_size doesn't work on /dev/null. */ + f = fopen (pa->filename, FOPEN_RB); if (f == NULL) fatal (_("cannot open: %s: %s"), pa->filename, strerror (errno)); - if (fread (pa->contents, 1, pa->size, f) == 0 - || ferror (f)) - fatal (_("%s: fread failed"), pa->filename); + off = 0; + alloc = 4096; + pa->contents = (bfd_byte *) xmalloc (alloc); + while (!feof (f)) + { + off_t got; + + if (off == alloc) + { + alloc <<= 1; + pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc); + } + + got = fread (pa->contents + off, 1, alloc - off, f); + if (ferror (f)) + fatal (_("%s: fread failed"), pa->filename); + + off += got; + } + + pa->size = off; fclose (f); @@ -3071,6 +3724,25 @@ copy_main (int argc, char *argv[]) } break; + case OPTION_DUMP_SECTION: + { + const char *s; + struct section_add *pa; + + s = strchr (optarg, '='); + + if (s == NULL) + fatal (_("bad format for %s"), "--dump-section"); + + pa = (struct section_add *) xmalloc (sizeof * pa); + pa->name = xstrndup (optarg, s - optarg); + pa->filename = s + 1; + pa->next = dump_sections; + pa->contents = NULL; + dump_sections = pa; + } + break; + case OPTION_CHANGE_START: change_start = parse_vma (optarg, "--change-start"); break; @@ -3079,23 +3751,27 @@ copy_main (int argc, char *argv[]) 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; } @@ -3110,38 +3786,46 @@ copy_main (int argc, char *argv[]) fatal (_("bad format for %s"), option); } } + else + { + /* Correct the context. */ + switch (c) + { + case OPTION_CHANGE_SECTION_ADDRESS: + context = SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_SET_VMA; + break; + case OPTION_CHANGE_SECTION_LMA: + context = SECTION_CONTEXT_SET_LMA; + break; + case OPTION_CHANGE_SECTION_VMA: + context = SECTION_CONTEXT_SET_VMA; + break; + } + } len = s - optarg; - name = xmalloc (len + 1); + name = (char *) xmalloc (len + 1); strncpy (name, optarg, len); name[len] = '\0'; - p = find_section_list (name, TRUE); + p = find_section_list (name, TRUE, context); val = parse_vma (s + 1, option); - - switch (*s) - { - case '=': what = CHANGE_SET; break; - case '-': val = - val; /* Drop through. */ - case '+': what = CHANGE_MODIFY; break; - } + if (*s == '-') + val = - val; switch (c) { case OPTION_CHANGE_SECTION_ADDRESS: - p->change_vma = what; - p->vma_val = val; + p->vma_val = val; /* Drop through. */ case OPTION_CHANGE_SECTION_LMA: - p->change_lma = what; - p->lma_val = val; + p->lma_val = val; break; case OPTION_CHANGE_SECTION_VMA: - p->change_vma = what; - p->vma_val = val; + p->vma_val = val; break; } } @@ -3160,10 +3844,18 @@ copy_main (int argc, char *argv[]) change_leading_char = TRUE; break; + case OPTION_COMPRESS_DEBUG_SECTIONS: + do_debug_sections = compress; + break; + case OPTION_DEBUGGING: convert_debugging = TRUE; break; + case OPTION_DECOMPRESS_DEBUG_SECTIONS: + do_debug_sections = decompress; + break; + case OPTION_GAP_FILL: { bfd_vma gap_fill_vma; @@ -3210,13 +3902,13 @@ copy_main (int argc, char *argv[]) fatal (_("bad format for %s"), "--redefine-sym"); len = s - optarg; - source = xmalloc (len + 1); + source = (char *) xmalloc (len + 1); strncpy (source, optarg, len); source[len] = '\0'; nextarg = s + 1; len = strlen (nextarg); - target = xmalloc (len + 1); + target = (char *) xmalloc (len + 1); strcpy (target, nextarg); redefine_list_append ("--redefine-sym", source, target); @@ -3232,6 +3924,7 @@ copy_main (int argc, char *argv[]) case OPTION_SET_SECTION_FLAGS: { + struct section_list *p; const char *s; int len; char *name; @@ -3241,13 +3934,12 @@ copy_main (int argc, char *argv[]) fatal (_("bad format for %s"), "--set-section-flags"); len = s - optarg; - name = xmalloc (len + 1); + name = (char *) xmalloc (len + 1); strncpy (name, optarg, len); name[len] = '\0'; - p = find_section_list (name, TRUE); + p = find_section_list (name, TRUE, SECTION_CONTEXT_SET_FLAGS); - p->set_flags = TRUE; p->flags = parse_flags (s + 1); } break; @@ -3268,7 +3960,7 @@ copy_main (int argc, char *argv[]) if (len == 0) fatal (_("bad format for %s"), "--rename-section"); - old_name = xmalloc (len + 1); + old_name = (char *) xmalloc (len + 1); strncpy (old_name, optarg, len); old_name[len] = 0; @@ -3288,7 +3980,7 @@ copy_main (int argc, char *argv[]) if (len == 0) fatal (_("bad format for %s"), "--rename-section"); - new_name = xmalloc (len + 1); + new_name = (char *) xmalloc (len + 1); strncpy (new_name, eq, len); new_name[len] = 0; @@ -3329,6 +4021,17 @@ copy_main (int argc, char *argv[]) add_specific_symbols (optarg, localize_specific_htab); break; + case OPTION_LONG_SECTION_NAMES: + if (!strcmp ("enable", optarg)) + long_section_names = ENABLE; + else if (!strcmp ("disable", optarg)) + long_section_names = DISABLE; + else if (!strcmp ("keep", optarg)) + long_section_names = KEEP; + else + fatal (_("unknown long section names option '%s'"), optarg); + break; + case OPTION_GLOBALIZE_SYMBOLS: add_specific_symbols (optarg, globalize_specific_htab); break; @@ -3379,6 +4082,10 @@ copy_main (int argc, char *argv[]) bfd_flags_to_set &= ~D_PAGED; break; + case OPTION_EXTRACT_DWO: + strip_symbols = STRIP_NONDWO; + break; + case OPTION_EXTRACT_SYMBOL: extract_symbol = TRUE; break; @@ -3397,6 +4104,59 @@ copy_main (int argc, char *argv[]) break; } + case OPTION_FILE_ALIGNMENT: + pe_file_alignment = parse_vma (optarg, "--file-alignment"); + break; + + case OPTION_HEAP: + { + char *end; + pe_heap_reserve = strtoul (optarg, &end, 0); + if (end == optarg + || (*end != '.' && *end != '\0')) + non_fatal (_("%s: invalid reserve value for --heap"), + optarg); + else if (*end != '\0') + { + pe_heap_commit = strtoul (end + 1, &end, 0); + if (*end != '\0') + non_fatal (_("%s: invalid commit value for --heap"), + optarg); + } + } + break; + + case OPTION_IMAGE_BASE: + pe_image_base = parse_vma (optarg, "--image-base"); + break; + + case OPTION_SECTION_ALIGNMENT: + pe_section_alignment = parse_vma (optarg, + "--section-alignment"); + break; + + case OPTION_SUBSYSTEM: + set_pe_subsystem (optarg); + break; + + case OPTION_STACK: + { + char *end; + pe_stack_reserve = strtoul (optarg, &end, 0); + if (end == optarg + || (*end != '.' && *end != '\0')) + non_fatal (_("%s: invalid reserve value for --stack"), + optarg); + else if (*end != '\0') + { + pe_stack_commit = strtoul (end + 1, &end, 0); + if (*end != '\0') + non_fatal (_("%s: invalid commit value for --stack"), + optarg); + } + } + break; + case 0: /* We've been given a long option. */ break; @@ -3419,9 +4179,15 @@ copy_main (int argc, char *argv[]) if (show_version) print_version ("objcopy"); + if (interleave && copy_byte == -1) + fatal (_("interleave start byte must be set with --byte")); + if (copy_byte >= interleave) fatal (_("byte number must be less than interleave")); + if (copy_width > interleave - copy_byte) + fatal (_("interleave width must be less than or equal to interleave - byte`")); + if (optind == argc || optind + 2 < argc) copy_usage (stderr, 1); @@ -3429,6 +4195,8 @@ copy_main (int argc, char *argv[]) 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; @@ -3436,27 +4204,57 @@ copy_main (int argc, char *argv[]) if (output_target == NULL) output_target = input_target; - if (binary_architecture != NULL) + /* Convert input EFI target to PEI target. */ + if (input_target != NULL + && strncmp (input_target, "efi-", 4) == 0) { - if (input_target && strcmp (input_target, "binary") == 0) - { - const bfd_arch_info_type * temp_arch_info; + char *efi; - temp_arch_info = bfd_scan_arch (binary_architecture); + efi = xstrdup (output_target + 4); + if (strncmp (efi, "bsdrv-", 6) == 0 + || strncmp (efi, "rtdrv-", 6) == 0) + efi += 2; + else if (strncmp (efi, "app-", 4) != 0) + fatal (_("unknown input EFI target: %s"), input_target); - if (temp_arch_info != NULL) - { - bfd_external_binary_architecture = temp_arch_info->arch; - bfd_external_machine = temp_arch_info->mach; - } - else - fatal (_("architecture %s unknown"), binary_architecture); + input_target = efi; + convert_efi_target (efi); + } + + /* Convert output EFI target to PEI target. */ + if (output_target != NULL + && strncmp (output_target, "efi-", 4) == 0) + { + char *efi; + + efi = xstrdup (output_target + 4); + if (strncmp (efi, "app-", 4) == 0) + { + if (pe_subsystem == -1) + pe_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION; } - else + else if (strncmp (efi, "bsdrv-", 6) == 0) { - non_fatal (_("Warning: input target 'binary' required for binary architecture parameter.")); - non_fatal (_(" Argument %s ignored"), binary_architecture); + if (pe_subsystem == -1) + pe_subsystem = IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER; + efi += 2; } + else if (strncmp (efi, "rtdrv-", 6) == 0) + { + if (pe_subsystem == -1) + pe_subsystem = IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER; + efi += 2; + } + else + fatal (_("unknown output EFI target: %s"), output_target); + + if (pe_file_alignment == (bfd_vma) -1) + pe_file_alignment = PE_DEF_FILE_ALIGNMENT; + if (pe_section_alignment == (bfd_vma) -1) + pe_section_alignment = PE_DEF_SECTION_ALIGNMENT; + + output_target = efi; + convert_efi_target (efi); } if (preserve_dates) @@ -3466,7 +4264,8 @@ copy_main (int argc, char *argv[]) /* If there is no destination file, or the source and destination files are the same, then create a temp and rename the result into the input. */ - if (output_filename == NULL || strcmp (input_filename, output_filename) == 0) + if (output_filename == NULL + || filename_cmp (input_filename, output_filename) == 0) tmpname = make_tempname (input_filename); else tmpname = output_filename; @@ -3475,24 +4274,27 @@ copy_main (int argc, char *argv[]) fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"), input_filename, strerror (errno)); - copy_file (input_filename, tmpname, input_target, output_target); + copy_file (input_filename, tmpname, input_target, output_target, input_arch); if (status == 0) { if (preserve_dates) set_times (tmpname, &statbuf); if (tmpname != output_filename) - smart_rename (tmpname, input_filename, preserve_dates); + status = (smart_rename (tmpname, input_filename, + preserve_dates) != 0); } else unlink_if_ordinary (tmpname); if (change_warn) { + struct section_list *p; + for (p = change_sections; p != NULL; p = p->next) { if (! p->used) { - if (p->change_vma != CHANGE_IGNORE) + if (p->context & (SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA)) { char buff [20]; @@ -3501,12 +4303,12 @@ copy_main (int argc, char *argv[]) /* 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]; @@ -3515,8 +4317,8 @@ copy_main (int argc, char *argv[]) /* 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); } }