X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Fobjcopy.c;h=873908c688d3d6b450dfe6f6e4faf147b3d45848;hb=5063a42103f83b921b0b6899acdd5d4d920fdc36;hp=230d3e564807eed2cc32d36df4482e48be9dc02b;hpb=dbb7c4414b09c017dafc73b63de13640f19c5735;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objcopy.c b/binutils/objcopy.c index 230d3e5648..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, 2009, 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright (C) 1991-2014 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -86,6 +84,7 @@ 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 @@ -95,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 { @@ -111,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. */ }; @@ -186,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; @@ -259,6 +262,7 @@ static enum long_section_name_handling long_section_names = KEEP; enum command_line_switch { OPTION_ADD_SECTION=150, + OPTION_DUMP_SECTION, OPTION_CHANGE_ADDRESSES, OPTION_CHANGE_LEADING_CHAR, OPTION_CHANGE_START, @@ -313,15 +317,19 @@ enum command_line_switch OPTION_SECTION_ALIGNMENT, OPTION_STACK, OPTION_INTERLEAVE_WIDTH, - OPTION_SUBSYSTEM + 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}, @@ -337,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'}, @@ -369,8 +378,12 @@ static struct option copy_options[] = {"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}, @@ -417,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}, @@ -459,6 +473,7 @@ extern bfd_boolean S3Forced; /* 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 *); @@ -478,18 +493,33 @@ copy_usage (FILE *stream, int exit_status) -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\ @@ -523,6 +553,7 @@ 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\ @@ -587,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\ @@ -647,6 +693,8 @@ 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 { @@ -657,7 +705,7 @@ parse_flags (const char *s) 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; @@ -667,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 = (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; @@ -924,6 +1033,17 @@ group_signature (asection *group) return NULL; } +/* Return TRUE if the section is a DWO section. */ + +static bfd_boolean +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 @@ -932,12 +1052,20 @@ 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; } @@ -948,12 +1076,24 @@ is_strip_section_1 (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; } @@ -1458,6 +1598,13 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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), @@ -1628,13 +1775,12 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) { 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. */ @@ -1667,86 +1813,156 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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); + } } } @@ -1841,6 +2057,8 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) || 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 @@ -1885,6 +2103,9 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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); @@ -2026,9 +2247,15 @@ 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); @@ -2440,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); @@ -2465,7 +2688,10 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) } 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 @@ -2508,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; @@ -2522,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; @@ -2588,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 = (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; 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 { @@ -2649,7 +2892,10 @@ 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 = (arelent **) xmalloc (relsize); @@ -2682,8 +2928,29 @@ 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) @@ -2733,7 +3000,11 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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; @@ -2747,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); @@ -2931,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[]) { @@ -2940,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", @@ -2958,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': @@ -2970,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; @@ -2985,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; @@ -3029,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 @@ -3111,7 +3402,7 @@ set_pe_subsystem (const char *s) } 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 }, @@ -3221,7 +3512,6 @@ 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; @@ -3274,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; @@ -3297,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; @@ -3310,6 +3598,7 @@ copy_main (int argc, char *argv[]) break; case OPTION_ADD_GNU_DEBUGLINK: + long_section_names = ENABLE ; gnu_debuglink_filename = optarg; break; @@ -3345,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; @@ -3427,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; @@ -3435,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; } @@ -3466,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 = (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; } } @@ -3596,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; @@ -3609,9 +3938,8 @@ copy_main (int argc, char *argv[]) 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; @@ -3754,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; @@ -3775,7 +4107,7 @@ copy_main (int argc, char *argv[]) case OPTION_FILE_ALIGNMENT: pe_file_alignment = parse_vma (optarg, "--file-alignment"); break; - + case OPTION_HEAP: { char *end; @@ -3793,20 +4125,20 @@ copy_main (int argc, char *argv[]) } } 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; @@ -3824,7 +4156,7 @@ copy_main (int argc, char *argv[]) } } break; - + case 0: /* We've been given a long option. */ break; @@ -3863,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; @@ -3954,11 +4288,13 @@ copy_main (int argc, char *argv[]) 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]; @@ -3967,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]; @@ -3981,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); } }