X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Fobjcopy.c;h=21f579366dd6b390c5820ec0108064c1a7b42d6b;hb=3ba3ce66272026709b0e77745193a157d757f0e2;hp=86232ad9555dcd0725277b5f0af80a69979a9e6d;hpb=842eba6688d36ea2752e66de0958df3e7af2c004;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objcopy.c b/binutils/objcopy.c index 86232ad955..21f579366d 100644 --- a/binutils/objcopy.c +++ b/binutils/objcopy.c @@ -1,5 +1,6 @@ /* objcopy.c -- copy object file from input to output, optionally massaging it. - Copyright (C) 1991, 92, 93, 94 Free Software Foundation, Inc. + Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000 + Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -15,31 +16,63 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ #include "bfd.h" -#include "sysdep.h" #include "progress.h" #include "bucomm.h" -#include +#include "getopt.h" #include "libiberty.h" +#include "budbg.h" +#include "filenames.h" +#include -static bfd_vma parse_vma PARAMS ((const char *, const char *)); +/* A list of symbols to explicitly strip out, or to keep. A linked + list is good enough for a small number from the command line, but + this will slow things down a lot if many symbols are being + deleted. */ + +struct symlist +{ + const char *name; + struct symlist *next; +}; + +/* A list to support redefine_sym. */ +struct redefine_node +{ + char *source; + char *target; + struct redefine_node *next; +}; + +static void copy_usage PARAMS ((FILE *, int)); +static void strip_usage PARAMS ((FILE *, int)); static flagword parse_flags PARAMS ((const char *)); -static char *make_tempname PARAMS ((char *)); static struct section_list *find_section_list PARAMS ((const char *, boolean)); static void setup_section PARAMS ((bfd *, asection *, PTR)); static void copy_section PARAMS ((bfd *, asection *, PTR)); static void get_sections PARAMS ((bfd *, asection *, PTR)); -static int compare_section_vma PARAMS ((const PTR, const PTR)); -static void add_strip_symbol PARAMS ((const char *)); -static boolean is_strip_symbol PARAMS ((const char *)); +static int compare_section_lma PARAMS ((const PTR, const PTR)); +static void add_specific_symbol PARAMS ((const char *, struct symlist **)); +static boolean is_specified_symbol PARAMS ((const char *, struct symlist *)); static boolean is_strip_section PARAMS ((bfd *, asection *)); static unsigned int filter_symbols - PARAMS ((bfd *, asymbol **, asymbol **, long)); + PARAMS ((bfd *, bfd *, asymbol **, asymbol **, long)); static void mark_symbols_used_in_relocations PARAMS ((bfd *, asection *, PTR)); - -#define nonfatal(s) {bfd_nonfatal(s); status = 1; return;} +static void filter_bytes PARAMS ((char *, bfd_size_type *)); +static boolean write_debugging_info PARAMS ((bfd *, PTR, long *, asymbol ***)); +static void copy_object PARAMS ((bfd *, bfd *)); +static void copy_archive PARAMS ((bfd *, bfd *, const char *)); +static void copy_file + PARAMS ((const char *, const char *, const char *, const char *)); +static int strip_main PARAMS ((int, char **)); +static int copy_main PARAMS ((int, char **)); +static const char *lookup_sym_redefinition PARAMS((const char *)); +static void redefine_list_append PARAMS ((const char *, const char *)); + +#define RETURN_NONFATAL(s) {bfd_nonfatal (s); status = 1; return;} static asymbol **isympp = NULL; /* Input symbols */ static asymbol **osympp = NULL; /* Output symbols that survive stripping */ @@ -49,14 +82,16 @@ static int copy_byte = -1; static int interleave = 4; static boolean verbose; /* Print file and target names. */ +static boolean preserve_dates; /* Preserve input file timestamp. */ static int status = 0; /* Exit status. */ enum strip_action { - strip_undef, - strip_none, /* don't strip */ - strip_debug, /* strip all debugger symbols */ - strip_all /* strip all symbols */ + STRIP_UNDEF, + STRIP_NONE, /* don't strip */ + STRIP_DEBUG, /* strip all debugger symbols */ + STRIP_UNNEEDED, /* strip unnecessary symbols */ + STRIP_ALL /* strip all symbols */ }; /* Which symbols to remove. */ @@ -64,46 +99,49 @@ static enum strip_action strip_symbols; enum locals_action { - locals_undef, - locals_start_L, /* discard locals starting with L */ - locals_all /* discard all locals */ + LOCALS_UNDEF, + LOCALS_START_L, /* discard locals starting with L */ + LOCALS_ALL /* discard all locals */ }; -/* Which local symbols to remove. Overrides strip_all. */ +/* Which local symbols to remove. Overrides STRIP_ALL. */ static enum locals_action discard_locals; -/* Structure used to hold lists of sections and actions to take. */ +/* 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 { - /* Next section to adjust. */ - struct section_list *next; - /* Section name. */ - const char *name; - /* Whether this entry was used. */ - boolean used; - /* Whether to remove this section. */ - boolean remove; - /* Whether to adjust or set VMA. */ - enum { ignore_vma, adjust_vma, set_vma } adjust; - /* Amount to adjust by or set to. */ - bfd_vma val; - /* Whether to set the section flags. */ - boolean set_flags; - /* What to set the section flags to. */ - flagword flags; + struct section_list * next; /* Next section to change. */ + const char * name; /* Section name. */ + boolean used; /* Whether this entry was used. */ + boolean remove; /* Whether to remove this section. */ + boolean copy; /* Whether to copy this section. */ + enum change_action change_vma;/* Whether to change or set VMA. */ + 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. */ + boolean set_flags; /* Whether to set the section flags. */ + flagword flags; /* What to set the section flags to. */ }; -static struct section_list *adjust_sections; +static struct section_list *change_sections; static boolean sections_removed; +static boolean sections_copied; -/* Adjustments to the start address. */ -static bfd_vma adjust_start = 0; +/* Changes to the start address. */ +static bfd_vma change_start = 0; static boolean set_start_set = false; static bfd_vma set_start; -/* Adjustments to section VMA's. */ -static bfd_vma adjust_section_vma = 0; +/* Changes to section addresses. */ +static bfd_vma change_section_address = 0; /* Filling gaps between sections. */ static boolean gap_fill_set = false; @@ -133,6 +171,53 @@ struct section_add static struct section_add *add_sections; +/* Whether to convert debugging information. */ + +static boolean convert_debugging = false; + +/* Whether to change the leading character in symbol names. */ + +static boolean change_leading_char = false; + +/* Whether to remove the leading character from global symbol names. */ + +static boolean remove_leading_char = false; + +/* List of symbols to strip, keep, localize, weaken, or redefine. */ + +static struct symlist *strip_specific_list = NULL; +static struct symlist *keep_specific_list = NULL; +static struct symlist *localize_specific_list = NULL; +static struct symlist *weaken_specific_list = NULL; +static struct redefine_node *redefine_sym_list = NULL; + +/* If this is true, we weaken global symbols (set BSF_WEAK). */ + +static boolean weaken = false; + +/* 150 isn't special; it's just an arbitrary non-ASCII char value. */ + +#define OPTION_ADD_SECTION 150 +#define OPTION_CHANGE_ADDRESSES (OPTION_ADD_SECTION + 1) +#define OPTION_CHANGE_LEADING_CHAR (OPTION_CHANGE_ADDRESSES + 1) +#define OPTION_CHANGE_START (OPTION_CHANGE_LEADING_CHAR + 1) +#define OPTION_CHANGE_SECTION_ADDRESS (OPTION_CHANGE_START + 1) +#define OPTION_CHANGE_SECTION_LMA (OPTION_CHANGE_SECTION_ADDRESS + 1) +#define OPTION_CHANGE_SECTION_VMA (OPTION_CHANGE_SECTION_LMA + 1) +#define OPTION_CHANGE_WARNINGS (OPTION_CHANGE_SECTION_VMA + 1) +#define OPTION_DEBUGGING (OPTION_CHANGE_WARNINGS + 1) +#define OPTION_GAP_FILL (OPTION_DEBUGGING + 1) +#define OPTION_NO_CHANGE_WARNINGS (OPTION_GAP_FILL + 1) +#define OPTION_PAD_TO (OPTION_NO_CHANGE_WARNINGS + 1) +#define OPTION_REMOVE_LEADING_CHAR (OPTION_PAD_TO + 1) +#define OPTION_SET_SECTION_FLAGS (OPTION_REMOVE_LEADING_CHAR + 1) +#define OPTION_SET_START (OPTION_SET_SECTION_FLAGS + 1) +#define OPTION_STRIP_UNNEEDED (OPTION_SET_START + 1) +#define OPTION_WEAKEN (OPTION_STRIP_UNNEEDED + 1) +#define OPTION_REDEFINE_SYM (OPTION_WEAKEN + 1) +#define OPTION_SREC_LEN (OPTION_REDEFINE_SYM + 1) +#define OPTION_SREC_FORCES3 (OPTION_SREC_LEN + 1) + /* Options to handle if running as "strip". */ static struct option strip_options[] = @@ -143,11 +228,14 @@ static struct option strip_options[] = {"help", no_argument, 0, 'h'}, {"input-format", required_argument, 0, 'I'}, /* Obsolete */ {"input-target", required_argument, 0, 'I'}, + {"keep-symbol", required_argument, 0, 'K'}, {"output-format", required_argument, 0, 'O'}, /* Obsolete */ {"output-target", required_argument, 0, 'O'}, + {"preserve-dates", no_argument, 0, 'p'}, {"remove-section", required_argument, 0, 'R'}, {"strip-all", no_argument, 0, 's'}, {"strip-debug", no_argument, 0, 'S'}, + {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, {"strip-symbol", required_argument, 0, 'N'}, {"target", required_argument, 0, 'F'}, {"verbose", no_argument, 0, 'v'}, @@ -157,81 +245,132 @@ static struct option strip_options[] = /* Options to handle if running as "objcopy". */ -/* 150 isn't special; it's just an arbitrary non-ASCII char value. */ - -#define OPTION_ADD_SECTION 150 -#define OPTION_ADJUST_START (OPTION_ADD_SECTION + 1) -#define OPTION_ADJUST_VMA (OPTION_ADJUST_START + 1) -#define OPTION_ADJUST_SECTION_VMA (OPTION_ADJUST_VMA + 1) -#define OPTION_ADJUST_WARNINGS (OPTION_ADJUST_SECTION_VMA + 1) -#define OPTION_GAP_FILL (OPTION_ADJUST_WARNINGS + 1) -#define OPTION_NO_ADJUST_WARNINGS (OPTION_GAP_FILL + 1) -#define OPTION_PAD_TO (OPTION_NO_ADJUST_WARNINGS + 1) -#define OPTION_SET_SECTION_FLAGS (OPTION_PAD_TO + 1) -#define OPTION_SET_START (OPTION_SET_SECTION_FLAGS + 1) - static struct option copy_options[] = { {"add-section", required_argument, 0, OPTION_ADD_SECTION}, - {"adjust-start", required_argument, 0, OPTION_ADJUST_START}, - {"adjust-vma", required_argument, 0, OPTION_ADJUST_VMA}, - {"adjust-section-vma", required_argument, 0, OPTION_ADJUST_SECTION_VMA}, - {"adjust-warnings", no_argument, 0, OPTION_ADJUST_WARNINGS}, + {"adjust-start", required_argument, 0, OPTION_CHANGE_START}, + {"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES}, + {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS}, + {"adjust-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS}, {"byte", required_argument, 0, 'b'}, + {"change-addresses", required_argument, 0, OPTION_CHANGE_ADDRESSES}, + {"change-leading-char", no_argument, 0, OPTION_CHANGE_LEADING_CHAR}, + {"change-section-address", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS}, + {"change-section-lma", required_argument, 0, OPTION_CHANGE_SECTION_LMA}, + {"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}, + {"debugging", no_argument, 0, OPTION_DEBUGGING}, {"discard-all", no_argument, 0, 'x'}, {"discard-locals", no_argument, 0, 'X'}, + {"only-section", required_argument, 0, 'j'}, {"format", required_argument, 0, 'F'}, /* Obsolete */ {"gap-fill", required_argument, 0, OPTION_GAP_FILL}, {"help", no_argument, 0, 'h'}, {"input-format", required_argument, 0, 'I'}, /* Obsolete */ {"input-target", required_argument, 0, 'I'}, {"interleave", required_argument, 0, 'i'}, - {"no-adjust-warnings", no_argument, 0, OPTION_NO_ADJUST_WARNINGS}, + {"keep-symbol", required_argument, 0, 'K'}, + {"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS}, + {"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS}, {"output-format", required_argument, 0, 'O'}, /* Obsolete */ {"output-target", required_argument, 0, 'O'}, {"pad-to", required_argument, 0, OPTION_PAD_TO}, + {"preserve-dates", no_argument, 0, 'p'}, + {"localize-symbol", required_argument, 0, 'L'}, + {"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR}, {"remove-section", required_argument, 0, 'R'}, {"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS}, {"set-start", required_argument, 0, OPTION_SET_START}, {"strip-all", no_argument, 0, 'S'}, {"strip-debug", no_argument, 0, 'g'}, + {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, {"strip-symbol", required_argument, 0, 'N'}, {"target", required_argument, 0, 'F'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, + {"weaken", no_argument, 0, OPTION_WEAKEN}, + {"weaken-symbol", required_argument, 0, 'W'}, + {"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM}, + {"srec-len", required_argument, 0, OPTION_SREC_LEN}, + {"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3}, {0, no_argument, 0, 0} }; /* IMPORTS */ extern char *program_name; -extern char *program_version; /* This flag distinguishes between strip and objcopy: 1 means this is 'strip'; 0 means this is 'objcopy'. -1 means if we should use argv[0] to decide. */ extern int is_strip; +/* The maximum length of an S record. This variable is declared in srec.c + and can be modified by the --srec-len parameter. */ +extern unsigned int Chunk; + +/* Restrict the generation of Srecords to type S3 only. + This variable is declare in bfd/srec.c and can be toggled + on by the --srec-forceS3 command line switch. */ +extern boolean S3Forced; static void copy_usage (stream, exit_status) FILE *stream; int exit_status; { - fprintf (stream, "\ -Usage: %s [-vVSgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-b byte]\n\ - [-R section] [-i interleave] [--interleave=interleave] [--byte=byte]\n\ - [--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\ - [--strip-all] [--strip-debug] [--discard-all] [--discard-locals]\n\ - [--remove-section=section] [--gap-fill=val] [--pad-to=address]\n", - program_name); - fprintf (stream, "\ - [--set-start=val] [--adjust-start=incr] [--adjust-vma=incr]\n\ - [--adjust-section-vma=section{=,+,-}val] [--adjust-warnings]\n\ - [--no-adjust-warnings] [--set-section-flags=section=flags]\n\ - [--add-section=sectionname=filename]\n\ - [--strip-symbol symbol] [-N symbol] [--verbose]\n\ - [--version] [--help]\n\ - in-file [out-file]\n"); + fprintf (stream, _("Usage: %s in-file [out-file]\n"), program_name); + fprintf (stream, _(" The switches are:\n")); + fprintf (stream, _("\ + -I --input-target Assume input file is in format \n\ + -O --output-target Create an output file in format \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\ + -j --only-section Only copy section into the output\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\n\ + --strip-unneeded Remove all symbols not needed by relocations\n\ + -N --strip-symbol Do not copy symbol \n\ + -K --keep-symbol Only copy symbol \n\ + -L --localize-symbol Force symbol to be marked as a local\n\ + -W --weaken-symbol Force symbol to be marked as a weak\n\ + --weaken Force all global symbols to be marked as weak\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\ + -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\ + --set-start Set the start address to \n\ + {--change-start|--adjust-start} \n\ + Add to the start address\n\ + {--change-addresses|--adjust-vma} \n\ + Add to LMA, VMA and start addresses\n\ + {--change-section-address|--adjust-section-vma} {=|+|-}\n\ + Change LMA and VMA of section by \n\ + --change-section-lma {=|+|-}\n\ + Change the LMA of section by \n\ + --change-section-vma {=|+|-}\n\ + Change the VMA of section by \n\ + {--[no-]change-warnings|--[no-]adjust-warnings}\n\ + Warn if a named section does not exist\n\ + --set-section-flags =\n\ + Set section 's properties to \n\ + --add-section = Add section found in to output\n\ + --change-leading-char Force output format's leading character style\n\ + --remove-leading-char Remove leading character from global symbols\n\ + --redefine-sym = Redefine symbol name to \n\ + --srec-len Restrict the length of generated Srecords\n\ + --srec-forceS3 Restrict the type of generated Srecords to S3\n\ + -v --verbose List all object files modified\n\ + -V --version Display this program's version number\n\ + -h --help Display this output\n\ +")); + list_supported_targets (program_name, stream); + if (exit_status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); exit (exit_status); } @@ -240,36 +379,33 @@ strip_usage (stream, exit_status) FILE *stream; int exit_status; { - fprintf (stream, "\ -Usage: %s [-vVsSgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-R section]\n\ - [--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\ - [--strip-all] [--strip-debug] [--discard-all] [--discard-locals]\n\ - [--strip-symbol symbol] [-N symbol]\n\ - [--remove-section=section] [--verbose] [--version] [--help] file...\n", - program_name); + fprintf (stream, _("Usage: %s in-file(s)\n"), program_name); + fprintf (stream, _(" The switches are:\n")); + fprintf (stream, _("\ + -I --input-target Assume input file is in format \n\ + -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\ + -R --remove-section Remove section from the output\n\ + -s --strip-all Remove all symbol and relocation information\n\ + -g -S --strip-debug Remove all debugging symbols\n\ + --strip-unneeded Remove all symbols not needed by relocations\n\ + -N --strip-symbol Do not copy symbol \n\ + -K --keep-symbol Only copy symbol \n\ + -x --discard-all Remove all non-global symbols\n\ + -X --discard-locals Remove any compiler-generated symbols\n\ + -v --verbose List all object files modified\n\ + -V --version Display this program's version number\n\ + -h --help Display this output\n\ + -o Place stripped output into \n\ +")); + + list_supported_targets (program_name, stream); + if (exit_status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); exit (exit_status); } -/* Parse a string into a VMA, with a fatal error if it can't be - parsed. */ - -static bfd_vma -parse_vma (s, arg) - const char *s; - const char *arg; -{ - bfd_vma ret; - const char *end; - - ret = bfd_scan_vma (s, &end, 0); - if (*end != '\0') - { - fprintf (stderr, "%s: %s: bad number: %s\n", program_name, arg, s); - exit (1); - } - return ret; -} - /* Parse section flags into a flagword, with a fatal error if the string can't be parsed. */ @@ -294,14 +430,31 @@ parse_flags (s) ++snext; } -#define PARSE_FLAG(fname,fval) if (strncmp (fname, s, len) == 0) ret |= fval; + if (0) ; +#define PARSE_FLAG(fname,fval) \ + else if (strncasecmp (fname, s, len) == 0) ret |= fval PARSE_FLAG ("alloc", SEC_ALLOC); PARSE_FLAG ("load", SEC_LOAD); + PARSE_FLAG ("noload", SEC_NEVER_LOAD); PARSE_FLAG ("readonly", SEC_READONLY); + PARSE_FLAG ("debug", SEC_DEBUGGING); PARSE_FLAG ("code", SEC_CODE); PARSE_FLAG ("data", SEC_DATA); PARSE_FLAG ("rom", SEC_ROM); + PARSE_FLAG ("share", SEC_SHARED); + PARSE_FLAG ("contents", SEC_HAS_CONTENTS); #undef PARSE_FLAG + else + { + char *copy; + + copy = 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"); + } s = snext; } @@ -310,36 +463,7 @@ parse_flags (s) return ret; } -/* Return the name of a temporary file in the same directory as FILENAME. */ - -static char * -make_tempname (filename) - char *filename; -{ - static char template[] = "stXXXXXX"; - char *tmpname; - char *slash = strrchr (filename, '/'); - - if (slash != (char *) NULL) - { - *slash = 0; - tmpname = xmalloc (strlen (filename) + sizeof (template) + 1); - strcpy (tmpname, filename); - strcat (tmpname, "/"); - strcat (tmpname, template); - mktemp (tmpname); - *slash = '/'; - } - else - { - tmpname = xmalloc (sizeof (template)); - strcpy (tmpname, template); - mktemp (tmpname); - } - return tmpname; -} - -/* Find and optionally add an entry in the adjust_sections list. */ +/* Find and optionally add an entry in the change_sections list. */ static struct section_list * find_section_list (name, add) @@ -348,7 +472,7 @@ find_section_list (name, add) { register struct section_list *p; - for (p = adjust_sections; p != NULL; p = p->next) + for (p = change_sections; p != NULL; p = p->next) if (strcmp (p->name, name) == 0) return p; @@ -359,48 +483,46 @@ find_section_list (name, add) p->name = name; p->used = false; p->remove = false; - p->adjust = ignore_vma; - p->val = 0; + p->copy = false; + p->change_vma = CHANGE_IGNORE; + p->change_lma = CHANGE_IGNORE; + p->vma_val = 0; + p->lma_val = 0; p->set_flags = false; p->flags = 0; - p->next = adjust_sections; - adjust_sections = p; + p->next = change_sections; + change_sections = p; return p; } -/* Make a list of symbols to explicitly strip out. A linked list is - good enough for a small number from the command line, but this will - slow things down a lot if many symbols are being deleted. */ +/* Add a symbol to strip_specific_list. */ -struct symlist -{ - const char *name; - struct symlist *next; -}; - -static struct symlist *strip_specific_list = NULL; - -static void -add_strip_symbol (name) +static void +add_specific_symbol (name, list) const char *name; + struct symlist **list; { struct symlist *tmp_list; tmp_list = (struct symlist *) xmalloc (sizeof (struct symlist)); tmp_list->name = name; - tmp_list->next = strip_specific_list; - strip_specific_list = tmp_list; + tmp_list->next = *list; + *list = tmp_list; } +/* See whether a symbol should be stripped or kept based on + strip_specific_list and keep_symbols. */ + static boolean -is_strip_symbol (name) +is_specified_symbol (name, list) const char *name; + struct symlist *list; { struct symlist *tmp_list; - for (tmp_list = strip_specific_list; tmp_list; tmp_list = tmp_list->next) + for (tmp_list = list; tmp_list; tmp_list = tmp_list->next) { if (strcmp (name, tmp_list->name) == 0) return true; @@ -412,15 +534,28 @@ is_strip_symbol (name) static boolean is_strip_section (abfd, sec) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; asection *sec; { struct section_list *p; - if (! sections_removed) + if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0 + && (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_UNNEEDED + || strip_symbols == STRIP_ALL + || discard_locals == LOCALS_ALL + || convert_debugging)) + return true; + + if (! sections_removed && ! sections_copied) return false; + p = find_section_list (bfd_get_section_name (abfd, sec), false); - return p != NULL && p->remove ? true : false; + if (sections_removed && p != NULL && p->remove) + return true; + if (sections_copied && (p == NULL || ! p->copy)) + return true; + return false; } /* Choose which symbol entries to copy; put the result in OSYMS. @@ -428,48 +563,179 @@ is_strip_section (abfd, sec) Return the number of symbols to print. */ static unsigned int -filter_symbols (abfd, osyms, isyms, symcount) +filter_symbols (abfd, obfd, osyms, isyms, symcount) bfd *abfd; + bfd *obfd; asymbol **osyms, **isyms; long symcount; { register asymbol **from = isyms, **to = osyms; long src_count = 0, dst_count = 0; + int relocatable = (abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC)) + == HAS_RELOC; for (; src_count < symcount; src_count++) { asymbol *sym = from[src_count]; flagword flags = sym->flags; + const char *name = bfd_asymbol_name (sym); int keep; - if ((flags & BSF_GLOBAL) /* Keep if external. */ - || (flags & BSF_KEEP) /* Keep if used in a relocation. */ - || bfd_is_und_section (bfd_get_section (sym)) - || bfd_is_com_section (bfd_get_section (sym))) + if (redefine_sym_list) + { + const char *old_name, *new_name; + + old_name = bfd_asymbol_name (sym); + new_name = lookup_sym_redefinition (old_name); + name = bfd_asymbol_name (sym) = new_name; + } + + if (change_leading_char + && (bfd_get_symbol_leading_char (abfd) + != bfd_get_symbol_leading_char (obfd)) + && (bfd_get_symbol_leading_char (abfd) == '\0' + || (name[0] == bfd_get_symbol_leading_char (abfd)))) + { + if (bfd_get_symbol_leading_char (obfd) == '\0') + name = bfd_asymbol_name (sym) = name + 1; + else + { + char *n; + + n = xmalloc (strlen (name) + 2); + n[0] = bfd_get_symbol_leading_char (obfd); + if (bfd_get_symbol_leading_char (abfd) == '\0') + strcpy (n + 1, name); + else + strcpy (n + 1, name + 1); + name = bfd_asymbol_name (sym) = n; + } + } + + if (remove_leading_char + && ((flags & BSF_GLOBAL) != 0 + || (flags & BSF_WEAK) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym))) + && name[0] == bfd_get_symbol_leading_char (abfd)) + name = bfd_asymbol_name (sym) = name + 1; + + if (strip_symbols == STRIP_ALL) + keep = 0; + else if ((flags & BSF_KEEP) != 0 /* Used in relocation. */ + || ((flags & BSF_SECTION_SYM) != 0 + && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags + & BSF_KEEP) != 0)) keep = 1; + else if (relocatable /* Relocatable file. */ + && (flags & (BSF_GLOBAL | BSF_WEAK)) != 0) + keep = 1; + else if ((flags & BSF_GLOBAL) != 0 /* Global symbol. */ + || (flags & BSF_WEAK) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym))) + keep = strip_symbols != STRIP_UNNEEDED; else if ((flags & BSF_DEBUGGING) != 0) /* Debugging symbol. */ - keep = strip_symbols != strip_debug; + keep = (strip_symbols != STRIP_DEBUG + && strip_symbols != STRIP_UNNEEDED + && ! convert_debugging); else /* Local symbol. */ - keep = discard_locals != locals_all - && (discard_locals != locals_start_L || - ! bfd_is_local_label (abfd, sym)); + keep = (strip_symbols != STRIP_UNNEEDED + && (discard_locals != LOCALS_ALL + && (discard_locals != LOCALS_START_L + || ! bfd_is_local_label (abfd, sym)))); - if (keep && is_strip_symbol (bfd_asymbol_name (sym))) + if (keep && is_specified_symbol (name, strip_specific_list)) keep = 0; + if (!keep && is_specified_symbol (name, keep_specific_list)) + keep = 1; if (keep && is_strip_section (abfd, bfd_get_section (sym))) keep = 0; + if (keep && (flags & BSF_GLOBAL) != 0 + && (weaken || is_specified_symbol (name, weaken_specific_list))) + { + sym->flags &=~ BSF_GLOBAL; + sym->flags |= BSF_WEAK; + } + if (keep && (flags & (BSF_GLOBAL | BSF_WEAK)) + && is_specified_symbol (name, localize_specific_list)) + { + sym->flags &= ~(BSF_GLOBAL | BSF_WEAK); + sym->flags |= BSF_LOCAL; + } + if (keep) to[dst_count++] = sym; } + to[dst_count] = NULL; + return dst_count; } +static const char * +lookup_sym_redefinition (source) + const char *source; +{ + const char *result; + struct redefine_node *list; + + result = source; + + for (list = redefine_sym_list; list != NULL; list = list->next) + { + if (strcmp (source, list->source) == 0) + { + result = list->target; + break; + } + } + return result; +} + +/* Add a node to a symbol redefine list */ + +static void +redefine_list_append (source, target) + const char *source; + const char *target; +{ + struct redefine_node **p; + struct redefine_node *list; + struct redefine_node *new_node; + + for (p = &redefine_sym_list; (list = *p) != NULL; p = &list->next) + { + if (strcmp (source, list->source) == 0) + { + fatal (_("%s: Multiple redefinition of symbol \"%s\""), + "--redefine-sym", + source); + } + + if (strcmp (target, list->target) == 0) + { + fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"), + "--redefine-sym", + target); + } + } + + new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node)); + + new_node->source = strdup (source); + new_node->target = strdup (target); + new_node->next = NULL; + + *p = new_node; +} + + /* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long. Adjust *SIZE. */ -void +static void filter_bytes (memhunk, size) char *memhunk; bfd_size_type *size; @@ -478,7 +744,10 @@ filter_bytes (memhunk, size) for (; from < end; from += interleave) *to++ = *from; - *size /= interleave; + if (*size % interleave > (bfd_size_type) copy_byte) + *size = (*size / interleave) + 1; + else + *size /= interleave; } /* Copy object file IBFD onto OBFD. */ @@ -493,50 +762,47 @@ copy_object (ibfd, obfd) asection **osections = NULL; bfd_size_type *gaps = NULL; bfd_size_type max_gap = 0; + long symsize; + PTR dhandle; + if (!bfd_set_format (obfd, bfd_get_format (ibfd))) - { - nonfatal (bfd_get_filename (obfd)); - } + RETURN_NONFATAL (bfd_get_filename (obfd)); if (verbose) - printf ("copy from %s(%s) to %s(%s)\n", - bfd_get_filename(ibfd), bfd_get_target(ibfd), - bfd_get_filename(obfd), bfd_get_target(obfd)); + printf (_("copy from %s(%s) to %s(%s)\n"), + bfd_get_filename (ibfd), bfd_get_target (ibfd), + bfd_get_filename (obfd), bfd_get_target (obfd)); if (set_start_set) start = set_start; else start = bfd_get_start_address (ibfd); - start += adjust_start; + start += change_start; if (!bfd_set_start_address (obfd, start) || !bfd_set_file_flags (obfd, (bfd_get_file_flags (ibfd) & bfd_applicable_file_flags (obfd)))) - { - nonfatal (bfd_get_filename (ibfd)); - } + RETURN_NONFATAL (bfd_get_filename (ibfd)); /* Copy architecture of input file to output file */ if (!bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd))) - { - fprintf (stderr, "Output file cannot represent architecture %s\n", + non_fatal (_("Warning: Output file cannot represent architecture %s"), bfd_printable_arch_mach (bfd_get_arch (ibfd), bfd_get_mach (ibfd))); - } + if (!bfd_set_format (obfd, bfd_get_format (ibfd))) - { - nonfatal (bfd_get_filename(ibfd)); - } + RETURN_NONFATAL (bfd_get_filename (ibfd)); if (isympp) free (isympp); + if (osympp != isympp) free (osympp); - /* bfd mandates that all output sections be created and sizes set before + /* BFD mandates that all output sections be created and sizes set before any output is done. Thus, we traverse all sections multiple times. */ bfd_map_over_sections (ibfd, setup_section, (void *) obfd); @@ -550,18 +816,17 @@ copy_object (ibfd, obfd) padd->section = bfd_make_section (obfd, padd->name); if (padd->section == NULL) { - fprintf (stderr, "%s: can't create section `%s': %s\n", - program_name, padd->name, - bfd_errmsg (bfd_get_error ())); + non_fatal (_("can't create section `%s': %s"), + padd->name, bfd_errmsg (bfd_get_error ())); status = 1; return; } else { flagword flags; - + if (! bfd_set_section_size (obfd, padd->section, padd->size)) - nonfatal (bfd_get_filename (obfd)); + RETURN_NONFATAL (bfd_get_filename (obfd)); pset = find_section_list (padd->name, false); if (pset != NULL) @@ -571,15 +836,25 @@ copy_object (ibfd, obfd) flags = pset->flags | SEC_HAS_CONTENTS; else flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA; + if (! bfd_set_section_flags (obfd, padd->section, flags)) - nonfatal (bfd_get_filename (obfd)); + RETURN_NONFATAL (bfd_get_filename (obfd)); - if (pset != NULL - && (pset->adjust == adjust_vma - || pset->adjust == set_vma)) + if (pset != NULL) { - if (! bfd_set_section_vma (obfd, padd->section, pset->val)) - nonfatal (bfd_get_filename (obfd)); + if (pset->change_vma != CHANGE_IGNORE) + if (! bfd_set_section_vma (obfd, padd->section, pset->vma_val)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + if (pset->change_lma != CHANGE_IGNORE) + { + padd->section->lma = pset->lma_val; + + if (! bfd_set_section_alignment + (obfd, padd->section, + bfd_section_alignment (obfd, padd->section))) + RETURN_NONFATAL (bfd_get_filename (obfd)); + } } } } @@ -601,7 +876,7 @@ copy_object (ibfd, obfd) set = osections; bfd_map_over_sections (obfd, get_sections, (void *) &set); - qsort (osections, c, sizeof (asection *), compare_section_vma); + qsort (osections, c, sizeof (asection *), compare_section_lma); gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type)); memset (gaps, 0, c * sizeof (bfd_size_type)); @@ -620,17 +895,16 @@ copy_object (ibfd, obfd) continue; size = bfd_section_size (obfd, osections[i]); - gap_start = bfd_section_vma (obfd, osections[i]) + size; - gap_stop = bfd_section_vma (obfd, osections[i + 1]); + gap_start = bfd_section_lma (obfd, osections[i]) + size; + gap_stop = bfd_section_lma (obfd, osections[i + 1]); if (gap_start < gap_stop) { if (! bfd_set_section_size (obfd, osections[i], size + (gap_stop - gap_start))) { - fprintf (stderr, "%s: Can't fill gap after %s: %s\n", - program_name, + non_fatal (_("Can't fill gap after %s: %s"), bfd_get_section_name (obfd, osections[i]), - bfd_errmsg (bfd_get_error())); + bfd_errmsg (bfd_get_error ())); status = 1; break; } @@ -643,74 +917,84 @@ copy_object (ibfd, obfd) if (pad_to_set) { - bfd_vma vma; + bfd_vma lma; bfd_size_type size; - vma = bfd_section_vma (obfd, osections[c - 1]); + lma = bfd_section_lma (obfd, osections[c - 1]); size = bfd_section_size (obfd, osections[c - 1]); - if (vma + size < pad_to) + if (lma + size < pad_to) { if (! bfd_set_section_size (obfd, osections[c - 1], - pad_to - vma)) + pad_to - lma)) { - fprintf (stderr, "%s: Can't add padding to %s: %s\n", - program_name, + non_fatal (_("Can't add padding to %s: %s"), bfd_get_section_name (obfd, osections[c - 1]), bfd_errmsg (bfd_get_error ())); status = 1; } else { - gaps[c - 1] = pad_to - (vma + size); - if (max_gap < pad_to - (vma + size)) - max_gap = pad_to - (vma + size); + gaps[c - 1] = pad_to - (lma + size); + if (max_gap < pad_to - (lma + size)) + max_gap = pad_to - (lma + size); } } - } + } } /* Symbol filtering must happen after the output sections have been created, but before their contents are set. */ - if (strip_symbols == strip_all && discard_locals == locals_undef) + dhandle = NULL; + symsize = bfd_get_symtab_upper_bound (ibfd); + if (symsize < 0) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + osympp = isympp = (asymbol **) xmalloc (symsize); + symcount = bfd_canonicalize_symtab (ibfd, isympp); + if (symcount < 0) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + if (convert_debugging) + dhandle = read_debugging_info (ibfd, isympp, symcount); + + if (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_ALL + || strip_symbols == STRIP_UNNEEDED + || discard_locals != LOCALS_UNDEF + || strip_specific_list != NULL + || keep_specific_list != NULL + || localize_specific_list != NULL + || weaken_specific_list != NULL + || sections_removed + || sections_copied + || convert_debugging + || change_leading_char + || remove_leading_char + || redefine_sym_list + || weaken) { - osympp = isympp = NULL; - symcount = 0; + /* Mark symbols used in output relocations so that they + are kept, even if they are local labels or static symbols. + + Note we iterate over the input sections examining their + relocations since the relocations for the output sections + haven't been set yet. mark_symbols_used_in_relocations will + ignore input sections which have no corresponding output + section. */ + if (strip_symbols != STRIP_ALL) + bfd_map_over_sections (ibfd, + mark_symbols_used_in_relocations, + (PTR)isympp); + osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *)); + symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount); } - else - { - long symsize; - symsize = bfd_get_symtab_upper_bound (ibfd); - if (symsize < 0) - { - nonfatal (bfd_get_filename (ibfd)); - } - - osympp = isympp = (asymbol **) xmalloc (symsize); - symcount = bfd_canonicalize_symtab (ibfd, isympp); - if (symcount < 0) - { - nonfatal (bfd_get_filename (ibfd)); - } - - if (strip_symbols == strip_debug - || discard_locals != locals_undef - || strip_specific_list - || sections_removed) + if (convert_debugging && dhandle != NULL) + { + if (! write_debugging_info (obfd, dhandle, &symcount, &osympp)) { - /* Mark symbols used in output relocations so that they - are kept, even if they are local labels or static symbols. - - Note we iterate over the input sections examining their - relocations since the relocations for the output sections - haven't been set yet. mark_symbols_used_in_relocations will - ignore input sections which have no corresponding output - section. */ - bfd_map_over_sections (ibfd, - mark_symbols_used_in_relocations, - (PTR)isympp); - osympp = (asymbol **) xmalloc (symcount * sizeof (asymbol *)); - symcount = filter_symbols (ibfd, osympp, isympp, symcount); + status = 1; + return; } } @@ -729,7 +1013,7 @@ copy_object (ibfd, obfd) (PTR) padd->contents, (file_ptr) 0, (bfd_size_type) padd->size)) - nonfatal (bfd_get_filename (obfd)); + RETURN_NONFATAL (bfd_get_filename (obfd)); } } @@ -743,7 +1027,7 @@ copy_object (ibfd, obfd) if (max_gap > 8192) max_gap = 8192; buf = (bfd_byte *) xmalloc (max_gap); - memset (buf, gap_fill, max_gap); + memset (buf, gap_fill, (size_t) max_gap); c = bfd_count_sections (obfd); for (i = 0; i < c; i++) @@ -763,11 +1047,11 @@ copy_object (ibfd, obfd) now = 8192; else now = left; + if (! bfd_set_section_contents (obfd, osections[i], buf, off, now)) - { - nonfatal (bfd_get_filename (obfd)); - } + RETURN_NONFATAL (bfd_get_filename (obfd)); + left -= now; off += now; } @@ -781,29 +1065,14 @@ copy_object (ibfd, obfd) important for the ECOFF code at least. */ if (!bfd_copy_private_bfd_data (ibfd, obfd)) { - fprintf (stderr, "%s: %s: error copying private BFD data: %s\n", - program_name, bfd_get_filename (obfd), - bfd_errmsg (bfd_get_error ())); + non_fatal (_("%s: error copying private BFD data: %s"), + bfd_get_filename (obfd), + bfd_errmsg (bfd_get_error ())); status = 1; return; } } -static char * -cat (a, b, c) - char *a; - char *b; - char *c; -{ - size_t size = strlen (a) + strlen (b) + strlen (c); - char *r = xmalloc (size + 1); - - strcpy (r, a); - strcat (r, b); - strcat (r, c); - return r; -} - /* Read each archive element in turn from IBFD, copy the contents to temp file, and keep the temp file handle. */ @@ -811,30 +1080,50 @@ static void copy_archive (ibfd, obfd, output_target) bfd *ibfd; bfd *obfd; - char *output_target; + const char *output_target; { struct name_list { struct name_list *next; char *name; + bfd *obfd; } *list, *l; bfd **ptr = &obfd->archive_head; bfd *this_element; char *dir = make_tempname (bfd_get_filename (obfd)); /* Make a temp directory to hold the contents. */ - mkdir (dir, 0700); +#if defined (_WIN32) && !defined (__CYGWIN32__) + if (mkdir (dir) != 0) +#else + if (mkdir (dir, 0700) != 0) +#endif + { + fatal (_("cannot mkdir %s for archive copying (error: %s)"), + dir, strerror (errno)); + } obfd->has_armap = ibfd->has_armap; list = NULL; this_element = bfd_openr_next_archived_file (ibfd, NULL); - while (this_element != (bfd *) NULL) + while (!status && this_element != (bfd *) NULL) { /* Create an output file for this member. */ - char *output_name = cat (dir, "/", bfd_get_filename(this_element)); + char *output_name = concat (dir, "/", bfd_get_filename (this_element), + (char *) NULL); bfd *output_bfd = bfd_openw (output_name, output_target); bfd *last_element; + struct stat buf; + int stat_status = 0; + + if (preserve_dates) + { + stat_status = bfd_stat_arch_elt (this_element, &buf); + if (stat_status != 0) + non_fatal (_("internal stat error on %s"), + bfd_get_filename (this_element)); + } l = (struct name_list *) xmalloc (sizeof (struct name_list)); l->name = output_name; @@ -842,24 +1131,29 @@ copy_archive (ibfd, obfd, output_target) list = l; if (output_bfd == (bfd *) NULL) - { - nonfatal (output_name); - } + RETURN_NONFATAL (output_name); + if (!bfd_set_format (obfd, bfd_get_format (ibfd))) - { - nonfatal (bfd_get_filename (obfd)); - } + RETURN_NONFATAL (bfd_get_filename (obfd)); if (bfd_check_format (this_element, bfd_object) == true) + copy_object (this_element, output_bfd); + + if (!bfd_close (output_bfd)) { - copy_object (this_element, output_bfd); + bfd_nonfatal (bfd_get_filename (output_bfd)); + /* Error in new object file. Don't change archive. */ + status = 1; } - bfd_close (output_bfd); + if (preserve_dates && stat_status == 0) + set_times (output_name, &buf); /* Open the newly output file and attach to our list. */ output_bfd = bfd_openr (output_name, output_target); + l->obfd = output_bfd; + *ptr = output_bfd; ptr = &output_bfd->next; @@ -872,29 +1166,28 @@ copy_archive (ibfd, obfd, output_target) *ptr = (bfd *) NULL; if (!bfd_close (obfd)) - { - nonfatal (bfd_get_filename (obfd)); - } + RETURN_NONFATAL (bfd_get_filename (obfd)); + + if (!bfd_close (ibfd)) + RETURN_NONFATAL (bfd_get_filename (ibfd)); /* Delete all the files that we opened. */ for (l = list; l != NULL; l = l->next) - unlink (l->name); - rmdir (dir); - - if (!bfd_close (ibfd)) { - nonfatal (bfd_get_filename (ibfd)); + bfd_close (l->obfd); + unlink (l->name); } + rmdir (dir); } /* The top-level control. */ static void copy_file (input_filename, output_filename, input_target, output_target) - char *input_filename; - char *output_filename; - char *input_target; - char *output_target; + const char *input_filename; + const char *output_filename; + const char *input_target; + const char *output_target; { bfd *ibfd; char **matching; @@ -904,9 +1197,7 @@ copy_file (input_filename, output_filename, input_target, output_target) ibfd = bfd_openr (input_filename, input_target); if (ibfd == NULL) - { - nonfatal (input_filename); - } + RETURN_NONFATAL (input_filename); if (bfd_check_format (ibfd, bfd_archive)) { @@ -919,9 +1210,8 @@ copy_file (input_filename, output_filename, input_target, output_target) obfd = bfd_openw (output_filename, output_target); if (obfd == NULL) - { - nonfatal (output_filename); - } + RETURN_NONFATAL (output_filename); + copy_archive (ibfd, obfd, output_target); } else if (bfd_check_format_matches (ibfd, bfd_object, &matching)) @@ -935,30 +1225,26 @@ copy_file (input_filename, output_filename, input_target, output_target) obfd = bfd_openw (output_filename, output_target); if (obfd == NULL) - { - nonfatal (output_filename); - } + RETURN_NONFATAL (output_filename); copy_object (ibfd, obfd); if (!bfd_close (obfd)) - { - nonfatal (output_filename); - } + RETURN_NONFATAL (output_filename); if (!bfd_close (ibfd)) - { - nonfatal (input_filename); - } + RETURN_NONFATAL (input_filename); } else { bfd_nonfatal (input_filename); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) { list_matching_formats (matching); free (matching); } + status = 1; } } @@ -975,57 +1261,83 @@ setup_section (ibfd, isection, obfdarg) bfd *obfd = (bfd *) obfdarg; struct section_list *p; sec_ptr osection; + bfd_size_type size; bfd_vma vma; + bfd_vma lma; flagword flags; - char *err; + const char *err; if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0 - && (strip_symbols == strip_debug - || strip_symbols == strip_all - || discard_locals == locals_all)) + && (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_UNNEEDED + || strip_symbols == STRIP_ALL + || discard_locals == LOCALS_ALL + || convert_debugging)) return; p = find_section_list (bfd_section_name (ibfd, isection), false); if (p != NULL) p->used = true; - if (p != NULL && p->remove) + if (sections_removed && p != NULL && p->remove) + return; + if (sections_copied && (p == NULL || ! p->copy)) return; osection = bfd_make_section_anyway (obfd, bfd_section_name (ibfd, isection)); + if (osection == NULL) { - err = "making"; + err = _("making"); goto loser; } - if (!bfd_set_section_size (obfd, - osection, - bfd_section_size (ibfd, isection))) + size = bfd_section_size (ibfd, isection); + if (copy_byte >= 0) + size = (size + interleave - 1) / interleave; + if (! bfd_set_section_size (obfd, osection, size)) { - err = "size"; + err = _("size"); goto loser; } vma = bfd_section_vma (ibfd, isection); - if (p != NULL && p->adjust == adjust_vma) - vma += p->val; - else if (p != NULL && p->adjust == set_vma) - vma = p->val; + 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; else - vma += adjust_section_vma; + vma += change_section_address; + if (! bfd_set_section_vma (obfd, osection, vma)) { - err = "vma"; + err = _("vma"); goto loser; } + lma = isection->lma; + if ((p != NULL) && p->change_lma != CHANGE_IGNORE) + { + if (p->change_lma == CHANGE_MODIFY) + lma += p->lma_val; + else if (p->change_lma == CHANGE_SET) + lma = p->lma_val; + else + abort (); + } + else + lma += change_section_address; + + osection->lma = lma; + + /* FIXME: This is probably not enough. If we change the LMA we + may have to recompute the header for the file as well. */ if (bfd_set_section_alignment (obfd, osection, bfd_section_alignment (ibfd, isection)) == false) { - err = "alignment"; + err = _("alignment"); goto loser; } @@ -1034,7 +1346,7 @@ setup_section (ibfd, isection, obfdarg) flags = p->flags | (flags & SEC_HAS_CONTENTS); if (!bfd_set_section_flags (obfd, osection, flags)) { - err = "flags"; + err = _("flags"); goto loser; } @@ -1048,7 +1360,7 @@ setup_section (ibfd, isection, obfdarg) from the input section to the output section. */ if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection)) { - err = "private data"; + err = _("private data"); goto loser; } @@ -1056,10 +1368,10 @@ setup_section (ibfd, isection, obfdarg) return; loser: - fprintf (stderr, "%s: %s: section `%s': error in %s: %s\n", - program_name, - bfd_get_filename (ibfd), bfd_section_name (ibfd, isection), - err, bfd_errmsg (bfd_get_error ())); + non_fatal (_("%s: section `%s': error in %s: %s"), + bfd_get_filename (ibfd), + bfd_section_name (ibfd, isection), + err, bfd_errmsg (bfd_get_error ())); status = 1; } @@ -1079,18 +1391,28 @@ copy_section (ibfd, isection, obfdarg) long relcount; sec_ptr osection; bfd_size_type size; + long relsize; + + /* If we have already failed earlier on, do not keep on generating + complaints now. */ + if (status != 0) + return; if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0 - && (strip_symbols == strip_debug - || strip_symbols == strip_all - || discard_locals == locals_all)) + && (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_UNNEEDED + || strip_symbols == STRIP_ALL + || discard_locals == LOCALS_ALL + || convert_debugging)) { return; } p = find_section_list (bfd_section_name (ibfd, isection), false); - if (p != NULL && p->remove) + if (sections_removed && p != NULL && p->remove) + return; + if (sections_copied && (p == NULL || ! p->copy)) return; osection = isection->output_section; @@ -1099,29 +1421,40 @@ copy_section (ibfd, isection, obfdarg) if (size == 0 || osection == 0) return; - if (strip_symbols == strip_all) + + relsize = bfd_get_reloc_upper_bound (ibfd, isection); + if (relsize < 0) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + if (relsize == 0) bfd_set_reloc (obfd, osection, (arelent **) NULL, 0); else { - long relsize; + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp); + if (relcount < 0) + RETURN_NONFATAL (bfd_get_filename (ibfd)); - relsize = bfd_get_reloc_upper_bound (ibfd, isection); - if (relsize < 0) - { - nonfatal (bfd_get_filename (ibfd)); - } - if (relsize == 0) - bfd_set_reloc (obfd, osection, (arelent **) NULL, 0); - else + if (strip_symbols == STRIP_ALL) { - relpp = (arelent **) xmalloc (relsize); - relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp); - if (relcount < 0) - { - nonfatal (bfd_get_filename (ibfd)); - } - bfd_set_reloc (obfd, osection, relpp, relcount); + /* Remove relocations which are not in + keep_strip_specific_list. */ + arelent **temp_relpp; + long temp_relcount = 0; + long i; + + temp_relpp = (arelent **) xmalloc (relsize); + for (i = 0; i < relcount; i++) + if (is_specified_symbol + (bfd_asymbol_name (*relpp [i]->sym_ptr_ptr), + keep_specific_list)) + temp_relpp [temp_relcount++] = relpp [i]; + relcount = temp_relcount; + free (relpp); + relpp = temp_relpp; } + bfd_set_reloc (obfd, osection, + (relcount == 0 ? (arelent **) NULL : relpp), relcount); } isection->_cooked_size = isection->_raw_size; @@ -1133,23 +1466,31 @@ copy_section (ibfd, isection, obfdarg) if (!bfd_get_section_contents (ibfd, isection, memhunk, (file_ptr) 0, size)) - { - nonfatal (bfd_get_filename (ibfd)); - } + RETURN_NONFATAL (bfd_get_filename (ibfd)); - if (copy_byte >= 0) - { - filter_bytes (memhunk, &size); - /* The section has gotten smaller. */ - if (!bfd_set_section_size (obfd, osection, size)) - nonfatal (bfd_get_filename (obfd)); - } + if (copy_byte >= 0) + filter_bytes (memhunk, &size); if (!bfd_set_section_contents (obfd, osection, memhunk, (file_ptr) 0, size)) - { - nonfatal (bfd_get_filename (obfd)); - } + RETURN_NONFATAL (bfd_get_filename (obfd)); + + free (memhunk); + } + else if (p != NULL && p->set_flags && (p->flags & SEC_HAS_CONTENTS) != 0) + { + PTR memhunk = (PTR) xmalloc ((unsigned) size); + + /* We don't permit the user to turn off the SEC_HAS_CONTENTS + flag--they can just remove the section entirely and add it + back again. However, we do permit them to turn on the + SEC_HAS_CONTENTS flag, and take it to mean that the section + contents should be zeroed out. */ + + memset (memhunk, 0, size); + if (! bfd_set_section_contents (obfd, osection, memhunk, (file_ptr) 0, + size)) + RETURN_NONFATAL (bfd_get_filename (obfd)); free (memhunk); } } @@ -1159,7 +1500,7 @@ copy_section (ibfd, isection, obfdarg) static void get_sections (obfd, osection, secppparg) - bfd *obfd; + bfd *obfd ATTRIBUTE_UNUSED; asection *osection; PTR secppparg; { @@ -1174,7 +1515,7 @@ get_sections (obfd, osection, secppparg) sections to the front, where they are easier to ignore. */ static int -compare_section_vma (arg1, arg2) +compare_section_lma (arg1, arg2) const PTR arg1; const PTR arg2; { @@ -1199,13 +1540,13 @@ compare_section_vma (arg1, arg2) return 1; } - /* Sort sections by VMA. */ - if ((*sec1)->vma > (*sec2)->vma) + /* Sort sections by LMA. */ + if ((*sec1)->lma > (*sec2)->lma) return 1; - else if ((*sec1)->vma < (*sec2)->vma) + else if ((*sec1)->lma < (*sec2)->lma) return -1; - /* Sort sections with the same VMA by size. */ + /* Sort sections with the same LMA by size. */ if ((*sec1)->_raw_size > (*sec2)->_raw_size) return 1; else if ((*sec1)->_raw_size < (*sec2)->_raw_size) @@ -1238,6 +1579,9 @@ mark_symbols_used_in_relocations (ibfd, isection, symbolsarg) if (relsize < 0) bfd_fatal (bfd_get_filename (ibfd)); + if (relsize == 0) + return; + relpp = (arelent **) xmalloc (relsize); relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, symbols); if (relcount < 0) @@ -1257,86 +1601,74 @@ mark_symbols_used_in_relocations (ibfd, isection, symbolsarg) free (relpp); } -/* The number of bytes to copy at once. */ -#define COPY_BUF 8192 - -/* Copy file FROM to file TO, performing no translations. - Return 0 if ok, -1 if error. */ +/* Write out debugging information. */ -static int -simple_copy (from, to) - char *from, *to; +static boolean +write_debugging_info (obfd, dhandle, symcountp, symppp) + bfd *obfd; + PTR dhandle; + long *symcountp ATTRIBUTE_UNUSED; + asymbol ***symppp ATTRIBUTE_UNUSED; { - int fromfd, tofd, nread; - char buf[COPY_BUF]; + if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour) + return write_ieee_debugging_info (obfd, dhandle); - fromfd = open (from, O_RDONLY); - if (fromfd < 0) - return -1; - tofd = open (to, O_WRONLY | O_CREAT | O_TRUNC); - if (tofd < 0) - { - close (fromfd); - return -1; - } - while ((nread = read (fromfd, buf, sizeof buf)) > 0) + if (bfd_get_flavour (obfd) == bfd_target_coff_flavour + || bfd_get_flavour (obfd) == bfd_target_elf_flavour) { - if (write (tofd, buf, nread) != nread) + bfd_byte *syms, *strings; + bfd_size_type symsize, stringsize; + asection *stabsec, *stabstrsec; + + if (! write_stabs_in_sections_debugging_info (obfd, dhandle, &syms, + &symsize, &strings, + &stringsize)) + return false; + + stabsec = bfd_make_section (obfd, ".stab"); + stabstrsec = bfd_make_section (obfd, ".stabstr"); + if (stabsec == NULL + || stabstrsec == NULL + || ! bfd_set_section_size (obfd, stabsec, symsize) + || ! bfd_set_section_size (obfd, stabstrsec, stringsize) + || ! bfd_set_section_alignment (obfd, stabsec, 2) + || ! bfd_set_section_alignment (obfd, stabstrsec, 0) + || ! bfd_set_section_flags (obfd, stabsec, + (SEC_HAS_CONTENTS + | SEC_READONLY + | SEC_DEBUGGING)) + || ! bfd_set_section_flags (obfd, stabstrsec, + (SEC_HAS_CONTENTS + | SEC_READONLY + | SEC_DEBUGGING))) { - close (fromfd); - close (tofd); - return -1; + non_fatal (_("%s: can't create debugging section: %s"), + bfd_get_filename (obfd), + bfd_errmsg (bfd_get_error ())); + return false; } - } - close (fromfd); - close (tofd); - if (nread < 0) - return -1; - return 0; -} -#ifndef S_ISLNK -#ifdef S_IFLNK -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#else -#define S_ISLNK(m) 0 -#define lstat stat -#endif -#endif - -/* Rename FROM to TO, copying if TO is a link. - Assumes that TO already exists, because FROM is a temp file. - Return 0 if ok, -1 if error. */ - -static int -smart_rename (from, to) - char *from, *to; -{ - struct stat s; - int ret = 0; - - if (lstat (to, &s)) - return -1; - - /* Use rename only if TO is not a symbolic link and has - only one hard link. */ - if (!S_ISLNK (s.st_mode) && s.st_nlink == 1) - { - ret = rename (from, to); - if (ret == 0) + /* We can get away with setting the section contents now because + the next thing the caller is going to do is copy over the + real sections. We may someday have to split the contents + setting out of this function. */ + if (! bfd_set_section_contents (obfd, stabsec, syms, (file_ptr) 0, + symsize) + || ! bfd_set_section_contents (obfd, stabstrsec, strings, + (file_ptr) 0, stringsize)) { - /* Try to preserve the permission bits and ownership of TO. */ - chmod (to, s.st_mode & 07777); - chown (to, s.st_uid, s.st_gid); + non_fatal (_("%s: can't set debugging section contents: %s"), + bfd_get_filename (obfd), + bfd_errmsg (bfd_get_error ())); + return false; } + + return true; } - else - { - ret = simple_copy (from, to); - if (ret == 0) - unlink (from); - } - return ret; + + non_fatal (_("%s: don't know how to write debugging information for %s"), + bfd_get_filename (obfd), bfd_get_target (obfd)); + return false; } static int @@ -1348,8 +1680,9 @@ strip_main (argc, argv) boolean show_version = false; int c, i; struct section_list *p; + char *output_file = NULL; - while ((c = getopt_long (argc, argv, "I:O:F:R:sSgxXVvN:", + while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXVv", strip_options, (int *) 0)) != EOF) { switch (c) @@ -1369,20 +1702,33 @@ strip_main (argc, argv) sections_removed = true; break; case 's': - strip_symbols = strip_all; + strip_symbols = STRIP_ALL; break; case 'S': case 'g': - strip_symbols = strip_debug; + case 'd': /* Historic BSD alias for -g. Used by early NetBSD. */ + strip_symbols = STRIP_DEBUG; + break; + case OPTION_STRIP_UNNEEDED: + strip_symbols = STRIP_UNNEEDED; + break; + case 'K': + add_specific_symbol (optarg, &keep_specific_list); break; case 'N': - add_strip_symbol (optarg); + add_specific_symbol (optarg, &strip_specific_list); + break; + case 'o': + output_file = optarg; + break; + case 'p': + preserve_dates = true; break; case 'x': - discard_locals = locals_all; + discard_locals = LOCALS_ALL; break; case 'X': - discard_locals = locals_start_L; + discard_locals = LOCALS_START_L; break; case 'v': verbose = true; @@ -1400,39 +1746,56 @@ strip_main (argc, argv) } if (show_version) - { - printf ("GNU %s version %s\n", program_name, program_version); - exit (0); - } + print_version ("strip"); /* Default is to strip all symbols. */ - if (strip_symbols == strip_undef - && discard_locals == locals_undef + if (strip_symbols == STRIP_UNDEF + && discard_locals == LOCALS_UNDEF && strip_specific_list == NULL) - strip_symbols = strip_all; + strip_symbols = STRIP_ALL; if (output_target == (char *) NULL) output_target = input_target; i = optind; - if (i == argc) + if (i == argc + || (output_file != NULL && (i + 1) < argc)) strip_usage (stderr, 1); for (; i < argc; i++) { int hold_status = status; + struct stat statbuf; + char *tmpname; - char *tmpname = make_tempname (argv[i]); + if (preserve_dates) + { + if (stat (argv[i], &statbuf) < 0) + { + non_fatal (_("%s: cannot stat: %s"), argv[i], strerror (errno)); + continue; + } + } + + if (output_file != NULL) + tmpname = output_file; + else + tmpname = make_tempname (argv[i]); status = 0; + copy_file (argv[i], tmpname, input_target, output_target); if (status == 0) { - smart_rename (tmpname, argv[i]); + if (preserve_dates) + set_times (tmpname, &statbuf); + if (output_file == NULL) + smart_rename (tmpname, argv[i], preserve_dates); status = hold_status; } else unlink (tmpname); - free (tmpname); + if (output_file == NULL) + free (tmpname); } return 0; @@ -1446,70 +1809,110 @@ copy_main (argc, argv) char *input_filename = NULL, *output_filename = NULL; char *input_target = NULL, *output_target = NULL; boolean show_version = false; - boolean adjust_warn = true; + boolean change_warn = true; int c; struct section_list *p; + struct stat statbuf; - while ((c = getopt_long (argc, argv, "b:i:I:s:O:d:F:R:SgxXVvN:", + while ((c = getopt_long (argc, argv, "b:i:I:j:K:N:s:O:d:F:L:R:SpgxXVvW:", copy_options, (int *) 0)) != EOF) { switch (c) { case 'b': - copy_byte = atoi(optarg); + copy_byte = atoi (optarg); if (copy_byte < 0) - { - fprintf (stderr, "%s: byte number must be non-negative\n", - program_name); - exit (1); - } + fatal (_("byte number must be non-negative")); break; + case 'i': - interleave = atoi(optarg); + interleave = atoi (optarg); if (interleave < 1) - { - fprintf(stderr, "%s: interleave must be positive\n", - program_name); - exit (1); - } + fatal (_("interleave must be positive")); break; + case 'I': case 's': /* "source" - 'I' is preferred */ input_target = optarg; break; + case 'O': case 'd': /* "destination" - 'O' is preferred */ output_target = optarg; break; + case 'F': input_target = output_target = optarg; break; + + case 'j': + p = find_section_list (optarg, true); + if (p->remove) + fatal (_("%s both copied and removed"), optarg); + p->copy = true; + sections_copied = true; + break; + case 'R': p = find_section_list (optarg, true); + if (p->copy) + fatal (_("%s both copied and removed"), optarg); p->remove = true; sections_removed = true; break; + case 'S': - strip_symbols = strip_all; + strip_symbols = STRIP_ALL; break; + case 'g': - strip_symbols = strip_debug; + strip_symbols = STRIP_DEBUG; + break; + + case OPTION_STRIP_UNNEEDED: + strip_symbols = STRIP_UNNEEDED; + break; + + case 'K': + add_specific_symbol (optarg, &keep_specific_list); break; + case 'N': - add_strip_symbol (optarg); + add_specific_symbol (optarg, &strip_specific_list); + break; + + case 'L': + add_specific_symbol (optarg, &localize_specific_list); break; + + case 'W': + add_specific_symbol (optarg, &weaken_specific_list); + break; + + case 'p': + preserve_dates = true; + break; + case 'x': - discard_locals = locals_all; + discard_locals = LOCALS_ALL; break; + case 'X': - discard_locals = locals_start_L; + discard_locals = LOCALS_START_L; break; + case 'v': verbose = true; break; + case 'V': show_version = true; break; + + case OPTION_WEAKEN: + weaken = true; + break; + case OPTION_ADD_SECTION: { const char *s; @@ -1520,20 +1923,12 @@ copy_main (argc, argv) FILE *f; s = strchr (optarg, '='); + if (s == NULL) - { - fprintf (stderr, - "%s: bad format for --add-section NAME=FILENAME\n", - program_name); - exit (1); - } + fatal (_("bad format for %s"), "--add-section"); - if (stat (s + 1, &st) < 0) - { - fprintf (stderr, "%s: ", program_name); - perror (s + 1); - exit (1); - } + if (stat (s + 1, & st) < 0) + fatal (_("cannot stat: %s: %s"), s + 1, strerror (errno)); pa = (struct section_add *) xmalloc (sizeof (struct section_add)); @@ -1547,35 +1942,50 @@ copy_main (argc, argv) pa->size = st.st_size; - pa->contents = xmalloc (pa->size); + pa->contents = (bfd_byte *) xmalloc (pa->size); f = fopen (pa->filename, FOPEN_RB); + if (f == NULL) - { - fprintf (stderr, "%s: ", program_name); - perror (pa->filename); - exit (1); - } + fatal (_("cannot open: %s: %s"), pa->filename, strerror (errno)); + if (fread (pa->contents, 1, pa->size, f) == 0 || ferror (f)) - { - fprintf (stderr, "%s: %s: fread failed\n", - program_name, pa->filename); - exit (1); - } + fatal (_("%s: fread failed"), pa->filename); + fclose (f); pa->next = add_sections; add_sections = pa; } break; - case OPTION_ADJUST_START: - adjust_start = parse_vma (optarg, "--adjust-start"); + + case OPTION_CHANGE_START: + change_start = parse_vma (optarg, "--change-start"); break; - case OPTION_ADJUST_SECTION_VMA: + + case OPTION_CHANGE_SECTION_ADDRESS: + case OPTION_CHANGE_SECTION_LMA: + case OPTION_CHANGE_SECTION_VMA: { 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"; + break; + case OPTION_CHANGE_SECTION_LMA: + option = "--change-section-lma"; + break; + case OPTION_CHANGE_SECTION_VMA: + option = "--change-section-vma"; + break; + } s = strchr (optarg, '='); if (s == NULL) @@ -1585,12 +1995,7 @@ copy_main (argc, argv) { s = strchr (optarg, '-'); if (s == NULL) - { - fprintf (stderr, - "%s: bad format for --adjust-section-vma\n", - program_name); - exit (1); - } + fatal (_("bad format for %s"), option); } } @@ -1601,25 +2006,52 @@ copy_main (argc, argv) p = find_section_list (name, true); - p->val = parse_vma (s + 1, "--adjust-section-vma"); + 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 == '=') - p->adjust = set_vma; - else + switch (c) { - p->adjust = adjust_vma; - if (*s == '-') - p->val = - p->val; + case OPTION_CHANGE_SECTION_ADDRESS: + p->change_vma = what; + p->vma_val = val; + /* Drop through. */ + + case OPTION_CHANGE_SECTION_LMA: + p->change_lma = what; + p->lma_val = val; + break; + + case OPTION_CHANGE_SECTION_VMA: + p->change_vma = what; + p->vma_val = val; + break; } } break; - case OPTION_ADJUST_VMA: - adjust_section_vma = parse_vma (optarg, "--adjust-vma"); - adjust_start = adjust_section_vma; + + case OPTION_CHANGE_ADDRESSES: + change_section_address = parse_vma (optarg, "--change-addresses"); + change_start = change_section_address; + break; + + case OPTION_CHANGE_WARNINGS: + change_warn = true; + break; + + case OPTION_CHANGE_LEADING_CHAR: + change_leading_char = true; break; - case OPTION_ADJUST_WARNINGS: - adjust_warn = true; + + case OPTION_DEBUGGING: + convert_debugging = true; break; + case OPTION_GAP_FILL: { bfd_vma gap_fill_vma; @@ -1628,21 +2060,62 @@ copy_main (argc, argv) gap_fill = (bfd_byte) gap_fill_vma; if ((bfd_vma) gap_fill != gap_fill_vma) { - fprintf (stderr, "%s: warning: truncating gap-fill from 0x", - program_name); - fprintf_vma (stderr, gap_fill_vma); - fprintf (stderr, "to 0x%x\n", (unsigned int) gap_fill); + char buff[20]; + + sprintf_vma (buff, gap_fill_vma); + + non_fatal (_("Warning: truncating gap-fill from 0x%s to 0x%x"), + buff, gap_fill); } gap_fill_set = true; } break; - case OPTION_NO_ADJUST_WARNINGS: - adjust_warn = false; + + case OPTION_NO_CHANGE_WARNINGS: + change_warn = false; break; + case OPTION_PAD_TO: pad_to = parse_vma (optarg, "--pad-to"); pad_to_set = true; break; + + case OPTION_REMOVE_LEADING_CHAR: + remove_leading_char = true; + break; + + case OPTION_REDEFINE_SYM: + { + /* Push this redefinition onto redefine_symbol_list. */ + + int len; + const char *s; + const char *nextarg; + char *source, *target; + + s = strchr (optarg, '='); + if (s == NULL) + { + fatal (_("bad format for %s"), "--redefine-sym"); + } + + len = s - optarg; + source = (char *) xmalloc (len + 1); + strncpy (source, optarg, len); + source[len] = '\0'; + + nextarg = s + 1; + len = strlen (nextarg); + target = (char *) xmalloc (len + 1); + strcpy (target, nextarg); + + redefine_list_append (source, target); + + free (source); + free (target); + } + break; + case OPTION_SET_SECTION_FLAGS: { const char *s; @@ -1651,11 +2124,7 @@ copy_main (argc, argv) s = strchr (optarg, '='); if (s == NULL) - { - fprintf (stderr, "%s: bad format for --set-section-flags\n", - program_name); - exit (1); - } + fatal (_("bad format for %s"), "--set-section-flags"); len = s - optarg; name = (char *) xmalloc (len + 1); @@ -1668,31 +2137,36 @@ copy_main (argc, argv) p->flags = parse_flags (s + 1); } break; + case OPTION_SET_START: set_start = parse_vma (optarg, "--set-start"); set_start_set = true; break; + + case OPTION_SREC_LEN: + Chunk = parse_vma (optarg, "--srec-len"); + break; + + case OPTION_SREC_FORCES3: + S3Forced = true; + break; + case 0: break; /* we've been given a long option */ + case 'h': copy_usage (stdout, 0); + default: copy_usage (stderr, 1); } } if (show_version) - { - printf ("GNU %s version %s\n", program_name, program_version); - exit (0); - } + print_version ("objcopy"); if (copy_byte >= interleave) - { - fprintf (stderr, "%s: byte number must be less than interleave\n", - program_name); - exit (1); - } + fatal (_("byte number must be less than interleave")); if (optind == argc || optind + 2 < argc) copy_usage (stderr, 1); @@ -1702,40 +2176,75 @@ copy_main (argc, argv) output_filename = argv[optind + 1]; /* Default is to strip no symbols. */ - if (strip_symbols == strip_undef && discard_locals == locals_undef) - strip_symbols = strip_none; + if (strip_symbols == STRIP_UNDEF && discard_locals == LOCALS_UNDEF) + strip_symbols = STRIP_NONE; if (output_target == (char *) NULL) output_target = input_target; + if (preserve_dates) + { + if (stat (input_filename, &statbuf) < 0) + fatal (_("Cannot stat: %s: %s"), input_filename, strerror (errno)); + } + /* If there is no destination file then create a temp and rename the result into the input. */ if (output_filename == (char *) NULL) { char *tmpname = make_tempname (input_filename); + copy_file (input_filename, tmpname, input_target, output_target); if (status == 0) - smart_rename (tmpname, input_filename); + { + if (preserve_dates) + set_times (tmpname, &statbuf); + smart_rename (tmpname, input_filename, preserve_dates); + } else unlink (tmpname); } else { copy_file (input_filename, output_filename, input_target, output_target); + if (status == 0 && preserve_dates) + set_times (output_filename, &statbuf); } - if (adjust_warn) + if (change_warn) { - for (p = adjust_sections; p != NULL; p = p->next) + for (p = change_sections; p != NULL; p = p->next) { - if (! p->used && p->adjust != ignore_vma) + if (! p->used) { - fprintf (stderr, "%s: warning: --adjust-section-vma %s%c0x", - program_name, p->name, - p->adjust == set_vma ? '=' : '+'); - fprintf_vma (stderr, p->val); - fprintf (stderr, " never used\n"); + if (p->change_vma != CHANGE_IGNORE) + { + char buff [20]; + + sprintf_vma (buff, p->vma_val); + + /* xgettext:c-format */ + non_fatal (_("%s %s%c0x%s never used"), + "--change-section-vma", + p->name, + p->change_vma == CHANGE_SET ? '=' : '+', + buff); + } + + if (p->change_lma != CHANGE_IGNORE) + { + char buff [20]; + + sprintf_vma (buff, p->lma_val); + + /* xgettext:c-format */ + non_fatal (_("%s %s%c0x%s never used"), + "--change-section-lma", + p->name, + p->change_lma == CHANGE_SET ? '=' : '+', + buff); + } } } } @@ -1748,20 +2257,35 @@ main (argc, argv) int argc; char *argv[]; { +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + program_name = argv[0]; xmalloc_set_program_name (program_name); START_PROGRESS (program_name, 0); - strip_symbols = strip_undef; - discard_locals = locals_undef; + strip_symbols = STRIP_UNDEF; + discard_locals = LOCALS_UNDEF; bfd_init (); + set_default_bfd_target (); if (is_strip < 0) { int i = strlen (program_name); - is_strip = (i >= 5 && strcmp (program_name + i - 5, "strip") == 0); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + /* Drop the .exe suffix, if any. */ + if (i > 4 && FILENAME_CMP (program_name + i - 4, ".exe") == 0) + { + i -= 4; + program_name[i] = '\0'; + } +#endif + is_strip = (i >= 5 && FILENAME_CMP (program_name + i - 5, "strip") == 0); } if (is_strip)