diff options
Diffstat (limited to 'binutils/objcopy.c')
-rw-r--r-- | binutils/objcopy.c | 2076 |
1 files changed, 0 insertions, 2076 deletions
diff --git a/binutils/objcopy.c b/binutils/objcopy.c deleted file mode 100644 index f2455baf650..00000000000 --- a/binutils/objcopy.c +++ /dev/null @@ -1,2076 +0,0 @@ -/* objcopy.c -- copy object file from input to output, optionally massaging it. - Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 1999 - Free Software Foundation, Inc. - - This file is part of GNU Binutils. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -#include "bfd.h" -#include "progress.h" -#include "bucomm.h" -#include "getopt.h" -#include "libiberty.h" -#include "budbg.h" -#include <sys/stat.h> - -/* A list of symbols to explicitly strip out, or to keep. A linked - list is good enough for a small number from the command line, but - this will slow things down a lot if many symbols are being - deleted. */ - -struct symlist -{ - const char *name; - struct symlist *next; -}; - -static void copy_usage PARAMS ((FILE *, int)); -static void strip_usage PARAMS ((FILE *, int)); -static flagword parse_flags PARAMS ((const 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_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 *, bfd *, asymbol **, asymbol **, long)); -static void mark_symbols_used_in_relocations PARAMS ((bfd *, asection *, PTR)); -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 **)); - -#define RETURN_NONFATAL(s) {bfd_nonfatal (s); status = 1; return;} - -static asymbol **isympp = NULL; /* Input symbols */ -static asymbol **osympp = NULL; /* Output symbols that survive stripping */ - -/* If `copy_byte' >= 0, copy only that byte of every `interleave' bytes. */ -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_UNNEEDED, /* strip unnecessary symbols */ - STRIP_ALL /* strip all symbols */ - }; - -/* Which symbols to remove. */ -static enum strip_action strip_symbols; - -enum locals_action - { - LOCALS_UNDEF, - LOCALS_START_L, /* discard locals starting with L */ - LOCALS_ALL /* discard all locals */ - }; - -/* Which local symbols to remove. Overrides STRIP_ALL. */ -static enum locals_action discard_locals; - -/* What kind of change to perform. */ -enum change_action -{ - CHANGE_IGNORE, - CHANGE_MODIFY, - CHANGE_SET -}; - -/* Structure used to hold lists of sections and actions to take. */ -struct section_list -{ - struct section_list * next; /* Next section to change. */ - const char * name; /* Section name. */ - 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 *change_sections; -static boolean sections_removed; -static boolean sections_copied; - -/* Changes to the start address. */ -static bfd_vma change_start = 0; -static boolean set_start_set = false; -static bfd_vma set_start; - -/* Changes to section addresses. */ -static bfd_vma change_section_address = 0; - -/* Filling gaps between sections. */ -static boolean gap_fill_set = false; -static bfd_byte gap_fill = 0; - -/* Pad to a given address. */ -static boolean pad_to_set = false; -static bfd_vma pad_to; - -/* List of sections to add. */ - -struct section_add -{ - /* Next section to add. */ - struct section_add *next; - /* Name of section to add. */ - const char *name; - /* Name of file holding section contents. */ - const char *filename; - /* Size of file. */ - size_t size; - /* Contents of file. */ - bfd_byte *contents; - /* BFD section, after it has been added. */ - asection *section; -}; - -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, and weaken. */ - -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; - -/* 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) - -/* Options to handle if running as "strip". */ - -static struct option strip_options[] = -{ - {"discard-all", no_argument, 0, 'x'}, - {"discard-locals", no_argument, 0, 'X'}, - {"format", required_argument, 0, 'F'}, /* Obsolete */ - {"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'}, - {"version", no_argument, 0, 'V'}, - {0, no_argument, 0, 0} -}; - -/* Options to handle if running as "objcopy". */ - -static struct option copy_options[] = -{ - {"add-section", required_argument, 0, OPTION_ADD_SECTION}, - {"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'}, - {"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'}, - {0, no_argument, 0, 0} -}; - -/* IMPORTS */ -extern char *program_name; - -/* 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; - - -static void -copy_usage (stream, exit_status) - FILE *stream; - int exit_status; -{ - fprintf (stream, _("\ -Usage: %s [-vVSpgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-b byte]\n\ - [-j section] [-R section]\n\ - [-i interleave] [--interleave=interleave] [--byte=byte]\n\ - [--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\ - [--strip-all] [--strip-debug] [--strip-unneeded] [--discard-all]\n\ - [--discard-locals] [--debugging]\n\ - [--only-section=section] [--remove-section=section]\n"), - program_name); - fprintf (stream, _("\ - [--gap-fill=val] [--pad-to=address] [--preserve-dates]\n\ - [--set-start=val] \n\ - [--change-start=incr] [--change-addresses=incr] \n\ - (--adjust-start and --adjust-vma are aliases for these two) \n\ - [--change-section-address=section{=,+,-}val]\n\ - (--adjust-section-vma is an alias for --change-section-address)\n\ - [--change-section-lma=section{=,+,-}val]\n\ - [--change-section-vma=section{=,+,-}val]\n\ - [--adjust-warnings] [--no-adjust-warnings]\n\ - [--change-warnings] [--no-change-warnings]\n\ - [--set-section-flags=section=flags] [--add-section=sectionname=filename]\n\ - [--keep-symbol symbol] [-K symbol] [--strip-symbol symbol] [-N symbol]\n\ - [--localize-symbol symbol] [-L symbol] [--weaken-symbol symbol]\n\ - [-W symbol] [--change-leading-char] [--remove-leading-char] [--weaken]\n\ - [--verbose] [--version] [--help] in-file [out-file]\n")); - list_supported_targets (program_name, stream); - if (exit_status == 0) - fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n")); - exit (exit_status); -} - -static void -strip_usage (stream, exit_status) - FILE *stream; - int exit_status; -{ - fprintf (stream, _("\ -Usage: %s [-vVsSpgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-R section]\n\ - [--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\ - [--strip-all] [--strip-debug] [--strip-unneeded] [--discard-all]\n\ - [--discard-locals] [--keep-symbol symbol] [-K symbol]\n\ - [--strip-symbol symbol] [-N symbol] [--remove-section=section]\n\ - [-o file] [--preserve-dates] [--verbose] [--version] [--help] file...\n"), - program_name); - list_supported_targets (program_name, stream); - if (exit_status == 0) - fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n")); - exit (exit_status); -} - -/* Parse section flags into a flagword, with a fatal error if the - string can't be parsed. */ - -static flagword -parse_flags (s) - const char *s; -{ - flagword ret; - const char *snext; - int len; - - ret = SEC_NO_FLAGS; - - do - { - snext = strchr (s, ','); - if (snext == NULL) - len = strlen (s); - else - { - len = snext - s; - ++snext; - } - - 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: alloc, load, noload, readonly, debug, code, data, rom, share, contents")); - } - - s = snext; - } - while (s != NULL); - - return ret; -} - -/* Find and optionally add an entry in the change_sections list. */ - -static struct section_list * -find_section_list (name, add) - const char *name; - boolean add; -{ - register struct section_list *p; - - for (p = change_sections; p != NULL; p = p->next) - if (strcmp (p->name, name) == 0) - return p; - - if (! add) - return NULL; - - p = (struct section_list *) xmalloc (sizeof (struct section_list)); - p->name = name; - p->used = false; - p->remove = false; - 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 = change_sections; - change_sections = p; - - return p; -} - -/* Add a symbol to strip_specific_list. */ - -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 = *list; - *list = tmp_list; -} - -/* See whether a symbol should be stripped or kept based on - strip_specific_list and keep_symbols. */ - -static boolean -is_specified_symbol (name, list) - const char *name; - struct symlist *list; -{ - struct symlist *tmp_list; - - for (tmp_list = list; tmp_list; tmp_list = tmp_list->next) - { - if (strcmp (name, tmp_list->name) == 0) - return true; - } - return false; -} - -/* See if a section is being removed. */ - -static boolean -is_strip_section (abfd, sec) - bfd *abfd ATTRIBUTE_UNUSED; - asection *sec; -{ - struct section_list *p; - - 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); - 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. - We don't copy in place, because that confuses the relocs. - Return the number of symbols to print. */ - -static unsigned int -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; - - 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 (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 ((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 - && strip_symbols != STRIP_UNNEEDED - && ! convert_debugging); - else /* Local symbol. */ - keep = (strip_symbols != STRIP_UNNEEDED - && (discard_locals != LOCALS_ALL - && (discard_locals != LOCALS_START_L - || ! bfd_is_local_label (abfd, 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; -} - -/* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long. - Adjust *SIZE. */ - -static void -filter_bytes (memhunk, size) - char *memhunk; - bfd_size_type *size; -{ - char *from = memhunk + copy_byte, *to = memhunk, *end = memhunk + *size; - - for (; from < end; from += interleave) - *to++ = *from; - if (*size % interleave > (bfd_size_type) copy_byte) - *size = (*size / interleave) + 1; - else - *size /= interleave; -} - -/* Copy object file IBFD onto OBFD. */ - -static void -copy_object (ibfd, obfd) - bfd *ibfd; - bfd *obfd; -{ - bfd_vma start; - long symcount; - 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))) - 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)); - - if (set_start_set) - start = set_start; - else - start = bfd_get_start_address (ibfd); - 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)))) - 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))) - 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))) - 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 - any output is done. Thus, we traverse all sections multiple times. */ - bfd_map_over_sections (ibfd, setup_section, (void *) obfd); - - if (add_sections != NULL) - { - struct section_add *padd; - struct section_list *pset; - - for (padd = add_sections; padd != NULL; padd = padd->next) - { - padd->section = bfd_make_section (obfd, padd->name); - if (padd->section == NULL) - { - 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)) - RETURN_NONFATAL (bfd_get_filename (obfd)); - - pset = find_section_list (padd->name, false); - if (pset != NULL) - pset->used = true; - - if (pset != NULL && pset->set_flags) - flags = pset->flags | SEC_HAS_CONTENTS; - else - flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA; - - if (! bfd_set_section_flags (obfd, padd->section, flags)) - RETURN_NONFATAL (bfd_get_filename (obfd)); - - if (pset != NULL) - { - 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)); - } - } - } - } - } - - if (gap_fill_set || pad_to_set) - { - asection **set; - unsigned int c, i; - - /* We must fill in gaps between the sections and/or we must pad - the last section to a specified address. We do this by - grabbing a list of the sections, sorting them by VMA, and - increasing the section sizes as required to fill the gaps. - We write out the gap contents below. */ - - c = bfd_count_sections (obfd); - osections = (asection **) xmalloc (c * sizeof (asection *)); - set = osections; - bfd_map_over_sections (obfd, get_sections, (void *) &set); - - 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)); - - if (gap_fill_set) - { - for (i = 0; i < c - 1; i++) - { - flagword flags; - bfd_size_type size; - bfd_vma gap_start, gap_stop; - - flags = bfd_get_section_flags (obfd, osections[i]); - if ((flags & SEC_HAS_CONTENTS) == 0 - || (flags & SEC_LOAD) == 0) - continue; - - size = bfd_section_size (obfd, osections[i]); - 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))) - { - non_fatal (_("Can't fill gap after %s: %s"), - bfd_get_section_name (obfd, osections[i]), - bfd_errmsg (bfd_get_error ())); - status = 1; - break; - } - gaps[i] = gap_stop - gap_start; - if (max_gap < gap_stop - gap_start) - max_gap = gap_stop - gap_start; - } - } - } - - if (pad_to_set) - { - bfd_vma lma; - bfd_size_type size; - - lma = bfd_section_lma (obfd, osections[c - 1]); - size = bfd_section_size (obfd, osections[c - 1]); - if (lma + size < pad_to) - { - if (! bfd_set_section_size (obfd, osections[c - 1], - pad_to - lma)) - { - non_fatal (_("Can't add padding to %s: %s"), - bfd_get_section_name (obfd, osections[c - 1]), - bfd_errmsg (bfd_get_error ())); - status = 1; - } - else - { - 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. */ - 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 - || weaken) - { - /* 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); - } - - if (convert_debugging && dhandle != NULL) - { - if (! write_debugging_info (obfd, dhandle, &symcount, &osympp)) - { - status = 1; - return; - } - } - - bfd_set_symtab (obfd, osympp, symcount); - - /* This has to happen after the symbol table has been set. */ - bfd_map_over_sections (ibfd, copy_section, (void *) obfd); - - if (add_sections != NULL) - { - struct section_add *padd; - - for (padd = add_sections; padd != NULL; padd = padd->next) - { - if (! bfd_set_section_contents (obfd, padd->section, - (PTR) padd->contents, - (file_ptr) 0, - (bfd_size_type) padd->size)) - RETURN_NONFATAL (bfd_get_filename (obfd)); - } - } - - if (gap_fill_set || pad_to_set) - { - bfd_byte *buf; - int c, i; - - /* Fill in the gaps. */ - - if (max_gap > 8192) - max_gap = 8192; - buf = (bfd_byte *) xmalloc (max_gap); - memset (buf, gap_fill, (size_t) max_gap); - - c = bfd_count_sections (obfd); - for (i = 0; i < c; i++) - { - if (gaps[i] != 0) - { - bfd_size_type left; - file_ptr off; - - left = gaps[i]; - off = bfd_section_size (obfd, osections[i]) - left; - while (left > 0) - { - bfd_size_type now; - - if (left > 8192) - now = 8192; - else - now = left; - - if (! bfd_set_section_contents (obfd, osections[i], buf, - off, now)) - RETURN_NONFATAL (bfd_get_filename (obfd)); - - left -= now; - off += now; - } - } - } - } - - /* Allow the BFD backend to copy any private data it understands - from the input BFD to the output BFD. This is done last to - permit the routine to look at the filtered symbol table, which is - important for the ECOFF code at least. */ - if (!bfd_copy_private_bfd_data (ibfd, obfd)) - { - non_fatal (_("%s: error copying private BFD data: %s"), - bfd_get_filename (obfd), - bfd_errmsg (bfd_get_error ())); - status = 1; - return; - } -} - -/* Read each archive element in turn from IBFD, copy the - contents to temp file, and keep the temp file handle. */ - -static void -copy_archive (ibfd, obfd, output_target) - bfd *ibfd; - bfd *obfd; - 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. */ -#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 (!status && this_element != (bfd *) NULL) - { - /* Create an output file for this member. */ - 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; - l->next = list; - list = l; - - if (output_bfd == (bfd *) NULL) - RETURN_NONFATAL (output_name); - - if (!bfd_set_format (obfd, bfd_get_format (ibfd))) - 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)) - { - bfd_nonfatal (bfd_get_filename (output_bfd)); - /* Error in new object file. Don't change archive. */ - status = 1; - } - - 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; - - last_element = this_element; - - this_element = bfd_openr_next_archived_file (ibfd, last_element); - - bfd_close (last_element); - } - *ptr = (bfd *) NULL; - - if (!bfd_close (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) - { - 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) - const char *input_filename; - const char *output_filename; - const char *input_target; - const char *output_target; -{ - bfd *ibfd; - char **matching; - - /* To allow us to do "strip *" without dying on the first - non-object file, failures are nonfatal. */ - - ibfd = bfd_openr (input_filename, input_target); - if (ibfd == NULL) - RETURN_NONFATAL (input_filename); - - if (bfd_check_format (ibfd, bfd_archive)) - { - bfd *obfd; - - /* bfd_get_target does not return the correct value until - bfd_check_format succeeds. */ - if (output_target == NULL) - output_target = bfd_get_target (ibfd); - - obfd = bfd_openw (output_filename, output_target); - if (obfd == NULL) - RETURN_NONFATAL (output_filename); - - copy_archive (ibfd, obfd, output_target); - } - else if (bfd_check_format_matches (ibfd, bfd_object, &matching)) - { - bfd *obfd; - - /* bfd_get_target does not return the correct value until - bfd_check_format succeeds. */ - if (output_target == NULL) - output_target = bfd_get_target (ibfd); - - obfd = bfd_openw (output_filename, output_target); - if (obfd == NULL) - RETURN_NONFATAL (output_filename); - - copy_object (ibfd, obfd); - - if (!bfd_close (obfd)) - RETURN_NONFATAL (output_filename); - - if (!bfd_close (ibfd)) - 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; - } -} - -/* Create a section in OBFD with the same name and attributes - as ISECTION in IBFD. */ - -static void -setup_section (ibfd, isection, obfdarg) - bfd *ibfd; - sec_ptr isection; - PTR 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; - - if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0 - && (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 (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"; - goto loser; - } - - 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"; - goto loser; - } - - vma = bfd_section_vma (ibfd, isection); - if (p != NULL && p->change_vma == CHANGE_MODIFY) - vma += p->vma_val; - else if (p != NULL && p->change_vma == CHANGE_SET) - vma = p->vma_val; - else - vma += change_section_address; - - if (! bfd_set_section_vma (obfd, osection, 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"; - goto loser; - } - - flags = bfd_get_section_flags (ibfd, isection); - if (p != NULL && p->set_flags) - flags = p->flags | (flags & SEC_HAS_CONTENTS); - if (!bfd_set_section_flags (obfd, osection, flags)) - { - err = "flags"; - goto loser; - } - - /* This used to be mangle_section; we do here to avoid using - bfd_get_section_by_name since some formats allow multiple - sections with the same name. */ - isection->output_section = osection; - isection->output_offset = 0; - - /* Allow the BFD backend to copy any private data it understands - from the input section to the output section. */ - if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection)) - { - err = "private data"; - goto loser; - } - - /* All went well */ - return; - -loser: - non_fatal (_("%s: section `%s': error in %s: %s"), - bfd_get_filename (ibfd), - bfd_section_name (ibfd, isection), - err, bfd_errmsg (bfd_get_error ())); - status = 1; -} - -/* 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. */ - -static void -copy_section (ibfd, isection, obfdarg) - bfd *ibfd; - sec_ptr isection; - PTR obfdarg; -{ - bfd *obfd = (bfd *) obfdarg; - struct section_list *p; - arelent **relpp; - 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_UNNEEDED - || strip_symbols == STRIP_ALL - || discard_locals == LOCALS_ALL - || convert_debugging)) - { - return; - } - - p = find_section_list (bfd_section_name (ibfd, isection), false); - - if (sections_removed && p != NULL && p->remove) - return; - if (sections_copied && (p == NULL || ! p->copy)) - return; - - osection = isection->output_section; - size = bfd_get_section_size_before_reloc (isection); - - if (size == 0 || osection == 0) - return; - - - 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 - { - relpp = (arelent **) xmalloc (relsize); - relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp); - if (relcount < 0) - RETURN_NONFATAL (bfd_get_filename (ibfd)); - - if (strip_symbols == STRIP_ALL) - { - /* 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; - isection->reloc_done = true; - - if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS) - { - PTR memhunk = (PTR) xmalloc ((unsigned) size); - - if (!bfd_get_section_contents (ibfd, isection, memhunk, (file_ptr) 0, - size)) - RETURN_NONFATAL (bfd_get_filename (ibfd)); - - if (copy_byte >= 0) - filter_bytes (memhunk, &size); - - if (!bfd_set_section_contents (obfd, osection, memhunk, (file_ptr) 0, - size)) - 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); - } -} - -/* Get all the sections. This is used when --gap-fill or --pad-to is - used. */ - -static void -get_sections (obfd, osection, secppparg) - bfd *obfd ATTRIBUTE_UNUSED; - asection *osection; - PTR secppparg; -{ - asection ***secppp = (asection ***) secppparg; - - **secppp = osection; - ++(*secppp); -} - -/* Sort sections by VMA. This is called via qsort, and is used when - --gap-fill or --pad-to is used. We force non loadable or empty - sections to the front, where they are easier to ignore. */ - -static int -compare_section_lma (arg1, arg2) - const PTR arg1; - const PTR arg2; -{ - const asection **sec1 = (const asection **) arg1; - const asection **sec2 = (const asection **) arg2; - flagword flags1, flags2; - - /* Sort non loadable sections to the front. */ - flags1 = (*sec1)->flags; - flags2 = (*sec2)->flags; - if ((flags1 & SEC_HAS_CONTENTS) == 0 - || (flags1 & SEC_LOAD) == 0) - { - if ((flags2 & SEC_HAS_CONTENTS) != 0 - && (flags2 & SEC_LOAD) != 0) - return -1; - } - else - { - if ((flags2 & SEC_HAS_CONTENTS) == 0 - || (flags2 & SEC_LOAD) == 0) - return 1; - } - - /* Sort sections by LMA. */ - if ((*sec1)->lma > (*sec2)->lma) - return 1; - else if ((*sec1)->lma < (*sec2)->lma) - return -1; - - /* 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) - return -1; - - return 0; -} - -/* Mark all the symbols which will be used in output relocations with - the BSF_KEEP flag so that those symbols will not be stripped. - - Ignore relocations which will not appear in the output file. */ - -static void -mark_symbols_used_in_relocations (ibfd, isection, symbolsarg) - bfd *ibfd; - sec_ptr isection; - PTR symbolsarg; -{ - asymbol **symbols = (asymbol **) symbolsarg; - long relsize; - arelent **relpp; - long relcount, i; - - /* Ignore an input section with no corresponding output section. */ - if (isection->output_section == NULL) - return; - - relsize = bfd_get_reloc_upper_bound (ibfd, isection); - 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) - bfd_fatal (bfd_get_filename (ibfd)); - - /* Examine each symbol used in a relocation. If it's not one of the - special bfd section symbols, then mark it with BSF_KEEP. */ - for (i = 0; i < relcount; i++) - { - if (*relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol - && *relpp[i]->sym_ptr_ptr != bfd_abs_section_ptr->symbol - && *relpp[i]->sym_ptr_ptr != bfd_und_section_ptr->symbol) - (*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP; - } - - if (relpp != NULL) - free (relpp); -} - -/* Write out debugging information. */ - -static boolean -write_debugging_info (obfd, dhandle, symcountp, symppp) - bfd *obfd; - PTR dhandle; - long *symcountp ATTRIBUTE_UNUSED; - asymbol ***symppp ATTRIBUTE_UNUSED; -{ - if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour) - return write_ieee_debugging_info (obfd, dhandle); - - if (bfd_get_flavour (obfd) == bfd_target_coff_flavour - || bfd_get_flavour (obfd) == bfd_target_elf_flavour) - { - bfd_byte *syms, *strings; - bfd_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))) - { - non_fatal (_("%s: can't create debugging section: %s"), - bfd_get_filename (obfd), - bfd_errmsg (bfd_get_error ())); - return false; - } - - /* We can get away with setting the section contents now because - the next thing the caller is going to do is copy over the - real sections. We may someday have to split the contents - setting out of this function. */ - if (! bfd_set_section_contents (obfd, stabsec, syms, (file_ptr) 0, - symsize) - || ! bfd_set_section_contents (obfd, stabstrsec, strings, - (file_ptr) 0, stringsize)) - { - non_fatal (_("%s: can't set debugging section contents: %s"), - bfd_get_filename (obfd), - bfd_errmsg (bfd_get_error ())); - return false; - } - - return true; - } - - non_fatal (_("%s: don't know how to write debugging information for %s"), - bfd_get_filename (obfd), bfd_get_target (obfd)); - return false; -} - -static int -strip_main (argc, argv) - int argc; - char *argv[]; -{ - char *input_target = NULL, *output_target = NULL; - boolean show_version = false; - int c, i; - struct section_list *p; - char *output_file = NULL; - - while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpgxXVv", - strip_options, (int *) 0)) != EOF) - { - switch (c) - { - case 'I': - input_target = optarg; - break; - case 'O': - output_target = optarg; - break; - case 'F': - input_target = output_target = optarg; - break; - case 'R': - p = find_section_list (optarg, true); - p->remove = true; - sections_removed = true; - break; - case 's': - strip_symbols = STRIP_ALL; - break; - case 'S': - case 'g': - 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_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; - break; - case 'X': - discard_locals = LOCALS_START_L; - break; - case 'v': - verbose = true; - break; - case 'V': - show_version = true; - break; - case 0: - break; /* we've been given a long option */ - case 'h': - strip_usage (stdout, 0); - default: - strip_usage (stderr, 1); - } - } - - if (show_version) - print_version ("strip"); - - /* Default is to strip all symbols. */ - if (strip_symbols == STRIP_UNDEF - && discard_locals == LOCALS_UNDEF - && strip_specific_list == NULL) - strip_symbols = STRIP_ALL; - - if (output_target == (char *) NULL) - output_target = input_target; - - i = optind; - 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; - - 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) - { - if (preserve_dates) - set_times (tmpname, &statbuf); - if (output_file == NULL) - smart_rename (tmpname, argv[i], preserve_dates); - status = hold_status; - } - else - unlink (tmpname); - if (output_file == NULL) - free (tmpname); - } - - return 0; -} - -static int -copy_main (argc, argv) - int argc; - char *argv[]; -{ - char *input_filename = NULL, *output_filename = NULL; - char *input_target = NULL, *output_target = NULL; - boolean show_version = false; - boolean change_warn = true; - int c; - struct section_list *p; - struct stat statbuf; - - 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); - if (copy_byte < 0) - fatal (_("byte number must be non-negative")); - break; - case 'i': - interleave = atoi (optarg); - if (interleave < 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; - break; - case 'g': - 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_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; - break; - case 'X': - 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; - struct stat st; - struct section_add *pa; - int len; - char *name; - FILE *f; - - s = strchr (optarg, '='); - - if (s == NULL) - fatal (_("bad format for --add-section NAME=FILENAME")); - - if (stat (s + 1, & st) < 0) - fatal (_("cannot stat: %s: %s"), s + 1, strerror (errno)); - - pa = (struct section_add *) xmalloc (sizeof (struct section_add)); - - len = s - optarg; - name = (char *) xmalloc (len + 1); - strncpy (name, optarg, len); - name[len] = '\0'; - pa->name = name; - - pa->filename = s + 1; - - pa->size = st.st_size; - - pa->contents = (bfd_byte *) xmalloc (pa->size); - f = fopen (pa->filename, FOPEN_RB); - - if (f == NULL) - fatal (_("cannot open: %s: %s"), pa->filename, strerror (errno)); - - if (fread (pa->contents, 1, pa->size, f) == 0 - || ferror (f)) - fatal (_("%s: fread failed"), pa->filename); - - fclose (f); - - pa->next = add_sections; - add_sections = pa; - } - break; - case OPTION_CHANGE_START: - change_start = parse_vma (optarg, "--change-start"); - break; - 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) - { - s = strchr (optarg, '+'); - if (s == NULL) - { - s = strchr (optarg, '-'); - if (s == NULL) - fatal (_("bad format for %s"), option); - } - } - - len = s - optarg; - name = (char *) xmalloc (len + 1); - strncpy (name, optarg, len); - name[len] = '\0'; - - p = find_section_list (name, true); - - val = parse_vma (s + 1, option); - - switch (*s) - { - case '=': what = CHANGE_SET; break; - case '-': val = - val; /* Drop through. */ - case '+': what = CHANGE_MODIFY; break; - } - - switch (c) - { - 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_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_DEBUGGING: - convert_debugging = true; - break; - case OPTION_GAP_FILL: - { - bfd_vma gap_fill_vma; - - gap_fill_vma = parse_vma (optarg, "--gap-fill"); - gap_fill = (bfd_byte) gap_fill_vma; - if ((bfd_vma) gap_fill != gap_fill_vma) - { - 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_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_SET_SECTION_FLAGS: - { - const char *s; - int len; - char *name; - - s = strchr (optarg, '='); - if (s == NULL) - fatal (_("bad format for --set-section-flags")); - - len = s - optarg; - name = (char *) xmalloc (len + 1); - strncpy (name, optarg, len); - name[len] = '\0'; - - p = find_section_list (name, true); - - p->set_flags = true; - p->flags = parse_flags (s + 1); - } - break; - case OPTION_SET_START: - set_start = parse_vma (optarg, "--set-start"); - set_start_set = 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) - print_version ("objcopy"); - - if (copy_byte >= interleave) - fatal (_("byte number must be less than interleave")); - - if (optind == argc || optind + 2 < argc) - copy_usage (stderr, 1); - - input_filename = argv[optind]; - if (optind + 1 < argc) - 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 (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) - { - 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 (change_warn) - { - for (p = change_sections; p != NULL; p = p->next) - { - if (! p->used) - { - if (p->change_vma != CHANGE_IGNORE) - { - char buff [20]; - - sprintf_vma (buff, p->vma_val); - - /* xgettext:c-format */ - non_fatal (_("Warning: --change-section-vma %s%c0x%s never used"), - 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 (_("Warning: --change-section-lma %s%c0x%s never used"), - p->name, - p->change_lma == CHANGE_SET ? '=' : '+', - buff); - } - } - } - } - - return 0; -} - -int -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; - - 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); - } - - if (is_strip) - strip_main (argc, argv); - else - copy_main (argc, argv); - - END_PROGRESS (program_name); - - return status; -} |