X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Fobjcopy.c;h=839d27bc17b4fb68687b5a73bc33689257bda7e4;hb=80fccad2d4ce82a2ed9a5d8d081eb2daefa09f9d;hp=25890176ba9a49dfd760255ac57d4de75cc0a8ff;hpb=f57a841aea536a33e06a67c13bb15245742ba330;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objcopy.c b/binutils/objcopy.c index 25890176ba..839d27bc17 100644 --- a/binutils/objcopy.c +++ b/binutils/objcopy.c @@ -1,6 +1,6 @@ /* 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 + 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -28,6 +28,7 @@ #include "budbg.h" #include "filenames.h" #include "fnmatch.h" +#include "elf-bfd.h" #include /* A list of symbols to explicitly strip out, or to keep. A linked @@ -148,6 +149,10 @@ static bfd_vma pad_to; /* Use alternate machine code? */ static int use_alt_mach_code = 0; +/* Output BFD flags user wants to set or clear */ +static flagword bfd_flags_to_set; +static flagword bfd_flags_to_clear; + /* List of sections to add. */ struct section_add { @@ -181,7 +186,7 @@ static bfd_boolean change_leading_char = FALSE; /* Whether to remove the leading character from global symbol names. */ static bfd_boolean remove_leading_char = FALSE; -/* Whether to permit wildcard in symbol comparasion. */ +/* Whether to permit wildcard in symbol comparison. */ static bfd_boolean wildcard = FALSE; /* List of symbols to strip, keep, localize, keep-global, weaken, @@ -237,7 +242,11 @@ enum command_line_switch OPTION_PREFIX_ALLOC_SECTIONS, OPTION_FORMATS_INFO, OPTION_ADD_GNU_DEBUGLINK, - OPTION_ONLY_KEEP_DEBUG + OPTION_ONLY_KEEP_DEBUG, + OPTION_READONLY_TEXT, + OPTION_WRITABLE_TEXT, + OPTION_PURE, + OPTION_IMPURE }; /* Options to handle if running as "strip". */ @@ -295,6 +304,7 @@ static struct option copy_options[] = {"format", required_argument, 0, 'F'}, /* Obsolete */ {"gap-fill", required_argument, 0, OPTION_GAP_FILL}, {"help", no_argument, 0, 'h'}, + {"impure", no_argument, 0, OPTION_IMPURE}, {"info", no_argument, 0, OPTION_FORMATS_INFO}, {"input-format", required_argument, 0, 'I'}, /* Obsolete */ {"input-target", required_argument, 0, 'I'}, @@ -316,6 +326,8 @@ static struct option copy_options[] = {"prefix-sections", required_argument, 0, OPTION_PREFIX_SECTIONS}, {"prefix-alloc-sections", required_argument, 0, OPTION_PREFIX_ALLOC_SECTIONS}, {"preserve-dates", no_argument, 0, 'p'}, + {"pure", no_argument, 0, OPTION_PURE}, + {"readonly-text", no_argument, 0, OPTION_READONLY_TEXT}, {"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM}, {"redefine-syms", required_argument, 0, OPTION_REDEFINE_SYMS}, {"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR}, @@ -337,6 +349,7 @@ static struct option copy_options[] = {"weaken-symbol", required_argument, 0, 'W'}, {"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS}, {"wildcard", no_argument, 0, 'w'}, + {"writable-text", no_argument, 0, OPTION_WRITABLE_TEXT}, {0, no_argument, 0, 0} }; @@ -364,6 +377,7 @@ extern unsigned long bfd_external_machine; /* Forward declarations. */ static void setup_section (bfd *, asection *, void *); +static void setup_bfd_headers (bfd *, bfd *); static void copy_section (bfd *, asection *, void *); static void get_sections (bfd *, asection *, void *); static int compare_section_lma (const void *, const void *); @@ -391,12 +405,13 @@ copy_usage (FILE *stream, int exit_status) -g --strip-debug Remove all debugging symbols & sections\n\ --strip-unneeded Remove all symbols not needed by relocations\n\ -N --strip-symbol Do not copy symbol \n\ + --only-keep-debug Strip everything but the debug information\n\ -K --keep-symbol Only copy symbol \n\ -L --localize-symbol Force symbol to be marked as a local\n\ -G --keep-global-symbol Localize all symbols except \n\ -W --weaken-symbol Force symbol to be marked as a weak\n\ --weaken Force all global symbols to be marked as weak\n\ - -w --wildcard Permit wildcard in symbol comparasion\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\ -i --interleave Only copy one out of every bytes\n\ @@ -433,6 +448,10 @@ copy_usage (FILE *stream, int exit_status) --keep-global-symbols -G for all symbols listed in \n\ --weaken-symbols -W for all symbols listed in \n\ --alt-machine-code Use alternate machine code for output\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\ + --impure Mark the output file as impure\n\ --prefix-symbols Add to start of every symbol name\n\ --prefix-sections Add to start of every section name\n\ --prefix-alloc-sections \n\ @@ -464,9 +483,10 @@ strip_usage (FILE *stream, int exit_status) -s --strip-all Remove all symbol and relocation information\n\ -g -S -d --strip-debug Remove all debugging symbols & sections\n\ --strip-unneeded Remove all symbols not needed by relocations\n\ + --only-keep-debug Strip everything but the debug information\n\ -N --strip-symbol= Do not copy symbol \n\ -K --keep-symbol= Only copy symbol \n\ - -w --wildcard Permit wildcard in symbol comparasion\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\ -v --verbose List all object files modified\n\ @@ -758,7 +778,7 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) return FALSE; } - return strip_symbols == STRIP_NONDEBUG ? TRUE : FALSE; + return FALSE; } /* Choose which symbol entries to copy; put the result in OSYMS. @@ -1066,26 +1086,10 @@ add_redefine_syms_file (const char *filename) free (buf); } -/* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long. - Adjust *SIZE. */ - -static void -filter_bytes (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. */ +/* Copy object file IBFD onto OBFD. + Returns TRUE upon success, FALSE otherwise. */ -static void +static bfd_boolean copy_object (bfd *ibfd, bfd *obfd) { bfd_vma start; @@ -1102,13 +1106,13 @@ copy_object (bfd *ibfd, bfd *obfd) if (ibfd->xvec->byteorder != obfd->xvec->byteorder && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) - { - fatal (_("Unable to change endianness of input file(s)")); - return; - } + fatal (_("Unable to change endianness of input file(s)")); if (!bfd_set_format (obfd, bfd_get_format (ibfd))) - RETURN_NONFATAL (bfd_get_filename (obfd)); + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } if (verbose) printf (_("copy from %s(%s) to %s(%s)\n"), @@ -1125,11 +1129,19 @@ copy_object (bfd *ibfd, bfd *obfd) need to be set for a core file. */ if (bfd_get_format (obfd) != bfd_core) { + flagword flags; + + flags = bfd_get_file_flags (ibfd); + flags |= bfd_flags_to_set; + flags &= ~bfd_flags_to_clear; + flags &= bfd_applicable_file_flags (obfd); + 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)); + || !bfd_set_file_flags (obfd, flags)) + { + bfd_nonfatal (bfd_get_filename (ibfd)); + return FALSE; + } } /* Copy architecture of input file to output file. */ @@ -1147,13 +1159,15 @@ copy_object (bfd *ibfd, bfd *obfd) non_fatal (_("Warning: Output file cannot represent architecture %s"), bfd_printable_arch_mach (bfd_get_arch (ibfd), bfd_get_mach (ibfd))); - status = 1; - return; + return FALSE; } } if (!bfd_set_format (obfd, bfd_get_format (ibfd))) - RETURN_NONFATAL (bfd_get_filename (ibfd)); + { + bfd_nonfatal (bfd_get_filename (ibfd)); + return FALSE; + } if (isympp) free (isympp); @@ -1165,6 +1179,8 @@ copy_object (bfd *ibfd, bfd *obfd) any output is done. Thus, we traverse all sections multiple times. */ bfd_map_over_sections (ibfd, setup_section, obfd); + setup_bfd_headers (ibfd, obfd); + if (add_sections != NULL) { struct section_add *padd; @@ -1179,12 +1195,14 @@ copy_object (bfd *ibfd, bfd *obfd) { non_fatal (_("can't create section `%s': %s"), padd->name, bfd_errmsg (bfd_get_error ())); - status = 1; - return; + return FALSE; } if (! bfd_set_section_size (obfd, padd->section, padd->size)) - RETURN_NONFATAL (bfd_get_filename (obfd)); + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } pset = find_section_list (padd->name, FALSE); if (pset != NULL) @@ -1196,23 +1214,32 @@ copy_object (bfd *ibfd, bfd *obfd) flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA; if (! bfd_set_section_flags (obfd, padd->section, flags)) - RETURN_NONFATAL (bfd_get_filename (obfd)); + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } 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)); + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } 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)); + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } } } } @@ -1224,7 +1251,16 @@ copy_object (bfd *ibfd, bfd *obfd) (obfd, gnu_debuglink_filename); if (gnu_debuglink_section == NULL) - RETURN_NONFATAL (gnu_debuglink_filename); + { + bfd_nonfatal (gnu_debuglink_filename); + return FALSE; + } + } + + if (bfd_count_sections (obfd) == 0) + { + non_fatal (_("there are no sections to be copied!")); + return FALSE; } if (gap_fill_set || pad_to_set) @@ -1314,12 +1350,18 @@ copy_object (bfd *ibfd, bfd *obfd) dhandle = NULL; symsize = bfd_get_symtab_upper_bound (ibfd); if (symsize < 0) - RETURN_NONFATAL (bfd_get_filename (ibfd)); + { + bfd_nonfatal (bfd_get_filename (ibfd)); + return FALSE; + } osympp = isympp = xmalloc (symsize); symcount = bfd_canonicalize_symtab (ibfd, isympp); if (symcount < 0) - RETURN_NONFATAL (bfd_get_filename (ibfd)); + { + bfd_nonfatal (bfd_get_filename (ibfd)); + return FALSE; + } if (convert_debugging) dhandle = read_debugging_info (ibfd, isympp, symcount); @@ -1364,7 +1406,7 @@ copy_object (bfd *ibfd, bfd *obfd) if (! write_debugging_info (obfd, dhandle, &symcount, &osympp)) { status = 1; - return; + return FALSE; } } @@ -1381,7 +1423,10 @@ copy_object (bfd *ibfd, bfd *obfd) { if (! bfd_set_section_contents (obfd, padd->section, padd->contents, 0, padd->size)) - RETURN_NONFATAL (bfd_get_filename (obfd)); + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } } } @@ -1389,7 +1434,10 @@ copy_object (bfd *ibfd, bfd *obfd) { if (! bfd_fill_in_gnu_debuglink_section (obfd, gnu_debuglink_section, gnu_debuglink_filename)) - RETURN_NONFATAL (gnu_debuglink_filename); + { + bfd_nonfatal (gnu_debuglink_filename); + return FALSE; + } } if (gap_fill_set || pad_to_set) @@ -1425,7 +1473,10 @@ copy_object (bfd *ibfd, bfd *obfd) if (! bfd_set_section_contents (obfd, osections[i], buf, off, now)) - RETURN_NONFATAL (bfd_get_filename (obfd)); + { + bfd_nonfatal (bfd_get_filename (obfd)); + return FALSE; + } left -= now; off += now; @@ -1448,18 +1499,17 @@ copy_object (bfd *ibfd, bfd *obfd) non_fatal (_("%s: error copying private BFD data: %s"), bfd_get_filename (obfd), bfd_errmsg (bfd_get_error ())); - status = 1; - return; + return FALSE; } /* 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")); - } + if (use_alt_mach_code != 0 + && ! bfd_alt_mach_code (obfd, use_alt_mach_code)) + non_fatal (_("unknown alternate machine code, ignored")); + + return TRUE; } #undef MKDIR @@ -1506,6 +1556,7 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target) bfd *last_element; struct stat buf; int stat_status = 0; + bfd_boolean delete = TRUE; /* Create an output file for this member. */ output_name = concat (dir, "/", @@ -1547,7 +1598,7 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target) RETURN_NONFATAL (output_name); if (bfd_check_format (this_element, bfd_object)) - copy_object (this_element, output_bfd); + delete = ! copy_object (this_element, output_bfd); if (!bfd_close (output_bfd)) { @@ -1556,22 +1607,30 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target) status = 1; } - if (preserve_dates && stat_status == 0) - set_times (output_name, &buf); + if (delete) + { + unlink (output_name); + status = 1; + } + else + { + 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); + /* Open the newly output file and attach to our list. */ + output_bfd = bfd_openr (output_name, output_target); - l->obfd = output_bfd; + l->obfd = output_bfd; - *ptr = output_bfd; - ptr = &output_bfd->next; + *ptr = output_bfd; + ptr = &output_bfd->next; - last_element = this_element; + last_element = this_element; - this_element = bfd_openr_next_archived_file (ibfd, last_element); + this_element = bfd_openr_next_archived_file (ibfd, last_element); - bfd_close (last_element); + bfd_close (last_element); + } } *ptr = NULL; @@ -1635,7 +1694,9 @@ copy_file (const char *input_filename, const char *output_filename, else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching)) { bfd *obfd; + bfd_boolean delete; do_copy: + /* bfd_get_target does not return the correct value until bfd_check_format succeeds. */ if (output_target == NULL) @@ -1645,13 +1706,19 @@ copy_file (const char *input_filename, const char *output_filename, if (obfd == NULL) RETURN_NONFATAL (output_filename); - copy_object (ibfd, obfd); + delete = ! copy_object (ibfd, obfd); if (!bfd_close (obfd)) RETURN_NONFATAL (output_filename); if (!bfd_close (ibfd)) RETURN_NONFATAL (input_filename); + + if (delete) + { + unlink (output_filename); + status = 1; + } } else { @@ -1744,6 +1811,32 @@ find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection, return old_name; } +/* Once each of the sections is copied, we may still need to do some + finalization work for private section headers. Do that here. */ + +static void +setup_bfd_headers (bfd *ibfd, bfd *obfd) +{ + const char *err; + + /* Allow the BFD backend to copy any private data it understands + from the input section to the output section. */ + if (! bfd_copy_private_header_data (ibfd, obfd)) + { + err = _("private header data"); + goto loser; + } + + /* All went well. */ + return; + +loser: + non_fatal (_("%s: error in %s: %s"), + bfd_get_filename (ibfd), + err, bfd_errmsg (bfd_get_error ())); + status = 1; +} + /* Create a section in OBFD with the same name and attributes as ISECTION in IBFD. */ @@ -1846,6 +1939,13 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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) + { + flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD); + if (obfd->xvec->flavour == bfd_target_elf_flavour) + elf_section_type (osection) = SHT_NOBITS; + } + if (!bfd_set_section_flags (obfd, osection, flags)) { err = _("flags"); @@ -1966,6 +2066,8 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) } bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount); + if (relcount == 0) + free (relpp); } isection->_cooked_size = isection->_raw_size; @@ -1980,7 +2082,18 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) RETURN_NONFATAL (bfd_get_filename (ibfd)); if (copy_byte >= 0) - filter_bytes (memhunk, &size); + { + /* Keep only every `copy_byte'th byte in MEMHUNK. */ + char *from = (char *) memhunk + copy_byte; + char *to = memhunk; + char *end = (char *) memhunk + size; + + for (; from < end; from += interleave) + *to++ = *from; + + size = (size + interleave - 1 - copy_byte) / interleave; + osection->lma /= interleave; + } if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size)) RETURN_NONFATAL (bfd_get_filename (obfd)); @@ -2782,6 +2895,26 @@ copy_main (int argc, char *argv[]) prefix_alloc_sections_string = optarg; break; + case OPTION_READONLY_TEXT: + bfd_flags_to_set |= WP_TEXT; + bfd_flags_to_clear &= ~WP_TEXT; + break; + + case OPTION_WRITABLE_TEXT: + bfd_flags_to_clear |= WP_TEXT; + bfd_flags_to_set &= ~WP_TEXT; + break; + + case OPTION_PURE: + bfd_flags_to_set |= D_PAGED; + bfd_flags_to_clear &= ~D_PAGED; + break; + + case OPTION_IMPURE: + bfd_flags_to_clear |= D_PAGED; + bfd_flags_to_set &= ~D_PAGED; + break; + case 0: /* We've been given a long option. */ break;