/* objcopy.c -- copy object file from input to output, optionally massaging it.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GNU Binutils.
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
\f
+#include "sysdep.h"
#include "bfd.h"
#include "progress.h"
-#include "bucomm.h"
#include "getopt.h"
#include "libiberty.h"
+#include "bucomm.h"
#include "budbg.h"
#include "filenames.h"
#include "fnmatch.h"
#include "elf-bfd.h"
#include <sys/stat.h>
+#include "libbfd.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
static bfd_boolean pad_to_set = FALSE;
static bfd_vma pad_to;
-/* Use alternate machine code? */
-static int use_alt_mach_code = 0;
+/* Use alternative machine code? */
+static unsigned long use_alt_mach_code = 0;
/* Output BFD flags user wants to set or clear */
static flagword bfd_flags_to_set;
/* Whether to permit wildcard in symbol comparison. */
static bfd_boolean wildcard = FALSE;
+/* True if --localize-hidden is in effect. */
+static bfd_boolean localize_hidden = FALSE;
+
/* List of symbols to strip, keep, localize, keep-global, weaken,
or redefine. */
static struct symlist *strip_specific_list = NULL;
/* If this is TRUE, we weaken global symbols (set BSF_WEAK). */
static bfd_boolean weaken = FALSE;
+/* If this is TRUE, we retain BSF_FILE symbols. */
+static bfd_boolean keep_file_symbols = FALSE;
+
/* Prefix symbols/sections. */
static char *prefix_symbols_string = 0;
static char *prefix_sections_string = 0;
static char *prefix_alloc_sections_string = 0;
+/* True if --extract-symbol was passed on the command line. */
+static bfd_boolean extract_symbol = FALSE;
+
+/* If `reverse_bytes' is nonzero, then reverse the order of every chunk
+ of <reverse_bytes> bytes within each output section. */
+static int reverse_bytes = 0;
+
+
/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
enum command_line_switch
{
OPTION_STRIP_UNNEEDED_SYMBOL,
OPTION_STRIP_UNNEEDED_SYMBOLS,
OPTION_KEEP_SYMBOLS,
+ OPTION_LOCALIZE_HIDDEN,
OPTION_LOCALIZE_SYMBOLS,
OPTION_GLOBALIZE_SYMBOL,
OPTION_GLOBALIZE_SYMBOLS,
OPTION_FORMATS_INFO,
OPTION_ADD_GNU_DEBUGLINK,
OPTION_ONLY_KEEP_DEBUG,
+ OPTION_KEEP_FILE_SYMBOLS,
OPTION_READONLY_TEXT,
OPTION_WRITABLE_TEXT,
OPTION_PURE,
- OPTION_IMPURE
+ OPTION_IMPURE,
+ OPTION_EXTRACT_SYMBOL,
+ OPTION_REVERSE_BYTES
};
/* Options to handle if running as "strip". */
{"info", no_argument, 0, OPTION_FORMATS_INFO},
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"input-target", required_argument, 0, 'I'},
+ {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
{"keep-symbol", required_argument, 0, 'K'},
{"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"debugging", no_argument, 0, OPTION_DEBUGGING},
{"discard-all", no_argument, 0, 'x'},
{"discard-locals", no_argument, 0, 'X'},
+ {"extract-symbol", no_argument, 0, OPTION_EXTRACT_SYMBOL},
{"format", required_argument, 0, 'F'}, /* Obsolete */
{"gap-fill", required_argument, 0, OPTION_GAP_FILL},
{"globalize-symbol", required_argument, 0, OPTION_GLOBALIZE_SYMBOL},
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"input-target", required_argument, 0, 'I'},
{"interleave", required_argument, 0, 'i'},
+ {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
{"keep-global-symbol", required_argument, 0, 'G'},
{"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
{"keep-symbol", required_argument, 0, 'K'},
{"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS},
+ {"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN},
{"localize-symbol", required_argument, 0, 'L'},
{"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
{"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
{"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
{"remove-section", required_argument, 0, 'R'},
{"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
+ {"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
{"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS},
{"set-start", required_argument, 0, OPTION_SET_START},
{"srec-len", required_argument, 0, OPTION_SREC_LEN},
Do not copy symbol <name> unless needed by\n\
relocations\n\
--only-keep-debug Strip everything but the debug information\n\
+ --extract-symbol Remove section contents but keep symbols\n\
-K --keep-symbol <name> Do not strip symbol <name>\n\
+ --keep-file-symbols Do not strip file symbol(s)\n\
+ --localize-hidden Turn all ELF hidden symbols into locals\n\
-L --localize-symbol <name> Force symbol <name> to be marked as a local\n\
--globalize-symbol <name> Force symbol <name> to be marked as a global\n\
-G --keep-global-symbol <name> Localize all symbols except <name>\n\
--rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\
--change-leading-char Force output format's leading character style\n\
--remove-leading-char Remove leading character from global symbols\n\
+ --reverse-bytes=<num> Reverse <num> bytes at a time, in output sections with content\n\
--redefine-sym <old>=<new> Redefine symbol name <old> to <new>\n\
--redefine-syms <file> --redefine-sym for all symbol pairs \n\
listed in <file>\n\
--globalize-symbols <file> --globalize-symbol for all 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\
+ --alt-machine-code <index> Use the target's <index>'th alternative machine\n\
--writable-text Mark the output text as writable\n\
--readonly-text Make the output text write protected\n\
--pure Mark the output file as demand paged\n\
Add <prefix> to start of every allocatable\n\
section name\n\
-v --verbose List all object files modified\n\
+ @<file> Read options from <file>\n\
-V --version Display this program's version number\n\
-h --help Display this output\n\
--info List object formats & architectures supported\n\
"));
list_supported_targets (program_name, stream);
- if (exit_status == 0)
+ if (REPORT_BUGS_TO[0] && exit_status == 0)
fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
exit (exit_status);
}
--only-keep-debug Strip everything but the debug information\n\
-N --strip-symbol=<name> Do not copy symbol <name>\n\
-K --keep-symbol=<name> Do not strip symbol <name>\n\
+ --keep-file-symbols Do not strip file symbol(s)\n\
-w --wildcard Permit wildcard in symbol comparison\n\
-x --discard-all Remove all non-global symbols\n\
-X --discard-locals Remove any compiler-generated symbols\n\
"));
list_supported_targets (program_name, stream);
- if (exit_status == 0)
+ if (REPORT_BUGS_TO[0] && exit_status == 0)
fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
exit (exit_status);
}
size = get_file_size (filename);
if (size == 0)
- return;
+ {
+ status = 1;
+ return;
+ }
buffer = xmalloc (size + 2);
f = fopen (filename, FOPEN_RT);
return FALSE;
}
+/* Return a pointer to the symbol used as a signature for GROUP. */
+
+static asymbol *
+group_signature (asection *group)
+{
+ bfd *abfd = group->owner;
+ Elf_Internal_Shdr *ghdr;
+
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ return NULL;
+
+ ghdr = &elf_section_data (group)->this_hdr;
+ if (ghdr->sh_link < elf_numsections (abfd))
+ {
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
+
+ if (symhdr->sh_type == SHT_SYMTAB
+ && ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
+ return isympp[ghdr->sh_info - 1];
+ }
+ return NULL;
+}
+
/* See if a section is being removed. */
static bfd_boolean
return FALSE;
}
+ if ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0)
+ {
+ asymbol *gsym;
+ const char *gname;
+
+ /* PR binutils/3166
+ Group sections look like debugging sections but they are not.
+ (They have a non-zero size but they are not ALLOCated). */
+ if (strip_symbols == STRIP_NONDEBUG)
+ return TRUE;
+
+ /* PR binutils/3181
+ If we are going to strip the group signature symbol, then
+ strip the group section too. */
+ gsym = group_signature (sec);
+ if (gsym != NULL)
+ gname = gsym->name;
+ else
+ gname = sec->name;
+ if ((strip_symbols == STRIP_ALL
+ && !is_specified_symbol (gname, keep_specific_list))
+ || is_specified_symbol (gname, strip_specific_list))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Return true if SYM is a hidden symbol. */
+
+static bfd_boolean
+is_hidden_symbol (asymbol *sym)
+{
+ elf_symbol_type *elf_sym;
+
+ elf_sym = elf_symbol_from (sym->the_bfd, sym);
+ if (elf_sym != NULL)
+ switch (ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other))
+ {
+ case STV_HIDDEN:
+ case STV_INTERNAL:
+ return TRUE;
+ }
return FALSE;
}
asymbol *sym = from[src_count];
flagword flags = sym->flags;
char *name = (char *) bfd_asymbol_name (sym);
- int keep;
+ bfd_boolean keep;
+ bfd_boolean used_in_reloc = FALSE;
bfd_boolean undefined;
bfd_boolean rem_leading_char;
bfd_boolean add_leading_char;
}
if (strip_symbols == STRIP_ALL)
- keep = 0;
+ keep = FALSE;
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;
+ {
+ keep = TRUE;
+ used_in_reloc = TRUE;
+ }
else if (relocatable /* Relocatable file. */
&& (flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
- keep = 1;
+ keep = TRUE;
else if (bfd_decode_symclass (sym) == 'I')
/* Global symbols in $idata sections need to be retained
even if relocatable is FALSE. External users of the
library containing the $idata section may reference these
symbols. */
- keep = 1;
+ keep = TRUE;
else if ((flags & BSF_GLOBAL) != 0 /* Global symbol. */
|| (flags & BSF_WEAK) != 0
|| undefined
else if (bfd_coff_get_comdat_section (abfd, bfd_get_section (sym)))
/* COMDAT sections store special information in local
symbols, so we cannot risk stripping any of them. */
- keep = 1;
+ keep = TRUE;
else /* Local symbol. */
keep = (strip_symbols != STRIP_UNNEEDED
&& (discard_locals != LOCALS_ALL
|| ! bfd_is_local_label (abfd, sym))));
if (keep && is_specified_symbol (name, strip_specific_list))
- keep = 0;
+ {
+ /* There are multiple ways to set 'keep' above, but if it
+ was the relocatable symbol case, then that's an error. */
+ if (used_in_reloc)
+ {
+ non_fatal (_("not stripping symbol `%s' because it is named in a relocation"), name);
+ status = 1;
+ }
+ else
+ keep = FALSE;
+ }
+
if (keep
&& !(flags & BSF_KEEP)
&& is_specified_symbol (name, strip_unneeded_list))
- keep = 0;
- if (!keep && is_specified_symbol (name, keep_specific_list))
- keep = 1;
+ keep = FALSE;
+
+ if (!keep
+ && ((keep_file_symbols && (flags & BSF_FILE))
+ || is_specified_symbol (name, keep_specific_list)))
+ keep = TRUE;
+
if (keep && is_strip_section (abfd, bfd_get_section (sym)))
- keep = 0;
+ keep = FALSE;
if (keep)
{
&& (flags & (BSF_GLOBAL | BSF_WEAK))
&& (is_specified_symbol (name, localize_specific_list)
|| (keepglobal_specific_list != NULL
- && ! is_specified_symbol (name, keepglobal_specific_list))))
+ && ! is_specified_symbol (name, keepglobal_specific_list))
+ || (localize_hidden && is_hidden_symbol (sym))))
{
sym->flags &= ~ (BSF_GLOBAL | BSF_WEAK);
sym->flags |= BSF_LOCAL;
bfd_get_archive_filename (ibfd), bfd_get_target (ibfd),
bfd_get_filename (obfd), bfd_get_target (obfd));
- if (set_start_set)
- start = set_start;
+ if (extract_symbol)
+ start = 0;
else
- start = bfd_get_start_address (ibfd);
- start += change_start;
+ {
+ if (set_start_set)
+ start = set_start;
+ else
+ start = bfd_get_start_address (ibfd);
+ start += change_start;
+ }
/* Neither the start address nor the flags
need to be set for a core file. */
if (osympp != isympp)
free (osympp);
+ isympp = NULL;
+ osympp = NULL;
+
+ symsize = bfd_get_symtab_upper_bound (ibfd);
+ if (symsize < 0)
+ {
+ bfd_nonfatal (bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
+ osympp = isympp = xmalloc (symsize);
+ symcount = bfd_canonicalize_symtab (ibfd, isympp);
+ if (symcount < 0)
+ {
+ bfd_nonfatal (bfd_get_filename (ibfd));
+ return FALSE;
+ }
+
/* 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, obfd);
if (pset != NULL && pset->set_flags)
flags = pset->flags | SEC_HAS_CONTENTS;
- padd->section = bfd_make_section_with_flags (obfd, padd->name, flags);
- if (padd->section == NULL)
+ /* bfd_make_section_with_flags() does not return very helpful
+ error codes, so check for the most likely user error first. */
+ if (bfd_get_section_by_name (obfd, padd->name))
{
- non_fatal (_("can't create section `%s': %s"),
- padd->name, bfd_errmsg (bfd_get_error ()));
+ non_fatal (_("can't add section '%s' - it already exists!"), padd->name);
return FALSE;
}
+ else
+ {
+ padd->section = bfd_make_section_with_flags (obfd, padd->name, flags);
+ if (padd->section == NULL)
+ {
+ non_fatal (_("can't create section `%s': %s"),
+ padd->name, bfd_errmsg (bfd_get_error ()));
+ return FALSE;
+ }
+ }
if (! bfd_set_section_size (obfd, padd->section, padd->size))
{
bfd_nonfatal (gnu_debuglink_filename);
return FALSE;
}
- }
- if (bfd_count_sections (obfd) == 0)
- {
- non_fatal (_("there are no sections to be copied!"));
- return FALSE;
+ /* Special processing for PE format files. We
+ have no way to distinguish PE from COFF here. */
+ if (bfd_get_flavour (obfd) == bfd_target_coff_flavour)
+ {
+ bfd_vma debuglink_vma;
+ asection * highest_section;
+ asection * sec;
+
+ /* The PE spec requires that all sections be adjacent and sorted
+ in ascending order of VMA. It also specifies that debug
+ sections should be last. This is despite the fact that debug
+ sections are not loaded into memory and so in theory have no
+ use for a VMA.
+
+ This means that the debuglink section must be given a non-zero
+ VMA which makes it contiguous with other debug sections. So
+ walk the current section list, find the section with the
+ highest VMA and start the debuglink section after that one. */
+ for (sec = obfd->sections, highest_section = NULL;
+ sec != NULL;
+ sec = sec->next)
+ if (sec->vma > 0
+ && (highest_section == NULL
+ || sec->vma > highest_section->vma))
+ highest_section = sec;
+
+ if (highest_section)
+ debuglink_vma = BFD_ALIGN (highest_section->vma
+ + highest_section->size,
+ /* FIXME: We ought to be using
+ COFF_PAGE_SIZE here or maybe
+ bfd_get_section_alignment() (if it
+ was set) but since this is for PE
+ and we know the required alignment
+ it is easier just to hard code it. */
+ 0x1000);
+ else
+ /* Umm, not sure what to do in this case. */
+ debuglink_vma = 0x1000;
+
+ bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma);
+ }
}
- if (gap_fill_set || pad_to_set)
+ if (bfd_count_sections (obfd) != 0
+ && (gap_fill_set || pad_to_set))
{
asection **set;
unsigned int c, i;
/* 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)
- {
- bfd_nonfatal (bfd_get_archive_filename (ibfd));
- return FALSE;
- }
-
- osympp = isympp = xmalloc (symsize);
- symcount = bfd_canonicalize_symtab (ibfd, isympp);
- if (symcount < 0)
- {
- bfd_nonfatal (bfd_get_filename (ibfd));
- return FALSE;
- }
-
if (convert_debugging)
dhandle = read_debugging_info (ibfd, isympp, symcount);
|| strip_symbols == STRIP_UNNEEDED
|| strip_symbols == STRIP_NONDEBUG
|| discard_locals != LOCALS_UNDEF
+ || localize_hidden
|| strip_specific_list != NULL
|| keep_specific_list != NULL
|| localize_specific_list != NULL
}
}
+ /* Do not copy backend data if --extract-symbol is passed; anything
+ that needs to look at the section contents will fail. */
+ if (extract_symbol)
+ return TRUE;
+
/* 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_get_flavour (ibfd) == bfd_target_elf_flavour
- && strip_symbols == STRIP_NONDEBUG)
- /* Do not copy the private data when creating an ELF format
- debug info file. We do not want the program headers. */
- ;
- else if (! bfd_copy_private_bfd_data (ibfd, obfd))
+ if (! bfd_copy_private_bfd_data (ibfd, obfd))
{
non_fatal (_("%s: error copying private BFD data: %s"),
bfd_get_filename (obfd),
/* 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
- && ! bfd_alt_mach_code (obfd, use_alt_mach_code))
- non_fatal (_("unknown alternate machine code, ignored"));
+ if (use_alt_mach_code != 0)
+ {
+ if (! bfd_alt_mach_code (obfd, use_alt_mach_code))
+ {
+ non_fatal (_("this target does not support %lu alternative machine codes"),
+ use_alt_mach_code);
+ if (bfd_get_flavour (obfd) == bfd_target_elf_flavour)
+ {
+ non_fatal (_("treating that number as an absolute e_machine value instead"));
+ elf_elfheader (obfd)->e_machine = use_alt_mach_code;
+ }
+ else
+ non_fatal (_("ignoring the alternative value"));
+ }
+ }
return TRUE;
}
-#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. */
+ contents to temp file, and keep the temp file handle.
+ If 'force_output_target' is TRUE then make sure that
+ all elements in the new archive are of the type
+ 'output_target'. */
static void
-copy_archive (bfd *ibfd, bfd *obfd, const char *output_target)
+copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
+ bfd_boolean force_output_target)
{
struct name_list
{
} *list, *l;
bfd **ptr = &obfd->archive_head;
bfd *this_element;
- char *dir = make_tempname (bfd_get_filename (obfd));
+ char * dir;
/* Make a temp directory to hold the contents. */
- if (MKDIR (dir, 0700) != 0)
- fatal (_("cannot mkdir %s for archive copying (error: %s)"),
- dir, strerror (errno));
+ dir = make_tempdir (bfd_get_filename (obfd));
+ if (dir == NULL)
+ fatal (_("cannot create tempdir for archive copying (error: %s)"),
+ strerror (errno));
obfd->has_armap = ibfd->has_armap;
/* 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));
+ output_name = make_tempdir (output_name);
+ if (output_name == NULL)
+ fatal (_("cannot create tempdir for archive copying (error: %s)"),
+ strerror (errno));
l = xmalloc (sizeof (struct name_list));
l->name = 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);
l->obfd = NULL;
list = l;
- if (output_bfd == NULL)
- RETURN_NONFATAL (output_name);
-
if (bfd_check_format (this_element, bfd_object))
{
+ /* PR binutils/3110: Cope with archives
+ containing multiple target types. */
+ if (force_output_target)
+ output_bfd = bfd_openw (output_name, output_target);
+ else
+ output_bfd = bfd_openw (output_name, bfd_get_target (this_element));
+
+ if (output_bfd == NULL)
+ RETURN_NONFATAL (output_name);
+
delete = ! copy_object (this_element, output_bfd);
if (! delete
non_fatal (_("Unable to recognise the format of the input file `%s'"),
bfd_get_archive_filename (this_element));
+ output_bfd = bfd_openw (output_name, output_target);
copy_unknown_element:
delete = !copy_unknown_object (this_element, output_bfd);
if (!bfd_close_all_done (output_bfd))
if (get_file_size (input_filename) < 1)
{
- non_fatal (_("error: the input file '%s' is empty"), input_filename);
status = 1;
return;
}
if (bfd_check_format (ibfd, bfd_archive))
{
+ bfd_boolean force_output_target;
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);
+ {
+ output_target = bfd_get_target (ibfd);
+ force_output_target = FALSE;
+ }
+ else
+ force_output_target = TRUE;
obfd = bfd_openw (output_filename, output_target);
if (obfd == NULL)
RETURN_NONFATAL (output_filename);
- copy_archive (ibfd, obfd, output_target);
+ copy_archive (ibfd, obfd, output_target, force_output_target);
}
else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching))
{
if (p != NULL && p->set_flags)
flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
- else if (strip_symbols == STRIP_NONDEBUG && (flags & SEC_ALLOC) != 0)
+ else if (strip_symbols == STRIP_NONDEBUG
+ && obfd->xvec->flavour != bfd_target_elf_flavour
+ && (flags & SEC_ALLOC) != 0)
flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD);
osection = bfd_make_section_anyway_with_flags (obfd, name, flags);
size = bfd_section_size (ibfd, isection);
if (copy_byte >= 0)
size = (size + interleave - 1) / interleave;
+ else if (extract_symbol)
+ size = 0;
if (! bfd_set_section_size (obfd, osection, size))
{
err = _("size");
else
vma += change_section_address;
- if (! bfd_set_section_vma (obfd, osection, vma))
+ if (! bfd_set_section_vma (obfd, osection, extract_symbol ? 0 : vma))
{
err = _("vma");
goto loser;
else
lma += change_section_address;
- osection->lma = lma;
+ osection->lma = extract_symbol ? 0 : lma;
/* FIXME: This is probably not enough. If we change the LMA we
may have to recompute the header for the file as well. */
bfd_get_section_by_name since some formats allow multiple
sections with the same name. */
isection->output_section = osection;
- isection->output_offset = 0;
+ isection->output_offset = extract_symbol ? vma : 0;
+
+ /* Do not copy backend data if --extract-symbol is passed; anything
+ that needs to look at the section contents will fail. */
+ if (extract_symbol)
+ return;
/* Allow the BFD backend to copy any private data it understands
from the input section to the output section. */
- if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour
- && strip_symbols == STRIP_NONDEBUG)
- /* Do not copy the private data when creating an ELF format
- debug info file. We do not want the program headers. */
- ;
- else if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
+ if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
{
err = _("private data");
goto loser;
}
+ else if ((isection->flags & SEC_GROUP) != 0)
+ {
+ asymbol *gsym = group_signature (isection);
+
+ if (gsym != NULL)
+ gsym->flags |= BSF_KEEP;
+ }
/* All went well. */
return;
free (relpp);
}
+ if (extract_symbol)
+ return;
+
if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
&& bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
{
if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size))
RETURN_NONFATAL (bfd_get_filename (ibfd));
+ if (reverse_bytes)
+ {
+ /* We don't handle leftover bytes (too many possible behaviors,
+ and we don't know what the user wants). The section length
+ must be a multiple of the number of bytes to swap. */
+ if ((size % reverse_bytes) == 0)
+ {
+ unsigned long i, j;
+ bfd_byte b;
+
+ for (i = 0; i < size; i += reverse_bytes)
+ for (j = 0; j < (unsigned long)(reverse_bytes / 2); j++)
+ {
+ bfd_byte *m = (bfd_byte *) memhunk;
+
+ b = m[i + j];
+ m[i + j] = m[(i + reverse_bytes) - (j + 1)];
+ m[(i + reverse_bytes) - (j + 1)] = b;
+ }
+ }
+ else
+ /* User must pad the section up in order to do this. */
+ fatal (_("cannot reverse bytes: length of section %s must be evenly divisible by %d"),
+ bfd_section_name (ibfd, isection), reverse_bytes);
+ }
+
if (copy_byte >= 0)
{
/* Keep only every `copy_byte'th byte in MEMHUNK. */
case OPTION_ONLY_KEEP_DEBUG:
strip_symbols = STRIP_NONDEBUG;
break;
+ case OPTION_KEEP_FILE_SYMBOLS:
+ keep_file_symbols = 1;
+ break;
case 0:
/* We've been given a long option. */
break;
char *tmpname;
if (get_file_size (argv[i]) < 1)
- continue;
+ {
+ status = 1;
+ continue;
+ }
if (preserve_dates)
/* No need to check the return value of stat().
It has already been checked in get_file_size(). */
stat (argv[i], &statbuf);
- if (output_file != NULL)
- tmpname = output_file;
- else
+ if (output_file == NULL || strcmp (argv[i], output_file) == 0)
tmpname = make_tempname (argv[i]);
- status = 0;
+ else
+ tmpname = output_file;
+
+ if (tmpname == NULL)
+ {
+ non_fatal (_("could not create temporary file to hold stripped copy of '%s'"),
+ argv[i]);
+ status = 1;
+ continue;
+ }
+ 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);
+ if (output_file != tmpname)
+ smart_rename (tmpname, output_file ? output_file : argv[i],
+ preserve_dates);
status = hold_status;
}
else
unlink_if_ordinary (tmpname);
- if (output_file == NULL)
+ if (output_file != tmpname)
free (tmpname);
}
- return 0;
+ return status;
}
static int
char * binary_architecture = NULL;
char *input_filename = NULL;
char *output_filename = NULL;
+ char *tmpname;
char *input_target = NULL;
char *output_target = NULL;
bfd_boolean show_version = FALSE;
strip_symbols = STRIP_NONDEBUG;
break;
+ case OPTION_KEEP_FILE_SYMBOLS:
+ keep_file_symbols = 1;
+ break;
+
case OPTION_ADD_GNU_DEBUGLINK:
gnu_debuglink_filename = optarg;
break;
size = get_file_size (s + 1);
if (size < 1)
- break;
+ {
+ status = 1;
+ break;
+ }
pa = xmalloc (sizeof (struct section_add));
add_specific_symbols (optarg, &keep_specific_list);
break;
+ case OPTION_LOCALIZE_HIDDEN:
+ localize_hidden = TRUE;
+ break;
+
case OPTION_LOCALIZE_SYMBOLS:
add_specific_symbols (optarg, &localize_specific_list);
break;
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"));
+ use_alt_mach_code = strtoul (optarg, NULL, 0);
+ if (use_alt_mach_code == 0)
+ fatal (_("unable to parse alternative machine code"));
break;
case OPTION_PREFIX_SYMBOLS:
bfd_flags_to_set &= ~D_PAGED;
break;
+ case OPTION_EXTRACT_SYMBOL:
+ extract_symbol = TRUE;
+ break;
+
+ case OPTION_REVERSE_BYTES:
+ {
+ int prev = reverse_bytes;
+
+ reverse_bytes = atoi (optarg);
+ if ((reverse_bytes <= 0) || ((reverse_bytes % 2) != 0))
+ fatal (_("number of bytes to reverse must be positive and even"));
+
+ if (prev && prev != reverse_bytes)
+ non_fatal (_("Warning: ignoring previous --reverse-bytes value of %d"),
+ prev);
+ break;
+ }
+
case 0:
/* We've been given a long option. */
break;
/* If there is no destination file, or the source and destination files
are the same, then create a temp and rename the result into the input. */
if (output_filename == NULL || strcmp (input_filename, output_filename) == 0)
- {
- 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);
- }
+ tmpname = make_tempname (input_filename);
else
+ tmpname = output_filename;
+
+ if (tmpname == NULL)
+ fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"),
+ input_filename, strerror (errno));
+
+ copy_file (input_filename, tmpname, input_target, output_target);
+ if (status == 0)
{
- copy_file (input_filename, output_filename, input_target, output_target);
-
- if (status == 0 && preserve_dates)
- set_times (output_filename, &statbuf);
- else if (status != 0)
- unlink_if_ordinary (output_filename);
+ if (preserve_dates)
+ set_times (tmpname, &statbuf);
+ if (tmpname != output_filename)
+ smart_rename (tmpname, input_filename, preserve_dates);
}
+ else
+ unlink_if_ordinary (tmpname);
if (change_warn)
{
START_PROGRESS (program_name, 0);
+ expandargv (&argc, &argv);
+
strip_symbols = STRIP_UNDEF;
discard_locals = LOCALS_UNDEF;