/* objcopy.c -- copy object file from input to output, optionally massaging it.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GNU Binutils.
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;
+
/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
enum command_line_switch
{
OPTION_READONLY_TEXT,
OPTION_WRITABLE_TEXT,
OPTION_PURE,
- OPTION_IMPURE
+ OPTION_IMPURE,
+ OPTION_EXTRACT_SYMBOL
};
/* Options to handle if running as "strip". */
{"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},
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\
--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);
}
"));
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);
}
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;
}
- /* 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 ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0
- && strip_symbols == STRIP_NONDEBUG)
- return TRUE;
+ 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;
}
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. */
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);
/* 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);
}
}
+ /* 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
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 (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))
{
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. */
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)
{
else
tmpname = make_tempname (argv[i]);
+ 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)
bfd_flags_to_set &= ~D_PAGED;
break;
+ case OPTION_EXTRACT_SYMBOL:
+ extract_symbol = TRUE;
+ break;
+
case 0:
/* We've been given a long option. */
break;
{
char *tmpname = make_tempname (input_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)
{