/* 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, 2005, 2006
Free Software Foundation, Inc.
This file is part of GNU Binutils.
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. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
\f
#include "bfd.h"
#include "progress.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;
+static flagword bfd_flags_to_clear;
/* List of sections to add. */
struct section_add
/* 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;
+/* 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;
+static struct symlist *strip_unneeded_list = NULL;
static struct symlist *keep_specific_list = NULL;
static struct symlist *localize_specific_list = NULL;
+static struct symlist *globalize_specific_list = NULL;
static struct symlist *keepglobal_specific_list = NULL;
static struct symlist *weaken_specific_list = NULL;
static struct redefine_node *redefine_sym_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;
OPTION_SREC_LEN,
OPTION_SREC_FORCES3,
OPTION_STRIP_SYMBOLS,
+ OPTION_STRIP_UNNEEDED_SYMBOL,
+ OPTION_STRIP_UNNEEDED_SYMBOLS,
OPTION_KEEP_SYMBOLS,
+ OPTION_LOCALIZE_HIDDEN,
OPTION_LOCALIZE_SYMBOLS,
+ OPTION_GLOBALIZE_SYMBOL,
+ OPTION_GLOBALIZE_SYMBOLS,
OPTION_KEEPGLOBAL_SYMBOLS,
OPTION_WEAKEN_SYMBOLS,
OPTION_RENAME_SECTION,
OPTION_PREFIX_ALLOC_SECTIONS,
OPTION_FORMATS_INFO,
OPTION_ADD_GNU_DEBUGLINK,
- OPTION_ONLY_KEEP_DEBUG
+ OPTION_ONLY_KEEP_DEBUG,
+ OPTION_KEEP_FILE_SYMBOLS,
+ OPTION_READONLY_TEXT,
+ OPTION_WRITABLE_TEXT,
+ OPTION_PURE,
+ OPTION_IMPURE
};
/* 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 */
{"discard-locals", no_argument, 0, 'X'},
{"format", required_argument, 0, 'F'}, /* Obsolete */
{"gap-fill", required_argument, 0, OPTION_GAP_FILL},
+ {"globalize-symbol", required_argument, 0, OPTION_GLOBALIZE_SYMBOL},
+ {"globalize-symbols", required_argument, 0, OPTION_GLOBALIZE_SYMBOLS},
{"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'},
{"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},
{"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},
{"strip-all", no_argument, 0, 'S'},
{"strip-debug", no_argument, 0, 'g'},
{"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
+ {"strip-unneeded-symbol", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOL},
+ {"strip-unneeded-symbols", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOLS},
{"strip-symbol", required_argument, 0, 'N'},
{"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS},
{"target", required_argument, 0, 'F'},
{"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}
};
/* 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 *);
-g --strip-debug Remove all debugging symbols & sections\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\
+ --strip-unneeded-symbol <name>\n\
+ Do not copy symbol <name> unless needed by\n\
+ relocations\n\
+ --only-keep-debug Strip everything but the debug information\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\
-W --weaken-symbol <name> Force symbol <name> 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 <number> Only copy one out of every <number> bytes\n\
--srec-len <number> Restrict the length of generated Srecords\n\
--srec-forceS3 Restrict the type of generated Srecords to S3\n\
--strip-symbols <file> -N for all symbols listed in <file>\n\
+ --strip-unneeded-symbols <file>\n\
+ --strip-unneeded-symbol for all symbols listed\n\
+ in <file>\n\
--keep-symbols <file> -K for all symbols listed in <file>\n\
--localize-symbols <file> -L for all symbols 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\
+ --impure Mark the output file as impure\n\
--prefix-symbols <prefix> Add <prefix> to start of every symbol name\n\
--prefix-sections <prefix> Add <prefix> to start of every section name\n\
--prefix-alloc-sections <prefix>\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\
-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=<name> Do not copy symbol <name>\n\
- -K --keep-symbol=<name> Only copy symbol <name>\n\
- -w --wildcard Permit wildcard in symbol comparasion\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\
-v --verbose List all object files modified\n\
PARSE_FLAG ("code", SEC_CODE);
PARSE_FLAG ("data", SEC_DATA);
PARSE_FLAG ("rom", SEC_ROM);
- PARSE_FLAG ("share", SEC_SHARED);
+ PARSE_FLAG ("share", SEC_COFF_SHARED);
PARSE_FLAG ("contents", SEC_HAS_CONTENTS);
#undef PARSE_FLAG
else
size = get_file_size (filename);
if (size == 0)
- return;
+ {
+ status = 1;
+ return;
+ }
buffer = xmalloc (size + 2);
f = fopen (filename, FOPEN_RT);
;
if (! IS_LINE_TERMINATOR (* extra))
- non_fatal (_("Ignoring rubbish found on line %d of %s"),
- line_count, filename);
+ non_fatal (_("%s:%d: Ignoring rubbish found on this line"),
+ filename, line_count);
}
* name_end = '\0';
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;
}
- return strip_symbols == STRIP_NONDEBUG ? TRUE : 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;
}
/* Choose which symbol entries to copy; put the result in OSYMS.
keep = (strip_symbols != STRIP_DEBUG
&& strip_symbols != STRIP_UNNEEDED
&& ! convert_debugging);
- else if (bfd_get_section (sym)->comdat)
+ 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;
if (keep && is_specified_symbol (name, strip_specific_list))
keep = 0;
- if (!keep && is_specified_symbol (name, keep_specific_list))
+ if (keep
+ && !(flags & BSF_KEEP)
+ && is_specified_symbol (name, strip_unneeded_list))
+ keep = 0;
+ if (!keep
+ && ((keep_file_symbols && (flags & BSF_FILE))
+ || 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 && !undefined && (flags & (BSF_GLOBAL | BSF_WEAK))
- && (is_specified_symbol (name, localize_specific_list)
- || (keepglobal_specific_list != NULL
- && ! is_specified_symbol (name, keepglobal_specific_list))))
+ if (keep)
{
- sym->flags &= ~(BSF_GLOBAL | BSF_WEAK);
- sym->flags |= BSF_LOCAL;
- }
+ if ((flags & BSF_GLOBAL) != 0
+ && (weaken || is_specified_symbol (name, weaken_specific_list)))
+ {
+ sym->flags &= ~ BSF_GLOBAL;
+ sym->flags |= BSF_WEAK;
+ }
- if (keep)
- to[dst_count++] = sym;
+ if (!undefined
+ && (flags & (BSF_GLOBAL | BSF_WEAK))
+ && (is_specified_symbol (name, localize_specific_list)
+ || (keepglobal_specific_list != NULL
+ && ! is_specified_symbol (name, keepglobal_specific_list))
+ || (localize_hidden && is_hidden_symbol (sym))))
+ {
+ sym->flags &= ~ (BSF_GLOBAL | BSF_WEAK);
+ sym->flags |= BSF_LOCAL;
+ }
+
+ if (!undefined
+ && (flags & BSF_LOCAL)
+ && is_specified_symbol (name, globalize_specific_list))
+ {
+ sym->flags &= ~ BSF_LOCAL;
+ sym->flags |= BSF_GLOBAL;
+ }
+
+ to[dst_count++] = sym;
+ }
}
to[dst_count] = NULL;
continue;
}
else
- fatal (_("%s: garbage at end of line %d"), filename, lineno);
+ fatal (_("%s:%d: garbage found at end of line"), filename, lineno);
comment:
if (len != 0 && (outsym_off == 0 || outsym_off == len))
- fatal (_("%s: missing new symbol name at line %d"), filename, lineno);
+ fatal (_("%s:%d: missing new symbol name"), filename, lineno);
buf[len++] = '\0';
/* Eat the rest of the line and finish it. */
}
if (len != 0)
- fatal (_("%s: premature end of file at line %d"), filename, lineno);
+ fatal (_("%s:%d: premature end of file"), filename, lineno);
free (buf);
}
-/* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long.
- Adjust *SIZE. */
+/* Copy unkown object file IBFD onto OBFD.
+ Returns TRUE upon success, FALSE otherwise. */
-static void
-filter_bytes (char *memhunk, bfd_size_type *size)
+static bfd_boolean
+copy_unknown_object (bfd *ibfd, bfd *obfd)
{
- char *from = memhunk + copy_byte, *to = memhunk, *end = memhunk + *size;
+ char *cbuf;
+ int tocopy;
+ long ncopied;
+ long size;
+ struct stat buf;
- for (; from < end; from += interleave)
- *to++ = *from;
+ if (bfd_stat_arch_elt (ibfd, &buf) != 0)
+ {
+ bfd_nonfatal (bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
- if (*size % interleave > (bfd_size_type) copy_byte)
- *size = (*size / interleave) + 1;
- else
- *size /= interleave;
+ size = buf.st_size;
+ if (size < 0)
+ {
+ non_fatal (_("stat returns negative size for `%s'"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
+ if (bfd_seek (ibfd, (file_ptr) 0, SEEK_SET) != 0)
+ {
+ bfd_nonfatal (bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
+ if (verbose)
+ printf (_("copy from `%s' [unknown] to `%s' [unknown]\n"),
+ bfd_get_archive_filename (ibfd), bfd_get_filename (obfd));
+
+ cbuf = xmalloc (BUFSIZE);
+ ncopied = 0;
+ while (ncopied < size)
+ {
+ tocopy = size - ncopied;
+ if (tocopy > BUFSIZE)
+ tocopy = BUFSIZE;
+
+ if (bfd_bread (cbuf, (bfd_size_type) tocopy, ibfd)
+ != (bfd_size_type) tocopy)
+ {
+ bfd_nonfatal (bfd_get_archive_filename (ibfd));
+ free (cbuf);
+ return FALSE;
+ }
+
+ if (bfd_bwrite (cbuf, (bfd_size_type) tocopy, obfd)
+ != (bfd_size_type) tocopy)
+ {
+ bfd_nonfatal (bfd_get_filename (obfd));
+ free (cbuf);
+ return FALSE;
+ }
+
+ ncopied += tocopy;
+ }
+
+ chmod (bfd_get_filename (obfd), buf.st_mode);
+ free (cbuf);
+ return TRUE;
}
-/* 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;
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"),
- bfd_get_filename (ibfd), bfd_get_target (ibfd),
+ printf (_("copy from `%s' [%s] to `%s' [%s]\n"),
+ bfd_get_archive_filename (ibfd), bfd_get_target (ibfd),
bfd_get_filename (obfd), bfd_get_target (obfd));
if (set_start_set)
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_archive_filename (ibfd));
+ return FALSE;
+ }
}
/* Copy architecture of input file to output file. */
if (!bfd_set_arch_mach (obfd, iarch, imach)
&& (ibfd->target_defaulted
|| bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
- non_fatal (_("Warning: Output file cannot represent architecture %s"),
- bfd_printable_arch_mach (bfd_get_arch (ibfd),
- bfd_get_mach (ibfd)));
+ {
+ if (bfd_get_arch (ibfd) == bfd_arch_unknown)
+ non_fatal (_("Unable to recognise the format of the input file `%s'"),
+ bfd_get_archive_filename (ibfd));
+ else
+ non_fatal (_("Warning: Output file cannot represent architecture `%s'"),
+ bfd_printable_arch_mach (bfd_get_arch (ibfd),
+ bfd_get_mach (ibfd)));
+ return FALSE;
+ }
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
- RETURN_NONFATAL (bfd_get_filename (ibfd));
+ {
+ bfd_nonfatal (bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
if (isympp)
free (isympp);
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);
+ setup_bfd_headers (ibfd, obfd);
+
if (add_sections != NULL)
{
struct section_add *padd;
{
flagword flags;
- 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;
- }
-
- 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;
+ flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
if (pset != NULL && pset->set_flags)
flags = pset->flags | SEC_HAS_CONTENTS;
+
+ /* 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 add section '%s' - it already exists!"), padd->name);
+ return FALSE;
+ }
else
- flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
+ {
+ 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_flags (obfd, padd->section, flags))
- RETURN_NONFATAL (bfd_get_filename (obfd));
+ if (! bfd_set_section_size (obfd, padd->section, padd->size))
+ {
+ 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;
+ }
}
}
}
(obfd, gnu_debuglink_filename);
if (gnu_debuglink_section == NULL)
- RETURN_NONFATAL (gnu_debuglink_filename);
+ {
+ bfd_nonfatal (gnu_debuglink_filename);
+ 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 (bfd_count_sections (obfd) == 0)
+ {
+ non_fatal (_("there are no sections to be copied!"));
+ return FALSE;
}
if (gap_fill_set || pad_to_set)
/* 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 = 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);
|| 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
+ || globalize_specific_list != NULL
|| keepglobal_specific_list != NULL
|| weaken_specific_list != NULL
|| prefix_symbols_string
if (! write_debugging_info (obfd, dhandle, &symcount, &osympp))
{
status = 1;
- return;
+ return FALSE;
}
}
{
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;
+ }
}
}
{
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)
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;
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
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 (! 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
#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
{
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, "/",
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 = xmalloc (sizeof (struct name_list));
l->name = output_name;
l->next = list;
+ l->obfd = NULL;
list = l;
- if (output_bfd == NULL)
- RETURN_NONFATAL (output_name);
-
if (bfd_check_format (this_element, bfd_object))
- copy_object (this_element, output_bfd);
+ {
+ /* 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);
- if (!bfd_close (output_bfd))
+ delete = ! copy_object (this_element, output_bfd);
+
+ if (! delete
+ || bfd_get_arch (this_element) != bfd_arch_unknown)
+ {
+ if (!bfd_close (output_bfd))
+ {
+ bfd_nonfatal (bfd_get_filename (output_bfd));
+ /* Error in new object file. Don't change archive. */
+ status = 1;
+ }
+ }
+ else
+ goto copy_unknown_element;
+ }
+ else
{
- bfd_nonfatal (bfd_get_filename (output_bfd));
- /* Error in new object file. Don't change archive. */
- status = 1;
+ 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))
+ {
+ 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);
+ 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;
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))
{
bfd *obfd;
do_copy:
+
/* bfd_get_target does not return the correct value until
bfd_check_format succeeds. */
if (output_target == NULL)
if (obfd == NULL)
RETURN_NONFATAL (output_filename);
- copy_object (ibfd, obfd);
+ if (! copy_object (ibfd, obfd))
+ status = 1;
if (!bfd_close (obfd))
RETURN_NONFATAL (output_filename);
if (!bfd_close (ibfd))
RETURN_NONFATAL (input_filename);
+
}
else
{
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. */
name = n;
}
- osection = bfd_make_section_anyway (obfd, name);
+ 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);
+
+ osection = bfd_make_section_anyway_with_flags (obfd, name, flags);
if (osection == NULL)
{
goto loser;
}
+ if (strip_symbols == STRIP_NONDEBUG
+ && obfd->xvec->flavour == bfd_target_elf_flavour
+ && (flags & SEC_ALLOC) != 0
+ && (p == NULL || !p->set_flags))
+ elf_section_type (osection) = SHT_NOBITS;
+
size = bfd_section_size (ibfd, isection);
if (copy_byte >= 0)
size = (size + interleave - 1) / interleave;
goto loser;
}
- if (p != NULL && p->set_flags)
- 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;
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;
return;
osection = isection->output_section;
- size = bfd_get_section_size_before_reloc (isection);
+ size = bfd_get_section_size (isection);
if (size == 0 || osection == 0)
return;
}
bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
+ if (relcount == 0)
+ free (relpp);
}
- isection->_cooked_size = isection->_raw_size;
- isection->reloc_done = TRUE;
-
if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
&& bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
{
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));
return -1;
/* Sort sections with the same LMA by size. */
- if ((*sec1)->_raw_size > (*sec2)->_raw_size)
+ if (bfd_get_section_size (*sec1) > bfd_get_section_size (*sec2))
return 1;
- else if ((*sec1)->_raw_size < (*sec2)->_raw_size)
+ else if (bfd_get_section_size (*sec1) < bfd_get_section_size (*sec2))
return -1;
return 0;
bfd_byte *syms, *strings;
bfd_size_type symsize, stringsize;
asection *stabsec, *stabstrsec;
+ flagword flags;
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");
+ flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING;
+ stabsec = bfd_make_section_with_flags (obfd, ".stab", flags);
+ stabstrsec = bfd_make_section_with_flags (obfd, ".stabstr", flags);
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)))
+ || ! bfd_set_section_alignment (obfd, stabstrsec, 0))
{
non_fatal (_("%s: can't create debugging section: %s"),
bfd_get_filename (obfd),
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().
tmpname = output_file;
else
tmpname = make_tempname (argv[i]);
- status = 0;
+ status = 0;
copy_file (argv[i], tmpname, input_target, output_target);
if (status == 0)
{
status = hold_status;
}
else
- unlink (tmpname);
+ unlink_if_ordinary (tmpname);
if (output_file == NULL)
free (tmpname);
}
- return 0;
+ return status;
}
static int
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;
add_specific_symbol (optarg, &strip_specific_list);
break;
+ case OPTION_STRIP_UNNEEDED_SYMBOL:
+ add_specific_symbol (optarg, &strip_unneeded_list);
+ break;
+
case 'L':
add_specific_symbol (optarg, &localize_specific_list);
break;
+ case OPTION_GLOBALIZE_SYMBOL:
+ add_specific_symbol (optarg, &globalize_specific_list);
+ break;
+
case 'G':
add_specific_symbol (optarg, &keepglobal_specific_list);
break;
size = get_file_size (s + 1);
if (size < 1)
- break;
+ {
+ status = 1;
+ break;
+ }
pa = xmalloc (sizeof (struct section_add));
add_specific_symbols (optarg, &strip_specific_list);
break;
+ case OPTION_STRIP_UNNEEDED_SYMBOLS:
+ add_specific_symbols (optarg, &strip_unneeded_list);
+ break;
+
case OPTION_KEEP_SYMBOLS:
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;
+ case OPTION_GLOBALIZE_SYMBOLS:
+ add_specific_symbols (optarg, &globalize_specific_list);
+ break;
+
case OPTION_KEEPGLOBAL_SYMBOLS:
add_specific_symbols (optarg, &keepglobal_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:
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;
if (status == 0 && preserve_dates)
set_times (output_filename, &statbuf);
+ else if (status != 0)
+ unlink_if_ordinary (output_filename);
}
if (change_warn)
START_PROGRESS (program_name, 0);
+ expandargv (&argc, &argv);
+
strip_symbols = STRIP_UNDEF;
discard_locals = LOCALS_UNDEF;