/* objcopy.c -- copy object file from input to output, optionally massaging it.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001
+ 2001, 2002
Free Software Foundation, Inc.
This file is part of GNU Binutils.
/* 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. */
+ deleted. */
struct symlist
{
static int copy_byte = -1;
static int interleave = 4;
-static boolean verbose; /* Print file and target names. */
+static boolean verbose; /* Print file and target names. */
static boolean preserve_dates; /* Preserve input file timestamp. */
static int status = 0; /* Exit status. */
STRIP_ALL /* strip all symbols */
};
-/* Which symbols to remove. */
+/* Which symbols to remove. */
static enum strip_action strip_symbols;
enum locals_action
static boolean pad_to_set = false;
static bfd_vma pad_to;
+/* Use alternate machine code? */
+static int use_alt_mach_code = 0;
+
/* List of sections to add. */
struct section_add
{
#define OPTION_KEEPGLOBAL_SYMBOLS (OPTION_LOCALIZE_SYMBOLS + 1)
#define OPTION_WEAKEN_SYMBOLS (OPTION_KEEPGLOBAL_SYMBOLS + 1)
#define OPTION_RENAME_SECTION (OPTION_WEAKEN_SYMBOLS + 1)
+#define OPTION_ALT_MACH_CODE (OPTION_RENAME_SECTION + 1)
/* Options to handle if running as "strip". */
{"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
{"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
{"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS},
+ {"alt-machine-code", required_argument, 0, OPTION_ALT_MACH_CODE},
{0, no_argument, 0, 0}
};
/* 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. */
+ -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
FILE *stream;
int exit_status;
{
- fprintf (stream, _("Usage: %s <switches> in-file [out-file]\n"), program_name);
- fprintf (stream, _(" The switches are:\n"));
+ fprintf (stream, _("Usage: %s [option(s)] in-file [out-file]\n"), program_name);
+ fprintf (stream, _(" Copies a binary file, possibly transforming it in the process\n"));
+ fprintf (stream, _(" The options are:\n"));
fprintf (stream, _("\
-I --input-target <bfdname> Assume input file is in format <bfdname>\n\
-O --output-target <bfdname> Create an output file in format <bfdname>\n\
--localize-symbols <file> -L for all symbols listed in <file>\n\
--keep-global-symbols <file> -G for all symbols listed in <file>\n\
--weaken-symbols <file> -W for all symbols listed in <file>\n\
+ --alt-machine-code <index> Use alternate machine code for output\n\
-v --verbose List all object files modified\n\
-V --version Display this program's version number\n\
-h --help Display this output\n\
FILE *stream;
int exit_status;
{
- fprintf (stream, _("Usage: %s <switches> in-file(s)\n"), program_name);
- fprintf (stream, _(" The switches are:\n"));
+ fprintf (stream, _("Usage: %s <option(s)> in-file(s)\n"), program_name);
+ fprintf (stream, _(" Removes symbols and sections from files\n"));
+ fprintf (stream, _(" The options are:\n"));
fprintf (stream, _("\
- -I --input-target <bfdname> Assume input file is in format <bfdname>\n\
- -O --output-target <bfdname> Create an output file in format <bfdname>\n\
- -F --target <bfdname> Set both input and output format to <bfdname>\n\
+ -I --input-target=<bfdname> Assume input file is in format <bfdname>\n\
+ -O --output-target=<bfdname> Create an output file in format <bfdname>\n\
+ -F --target=<bfdname> Set both input and output format to <bfdname>\n\
-p --preserve-dates Copy modified/access timestamps to the output\n\
- -R --remove-section <name> Remove section <name> from the output\n\
+ -R --remove-section=<name> Remove section <name> from the output\n\
-s --strip-all Remove all symbol and relocation information\n\
- -g -S --strip-debug Remove all debugging symbols\n\
+ -g -S -d --strip-debug Remove all debugging symbols\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
- -N --strip-symbol <name> Do not copy symbol <name>\n\
- -K --keep-symbol <name> Only copy symbol <name>\n\
+ -N --strip-symbol=<name> Do not copy symbol <name>\n\
+ -K --keep-symbol=<name> Only copy symbol <name>\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\
*list = tmp_list;
}
-/* Add symbols listed in `filename' to strip_specific_list. */
+/* Add symbols listed in `filename' to strip_specific_list. */
#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t')
#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
char * line;
char * buffer;
unsigned int line_count;
-
+
if (stat (filename, & st) < 0)
fatal (_("cannot stat: %s: %s"), filename, strerror (errno));
if (st.st_size == 0)
buffer [st.st_size + 1] = '\0';
line_count = 1;
-
+
for (line = buffer; * line != '\0'; line ++)
{
char * eol;
++ eol;
finished = true;
break;
-
+
case '\r':
* eol = '\0';
/* Cope with \r\n. */
++ eol;
finished = true;
break;
-
+
case 0:
finished = true;
break;
-
+
case '#':
/* Line comment, Terminate the line here, in case a
name is present and then allow the rest of the
loop to find the real end of the line. */
* eol = '\0';
break;
-
+
default:
break;
}
for (name_end = name;
(! IS_WHITESPACE (* name_end))
&& (! IS_LINE_TERMINATOR (* name_end));
- name_end ++)
- ;
+ name_end ++)
+ ;
if (! IS_LINE_TERMINATOR (* name_end))
{
non_fatal (_("Ignoring rubbish found on line %d of %s"),
line_count, filename);
}
-
+
* name_end = '\0';
if (name_end > name)
&& ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags
& BSF_KEEP) != 0))
keep = 1;
- else if (relocatable /* Relocatable file. */
+ else if (relocatable /* Relocatable file. */
&& (flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
keep = 1;
else if (bfd_decode_symclass (sym) == 'I')
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));
+ /* Neither the start address nor the flags
+ need to be set for a core file. */
+ if (bfd_get_format (obfd) != bfd_core)
+ {
+ 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),
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 ()));
+ bfd_get_section_name (obfd, osections[i]),
+ bfd_errmsg (bfd_get_error ()));
status = 1;
break;
}
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 ()));
+ bfd_get_section_name (obfd, osections[c - 1]),
+ bfd_errmsg (bfd_get_error ()));
status = 1;
}
else
status = 1;
return;
}
+
+ /* Switch to the alternate machine code. We have to do this at the
+ very end, because we only initialize the header when we create
+ the first section. */
+ if (use_alt_mach_code != 0)
+ {
+ if (!bfd_alt_mach_code (obfd, use_alt_mach_code))
+ non_fatal (_("unknown alternate machine code, ignored"));
+ }
}
+#undef MKDIR
+#if defined (_WIN32) && !defined (__CYGWIN32__)
+#define MKDIR(DIR, MODE) mkdir (DIR)
+#else
+#define MKDIR(DIR, MODE) mkdir (DIR, MODE)
+#endif
+
/* Read each archive element in turn from IBFD, copy the
contents to temp file, and keep the temp file handle. */
struct name_list
{
struct name_list *next;
- char *name;
+ const char *name;
bfd *obfd;
} *list, *l;
bfd **ptr = &obfd->archive_head;
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
+ if (MKDIR (dir, 0700) != 0)
{
fatal (_("cannot mkdir %s for archive copying (error: %s)"),
dir, strerror (errno));
this_element = bfd_openr_next_archived_file (ibfd, NULL);
+ if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
+ RETURN_NONFATAL (bfd_get_filename (obfd));
+
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);
+ char *output_name;
+ bfd *output_bfd;
bfd *last_element;
struct stat buf;
int stat_status = 0;
+ /* Create an output file for this member. */
+ output_name = concat (dir, "/",
+ bfd_get_filename (this_element), (char *) 0);
+
+ /* If the file already exists, make another temp dir. */
+ if (stat (output_name, &buf) >= 0)
+ {
+ output_name = make_tempname (output_name);
+ if (MKDIR (output_name, 0700) != 0)
+ {
+ fatal (_("cannot mkdir %s for archive copying (error: %s)"),
+ output_name, strerror (errno));
+ }
+ l = (struct name_list *) xmalloc (sizeof (struct name_list));
+ l->name = output_name;
+ l->next = list;
+ l->obfd = NULL;
+ list = l;
+ output_name = concat (output_name, "/",
+ bfd_get_filename (this_element), (char *) 0);
+ }
+
+ output_bfd = bfd_openw (output_name, output_target);
if (preserve_dates)
{
stat_status = bfd_stat_arch_elt (this_element, &buf);
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. */
+ /* Error in new object file. Don't change archive. */
status = 1;
}
/* Delete all the files that we opened. */
for (l = list; l != NULL; l = l->next)
{
- bfd_close (l->obfd);
- unlink (l->name);
+ if (l->obfd == NULL)
+ rmdir (l->name);
+ else
+ {
+ bfd_close (l->obfd);
+ unlink (l->name);
+ }
}
rmdir (dir);
}
copy_archive (ibfd, obfd, output_target);
}
- else if (bfd_check_format_matches (ibfd, bfd_object, &matching))
+ else if (bfd_check_format_matches (ibfd, bfd_object, &matching)
+ || bfd_check_format_matches (ibfd, bfd_core, &matching))
{
bfd *obfd;
if (strcmp (rename->new_name, new_name) == 0
&& rename->flags == flags)
return;
-
+
fatal (_("Multiple renames of section %s"), old_name);
}
rename->new_name = new_name;
rename->flags = flags;
rename->next = section_rename_list;
-
+
section_rename_list = rename;
}
flagword flags;
const char *err;
const char * name;
-
+
if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0
&& (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_UNNEEDED
/* Get the, possibly new, name of the output section. */
name = find_section_rename (ibfd, isection, & flags);
-
+
osection = bfd_make_section_anyway (obfd, name);
if (osection == NULL)
}
if (p != NULL && p->set_flags)
- flags = p->flags | (flags & SEC_HAS_CONTENTS);
+ flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
if (!bfd_set_section_flags (obfd, osection, flags))
{
err = _("flags");
goto loser;
}
+ /* Copy merge entity size. */
+ osection->entsize = isection->entsize;
+
/* 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. */
sec_ptr osection;
bfd_size_type size;
long relsize;
+ flagword flags;
/* If we have already failed earlier on,
do not keep on generating complaints now. */
if (status != 0)
return;
- if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0
+ flags = bfd_get_section_flags (ibfd, isection);
+ if ((flags & SEC_DEBUGGING) != 0
&& (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_UNNEEDED
|| strip_symbols == STRIP_ALL
|| convert_debugging))
return;
+ if ((flags & SEC_GROUP) != 0)
+ return;
+
p = find_section_list (bfd_section_name (ibfd, isection), false);
if (sections_removed && p != NULL && p->remove)
if (size == 0 || osection == 0)
return;
- relsize = bfd_get_reloc_upper_bound (ibfd, isection);
+ /* Core files do not need to be relocated. */
+ if (bfd_get_format (obfd) == bfd_core)
+ relsize = 0;
+ else
+ relsize = bfd_get_reloc_upper_bound (ibfd, isection);
+
if (relsize < 0)
RETURN_NONFATAL (bfd_get_filename (ibfd));
if (strip_symbols == STRIP_ALL)
{
/* Remove relocations which are not in
- keep_strip_specific_list. */
+ keep_strip_specific_list. */
arelent **temp_relpp;
long temp_relcount = 0;
long i;
isection->_cooked_size = isection->_raw_size;
isection->reloc_done = true;
- if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS)
+ if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
+ && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
{
PTR memhunk = (PTR) xmalloc ((unsigned) size);
struct section_list *p;
char *output_file = NULL;
- while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXVv",
+ while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVv",
strip_options, (int *) 0)) != EOF)
{
switch (c)
case 0:
/* We've been given a long option. */
break;
+ case 'H':
case 'h':
strip_usage (stdout, 0);
default:
struct section_list *p;
struct stat statbuf;
- while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXVvW:",
+ while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:",
copy_options, (int *) 0)) != EOF)
{
switch (c)
fatal (_("byte number must be non-negative"));
break;
- case 'B':
- binary_architecture = optarg;
- break;
+ case 'B':
+ binary_architecture = optarg;
+ break;
case 'i':
interleave = atoi (optarg);
case OPTION_RENAME_SECTION:
{
flagword flags;
- const char * s;
- char * old_name;
- char * new_name;
+ const char *eq, *fl;
+ char *old_name;
+ char *new_name;
unsigned int len;
- s = strchr (optarg, '=');
- if (s == NULL)
+ eq = strchr (optarg, '=');
+ if (eq == NULL)
fatal (_("bad format for %s"), "--rename-section");
- len = s - optarg;
+ len = eq - optarg;
if (len == 0)
- fatal (_("no old name is %s"), "--rename-section");
+ fatal (_("bad format for %s"), "--rename-section");
old_name = (char *) xmalloc (len + 1);
strncpy (old_name, optarg, len);
old_name[len] = 0;
- s = strchr (optarg + len, ',');
- if (s)
+ eq++;
+ fl = strchr (eq, ',');
+ if (fl)
{
- unsigned int new_len;
-
- flags = parse_flags (s + 1);
- new_len = s - (optarg + len);
- if (new_len == 0)
- fatal (_("no new name in %s"), "--rename-section");
- new_name = (char *) xmalloc (new_len + 1);
- strncpy (new_name, optarg + len, new_len);
- new_name [new_len] = 0;
+ flags = parse_flags (fl + 1);
+ len = fl - eq;
}
else
{
- s = optarg + len;
- len = strlen (s);
- if (len == 0)
- fatal (_("no new name in %s"), "--rename-section");
- new_name = (char *) xmalloc (len + 1);
- strcpy (new_name, s);
flags = -1;
+ len = strlen (eq);
}
+ if (len == 0)
+ fatal (_("bad format for %s"), "--rename-section");
+
+ new_name = (char *) xmalloc (len + 1);
+ strncpy (new_name, eq, len);
+ new_name[len] = 0;
+
add_section_rename (old_name, new_name, flags);
}
break;
set_start_set = true;
break;
- case OPTION_SREC_LEN:
- Chunk = parse_vma (optarg, "--srec-len");
- break;
+ case OPTION_SREC_LEN:
+ Chunk = parse_vma (optarg, "--srec-len");
+ break;
- case OPTION_SREC_FORCES3:
+ case OPTION_SREC_FORCES3:
S3Forced = true;
- break;
+ break;
case OPTION_STRIP_SYMBOLS:
add_specific_symbols (optarg, &strip_specific_list);
add_specific_symbols (optarg, &weaken_specific_list);
break;
+ case OPTION_ALT_MACH_CODE:
+ use_alt_mach_code = atoi (optarg);
+ if (use_alt_mach_code <= 0)
+ fatal (_("alternate machine code index must be positive"));
+ break;
+
case 0:
break; /* we've been given a long option */
+ case 'H':
case 'h':
copy_usage (stdout, 0);
if (binary_architecture != (char *) NULL)
{
if (input_target && strcmp (input_target, "binary") == 0)
- {
- const bfd_arch_info_type * temp_arch_info;
+ {
+ const bfd_arch_info_type * temp_arch_info;
temp_arch_info = bfd_scan_arch (binary_architecture);
- if (temp_arch_info != NULL)
- bfd_external_binary_architecture = temp_arch_info->arch;
- else
- fatal (_("architecture %s unknown"), binary_architecture);
- }
+ if (temp_arch_info != NULL)
+ bfd_external_binary_architecture = temp_arch_info->arch;
+ else
+ fatal (_("architecture %s unknown"), binary_architecture);
+ }
else
{
non_fatal (_("Warning: input target 'binary' required for binary architecture parameter."));
return 0;
}
+int main PARAMS ((int, char **));
+
int
main (argc, argv)
int argc;
{
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
setlocale (LC_MESSAGES, "");
+#endif
+#if defined (HAVE_SETLOCALE)
+ setlocale (LC_CTYPE, "");
#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);