/* objcopy.c -- copy object file from input to output, optionally massaging it.
- Copyright (C) 1991-2015 Free Software Foundation, Inc.
+ Copyright (C) 1991-2020 Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "filenames.h"
#include "fnmatch.h"
#include "elf-bfd.h"
-#include "libbfd.h"
#include "coff/internal.h"
#include "libcoff.h"
+#include "safe-ctype.h"
/* FIXME: See bfd/peXXigen.c for why we include an architecture specific
header in generic PE code. */
bfd_boolean found;
};
-/* A list to support redefine_sym. */
+/* A node includes symbol name mapping to support redefine_sym. */
struct redefine_node
{
char *source;
char *target;
- struct redefine_node *next;
};
struct addsym_node
long symval;
flagword flags;
char * section;
- char * othersym;
+ const char * othersym;
};
typedef struct section_rename
static bfd_boolean verbose; /* Print file and target names. */
static bfd_boolean preserve_dates; /* Preserve input file timestamp. */
static int deterministic = -1; /* Enable deterministic archives. */
-static int status = 0; /* Exit status. */
+static int status = 0; /* Exit status. */
+
+static bfd_boolean merge_notes = FALSE; /* Merge note sections. */
+
+typedef struct merged_note_section
+{
+ asection * sec; /* The section that is being merged. */
+ bfd_byte * contents;/* New contents of the section. */
+ bfd_size_type size; /* New size of the section. */
+ struct merged_note_section * next; /* Link to next merged note section. */
+} merged_note_section;
enum strip_action
{
COPY and REMOVE are mutually exlusive. SET and ALTER are mutually exclusive. */
#define SECTION_CONTEXT_REMOVE (1 << 0) /* Remove this section. */
#define SECTION_CONTEXT_COPY (1 << 1) /* Copy this section, delete all non-copied section. */
-#define SECTION_CONTEXT_SET_VMA (1 << 2) /* Set the sections' VMA address. */
-#define SECTION_CONTEXT_ALTER_VMA (1 << 3) /* Increment or decrement the section's VMA address. */
-#define SECTION_CONTEXT_SET_LMA (1 << 4) /* Set the sections' LMA address. */
-#define SECTION_CONTEXT_ALTER_LMA (1 << 5) /* Increment or decrement the section's LMA address. */
-#define SECTION_CONTEXT_SET_FLAGS (1 << 6) /* Set the section's flags. */
+#define SECTION_CONTEXT_KEEP (1 << 2) /* Keep this section. */
+#define SECTION_CONTEXT_SET_VMA (1 << 3) /* Set the sections' VMA address. */
+#define SECTION_CONTEXT_ALTER_VMA (1 << 4) /* Increment or decrement the section's VMA address. */
+#define SECTION_CONTEXT_SET_LMA (1 << 5) /* Set the sections' LMA address. */
+#define SECTION_CONTEXT_ALTER_LMA (1 << 6) /* Increment or decrement the section's LMA address. */
+#define SECTION_CONTEXT_SET_FLAGS (1 << 7) /* Set the section's flags. */
+#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 8) /* Remove relocations for this section. */
+#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 9) /* Set alignment for section. */
bfd_vma vma_val; /* Amount to change by or set to. */
bfd_vma lma_val; /* Amount to change by or set to. */
flagword flags; /* What to set the section flags to. */
+ unsigned int alignment; /* Alignment of output section. */
};
static struct section_list *change_sections;
decompress = 1 << 4
} do_debug_sections = nothing;
+/* Whether to generate ELF common symbols with the STT_COMMON type. */
+static enum bfd_link_elf_stt_common do_elf_stt_common = unchanged;
+
/* Whether to change the leading character in symbol names. */
static bfd_boolean change_leading_char = FALSE;
static htab_t globalize_specific_htab = NULL;
static htab_t keepglobal_specific_htab = NULL;
static htab_t weaken_specific_htab = NULL;
-static struct redefine_node *redefine_sym_list = NULL;
+static htab_t redefine_specific_htab = NULL;
+static htab_t redefine_specific_reverse_htab = NULL;
static struct addsym_node *add_sym_list = NULL, **add_sym_tail = &add_sym_list;
static int add_symbols = 0;
+static char *strip_specific_buffer = NULL;
+static char *strip_unneeded_buffer = NULL;
+static char *keep_specific_buffer = NULL;
+static char *localize_specific_buffer = NULL;
+static char *globalize_specific_buffer = NULL;
+static char *keepglobal_specific_buffer = NULL;
+static char *weaken_specific_buffer = NULL;
+
/* If this is TRUE, we weaken global symbols (set BSF_WEAK). */
static bfd_boolean weaken = FALSE;
OPTION_DEBUGGING,
OPTION_DECOMPRESS_DEBUG_SECTIONS,
OPTION_DUMP_SECTION,
+ OPTION_ELF_STT_COMMON,
OPTION_EXTRACT_DWO,
OPTION_EXTRACT_SYMBOL,
OPTION_FILE_ALIGNMENT,
OPTION_INTERLEAVE_WIDTH,
OPTION_KEEPGLOBAL_SYMBOLS,
OPTION_KEEP_FILE_SYMBOLS,
+ OPTION_KEEP_SECTION,
OPTION_KEEP_SYMBOLS,
OPTION_LOCALIZE_HIDDEN,
OPTION_LOCALIZE_SYMBOLS,
OPTION_LONG_SECTION_NAMES,
+ OPTION_MERGE_NOTES,
+ OPTION_NO_MERGE_NOTES,
OPTION_NO_CHANGE_WARNINGS,
OPTION_ONLY_KEEP_DEBUG,
OPTION_PAD_TO,
OPTION_REDEFINE_SYM,
OPTION_REDEFINE_SYMS,
OPTION_REMOVE_LEADING_CHAR,
+ OPTION_REMOVE_RELOCS,
OPTION_RENAME_SECTION,
OPTION_REVERSE_BYTES,
- OPTION_SECTION_ALIGNMENT,
+ OPTION_PE_SECTION_ALIGNMENT,
OPTION_SET_SECTION_FLAGS,
+ OPTION_SET_SECTION_ALIGNMENT,
OPTION_SET_START,
OPTION_SREC_FORCES3,
OPTION_SREC_LEN,
OPTION_STRIP_UNNEEDED_SYMBOLS,
OPTION_SUBSYSTEM,
OPTION_UPDATE_SECTION,
+ OPTION_VERILOG_DATA_WIDTH,
OPTION_WEAKEN,
OPTION_WEAKEN_SYMBOLS,
OPTION_WRITABLE_TEXT
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"input-target", required_argument, 0, 'I'},
{"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
+ {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
{"keep-symbol", required_argument, 0, 'K'},
+ {"merge-notes", no_argument, 0, 'M'},
+ {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
{"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
{"output-file", required_argument, 0, 'o'},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
{"preserve-dates", no_argument, 0, 'p'},
{"remove-section", required_argument, 0, 'R'},
+ {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
{"strip-all", no_argument, 0, 's'},
{"strip-debug", no_argument, 0, 'S'},
{"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
{"discard-all", no_argument, 0, 'x'},
{"discard-locals", no_argument, 0, 'X'},
{"dump-section", required_argument, 0, OPTION_DUMP_SECTION},
+ {"elf-stt-common", required_argument, 0, OPTION_ELF_STT_COMMON},
{"enable-deterministic-archives", no_argument, 0, 'D'},
{"extract-dwo", no_argument, 0, OPTION_EXTRACT_DWO},
{"extract-symbol", no_argument, 0, OPTION_EXTRACT_SYMBOL},
{"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-section", required_argument, 0, OPTION_KEEP_SECTION},
{"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},
{"long-section-names", required_argument, 0, OPTION_LONG_SECTION_NAMES},
+ {"merge-notes", no_argument, 0, 'M'},
+ {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
{"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
{"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
{"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
{"redefine-syms", required_argument, 0, OPTION_REDEFINE_SYMS},
{"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
{"remove-section", required_argument, 0, 'R'},
+ {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
{"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
{"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
- {"section-alignment", required_argument, 0, OPTION_SECTION_ALIGNMENT},
+ {"section-alignment", required_argument, 0, OPTION_PE_SECTION_ALIGNMENT},
{"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS},
+ {"set-section-alignment", required_argument, 0, OPTION_SET_SECTION_ALIGNMENT},
{"set-start", required_argument, 0, OPTION_SET_START},
{"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3},
{"srec-len", required_argument, 0, OPTION_SREC_LEN},
{"target", required_argument, 0, 'F'},
{"update-section", required_argument, 0, OPTION_UPDATE_SECTION},
{"verbose", no_argument, 0, 'v'},
+ {"verilog-data-width", required_argument, 0, OPTION_VERILOG_DATA_WIDTH},
{"version", no_argument, 0, 'V'},
{"weaken", no_argument, 0, OPTION_WEAKEN},
{"weaken-symbol", required_argument, 0, 'W'},
-1 means if we should use argv[0] to decide. */
extern int is_strip;
-/* The maximum length of an S record. This variable is declared in srec.c
+/* The maximum length of an S record. This variable is defined in srec.c
and can be modified by the --srec-len parameter. */
-extern unsigned int Chunk;
+extern unsigned int _bfd_srec_len;
/* Restrict the generation of Srecords to type S3 only.
- This variable is declare in bfd/srec.c and can be toggled
+ This variable is defined in bfd/srec.c and can be toggled
on by the --srec-forceS3 command line switch. */
-extern bfd_boolean S3Forced;
+extern bfd_boolean _bfd_srec_forceS3;
+
+/* Width of data in bytes for verilog output.
+ This variable is declared in bfd/verilog.c and can be modified by
+ the --verilog-data-width parameter. */
+extern unsigned int VerilogDataWidth;
/* Forward declarations. */
static void setup_section (bfd *, asection *, void *);
static void mark_symbols_used_in_relocations (bfd *, asection *, void *);
static bfd_boolean write_debugging_info (bfd *, void *, long *, asymbol ***);
static const char *lookup_sym_redefinition (const char *);
+static const char *find_section_rename (const char *, flagword *);
\f
-static void
+ATTRIBUTE_NORETURN static void
copy_usage (FILE *stream, int exit_status)
{
fprintf (stream, _("Usage: %s [option(s)] in-file [out-file]\n"), program_name);
-j --only-section <name> Only copy section <name> into the output\n\
--add-gnu-debuglink=<file> Add section .gnu_debuglink linking to <file>\n\
-R --remove-section <name> Remove section <name> from the output\n\
+ --remove-relocations <name> Remove relocations from section <name>\n\
-S --strip-all Remove all symbol and relocation information\n\
-g --strip-debug Remove all debugging symbols & sections\n\
--strip-dwo Remove all DWO sections\n\
--only-keep-debug Strip everything but the debug information\n\
--extract-dwo Copy only DWO sections\n\
--extract-symbol Remove section contents but keep symbols\n\
+ --keep-section <name> Do not strip section <name>\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\
Warn if a named section does not exist\n\
--set-section-flags <name>=<flags>\n\
Set section <name>'s properties to <flags>\n\
+ --set-section-alignment <name>=<align>\n\
+ Set section <name>'s alignment to <align> bytes\n\
--add-section <name>=<file> Add section <name> found in <file> to output\n\
--update-section <name>=<file>\n\
Update contents of section <name> with\n\
--compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
Compress DWARF debug sections using zlib\n\
--decompress-debug-sections Decompress DWARF debug sections using zlib\n\
+ --elf-stt-common=[yes|no] Generate ELF common symbols with STT_COMMON\n\
+ type\n\
+ --verilog-data-width <number> Specifies data width, in bytes, for verilog output\n\
+ -M --merge-notes Remove redundant entries in note sections\n\
+ --no-merge-notes Do not attempt to remove redundant notes (default)\n\
-v --verbose List all object files modified\n\
@<file> Read options from <file>\n\
-V --version Display this program's version number\n\
exit (exit_status);
}
-static void
+ATTRIBUTE_NORETURN static void
strip_usage (FILE *stream, int exit_status)
{
fprintf (stream, _("Usage: %s <option(s)> in-file(s)\n"), program_name);
Disable -D behavior (default)\n"));
fprintf (stream, _("\
-R --remove-section=<name> Also remove section <name> from the output\n\
+ --remove-relocations <name> Remove relocations from section <name>\n\
-s --strip-all Remove all symbol and relocation information\n\
-g -S -d --strip-debug Remove all debugging symbols & sections\n\
--strip-dwo Remove all DWO sections\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
--only-keep-debug Strip everything but the debug information\n\
+ -M --merge-notes Remove redundant entries in note sections (default)\n\
+ --no-merge-notes Do not attempt to remove redundant notes\n\
-N --strip-symbol=<name> Do not copy symbol <name>\n\
+ --keep-section=<name> Do not strip section <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\
}
if (0) ;
-#define PARSE_FLAG(fname,fval) \
- else if (strncasecmp (fname, s, len) == 0) ret |= fval
+#define PARSE_FLAG(fname,fval) \
+ else if (strncasecmp (fname, s, len) == 0) ret |= fval
PARSE_FLAG ("alloc", SEC_ALLOC);
PARSE_FLAG ("load", SEC_LOAD);
PARSE_FLAG ("noload", SEC_NEVER_LOAD);
PARSE_FLAG ("code", SEC_CODE);
PARSE_FLAG ("data", SEC_DATA);
PARSE_FLAG ("rom", SEC_ROM);
+ PARSE_FLAG ("exclude", SEC_EXCLUDE);
PARSE_FLAG ("share", SEC_COFF_SHARED);
PARSE_FLAG ("contents", SEC_HAS_CONTENTS);
PARSE_FLAG ("merge", SEC_MERGE);
copy[len] = '\0';
non_fatal (_("unrecognized section flag `%s'"), copy);
fatal (_("supported flags: %s"),
- "alloc, load, noload, readonly, debug, code, data, rom, share, contents, merge, strings");
+ "alloc, load, noload, readonly, debug, code, data, rom, exclude, share, contents, merge, strings");
}
s = snext;
string can't be parsed. */
static flagword
-parse_symflags (const char *s, char **other)
+parse_symflags (const char *s, const char **other)
{
flagword ret;
const char *snext;
- int len;
+ size_t len;
ret = BSF_NO_FLAGS;
{
snext = strchr (s, ',');
if (snext == NULL)
- len = strlen (s);
+ len = strlen (s);
else
{
len = snext - s;
++snext;
}
-#define PARSE_FLAG(fname,fval) \
- else if (len == (int) sizeof fname - 1 && strncasecmp (fname, s, len) == 0) \
+#define PARSE_FLAG(fname, fval) \
+ else if (len == sizeof fname - 1 \
+ && strncasecmp (fname, s, len) == 0) \
ret |= fval
-#define PARSE_OTHER(fname,fval) \
- else if (len >= (int) sizeof fname && strncasecmp (fname, s, sizeof fname - 1) == 0) \
+#define PARSE_OTHER(fname, fval) \
+ else if (len >= sizeof fname \
+ && strncasecmp (fname, s, sizeof fname - 1) == 0) \
fval = xstrndup (s + sizeof fname - 1, len - sizeof fname + 1)
-
+
if (0) ;
PARSE_FLAG ("local", BSF_LOCAL);
PARSE_FLAG ("global", BSF_GLOBAL);
copy[len] = '\0';
non_fatal (_("unrecognized symbol flag `%s'"), copy);
fatal (_("supported flags: %s"),
- "local, global, export, debug, function, weak, section, "
- "constructor, warning, indirect, file, object, synthetic, "
- "indirect-function, unique-object, before=<othersym>");
+ "local, global, export, debug, function, weak, section, "
+ "constructor, warning, indirect, file, object, synthetic, "
+ "indirect-function, unique-object, before=<othersym>");
}
s = snext;
static struct section_list *
find_section_list (const char *name, bfd_boolean add, unsigned int context)
{
- struct section_list *p;
+ struct section_list *p, *match = NULL;
/* assert ((context & ((1 << 7) - 1)) != 0); */
}
/* If we are not adding a new name/pattern then
only check for a match if the context applies. */
- else if ((p->context & context)
- /* We could check for the presence of wildchar characters
- first and choose between calling strcmp and fnmatch,
- but is that really worth it ? */
- && fnmatch (p->pattern, name, 0) == 0)
- {
- p->used = TRUE;
- return p;
- }
+ else if (p->context & context)
+ {
+ /* We could check for the presence of wildchar characters
+ first and choose between calling strcmp and fnmatch,
+ but is that really worth it ? */
+ if (p->pattern [0] == '!')
+ {
+ if (fnmatch (p->pattern + 1, name, 0) == 0)
+ {
+ p->used = TRUE;
+ return NULL;
+ }
+ }
+ else
+ {
+ if (fnmatch (p->pattern, name, 0) == 0)
+ {
+ if (match == NULL)
+ match = p;
+ }
+ }
+ }
}
if (! add)
- return NULL;
+ {
+ if (match != NULL)
+ match->used = TRUE;
+ return match;
+ }
p = (struct section_list *) xmalloc (sizeof (struct section_list));
p->pattern = name;
p->vma_val = 0;
p->lma_val = 0;
p->flags = 0;
+ p->alignment = 0;
p->next = change_sections;
change_sections = p;
return p;
}
+/* S1 is the entry node already in the table, S2 is the key node. */
+
+static int
+eq_string_redefnode (const void *s1, const void *s2)
+{
+ struct redefine_node *node1 = (struct redefine_node *) s1;
+ struct redefine_node *node2 = (struct redefine_node *) s2;
+ return !strcmp ((const char *) node1->source, (const char *) node2->source);
+}
+
+/* P is redefine node. Hash value is generated from its "source" filed. */
+
+static hashval_t
+htab_hash_redefnode (const void *p)
+{
+ struct redefine_node *redefnode = (struct redefine_node *) p;
+ return htab_hash_string (redefnode->source);
+}
+
+/* Create hashtab used for redefine node. */
+
+static htab_t
+create_symbol2redef_htab (void)
+{
+ return htab_create_alloc (16, htab_hash_redefnode, eq_string_redefnode, NULL,
+ xcalloc, free);
+}
+
/* There is htab_hash_string but no htab_eq_string. Makes sense. */
static int
globalize_specific_htab = create_symbol_htab ();
keepglobal_specific_htab = create_symbol_htab ();
weaken_specific_htab = create_symbol_htab ();
+ redefine_specific_htab = create_symbol2redef_htab ();
+ /* As there is no bidirectional hash table in libiberty, need a reverse table
+ to check duplicated target string. */
+ redefine_specific_reverse_htab = create_symbol_htab ();
}
/* Add a symbol to strip_specific_list. */
*htab_find_slot (htab, name, INSERT) = (char *) name;
}
+/* Like add_specific_symbol, but the element type is void *. */
+
+static void
+add_specific_symbol_node (const void *node, htab_t htab)
+{
+ *htab_find_slot (htab, node, INSERT) = (void *) node;
+}
+
/* Add symbols listed in `filename' to strip_specific_list. */
#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t')
#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
static void
-add_specific_symbols (const char *filename, htab_t htab)
+add_specific_symbols (const char *filename, htab_t htab, char **buffer_p)
{
off_t size;
FILE * f;
line = eol;
line_count ++;
}
+
+ /* Do not free the buffer. Parts of it will have been referenced
+ in the calls to add_specific_symbol. */
+ *buffer_p = buffer;
}
/* See whether a symbol should be stripped or kept
bfd *abfd = group->owner;
Elf_Internal_Shdr *ghdr;
+ /* PR 20089: An earlier error may have prevented us from loading the symbol table. */
+ if (isympp == NULL)
+ return NULL;
+
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))
+ if (ghdr->sh_link == elf_onesymtab (abfd))
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
+ Elf_Internal_Shdr *symhdr = &elf_symtab_hdr (abfd);
- if (symhdr->sh_type == SHT_SYMTAB
+ if (ghdr->sh_info > 0
&& ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
return isympp[ghdr->sh_info - 1];
}
static bfd_boolean
is_dwo_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
- const char *name = bfd_get_section_name (abfd, sec);
+ const char *name = bfd_section_name (sec);
int len = strlen (name);
return strncmp (name + len - 4, ".dwo", 4) == 0;
struct section_add *pupdate;
for (pupdate = update_sections;
- pupdate != NULL;
- pupdate = pupdate->next)
+ pupdate != NULL;
+ pupdate = pupdate->next)
{
- if (strcmp (sec->name, pupdate->name) == 0)
- return TRUE;
- }
+ if (strcmp (sec->name, pupdate->name) == 0)
+ return TRUE;
+ }
}
return FALSE;
}
+static bfd_boolean
+is_mergeable_note_section (bfd * abfd, asection * sec)
+{
+ if (merge_notes
+ && bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && elf_section_data (sec)->this_hdr.sh_type == SHT_NOTE
+ /* FIXME: We currently only support merging GNU_BUILD_NOTEs.
+ We should add support for more note types. */
+ && ((elf_section_data (sec)->this_hdr.sh_flags & SHF_GNU_BUILD_NOTE) != 0
+ /* Old versions of GAS (prior to 2.27) could not set the section
+ flags to OS-specific values, so we also accept sections that
+ start with the expected name. */
+ || (CONST_STRNEQ (sec->name, GNU_BUILD_ATTRS_SECTION_NAME))))
+ return TRUE;
+
+ return FALSE;
+}
+
/* See if a non-group section is being removed. */
static bfd_boolean
is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
+ if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)
+ != NULL)
+ return FALSE;
+
if (sections_removed || sections_copied)
{
struct section_list *p;
struct section_list *q;
- p = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
+ p = find_section_list (bfd_section_name (sec), FALSE,
SECTION_CONTEXT_REMOVE);
- q = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
+ q = find_section_list (bfd_section_name (sec), FALSE,
SECTION_CONTEXT_COPY);
if (p && q)
fatal (_("error: section %s matches both remove and copy options"),
- bfd_get_section_name (abfd, sec));
+ bfd_section_name (sec));
if (p && is_update_section (abfd, sec))
- fatal (_("error: section %s matches both update and remove options"),
- bfd_get_section_name (abfd, sec));
+ fatal (_("error: section %s matches both update and remove options"),
+ bfd_section_name (sec));
if (p != NULL)
return TRUE;
return TRUE;
}
- if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0)
+ if ((bfd_section_flags (sec) & SEC_DEBUGGING) != 0)
{
if (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_UNNEEDED
/* By default we don't want to strip .reloc section.
This section has for pe-coff special meaning. See
pe-dll.c file in ld, and peXXigen.c in bfd for details. */
- if (strcmp (bfd_get_section_name (abfd, sec), ".reloc") != 0)
+ if (strcmp (bfd_section_name (sec), ".reloc") != 0)
return TRUE;
}
if (is_strip_section_1 (abfd, sec))
return TRUE;
- if ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0)
+ if ((bfd_section_flags (sec) & SEC_GROUP) != 0)
{
asymbol *gsym;
const char *gname;
asection *elt, *first;
+ gsym = group_signature (sec);
+ /* Strip groups without a valid signature. */
+ if (gsym == NULL)
+ 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;
+ gname = gsym->name;
if ((strip_symbols == STRIP_ALL
&& !is_specified_symbol (gname, keep_specific_htab))
|| is_specified_symbol (gname, strip_specific_htab))
is_nondebug_keep_contents_section (bfd *ibfd, asection *isection)
{
/* Always keep ELF note sections. */
- if (ibfd->xvec->flavour == bfd_target_elf_flavour)
- return (elf_section_type (isection) == SHT_NOTE);
+ if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour)
+ return elf_section_type (isection) == SHT_NOTE;
/* Always keep the .buildid section for PE/COFF.
Strictly, this should be written "always keep the section storing the debug
directory", but that may be the .text section for objects produced by some
tools, which it is not sensible to keep. */
- if (ibfd->xvec->flavour == bfd_target_coff_flavour)
- return (strcmp (bfd_get_section_name (ibfd, isection), ".buildid") == 0);
+ if (bfd_get_flavour (ibfd) == bfd_target_coff_flavour)
+ return strcmp (bfd_section_name (isection), ".buildid") == 0;
return FALSE;
}
return FALSE;
}
+/* Empty name is hopefully never a valid symbol name. */
+static const char * empty_name = "";
+
static bfd_boolean
need_sym_before (struct addsym_node **node, const char *sym)
{
{
if (!ptr->othersym)
break;
+ if (ptr->othersym == empty_name)
+ continue;
else if (strcmp (ptr->othersym, sym) == 0)
{
- free (ptr->othersym);
- ptr->othersym = ""; /* Empty name is hopefully never a valid symbol name. */
+ free ((char *) ptr->othersym);
+ ptr->othersym = empty_name;
*node = ptr;
return TRUE;
}
static asymbol *
create_new_symbol (struct addsym_node *ptr, bfd *obfd)
{
- asymbol *sym = bfd_make_empty_symbol(obfd);
+ asymbol *sym = bfd_make_empty_symbol (obfd);
- bfd_asymbol_name(sym) = ptr->symdef;
+ bfd_set_asymbol_name (sym, ptr->symdef);
sym->value = ptr->symval;
sym->flags = ptr->flags;
if (ptr->section)
fatal (_("Section %s not found"), ptr->section);
sym->section = sec;
}
- else
- sym->section = bfd_abs_section_ptr;
+ else
+ sym->section = bfd_abs_section_ptr;
return sym;
}
bfd_boolean rem_leading_char;
bfd_boolean add_leading_char;
- undefined = bfd_is_und_section (bfd_get_section (sym));
+ undefined = bfd_is_und_section (bfd_asymbol_section (sym));
if (add_sym_list)
{
to[dst_count++] = create_new_symbol (ptr, obfd);
}
- if (redefine_sym_list)
+ if (htab_elements (redefine_specific_htab) || section_rename_list)
{
- char *old_name, *new_name;
+ char *new_name;
- old_name = (char *) bfd_asymbol_name (sym);
- new_name = (char *) lookup_sym_redefinition (old_name);
- bfd_asymbol_name (sym) = new_name;
+ new_name = (char *) lookup_sym_redefinition (name);
+ if (new_name == name
+ && (flags & BSF_SECTION_SYM) != 0)
+ new_name = (char *) find_section_rename (name, NULL);
+ bfd_set_asymbol_name (sym, new_name);
name = new_name;
}
/* Check if we will remove the current leading character. */
rem_leading_char =
- (name[0] == bfd_get_symbol_leading_char (abfd))
- && (change_leading_char
- || (remove_leading_char
- && ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
- || undefined
- || bfd_is_com_section (bfd_get_section (sym)))));
+ (name[0] != '\0'
+ && name[0] == bfd_get_symbol_leading_char (abfd)
+ && (change_leading_char
+ || (remove_leading_char
+ && ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
+ || undefined
+ || bfd_is_com_section (bfd_asymbol_section (sym))))));
/* Check if we will add a new leading character. */
add_leading_char =
/* Short circuit for change_leading_char if we can do it in-place. */
if (rem_leading_char && add_leading_char && !prefix_symbols_string)
- {
+ {
name[0] = bfd_get_symbol_leading_char (obfd);
- bfd_asymbol_name (sym) = name;
+ bfd_set_asymbol_name (sym, name);
rem_leading_char = FALSE;
add_leading_char = FALSE;
- }
+ }
/* Remove leading char. */
if (rem_leading_char)
- bfd_asymbol_name (sym) = ++name;
+ bfd_set_asymbol_name (sym, ++name);
/* Add new leading char and/or prefix. */
if (add_leading_char || prefix_symbols_string)
- {
- char *n, *ptr;
+ {
+ char *n, *ptr;
+ size_t len = strlen (name) + 1;
+
+ if (add_leading_char)
+ len++;
+ if (prefix_symbols_string)
+ len += strlen (prefix_symbols_string);
- ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string)
- + strlen (name) + 1);
- if (add_leading_char)
+ ptr = n = (char *) xmalloc (len);
+ if (add_leading_char)
*ptr++ = bfd_get_symbol_leading_char (obfd);
- if (prefix_symbols_string)
- {
- strcpy (ptr, prefix_symbols_string);
- ptr += strlen (prefix_symbols_string);
- }
+ if (prefix_symbols_string)
+ {
+ strcpy (ptr, prefix_symbols_string);
+ ptr += strlen (prefix_symbols_string);
+ }
- strcpy (ptr, name);
- bfd_asymbol_name (sym) = n;
- name = n;
+ strcpy (ptr, name);
+ bfd_set_asymbol_name (sym, n);
+ name = n;
}
if (strip_symbols == STRIP_ALL)
keep = FALSE;
else if ((flags & BSF_KEEP) != 0 /* Used in relocation. */
|| ((flags & BSF_SECTION_SYM) != 0
- && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags
+ && ((*bfd_asymbol_section (sym)->symbol_ptr_ptr)->flags
& BSF_KEEP) != 0))
{
keep = TRUE;
}
else if (relocatable /* Relocatable file. */
&& ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
- || bfd_is_com_section (bfd_get_section (sym))))
+ || bfd_is_com_section (bfd_asymbol_section (sym))))
keep = TRUE;
else if (bfd_decode_symclass (sym) == 'I')
/* Global symbols in $idata sections need to be retained
else if ((flags & BSF_GLOBAL) != 0 /* Global symbol. */
|| (flags & BSF_WEAK) != 0
|| undefined
- || bfd_is_com_section (bfd_get_section (sym)))
+ || bfd_is_com_section (bfd_asymbol_section (sym)))
keep = strip_symbols != STRIP_UNNEEDED;
else if ((flags & BSF_DEBUGGING) != 0) /* Debugging symbol. */
keep = (strip_symbols != STRIP_DEBUG
&& strip_symbols != STRIP_UNNEEDED
&& ! convert_debugging);
- else if (bfd_coff_get_comdat_section (abfd, bfd_get_section (sym)))
+ else if (bfd_coff_get_comdat_section (abfd, bfd_asymbol_section (sym)))
/* COMDAT sections store special information in local
symbols, so we cannot risk stripping any of them. */
keep = TRUE;
|| is_specified_symbol (name, keep_specific_htab)))
keep = TRUE;
- if (keep && is_strip_section (abfd, bfd_get_section (sym)))
+ if (keep && is_strip_section (abfd, bfd_asymbol_section (sym)))
keep = FALSE;
if (keep)
{
if (ptr->othersym)
{
- if (strcmp (ptr->othersym, ""))
+ if (ptr->othersym != empty_name)
fatal (_("'before=%s' not found"), ptr->othersym);
}
else
static const char *
lookup_sym_redefinition (const char *source)
{
- struct redefine_node *list;
-
- for (list = redefine_sym_list; list != NULL; list = list->next)
- if (strcmp (source, list->source) == 0)
- return list->target;
+ struct redefine_node key_node = {(char *) source, NULL};
+ struct redefine_node *redef_node
+ = (struct redefine_node *) htab_find (redefine_specific_htab, &key_node);
- return source;
+ return redef_node == NULL ? source : redef_node->target;
}
-/* Add a node to a symbol redefine list. */
+/* Insert a node into symbol redefine hash tabel. */
static void
-redefine_list_append (const char *cause, const char *source, const char *target)
+add_redefine_and_check (const char *cause, const char *source,
+ const char *target)
{
- struct redefine_node **p;
- struct redefine_node *list;
- struct redefine_node *new_node;
+ struct redefine_node *new_node
+ = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
- for (p = &redefine_sym_list; (list = *p) != NULL; p = &list->next)
- {
- if (strcmp (source, list->source) == 0)
- fatal (_("%s: Multiple redefinition of symbol \"%s\""),
- cause, source);
+ new_node->source = strdup (source);
+ new_node->target = strdup (target);
- if (strcmp (target, list->target) == 0)
- fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
- cause, target);
- }
+ if (htab_find (redefine_specific_htab, new_node) != HTAB_EMPTY_ENTRY)
+ fatal (_("%s: Multiple redefinition of symbol \"%s\""),
+ cause, source);
- new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
+ if (htab_find (redefine_specific_reverse_htab, target) != HTAB_EMPTY_ENTRY)
+ fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
+ cause, target);
- new_node->source = strdup (source);
- new_node->target = strdup (target);
- new_node->next = NULL;
+ /* Insert the NEW_NODE into hash table for quick search. */
+ add_specific_symbol_node (new_node, redefine_specific_htab);
+
+ /* Insert the target string into the reverse hash table, this is needed for
+ duplicated target string check. */
+ add_specific_symbol (new_node->target, redefine_specific_reverse_htab);
- *p = new_node;
}
/* Handle the --redefine-syms option. Read lines containing "old new"
if ((c == '\r' && (c = getc (file)) == '\n')
|| c == '\n' || c == EOF)
{
- end_of_line:
+ end_of_line:
/* Append the redefinition to the list. */
if (buf[0] != '\0')
- redefine_list_append (filename, &buf[0], &buf[outsym_off]);
+ add_redefine_and_check (filename, &buf[0], &buf[outsym_off]);
lineno++;
len = 0;
}
else
fatal (_("%s:%d: garbage found at end of line"), filename, lineno);
- comment:
+ comment:
if (len != 0 && (outsym_off == 0 || outsym_off == len))
fatal (_("%s:%d: missing new symbol name"), filename, lineno);
buf[len++] = '\0';
fatal (_("%s:%d: premature end of file"), filename, lineno);
free (buf);
+ fclose (file);
}
-/* Copy unkown object file IBFD onto OBFD.
+/* Copy unknown object file IBFD onto OBFD.
Returns TRUE upon success, FALSE otherwise. */
static bfd_boolean
return FALSE;
}
- ncopied += tocopy;
+ ncopied += tocopy;
+ }
+
+ /* We should at least to be able to read it back when copying an
+ unknown object in an archive. */
+ chmod (bfd_get_filename (obfd), buf.st_mode | S_IRUSR);
+ free (cbuf);
+ return TRUE;
+}
+
+typedef struct objcopy_internal_note
+{
+ Elf_Internal_Note note;
+ unsigned long padded_namesz;
+ bfd_vma start;
+ bfd_vma end;
+} objcopy_internal_note;
+
+#define DEBUG_MERGE 0
+
+#if DEBUG_MERGE
+#define merge_debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
+#else
+#define merge_debug(format, ...)
+#endif
+
+/* Returns TRUE iff PNOTE1 overlaps or adjoins PNOTE2. */
+
+static bfd_boolean
+overlaps_or_adjoins (objcopy_internal_note * pnote1,
+ objcopy_internal_note * pnote2)
+{
+ if (pnote1->end < pnote2->start)
+ /* FIXME: Alignment of 16 bytes taken from x86_64 binaries.
+ Really we should extract the alignment of the section
+ covered by the notes. */
+ return BFD_ALIGN (pnote1->end, 16) < pnote2->start;
+
+ if (pnote2->end < pnote2->start)
+ return BFD_ALIGN (pnote2->end, 16) < pnote1->start;
+
+ if (pnote1->end < pnote2->end)
+ return TRUE;
+
+ if (pnote2->end < pnote1->end)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Returns TRUE iff NEEDLE is fully contained by HAYSTACK. */
+
+static bfd_boolean
+contained_by (objcopy_internal_note * needle,
+ objcopy_internal_note * haystack)
+{
+ return needle->start >= haystack->start && needle->end <= haystack->end;
+}
+
+static bfd_boolean
+is_open_note (objcopy_internal_note * pnote)
+{
+ return pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_OPEN;
+}
+
+static bfd_boolean
+is_func_note (objcopy_internal_note * pnote)
+{
+ return pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_FUNC;
+}
+
+static bfd_boolean
+is_deleted_note (objcopy_internal_note * pnote)
+{
+ return pnote->note.type == 0;
+}
+
+static bfd_boolean
+is_version_note (objcopy_internal_note * pnote)
+{
+ return (pnote->note.namesz > 4
+ && pnote->note.namedata[0] == 'G'
+ && pnote->note.namedata[1] == 'A'
+ && pnote->note.namedata[2] == '$'
+ && pnote->note.namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION);
+}
+
+static bfd_boolean
+is_64bit (bfd * abfd)
+{
+ /* Should never happen, but let's be paranoid. */
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ return FALSE;
+
+ return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64;
+}
+
+/* This sorting function is used to get the notes into an order
+ that makes merging easy. */
+
+static int
+compare_gnu_build_notes (const void * data1, const void * data2)
+{
+ objcopy_internal_note * pnote1 = (objcopy_internal_note *) data1;
+ objcopy_internal_note * pnote2 = (objcopy_internal_note *) data2;
+
+ /* Sort notes based upon the attribute they record. */
+ int cmp = memcmp (pnote1->note.namedata + 3,
+ pnote2->note.namedata + 3,
+ pnote1->note.namesz < pnote2->note.namesz ?
+ pnote1->note.namesz - 3 : pnote2->note.namesz - 3);
+ if (cmp)
+ return cmp;
+
+ if (pnote1->end < pnote2->start)
+ return -1;
+ if (pnote1->start > pnote2->end)
+ return 1;
+
+ /* Overlaps - we should merge the two ranges. */
+ if (pnote1->start < pnote2->start)
+ return -1;
+ if (pnote1->end > pnote2->end)
+ return 1;
+ if (pnote1->end < pnote2->end)
+ return -1;
+
+ /* Put OPEN notes before function notes. */
+ if (is_open_note (pnote1) && ! is_open_note (pnote2))
+ return -1;
+ if (! is_open_note (pnote1) && is_open_note (pnote2))
+ return 1;
+
+ return 0;
+}
+
+/* This sorting function is used to get the notes into an order
+ that makes eliminating address ranges easier. */
+
+static int
+sort_gnu_build_notes (const void * data1, const void * data2)
+{
+ objcopy_internal_note * pnote1 = (objcopy_internal_note *) data1;
+ objcopy_internal_note * pnote2 = (objcopy_internal_note *) data2;
+
+ if (pnote1->note.type != pnote2->note.type)
+ {
+ /* Move deleted notes to the end. */
+ if (is_deleted_note (pnote1)) /* 1: OFD 2: OFD */
+ return 1;
+
+ /* Move OPEN notes to the start. */
+ if (is_open_note (pnote1)) /* 1: OF 2: OFD */
+ return -1;
+
+ if (is_deleted_note (pnote2)) /* 1: F 2: O D */
+ return -1;
+
+ return 1; /* 1: F 2: O */
+ }
+
+ /* Sort by starting address. */
+ if (pnote1->start < pnote2->start)
+ return -1;
+ if (pnote1->start > pnote2->start)
+ return 1;
+
+ /* Then by end address (bigger range first). */
+ if (pnote1->end > pnote2->end)
+ return -1;
+ if (pnote1->end < pnote2->end)
+ return 1;
+
+ /* Then by attribute type. */
+ if (pnote1->note.namesz > 4
+ && pnote2->note.namesz > 4
+ && pnote1->note.namedata[3] != pnote2->note.namedata[3])
+ return pnote1->note.namedata[3] - pnote2->note.namedata[3];
+
+ return 0;
+}
+
+/* Merge the notes on SEC, removing redundant entries.
+ Returns the new, smaller size of the section upon success. */
+
+static bfd_size_type
+merge_gnu_build_notes (bfd * abfd,
+ asection * sec,
+ bfd_size_type size,
+ bfd_byte * contents)
+{
+ objcopy_internal_note * pnotes_end;
+ objcopy_internal_note * pnotes = NULL;
+ objcopy_internal_note * pnote;
+ bfd_size_type remain = size;
+ unsigned version_1_seen = 0;
+ unsigned version_2_seen = 0;
+ unsigned version_3_seen = 0;
+ const char * err = NULL;
+ bfd_byte * in = contents;
+ unsigned long previous_func_start = 0;
+ unsigned long previous_open_start = 0;
+ unsigned long previous_func_end = 0;
+ unsigned long previous_open_end = 0;
+ long relsize;
+
+ relsize = bfd_get_reloc_upper_bound (abfd, sec);
+ if (relsize > 0)
+ {
+ arelent ** relpp;
+ long relcount;
+
+ /* If there are relocs associated with this section then we
+ cannot safely merge it. */
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
+ free (relpp);
+ if (relcount != 0)
+ {
+ if (! is_strip)
+ non_fatal (_("%s[%s]: Cannot merge - there are relocations against this section"),
+ bfd_get_filename (abfd), bfd_section_name (sec));
+ goto done;
+ }
+ }
+
+ /* Make a copy of the notes and convert to our internal format.
+ Minimum size of a note is 12 bytes. Also locate the version
+ notes and check them. */
+ pnote = pnotes = (objcopy_internal_note *)
+ xcalloc ((size / 12), sizeof (* pnote));
+ while (remain >= 12)
+ {
+ bfd_vma start, end;
+
+ pnote->note.namesz = bfd_get_32 (abfd, in);
+ pnote->note.descsz = bfd_get_32 (abfd, in + 4);
+ pnote->note.type = bfd_get_32 (abfd, in + 8);
+ pnote->padded_namesz = (pnote->note.namesz + 3) & ~3;
+
+ if (((pnote->note.descsz + 3) & ~3) != pnote->note.descsz)
+ {
+ err = _("corrupt GNU build attribute note: description size not a factor of 4");
+ goto done;
+ }
+
+ if (pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_OPEN
+ && pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
+ {
+ err = _("corrupt GNU build attribute note: wrong note type");
+ goto done;
+ }
+
+ if (pnote->padded_namesz + pnote->note.descsz + 12 > remain)
+ {
+ err = _("corrupt GNU build attribute note: note too big");
+ goto done;
+ }
+
+ if (pnote->note.namesz < 2)
+ {
+ err = _("corrupt GNU build attribute note: name too small");
+ goto done;
+ }
+
+ pnote->note.namedata = (char *)(in + 12);
+ pnote->note.descdata = (char *)(in + 12 + pnote->padded_namesz);
+
+ remain -= 12 + pnote->padded_namesz + pnote->note.descsz;
+ in += 12 + pnote->padded_namesz + pnote->note.descsz;
+
+ if (pnote->note.namesz > 2
+ && pnote->note.namedata[0] == '$'
+ && pnote->note.namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION
+ && pnote->note.namedata[2] == '1')
+ ++ version_1_seen;
+ else if (is_version_note (pnote))
+ {
+ if (pnote->note.namedata[4] == '2')
+ ++ version_2_seen;
+ else if (pnote->note.namedata[4] == '3')
+ ++ version_3_seen;
+ else
+ {
+ err = _("corrupt GNU build attribute note: unsupported version");
+ goto done;
+ }
+ }
+
+ switch (pnote->note.descsz)
+ {
+ case 0:
+ start = end = 0;
+ break;
+
+ case 4:
+ start = bfd_get_32 (abfd, pnote->note.descdata);
+ /* FIXME: For version 1 and 2 notes we should try to
+ calculate the end address by finding a symbol whose
+ value is START, and then adding in its size.
+
+ For now though, since v1 and v2 was not intended to
+ handle gaps, we chose an artificially large end
+ address. */
+ end = (bfd_vma) -1;
+ break;
+
+ case 8:
+ if (! is_64bit (abfd))
+ {
+ start = bfd_get_32 (abfd, pnote->note.descdata);
+ end = bfd_get_32 (abfd, pnote->note.descdata + 4);
+ }
+ else
+ {
+ start = bfd_get_64 (abfd, pnote->note.descdata);
+ /* FIXME: For version 1 and 2 notes we should try to
+ calculate the end address by finding a symbol whose
+ value is START, and then adding in its size.
+
+ For now though, since v1 and v2 was not intended to
+ handle gaps, we chose an artificially large end
+ address. */
+ end = (bfd_vma) -1;
+ }
+ break;
+
+ case 16:
+ start = bfd_get_64 (abfd, pnote->note.descdata);
+ end = bfd_get_64 (abfd, pnote->note.descdata + 8);
+ break;
+
+ default:
+ err = _("corrupt GNU build attribute note: bad description size");
+ goto done;
+ }
+
+ if (is_open_note (pnote))
+ {
+ if (start)
+ previous_open_start = start;
+
+ pnote->start = previous_open_start;
+
+ if (end)
+ previous_open_end = end;
+
+ pnote->end = previous_open_end;
+ }
+ else
+ {
+ if (start)
+ previous_func_start = start;
+
+ pnote->start = previous_func_start;
+
+ if (end)
+ previous_func_end = end;
+
+ pnote->end = previous_func_end;
+ }
+
+ if (pnote->note.namedata[pnote->note.namesz - 1] != 0)
+ {
+ err = _("corrupt GNU build attribute note: name not NUL terminated");
+ goto done;
+ }
+
+ pnote ++;
+ }
+
+ pnotes_end = pnote;
+
+ /* Check that the notes are valid. */
+ if (remain != 0)
+ {
+ err = _("corrupt GNU build attribute notes: excess data at end");
+ goto done;
+ }
+
+ if (version_1_seen == 0 && version_2_seen == 0 && version_3_seen == 0)
+ {
+#if 0
+ err = _("bad GNU build attribute notes: no known versions detected");
+ goto done;
+#else
+ /* This happens with glibc. No idea why. */
+ non_fatal (_("%s[%s]: Warning: version note missing - assuming version 3"),
+ bfd_get_filename (abfd), bfd_section_name (sec));
+ version_3_seen = 2;
+#endif
+ }
+
+ if ( (version_1_seen > 0 && version_2_seen > 0)
+ || (version_1_seen > 0 && version_3_seen > 0)
+ || (version_2_seen > 0 && version_3_seen > 0))
+ {
+ err = _("bad GNU build attribute notes: multiple different versions");
+ goto done;
+ }
+
+ /* We are now only supporting the merging v3+ notes
+ - it makes things much simpler. */
+ if (version_3_seen == 0)
+ {
+ merge_debug ("%s: skipping merge - not using v3 notes", bfd_section_name (sec));
+ goto done;
+ }
+
+ merge_debug ("Merging section %s which contains %ld notes\n",
+ sec->name, pnotes_end - pnotes);
+
+ /* Sort the notes. */
+ qsort (pnotes, pnotes_end - pnotes, sizeof (* pnotes),
+ compare_gnu_build_notes);
+
+#if DEBUG_MERGE
+ merge_debug ("Results of initial sort:\n");
+ for (pnote = pnotes; pnote < pnotes_end; pnote ++)
+ merge_debug ("offset %#08lx range %#08lx..%#08lx type %ld attribute %d namesz %ld\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ pnote->start, pnote->end,
+ pnote->note.type,
+ pnote->note.namedata[3],
+ pnote->note.namesz
+ );
+#endif
+
+ /* Now merge the notes. The rules are:
+ 1. If a note has a zero range, it can be eliminated.
+ 2. If two notes have the same namedata then:
+ 2a. If one note's range is fully covered by the other note
+ then it can be deleted.
+ 2b. If one note's range partially overlaps or adjoins the
+ other note then if they are both of the same type (open
+ or func) then they can be merged and one deleted. If
+ they are of different types then they cannot be merged. */
+ for (pnote = pnotes; pnote < pnotes_end; pnote ++)
+ {
+ /* Skip already deleted notes.
+ FIXME: Can this happen ? We are scanning forwards and
+ deleting backwards after all. */
+ if (is_deleted_note (pnote))
+ continue;
+
+ /* Rule 1 - delete 0-range notes. */
+ if (pnote->start == pnote->end)
+ {
+ merge_debug ("Delete note at offset %#08lx - empty range\n",
+ (pnote->note.namedata - (char *) contents) - 12);
+ pnote->note.type = 0;
+ continue;
+ }
+
+ int iter;
+ objcopy_internal_note * back;
+
+ /* Rule 2: Check to see if there is an identical previous note. */
+ for (iter = 0, back = pnote - 1; back >= pnotes; back --)
+ {
+ if (is_deleted_note (back))
+ continue;
+
+ /* Our sorting function should have placed all identically
+ attributed notes together, so if we see a note of a different
+ attribute type stop searching. */
+ if (back->note.namesz != pnote->note.namesz
+ || memcmp (back->note.namedata,
+ pnote->note.namedata, pnote->note.namesz) != 0)
+ break;
+
+ if (back->start == pnote->start
+ && back->end == pnote->end)
+ {
+ merge_debug ("Delete note at offset %#08lx - duplicate of note at offset %#08lx\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ (back->note.namedata - (char *) contents) - 12);
+ pnote->note.type = 0;
+ break;
+ }
+
+ /* Rule 2a. */
+ if (contained_by (pnote, back))
+ {
+ merge_debug ("Delete note at offset %#08lx - fully contained by note at %#08lx\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ (back->note.namedata - (char *) contents) - 12);
+ pnote->note.type = 0;
+ break;
+ }
+
+#if DEBUG_MERGE
+ /* This should not happen as we have sorted the
+ notes with earlier starting addresses first. */
+ if (contained_by (back, pnote))
+ merge_debug ("ERROR: UNEXPECTED CONTAINMENT\n");
+#endif
+
+ /* Rule 2b. */
+ if (overlaps_or_adjoins (back, pnote)
+ && is_func_note (back) == is_func_note (pnote))
+ {
+ merge_debug ("Delete note at offset %#08lx - merge into note at %#08lx\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ (back->note.namedata - (char *) contents) - 12);
+
+ back->end = back->end > pnote->end ? back->end : pnote->end;
+ back->start = back->start < pnote->start ? back->start : pnote->start;
+ pnote->note.type = 0;
+ break;
+ }
+
+ /* Don't scan too far back however. */
+ if (iter ++ > 16)
+ {
+ /* FIXME: Not sure if this can ever be triggered. */
+ merge_debug ("ITERATION LIMIT REACHED\n");
+ break;
+ }
+ }
+#if DEBUG_MERGE
+ if (! is_deleted_note (pnote))
+ merge_debug ("Unable to do anything with note at %#08lx\n",
+ (pnote->note.namedata - (char *) contents) - 12);
+#endif
+ }
+
+ /* Resort the notes. */
+ merge_debug ("Final sorting of notes\n");
+ qsort (pnotes, pnotes_end - pnotes, sizeof (* pnotes), sort_gnu_build_notes);
+
+ /* Reconstruct the ELF notes. */
+ bfd_byte * new_contents;
+ bfd_byte * old;
+ bfd_byte * new;
+ bfd_size_type new_size;
+ bfd_vma prev_start = 0;
+ bfd_vma prev_end = 0;
+
+ /* Not sure how, but the notes might grow in size.
+ (eg see PR 1774507). Allow for this here. */
+ new = new_contents = xmalloc (size * 2);
+ for (pnote = pnotes, old = contents;
+ pnote < pnotes_end;
+ pnote ++)
+ {
+ bfd_size_type note_size = 12 + pnote->padded_namesz + pnote->note.descsz;
+
+ if (! is_deleted_note (pnote))
+ {
+ /* Create the note, potentially using the
+ address range of the previous note. */
+ if (pnote->start == prev_start && pnote->end == prev_end)
+ {
+ bfd_put_32 (abfd, pnote->note.namesz, new);
+ bfd_put_32 (abfd, 0, new + 4);
+ bfd_put_32 (abfd, pnote->note.type, new + 8);
+ new += 12;
+ memcpy (new, pnote->note.namedata, pnote->note.namesz);
+ if (pnote->note.namesz < pnote->padded_namesz)
+ memset (new + pnote->note.namesz, 0, pnote->padded_namesz - pnote->note.namesz);
+ new += pnote->padded_namesz;
+ }
+ else
+ {
+ bfd_put_32 (abfd, pnote->note.namesz, new);
+ bfd_put_32 (abfd, is_64bit (abfd) ? 16 : 8, new + 4);
+ bfd_put_32 (abfd, pnote->note.type, new + 8);
+ new += 12;
+ memcpy (new, pnote->note.namedata, pnote->note.namesz);
+ if (pnote->note.namesz < pnote->padded_namesz)
+ memset (new + pnote->note.namesz, 0, pnote->padded_namesz - pnote->note.namesz);
+ new += pnote->padded_namesz;
+ if (is_64bit (abfd))
+ {
+ bfd_put_64 (abfd, pnote->start, new);
+ bfd_put_64 (abfd, pnote->end, new + 8);
+ new += 16;
+ }
+ else
+ {
+ bfd_put_32 (abfd, pnote->start, new);
+ bfd_put_32 (abfd, pnote->end, new + 4);
+ new += 8;
+ }
+
+ prev_start = pnote->start;
+ prev_end = pnote->end;
+ }
+ }
+
+ old += note_size;
+ }
+
+#if DEBUG_MERGE
+ merge_debug ("Results of merge:\n");
+ for (pnote = pnotes; pnote < pnotes_end; pnote ++)
+ if (! is_deleted_note (pnote))
+ merge_debug ("offset %#08lx range %#08lx..%#08lx type %ld attribute %d namesz %ld\n",
+ (pnote->note.namedata - (char *) contents) - 12,
+ pnote->start, pnote->end,
+ pnote->note.type,
+ pnote->note.namedata[3],
+ pnote->note.namesz
+ );
+#endif
+
+ new_size = new - new_contents;
+ if (new_size < size)
+ {
+ memcpy (contents, new_contents, new_size);
+ size = new_size;
}
+ free (new_contents);
- /* We should at least to be able to read it back when copying an
- unknown object in an archive. */
- chmod (bfd_get_filename (obfd), buf.st_mode | S_IRUSR);
- free (cbuf);
- return TRUE;
+ done:
+ if (err)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ bfd_nonfatal_message (NULL, abfd, sec, err);
+ status = 1;
+ }
+
+ free (pnotes);
+ return size;
+}
+
+static flagword
+check_new_section_flags (flagword flags, bfd * abfd, const char * secname)
+{
+ /* Only set the SEC_COFF_SHARED flag on COFF files.
+ The same bit value is used by ELF targets to indicate
+ compressed sections, and setting that flag here breaks
+ things. */
+ if ((flags & SEC_COFF_SHARED)
+ && bfd_get_flavour (abfd) != bfd_target_coff_flavour)
+ {
+ non_fatal (_("%s[%s]: Note - dropping 'share' flag as output format is not COFF"),
+ bfd_get_filename (abfd), secname);
+ flags &= ~ SEC_COFF_SHARED;
+ }
+ return flags;
}
/* Copy object file IBFD onto OBFD.
bfd_vma start;
long symcount;
asection **osections = NULL;
+ asection *osec;
asection *gnu_debuglink_section = NULL;
bfd_size_type *gaps = NULL;
bfd_size_type max_gap = 0;
void *dhandle;
enum bfd_architecture iarch;
unsigned int imach;
- unsigned int c, i;
+ unsigned int num_sec, i;
if (ibfd->xvec->byteorder != obfd->xvec->byteorder
&& ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
{
/* PR 17636: Call non-fatal so that we return to our parent who
may need to tidy temporary files. */
- non_fatal (_("Unable to change endianness of input file(s)"));
+ non_fatal (_("unable to change endianness of '%s'"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
+ if (ibfd->read_only)
+ {
+ non_fatal (_("unable to modify '%s' due to errors"),
+ bfd_get_archive_filename (ibfd));
return FALSE;
}
return FALSE;
}
- if ((do_debug_sections & compress) != 0
- && do_debug_sections != compress
- && ibfd->xvec->flavour != bfd_target_elf_flavour)
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
{
- non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
- bfd_get_archive_filename (ibfd));
- return FALSE;
+ if ((do_debug_sections & compress) != 0
+ && do_debug_sections != compress)
+ {
+ non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
+ if (do_elf_stt_common)
+ {
+ non_fatal (_("--elf-stt-common=[yes|no] is unsupported on `%s'"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
}
if (verbose)
imach = bfd_get_mach (ibfd);
if (input_arch)
{
- if (bfd_get_arch_info (ibfd) == NULL
- || bfd_get_arch_info (ibfd)->arch == bfd_arch_unknown)
+ if (iarch == bfd_arch_unknown)
{
iarch = input_arch->arch;
imach = input_arch->mach;
non_fatal (_("Input file `%s' ignores binary architecture parameter."),
bfd_get_archive_filename (ibfd));
}
+ if (iarch == bfd_arch_unknown
+ && bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ && bfd_get_flavour (obfd) == bfd_target_elf_flavour)
+ {
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+ iarch = bed->arch;
+ imach = 0;
+ }
if (!bfd_set_arch_mach (obfd, iarch, imach)
&& (ibfd->target_defaulted
|| bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
pe_data_type *pe = pe_data (obfd);
/* Copy PE parameters before changing them. */
- if (ibfd->xvec->flavour == bfd_target_coff_flavour
+ if (bfd_get_flavour (ibfd) == bfd_target_coff_flavour
&& bfd_pei_p (ibfd))
pe->pe_opthdr = pe_data (ibfd)->pe_opthdr;
file_alignment, section_alignment);
}
+
+ if (preserve_dates
+ && bfd_get_flavour (ibfd) == bfd_target_coff_flavour
+ && bfd_pei_p (ibfd))
+ pe->timestamp = pe_data (ibfd)->coff.timestamp;
}
if (isympp)
pset = find_section_list (padd->name, FALSE,
SECTION_CONTEXT_SET_FLAGS);
if (pset != NULL)
- flags = pset->flags | SEC_HAS_CONTENTS;
+ {
+ flags = pset->flags | SEC_HAS_CONTENTS;
+ flags = check_new_section_flags (flags, obfd, padd->name);
+ }
else
flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
if (bfd_get_section_by_name (obfd, padd->name))
{
bfd_nonfatal_message (NULL, obfd, NULL,
- _("can't add section '%s'"), padd->name);
+ _("can't add section '%s'"), padd->name);
return FALSE;
}
else
{
/* We use LINKER_CREATED here so that the backend hooks
- will create any special section type information,
- instead of presuming we know what we're doing merely
- because we set the flags. */
+ will create any special section type information,
+ instead of presuming we know what we're doing merely
+ because we set the flags. */
padd->section = bfd_make_section_with_flags
(obfd, padd->name, flags | SEC_LINKER_CREATED);
if (padd->section == NULL)
}
}
- if (! bfd_set_section_size (obfd, padd->section, padd->size))
+ if (!bfd_set_section_size (padd->section, padd->size))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
pset = find_section_list (padd->name, FALSE,
SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA);
if (pset != NULL
- && ! bfd_set_section_vma (obfd, padd->section, pset->vma_val))
+ && !bfd_set_section_vma (padd->section, pset->vma_val))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
{
padd->section->lma = pset->lma_val;
- if (! bfd_set_section_alignment
- (obfd, padd->section,
- bfd_section_alignment (obfd, padd->section)))
+ if (!bfd_set_section_alignment
+ (padd->section, bfd_section_alignment (padd->section)))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
pupdate != NULL;
pupdate = pupdate->next)
{
- asection *osec;
-
pupdate->section = bfd_get_section_by_name (ibfd, pupdate->name);
if (pupdate->section == NULL)
{
}
osec = pupdate->section->output_section;
- if (! bfd_set_section_size (obfd, osec, pupdate->size))
+ if (!bfd_set_section_size (osec, pupdate->size))
{
bfd_nonfatal_message (NULL, obfd, osec, NULL);
return FALSE;
}
}
+ merged_note_section * merged_note_sections = NULL;
+ if (merge_notes)
+ {
+ /* This palaver is necessary because we must set the output
+ section size first, before its contents are ready. */
+ for (osec = ibfd->sections; osec != NULL; osec = osec->next)
+ {
+ if (! is_mergeable_note_section (ibfd, osec))
+ continue;
+
+ /* If the section is going to be completly deleted then
+ do not bother to merge it. */
+ if (osec->output_section == NULL)
+ continue;
+
+ bfd_size_type size = bfd_section_size (osec);
+
+ if (size == 0)
+ {
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("warning: note section is empty"));
+ continue;
+ }
+
+ merged_note_section * merged = xmalloc (sizeof * merged);
+ merged->contents = NULL;
+ if (! bfd_get_full_section_contents (ibfd, osec, & merged->contents))
+ {
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("warning: could not load note section"));
+ free (merged);
+ continue;
+ }
+
+ merged->size = merge_gnu_build_notes (ibfd, osec, size,
+ merged->contents);
+
+ /* FIXME: Once we have read the contents in, we must write
+ them out again. So even if the mergeing has achieved
+ nothing we still add this entry to the merge list. */
+
+ if (size != merged->size
+ && !bfd_set_section_size (osec->output_section, merged->size))
+ {
+ bfd_nonfatal_message (NULL, obfd, osec,
+ _("warning: failed to set merged notes size"));
+ free (merged->contents);
+ free (merged);
+ continue;
+ }
+
+ /* Add section to list of merged sections. */
+ merged->sec = osec;
+ merged->next = merged_note_sections;
+ merged_note_sections = merged;
+ }
+ }
+
if (dump_sections != NULL)
{
struct section_add * pdump;
for (pdump = dump_sections; pdump != NULL; pdump = pdump->next)
{
- asection * sec;
+ FILE * f;
+ bfd_byte *contents;
- sec = bfd_get_section_by_name (ibfd, pdump->name);
- if (sec == NULL)
+ osec = bfd_get_section_by_name (ibfd, pdump->name);
+ if (osec == NULL)
{
bfd_nonfatal_message (NULL, ibfd, NULL,
_("can't dump section '%s' - it does not exist"),
continue;
}
- if ((bfd_get_section_flags (ibfd, sec) & SEC_HAS_CONTENTS) == 0)
+ if ((bfd_section_flags (osec) & SEC_HAS_CONTENTS) == 0)
{
- bfd_nonfatal_message (NULL, ibfd, sec,
+ bfd_nonfatal_message (NULL, ibfd, osec,
_("can't dump section - it has no contents"));
continue;
}
- bfd_size_type size = bfd_get_section_size (sec);
- if (size == 0)
- {
- bfd_nonfatal_message (NULL, ibfd, sec,
- _("can't dump section - it is empty"));
- continue;
- }
+ bfd_size_type size = bfd_section_size (osec);
+ /* Note - we allow the dumping of zero-sized sections,
+ creating an empty file. */
- FILE * f;
f = fopen (pdump->filename, FOPEN_WB);
if (f == NULL)
{
continue;
}
- bfd_byte * contents = xmalloc (size);
- if (bfd_get_section_contents (ibfd, sec, contents, 0, size))
+ if (bfd_malloc_and_get_section (ibfd, osec, &contents))
{
- if (fwrite (contents, 1, size, f) != size)
+ if (size != 0 && fwrite (contents, 1, size, f) != size)
{
non_fatal (_("error writing section contents to %s (error: %s)"),
pdump->filename,
strerror (errno));
+ free (contents);
+ fclose (f);
return FALSE;
}
}
else
- bfd_nonfatal_message (NULL, ibfd, sec,
+ bfd_nonfatal_message (NULL, ibfd, osec,
_("could not retrieve section contents"));
fclose (f);
{
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
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
+ for (osec = obfd->sections, highest_section = NULL;
+ osec != NULL;
+ osec = osec->next)
+ if (osec->vma > 0
&& (highest_section == NULL
- || sec->vma > highest_section->vma))
- highest_section = sec;
+ || osec->vma > highest_section->vma))
+ highest_section = osec;
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
+ bfd_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. */
/* Umm, not sure what to do in this case. */
debuglink_vma = 0x1000;
- bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma);
+ bfd_set_section_vma (gnu_debuglink_section, debuglink_vma);
}
}
}
- c = bfd_count_sections (obfd);
- if (c != 0
+ num_sec = bfd_count_sections (obfd);
+ if (num_sec != 0
&& (gap_fill_set || pad_to_set))
{
asection **set;
increasing the section sizes as required to fill the gaps.
We write out the gap contents below. */
- osections = (asection **) xmalloc (c * sizeof (asection *));
+ osections = xmalloc (num_sec * sizeof (*osections));
set = osections;
bfd_map_over_sections (obfd, get_sections, &set);
- qsort (osections, c, sizeof (asection *), compare_section_lma);
+ qsort (osections, num_sec, sizeof (*osections), compare_section_lma);
- gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type));
- memset (gaps, 0, c * sizeof (bfd_size_type));
+ gaps = xmalloc (num_sec * sizeof (*gaps));
+ memset (gaps, 0, num_sec * sizeof (*gaps));
if (gap_fill_set)
{
- for (i = 0; i < c - 1; i++)
+ for (i = 0; i < num_sec - 1; i++)
{
flagword flags;
- bfd_size_type size;
- bfd_vma gap_start, gap_stop;
+ bfd_size_type size; /* Octets. */
+ bfd_vma gap_start, gap_stop; /* Octets. */
+ unsigned int opb1 = bfd_octets_per_byte (obfd, osections[i]);
+ unsigned int opb2 = bfd_octets_per_byte (obfd, osections[i+1]);
- flags = bfd_get_section_flags (obfd, osections[i]);
+ flags = bfd_section_flags (osections[i]);
if ((flags & SEC_HAS_CONTENTS) == 0
|| (flags & SEC_LOAD) == 0)
continue;
- size = bfd_section_size (obfd, osections[i]);
- gap_start = bfd_section_lma (obfd, osections[i]) + size;
- gap_stop = bfd_section_lma (obfd, osections[i + 1]);
+ size = bfd_section_size (osections[i]);
+ gap_start = bfd_section_lma (osections[i]) * opb1 + size;
+ gap_stop = bfd_section_lma (osections[i + 1]) * opb2;
if (gap_start < gap_stop)
{
- if (! bfd_set_section_size (obfd, osections[i],
- size + (gap_stop - gap_start)))
+ if (!bfd_set_section_size (osections[i],
+ size + (gap_stop - gap_start)))
{
bfd_nonfatal_message (NULL, obfd, osections[i],
_("Can't fill gap after section"));
if (pad_to_set)
{
- bfd_vma lma;
- bfd_size_type size;
-
- lma = bfd_section_lma (obfd, osections[c - 1]);
- size = bfd_section_size (obfd, osections[c - 1]);
- if (lma + size < pad_to)
+ bfd_vma lma; /* Octets. */
+ bfd_size_type size; /* Octets. */
+ unsigned int opb = bfd_octets_per_byte (obfd, osections[num_sec - 1]);
+ bfd_vma _pad_to = pad_to * opb;
+
+ lma = bfd_section_lma (osections[num_sec - 1]) * opb;
+ size = bfd_section_size (osections[num_sec - 1]);
+ if (lma + size < _pad_to)
{
- if (! bfd_set_section_size (obfd, osections[c - 1],
- pad_to - lma))
+ if (!bfd_set_section_size (osections[num_sec - 1], _pad_to - lma))
{
- bfd_nonfatal_message (NULL, obfd, osections[c - 1],
+ bfd_nonfatal_message (NULL, obfd, osections[num_sec - 1],
_("can't add padding"));
status = 1;
}
else
{
- gaps[c - 1] = pad_to - (lma + size);
- if (max_gap < pad_to - (lma + size))
- max_gap = pad_to - (lma + size);
+ gaps[num_sec - 1] = _pad_to - (lma + size);
+ if (max_gap < _pad_to - (lma + size))
+ max_gap = _pad_to - (lma + size);
}
}
}
|| htab_elements (globalize_specific_htab) != 0
|| htab_elements (keepglobal_specific_htab) != 0
|| htab_elements (weaken_specific_htab) != 0
+ || htab_elements (redefine_specific_htab) != 0
|| prefix_symbols_string
|| sections_removed
|| sections_copied
|| convert_debugging
|| change_leading_char
|| remove_leading_char
- || redefine_sym_list
+ || section_rename_list
|| weaken
|| add_symbols)
{
ignore input sections which have no corresponding output
section. */
if (strip_symbols != STRIP_ALL)
- bfd_map_over_sections (ibfd,
- mark_symbols_used_in_relocations,
- isympp);
+ {
+ bfd_set_error (bfd_error_no_error);
+ bfd_map_over_sections (ibfd,
+ mark_symbols_used_in_relocations,
+ isympp);
+ if (bfd_get_error () != bfd_error_no_error)
+ {
+ status = 1;
+ return FALSE;
+ }
+ }
+
osympp = (asymbol **) xmalloc ((symcount + add_symbols + 1) * sizeof (asymbol *));
symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
}
if (convert_debugging && dhandle != NULL)
{
- if (! write_debugging_info (obfd, dhandle, &symcount, &osympp))
+ bfd_boolean res;
+
+ res = write_debugging_info (obfd, dhandle, &symcount, &osympp);
+
+ free (dhandle);
+ dhandle = NULL; /* Paranoia... */
+
+ if (! res)
{
status = 1;
return FALSE;
struct section_add *pupdate;
for (pupdate = update_sections;
- pupdate != NULL;
- pupdate = pupdate->next)
+ pupdate != NULL;
+ pupdate = pupdate->next)
{
- asection *osec;
-
osec = pupdate->section->output_section;
if (! bfd_set_section_contents (obfd, osec, pupdate->contents,
- 0, pupdate->size))
+ 0, pupdate->size))
{
bfd_nonfatal_message (NULL, obfd, osec, NULL);
return FALSE;
}
}
+ if (merged_note_sections != NULL)
+ {
+ merged_note_section * merged = NULL;
+
+ for (osec = obfd->sections; osec != NULL; osec = osec->next)
+ {
+ if (! is_mergeable_note_section (obfd, osec))
+ continue;
+
+ if (merged == NULL)
+ merged = merged_note_sections;
+
+ /* It is likely that output sections are in the same order
+ as the input sections, but do not assume that this is
+ the case. */
+ if (strcmp (bfd_section_name (merged->sec),
+ bfd_section_name (osec)) != 0)
+ {
+ for (merged = merged_note_sections;
+ merged != NULL;
+ merged = merged->next)
+ if (strcmp (bfd_section_name (merged->sec),
+ bfd_section_name (osec)) == 0)
+ break;
+
+ if (merged == NULL)
+ {
+ bfd_nonfatal_message
+ (NULL, obfd, osec,
+ _("error: failed to locate merged notes"));
+ continue;
+ }
+ }
+
+ if (merged->contents == NULL)
+ {
+ bfd_nonfatal_message
+ (NULL, obfd, osec,
+ _("error: failed to merge notes"));
+ continue;
+ }
+
+ if (! bfd_set_section_contents (obfd, osec, merged->contents, 0,
+ merged->size))
+ {
+ bfd_nonfatal_message
+ (NULL, obfd, osec,
+ _("error: failed to copy merged notes into output"));
+ return FALSE;
+ }
+
+ merged = merged->next;
+ }
+
+ /* Free the memory. */
+ merged_note_section * next;
+ for (merged = merged_note_sections; merged != NULL; merged = next)
+ {
+ next = merged->next;
+ free (merged->contents);
+ free (merged);
+ }
+ }
+ else if (merge_notes && ! is_strip)
+ non_fatal (_("%s: Could not find any mergeable note sections"),
+ bfd_get_filename (ibfd));
+
if (gnu_debuglink_filename != NULL)
{
if (! bfd_fill_in_gnu_debuglink_section
}
}
- if (gap_fill_set || pad_to_set)
+ if (gaps != NULL)
{
bfd_byte *buf;
buf = (bfd_byte *) xmalloc (max_gap);
memset (buf, gap_fill, max_gap);
- c = bfd_count_sections (obfd);
- for (i = 0; i < c; i++)
+ for (i = 0; i < num_sec; i++)
{
if (gaps[i] != 0)
{
file_ptr off;
left = gaps[i];
- off = bfd_section_size (obfd, osections[i]) - left;
+ off = bfd_section_size (osections[i]) - left;
while (left > 0)
{
off, now))
{
bfd_nonfatal_message (NULL, obfd, osections[i], NULL);
+ free (buf);
return FALSE;
}
}
}
}
+
+ free (buf);
+ free (gaps);
+ gaps = NULL;
}
/* Allow the BFD backend to copy any private data it understands
char *dir;
const char *filename;
+ /* PR 24281: It is not clear what should happen when copying a thin archive.
+ One part is straight forward - if the output archive is in a different
+ directory from the input archive then any relative paths in the library
+ should be adjusted to the new location. But if any transformation
+ options are active (eg strip, rename, add, etc) then the implication is
+ that these should be applied to the files pointed to by the archive.
+ But since objcopy is not destructive, this means that new files must be
+ created, and there is no guidance for the names of the new files. (Plus
+ this conflicts with one of the goals of thin libraries - only taking up
+ a minimal amount of space in the file system).
+
+ So for now we fail if an attempt is made to copy such libraries. */
+ if (ibfd->is_thin_archive)
+ {
+ status = 1;
+ bfd_set_error (bfd_error_invalid_operation);
+ bfd_nonfatal_message (NULL, ibfd, NULL,
+ _("sorry: copying thin archives is not currently supported"));
+ return;
+ }
+
/* Make a temp directory to hold the contents. */
dir = make_tempdir (bfd_get_filename (obfd));
if (dir == NULL)
- fatal (_("cannot create tempdir for archive copying (error: %s)"),
+ fatal (_("cannot create tempdir for archive copying (error: %s)"),
strerror (errno));
if (strip_symbols == STRIP_ALL)
/* If the file already exists, make another temp dir. */
if (stat (output_name, &buf) >= 0)
{
- output_name = make_tempdir (output_name);
- if (output_name == NULL)
+ char * tmpdir = make_tempdir (output_name);
+
+ free (output_name);
+ if (tmpdir == NULL)
{
non_fatal (_("cannot create tempdir for archive copying (error: %s)"),
strerror (errno));
}
l = (struct name_list *) xmalloc (sizeof (struct name_list));
- l->name = output_name;
+ l->name = tmpdir;
l->next = list;
l->obfd = NULL;
list = l;
- output_name = concat (output_name, "/",
+ output_name = concat (tmpdir, "/",
bfd_get_filename (this_element), (char *) 0);
}
cleanup_and_exit:
/* Delete all the files that we opened. */
- for (l = list; l != NULL; l = l->next)
- {
- if (l->obfd == NULL)
- rmdir (l->name);
- else
- {
- bfd_close (l->obfd);
- unlink (l->name);
- }
- }
+ {
+ struct name_list * next;
+
+ for (l = list; l != NULL; l = next)
+ {
+ if (l->obfd == NULL)
+ rmdir (l->name);
+ else
+ {
+ bfd_close (l->obfd);
+ unlink (l->name);
+ }
+ next = l->next;
+ free (l);
+ }
+ }
rmdir (dir);
}
break;
}
+ switch (do_elf_stt_common)
+ {
+ case elf_stt_common:
+ ibfd->flags |= BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON;
+ break;
+ break;
+ case no_elf_stt_common:
+ ibfd->flags |= BFD_CONVERT_ELF_COMMON;
+ break;
+ default:
+ break;
+ }
+
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. */
+ bfd_check_format succeeds. */
if (output_target == NULL)
{
output_target = bfd_get_target (ibfd);
status = 1;
return;
}
+
+ if (gnu_debuglink_filename != NULL)
+ {
+ non_fatal (_("--add-gnu-debuglink ignored for archive %s"),
+ bfd_get_filename (ibfd));
+ gnu_debuglink_filename = NULL;
+ }
+
/* This is a no-op on non-Coff targets. */
set_long_section_mode (obfd, ibfd, long_section_names);
do_copy:
/* bfd_get_target does not return the correct value until
- bfd_check_format succeeds. */
+ bfd_check_format succeeds. */
if (output_target == NULL)
output_target = bfd_get_target (ibfd);
}
/* Check the section rename list for a new name of the input section
- ISECTION. Return the new name if one is found.
- Also set RETURNED_FLAGS to the flags to be used for this section. */
+ called OLD_NAME. Returns the new name if one is found and sets
+ RETURNED_FLAGS if non-NULL to the flags to be used for this section. */
static const char *
-find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection,
- flagword * returned_flags)
+find_section_rename (const char *old_name, flagword *returned_flags)
{
- const char * old_name = bfd_section_name (ibfd, isection);
- section_rename * srename;
-
- /* Default to using the flags of the input section. */
- * returned_flags = bfd_get_section_flags (ibfd, isection);
+ const section_rename *srename;
for (srename = section_rename_list; srename != NULL; srename = srename->next)
if (strcmp (srename->old_name, old_name) == 0)
{
- if (srename->flags != (flagword) -1)
- * returned_flags = srename->flags;
+ if (returned_flags != NULL && srename->flags != (flagword) -1)
+ *returned_flags = srename->flags;
return srename->new_name;
}
flagword flags;
const char *err;
const char * name;
+ const char * new_name;
char *prefix = NULL;
bfd_boolean make_nobits;
+ unsigned int alignment;
if (is_strip_section (ibfd, isection))
return;
/* Get the, possibly new, name of the output section. */
- name = find_section_rename (ibfd, isection, & flags);
+ name = bfd_section_name (isection);
+ flags = bfd_section_flags (isection);
+ if (bfd_get_flavour (ibfd) != bfd_get_flavour (obfd))
+ {
+ flags &= bfd_applicable_section_flags (ibfd);
+ flags &= bfd_applicable_section_flags (obfd);
+ }
+ new_name = find_section_rename (name, &flags);
+ if (new_name != name)
+ {
+ name = new_name;
+ flags = check_new_section_flags (flags, obfd, name);
+ }
/* Prefix sections. */
- if ((prefix_alloc_sections_string)
- && (bfd_get_section_flags (ibfd, isection) & SEC_ALLOC))
+ if (prefix_alloc_sections_string
+ && (bfd_section_flags (isection) & SEC_ALLOC) != 0)
prefix = prefix_alloc_sections_string;
else if (prefix_sections_string)
prefix = prefix_sections_string;
make_nobits = FALSE;
- p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ p = find_section_list (bfd_section_name (isection), FALSE,
SECTION_CONTEXT_SET_FLAGS);
if (p != NULL)
- flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
+ {
+ flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
+ flags = check_new_section_flags (flags, obfd, bfd_section_name (isection));
+ }
else if (strip_symbols == STRIP_NONDEBUG
&& (flags & (SEC_ALLOC | SEC_GROUP)) != 0
- && !is_nondebug_keep_contents_section (ibfd, isection))
+ && !is_nondebug_keep_contents_section (ibfd, isection))
{
flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
- if (obfd->xvec->flavour == bfd_target_elf_flavour)
+ if (bfd_get_flavour (obfd) == bfd_target_elf_flavour)
{
make_nobits = TRUE;
if (make_nobits)
elf_section_type (osection) = SHT_NOBITS;
- size = bfd_section_size (ibfd, isection);
+ size = bfd_section_size (isection);
size = bfd_convert_section_size (ibfd, isection, obfd, size);
if (copy_byte >= 0)
size = (size + interleave - 1) / interleave * copy_width;
else if (extract_symbol)
size = 0;
- if (! bfd_set_section_size (obfd, osection, size))
+ if (!bfd_set_section_size (osection, size))
{
err = _("failed to set size");
goto loser;
}
- vma = bfd_section_vma (ibfd, isection);
- p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ vma = bfd_section_vma (isection);
+ p = find_section_list (bfd_section_name (isection), FALSE,
SECTION_CONTEXT_ALTER_VMA | SECTION_CONTEXT_SET_VMA);
if (p != NULL)
{
else
vma += change_section_address;
- if (! bfd_set_section_vma (obfd, osection, vma))
+ if (!bfd_set_section_vma (osection, vma))
{
err = _("failed to set vma");
goto loser;
}
lma = isection->lma;
- p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ p = find_section_list (bfd_section_name (isection), FALSE,
SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_SET_LMA);
if (p != NULL)
{
osection->lma = lma;
+ p = find_section_list (bfd_section_name (isection), FALSE,
+ SECTION_CONTEXT_SET_ALIGNMENT);
+ if (p != NULL)
+ alignment = p->alignment;
+ else
+ alignment = bfd_section_alignment (isection);
+
/* FIXME: This is probably not enough. If we change the LMA we
may have to recompute the header for the file as well. */
- if (!bfd_set_section_alignment (obfd,
- osection,
- bfd_section_alignment (ibfd, isection)))
+ if (!bfd_set_section_alignment (osection, alignment))
{
err = _("failed to set alignment");
goto loser;
if (gsym != NULL)
{
gsym->flags |= BSF_KEEP;
- if (ibfd->xvec->flavour == bfd_target_elf_flavour)
+ if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour)
elf_group_id (isection) = gsym;
}
}
/* All went well. */
return;
-loser:
+ loser:
status = 1;
bfd_nonfatal_message (NULL, obfd, osection, err);
}
/* Return TRUE if input section ISECTION should be skipped. */
static bfd_boolean
-skip_section (bfd *ibfd, sec_ptr isection)
+skip_section (bfd *ibfd, sec_ptr isection, bfd_boolean skip_copy)
{
sec_ptr osection;
bfd_size_type size;
if (is_update_section (ibfd, isection))
return TRUE;
- flags = bfd_get_section_flags (ibfd, isection);
+ /* When merging a note section we skip the copying of the contents,
+ but not the copying of the relocs associated with the contents. */
+ if (skip_copy && is_mergeable_note_section (ibfd, isection))
+ return TRUE;
+
+ flags = bfd_section_flags (isection);
if ((flags & SEC_GROUP) != 0)
return TRUE;
osection = isection->output_section;
- size = bfd_get_section_size (isection);
+ size = bfd_section_size (isection);
if (size == 0 || osection == 0)
return TRUE;
return FALSE;
}
+/* Add section SECTION_PATTERN to the list of sections that will have their
+ relocations removed. */
+
+static void
+handle_remove_relocations_option (const char *section_pattern)
+{
+ find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE_RELOCS);
+}
+
+/* Return TRUE if ISECTION from IBFD should have its relocations removed,
+ otherwise return FALSE. If the user has requested that relocations be
+ removed from a section that does not have relocations then this
+ function will still return TRUE. */
+
+static bfd_boolean
+discard_relocations (bfd *ibfd ATTRIBUTE_UNUSED, asection *isection)
+{
+ return (find_section_list (bfd_section_name (isection), FALSE,
+ SECTION_CONTEXT_REMOVE_RELOCS) != NULL);
+}
+
+/* Wrapper for dealing with --remove-section (-R) command line arguments.
+ A special case is detected here, if the user asks to remove a relocation
+ section (one starting with ".rela" or ".rel") then this removal must
+ be done using a different technique in a relocatable object. */
+
+static void
+handle_remove_section_option (const char *section_pattern)
+{
+ find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE);
+ if (strncmp (section_pattern, ".rel", 4) == 0)
+ {
+ section_pattern += 4;
+ if (*section_pattern == 'a')
+ section_pattern++;
+ if (*section_pattern)
+ handle_remove_relocations_option (section_pattern);
+ }
+ sections_removed = TRUE;
+}
+
/* Copy relocations in input section ISECTION of IBFD to an output
section with the same name in OBFDARG. If stripping then don't
copy any relocation info. */
long relcount;
sec_ptr osection;
- if (skip_section (ibfd, isection))
+ if (skip_section (ibfd, isection, FALSE))
return;
osection = isection->output_section;
/* Core files and DWO files do not need to be relocated. */
- if (bfd_get_format (obfd) == bfd_core || strip_symbols == STRIP_NONDWO)
+ if (bfd_get_format (obfd) == bfd_core
+ || strip_symbols == STRIP_NONDWO
+ || discard_relocations (ibfd, isection))
relsize = 0;
else
{
}
else
{
- relpp = (arelent **) xmalloc (relsize);
- relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
- if (relcount < 0)
+ if (isection->orelocation != NULL)
{
- status = 1;
- bfd_nonfatal_message (NULL, ibfd, isection,
- _("relocation count is negative"));
- return;
+ /* Some other function has already set up the output relocs
+ for us, so scan those instead of the default relocs. */
+ relcount = isection->reloc_count;
+ relpp = isection->orelocation;
+ }
+ else
+ {
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
+ if (relcount < 0)
+ {
+ status = 1;
+ bfd_nonfatal_message (NULL, ibfd, isection,
+ _("relocation count is negative"));
+ free (relpp);
+ return;
+ }
}
if (strip_symbols == STRIP_ALL)
for (i = 0; i < relcount; i++)
{
/* PR 17512: file: 9e907e0c. */
- if (relpp[i]->sym_ptr_ptr)
+ if (relpp[i]->sym_ptr_ptr
+ /* PR 20096 */
+ && * relpp[i]->sym_ptr_ptr)
if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
keep_specific_htab))
temp_relpp [temp_relcount++] = relpp [i];
}
relcount = temp_relcount;
- free (relpp);
+ if (relpp != isection->orelocation)
+ free (relpp);
relpp = temp_relpp;
}
if (relcount == 0)
{
osection->flags &= ~SEC_RELOC;
- free (relpp);
+ if (relpp != isection->orelocation)
+ free (relpp);
}
}
}
sec_ptr osection;
bfd_size_type size;
- if (skip_section (ibfd, isection))
+ if (skip_section (ibfd, isection, TRUE))
return;
osection = isection->output_section;
ELF classes of input and output aren't the same. We can't use
the output section size since --interleave will shrink the output
section. Size will be updated if the section is converted. */
- size = bfd_get_section_size (isection);
+ size = bfd_section_size (isection);
- if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
- && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
+ if (bfd_section_flags (isection) & SEC_HAS_CONTENTS
+ && bfd_section_flags (osection) & SEC_HAS_CONTENTS)
{
bfd_byte *memhunk = NULL;
{
status = 1;
bfd_nonfatal_message (NULL, ibfd, isection, NULL);
+ free (memhunk);
return;
}
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);
+ bfd_section_name (isection), reverse_bytes);
}
if (copy_byte >= 0)
char *end = (char *) memhunk + size;
int i;
+ /* If the section address is not exactly divisible by the interleave,
+ then we must bias the from address. If the copy_byte is less than
+ the bias, then we must skip forward one interleave, and increment
+ the final lma. */
+ int extra = isection->lma % interleave;
+ from -= extra;
+ if (copy_byte < extra)
+ from += interleave;
+
for (; from < end; from += interleave)
for (i = 0; i < copy_width; i++)
{
size = (size + interleave - 1 - copy_byte) / interleave * copy_width;
osection->lma /= interleave;
+ if (copy_byte < extra)
+ osection->lma++;
}
if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
{
status = 1;
bfd_nonfatal_message (NULL, obfd, osection, NULL);
+ free (memhunk);
return;
}
free (memhunk);
}
- else if ((p = find_section_list (bfd_get_section_name (ibfd, isection),
+ else if ((p = find_section_list (bfd_section_name (isection),
FALSE, SECTION_CONTEXT_SET_FLAGS)) != NULL
&& (p->flags & SEC_HAS_CONTENTS) != 0)
{
{
status = 1;
bfd_nonfatal_message (NULL, obfd, osection, NULL);
+ free (memhunk);
return;
}
free (memhunk);
++(*secppp);
}
-/* Sort sections by VMA. This is called via qsort, and is used when
+/* Sort sections by LMA. This is called via qsort, and is used when
--gap-fill or --pad-to is used. We force non loadable or empty
sections to the front, where they are easier to ignore. */
static int
compare_section_lma (const void *arg1, const void *arg2)
{
- const asection *const *sec1 = (const asection * const *) arg1;
- const asection *const *sec2 = (const asection * const *) arg2;
+ const asection *sec1 = *(const asection **) arg1;
+ const asection *sec2 = *(const asection **) arg2;
flagword flags1, flags2;
/* Sort non loadable sections to the front. */
- flags1 = (*sec1)->flags;
- flags2 = (*sec2)->flags;
+ flags1 = sec1->flags;
+ flags2 = sec2->flags;
if ((flags1 & SEC_HAS_CONTENTS) == 0
|| (flags1 & SEC_LOAD) == 0)
{
}
/* Sort sections by LMA. */
- if ((*sec1)->lma > (*sec2)->lma)
+ if (sec1->lma > sec2->lma)
return 1;
- else if ((*sec1)->lma < (*sec2)->lma)
+ if (sec1->lma < sec2->lma)
return -1;
/* Sort sections with the same LMA by size. */
- if (bfd_get_section_size (*sec1) > bfd_get_section_size (*sec2))
+ if (bfd_section_size (sec1) > bfd_section_size (sec2))
return 1;
- else if (bfd_get_section_size (*sec1) < bfd_get_section_size (*sec2))
+ if (bfd_section_size (sec1) < bfd_section_size (sec2))
return -1;
+ if (sec1->id > sec2->id)
+ return 1;
+ if (sec1->id < sec2->id)
+ return -1;
return 0;
}
special bfd section symbols, then mark it with BSF_KEEP. */
for (i = 0; i < relcount; i++)
{
- if (*relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
+ /* See PRs 20923 and 20930 for reproducers for the NULL tests. */
+ if (relpp[i]->sym_ptr_ptr != NULL
+ && * relpp[i]->sym_ptr_ptr != NULL
+ && *relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
&& *relpp[i]->sym_ptr_ptr != bfd_abs_section_ptr->symbol
&& *relpp[i]->sym_ptr_ptr != bfd_und_section_ptr->symbol)
(*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP;
long *symcountp ATTRIBUTE_UNUSED,
asymbol ***symppp ATTRIBUTE_UNUSED)
{
- if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour)
- return write_ieee_debugging_info (obfd, dhandle);
-
if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
|| bfd_get_flavour (obfd) == bfd_target_elf_flavour)
{
- bfd_byte *syms, *strings;
+ bfd_byte *syms, *strings = NULL;
bfd_size_type symsize, stringsize;
asection *stabsec, *stabstrsec;
flagword 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_size (stabsec, symsize)
+ || !bfd_set_section_size (stabstrsec, stringsize)
+ || !bfd_set_section_alignment (stabsec, 2)
+ || !bfd_set_section_alignment (stabstrsec, 0))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't create debugging section"));
+ free (strings);
return FALSE;
}
/* We can get away with setting the section contents now because
- the next thing the caller is going to do is copy over the
- real sections. We may someday have to split the contents
- setting out of this function. */
+ the next thing the caller is going to do is copy over the
+ real sections. We may someday have to split the contents
+ setting out of this function. */
if (! bfd_set_section_contents (obfd, stabsec, syms, 0, symsize)
|| ! bfd_set_section_contents (obfd, stabstrsec, strings, 0,
stringsize))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't set debugging section contents"));
+ free (strings);
return FALSE;
}
bfd_nonfatal_message (NULL, obfd, NULL,
_("don't know how to write debugging information for %s"),
- bfd_get_target (obfd));
+ bfd_get_target (obfd));
return FALSE;
}
int c;
int i;
char *output_file = NULL;
+ bfd_boolean merge_notes_set = FALSE;
- while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvwDU",
+ while ((c = getopt_long (argc, argv, "I:O:F:K:MN:R:o:sSpdgxXHhVvwDU",
strip_options, (int *) 0)) != EOF)
{
switch (c)
input_target = output_target = optarg;
break;
case 'R':
- find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
- sections_removed = TRUE;
+ handle_remove_section_option (optarg);
+ break;
+ case OPTION_KEEP_SECTION:
+ find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+ break;
+ case OPTION_REMOVE_RELOCS:
+ handle_remove_relocations_option (optarg);
break;
case 's':
strip_symbols = STRIP_ALL;
case 'K':
add_specific_symbol (optarg, keep_specific_htab);
break;
+ case 'M':
+ merge_notes = TRUE;
+ merge_notes_set = TRUE;
+ break;
+ case OPTION_NO_MERGE_NOTES:
+ merge_notes = FALSE;
+ merge_notes_set = TRUE;
+ break;
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
break;
}
}
+ /* If the user has not expressly chosen to merge/not-merge ELF notes
+ then enable the merging unless we are stripping debug or dwo info. */
+ if (! merge_notes_set
+ && (strip_symbols == STRIP_UNDEF
+ || strip_symbols == STRIP_ALL
+ || strip_symbols == STRIP_UNNEEDED
+ || strip_symbols == STRIP_NONDEBUG
+ || strip_symbols == STRIP_NONDWO))
+ merge_notes = TRUE;
+
if (formats_info)
{
display_info ();
static struct section_add *
init_section_add (const char *arg,
- struct section_add *next,
- const char *option)
+ struct section_add *next,
+ const char *option)
{
struct section_add *pa;
const char *s;
f = fopen (pa->filename, FOPEN_RB);
if (f == NULL)
fatal (_("cannot open: %s: %s"),
- pa->filename, strerror (errno));
+ pa->filename, strerror (errno));
off = 0;
alloc = 4096;
off_t got;
if (off == alloc)
- {
- alloc <<= 1;
- pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
- }
+ {
+ alloc <<= 1;
+ pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
+ }
got = fread (pa->contents + off, 1, alloc - off, f);
if (ferror (f))
- fatal (_("%s: fread failed"), pa->filename);
+ fatal (_("%s: fread failed"), pa->filename);
off += got;
}
bfd_boolean show_version = FALSE;
bfd_boolean change_warn = TRUE;
bfd_boolean formats_info = FALSE;
+ bfd_boolean use_globalize = FALSE;
+ bfd_boolean use_keep_global = FALSE;
int c;
struct stat statbuf;
const bfd_arch_info_type *input_arch = NULL;
- while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:wDU",
+ while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:MN:s:O:d:F:L:G:R:SpgxXHhVvW:wDU",
copy_options, (int *) 0)) != EOF)
{
switch (c)
break;
case 'R':
- find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
- sections_removed = TRUE;
+ handle_remove_section_option (optarg);
+ break;
+
+ case OPTION_KEEP_SECTION:
+ find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+ break;
+
+ case OPTION_REMOVE_RELOCS:
+ handle_remove_relocations_option (optarg);
break;
case 'S':
add_specific_symbol (optarg, keep_specific_htab);
break;
+ case 'M':
+ merge_notes = TRUE;
+ break;
+ case OPTION_NO_MERGE_NOTES:
+ merge_notes = FALSE;
+ break;
+
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
break;
break;
case OPTION_GLOBALIZE_SYMBOL:
+ use_globalize = TRUE;
add_specific_symbol (optarg, globalize_specific_htab);
break;
case 'G':
+ use_keep_global = TRUE;
add_specific_symbol (optarg, keepglobal_specific_htab);
break;
break;
case OPTION_ADD_SECTION:
- add_sections = init_section_add (optarg, add_sections,
- "--add-section");
- section_add_load_file (add_sections);
+ add_sections = init_section_add (optarg, add_sections,
+ "--add-section");
+ section_add_load_file (add_sections);
break;
case OPTION_UPDATE_SECTION:
update_sections = init_section_add (optarg, update_sections,
- "--update-section");
+ "--update-section");
section_add_load_file (update_sections);
break;
case OPTION_DUMP_SECTION:
- dump_sections = init_section_add (optarg, dump_sections,
- "--dump-section");
+ dump_sections = init_section_add (optarg, dump_sections,
+ "--dump-section");
break;
case OPTION_ADD_SYMBOL:
}
t = strchr (t + 1, ',');
+ newsym->othersym = NULL;
if (t)
newsym->flags = parse_symflags (t+1, &newsym->othersym);
else
{
case OPTION_CHANGE_SECTION_ADDRESS:
p->vma_val = val;
- /* Drop through. */
+ /* Fall through. */
case OPTION_CHANGE_SECTION_LMA:
p->lma_val = val;
do_debug_sections = decompress;
break;
+ case OPTION_ELF_STT_COMMON:
+ if (strcasecmp (optarg, "yes") == 0)
+ do_elf_stt_common = elf_stt_common;
+ else if (strcasecmp (optarg, "no") == 0)
+ do_elf_stt_common = no_elf_stt_common;
+ else
+ fatal (_("unrecognized --elf-stt-common= option `%s'"),
+ optarg);
+ break;
+
case OPTION_GAP_FILL:
{
bfd_vma gap_fill_vma;
case OPTION_REDEFINE_SYM:
{
- /* Push this redefinition onto redefine_symbol_list. */
+ /* Insert this redefinition onto redefine_specific_htab. */
int len;
const char *s;
target = (char *) xmalloc (len + 1);
strcpy (target, nextarg);
- redefine_list_append ("--redefine-sym", source, target);
+ add_redefine_and_check ("--redefine-sym", source, target);
free (source);
free (target);
}
break;
+ case OPTION_SET_SECTION_ALIGNMENT:
+ {
+ struct section_list *p;
+ const char *s;
+ int len;
+ char *name;
+ int palign, align;
+
+ s = strchr (optarg, '=');
+ if (s == NULL)
+ fatal (_("bad format for --set-section-alignment: argument needed"));
+
+ align = atoi (s + 1);
+ if (align <= 0)
+ fatal (_("bad format for --set-section-alignment: numeric argument needed"));
+
+ /* Convert integer alignment into a power-of-two alignment. */
+ palign = 0;
+ while ((align & 1) == 0)
+ {
+ align >>= 1;
+ ++palign;
+ }
+
+ if (align != 1)
+ /* Number has more than on 1, i.e. wasn't a power of 2. */
+ fatal (_("bad format for --set-section-alignment: alignment is not a power of two"));
+
+ /* Add the alignment setting to the section list. */
+ len = s - optarg;
+ name = (char *) xmalloc (len + 1);
+ strncpy (name, optarg, len);
+ name[len] = '\0';
+
+ p = find_section_list (name, TRUE, SECTION_CONTEXT_SET_ALIGNMENT);
+ if (p)
+ p->alignment = palign;
+ }
+ break;
+
case OPTION_RENAME_SECTION:
{
flagword flags;
break;
case OPTION_SREC_LEN:
- Chunk = parse_vma (optarg, "--srec-len");
+ _bfd_srec_len = parse_vma (optarg, "--srec-len");
break;
case OPTION_SREC_FORCES3:
- S3Forced = TRUE;
+ _bfd_srec_forceS3 = TRUE;
break;
case OPTION_STRIP_SYMBOLS:
- add_specific_symbols (optarg, strip_specific_htab);
+ add_specific_symbols (optarg, strip_specific_htab,
+ &strip_specific_buffer);
break;
case OPTION_STRIP_UNNEEDED_SYMBOLS:
- add_specific_symbols (optarg, strip_unneeded_htab);
+ add_specific_symbols (optarg, strip_unneeded_htab,
+ &strip_unneeded_buffer);
break;
case OPTION_KEEP_SYMBOLS:
- add_specific_symbols (optarg, keep_specific_htab);
+ add_specific_symbols (optarg, keep_specific_htab,
+ &keep_specific_buffer);
break;
case OPTION_LOCALIZE_HIDDEN:
break;
case OPTION_LOCALIZE_SYMBOLS:
- add_specific_symbols (optarg, localize_specific_htab);
+ add_specific_symbols (optarg, localize_specific_htab,
+ &localize_specific_buffer);
break;
case OPTION_LONG_SECTION_NAMES:
break;
case OPTION_GLOBALIZE_SYMBOLS:
- add_specific_symbols (optarg, globalize_specific_htab);
+ use_globalize = TRUE;
+ add_specific_symbols (optarg, globalize_specific_htab,
+ &globalize_specific_buffer);
break;
case OPTION_KEEPGLOBAL_SYMBOLS:
- add_specific_symbols (optarg, keepglobal_specific_htab);
+ use_keep_global = TRUE;
+ add_specific_symbols (optarg, keepglobal_specific_htab,
+ &keepglobal_specific_buffer);
break;
case OPTION_WEAKEN_SYMBOLS:
- add_specific_symbols (optarg, weaken_specific_htab);
+ add_specific_symbols (optarg, weaken_specific_htab,
+ &weaken_specific_buffer);
break;
case OPTION_ALT_MACH_CODE:
break;
case OPTION_REVERSE_BYTES:
- {
- int prev = 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"));
+ 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;
- }
+ if (prev && prev != reverse_bytes)
+ non_fatal (_("Warning: ignoring previous --reverse-bytes value of %d"),
+ prev);
+ break;
+ }
case OPTION_FILE_ALIGNMENT:
pe_file_alignment = parse_vma (optarg, "--file-alignment");
break;
case OPTION_HEAP:
- {
- char *end;
- pe_heap_reserve = strtoul (optarg, &end, 0);
- if (end == optarg
- || (*end != '.' && *end != '\0'))
- non_fatal (_("%s: invalid reserve value for --heap"),
- optarg);
- else if (*end != '\0')
- {
- pe_heap_commit = strtoul (end + 1, &end, 0);
- if (*end != '\0')
- non_fatal (_("%s: invalid commit value for --heap"),
- optarg);
- }
- }
+ {
+ char *end;
+ pe_heap_reserve = strtoul (optarg, &end, 0);
+ if (end == optarg
+ || (*end != '.' && *end != '\0'))
+ non_fatal (_("%s: invalid reserve value for --heap"),
+ optarg);
+ else if (*end != '\0')
+ {
+ pe_heap_commit = strtoul (end + 1, &end, 0);
+ if (*end != '\0')
+ non_fatal (_("%s: invalid commit value for --heap"),
+ optarg);
+ }
+ }
break;
case OPTION_IMAGE_BASE:
pe_image_base = parse_vma (optarg, "--image-base");
break;
- case OPTION_SECTION_ALIGNMENT:
+ case OPTION_PE_SECTION_ALIGNMENT:
pe_section_alignment = parse_vma (optarg,
"--section-alignment");
break;
break;
case OPTION_STACK:
- {
- char *end;
- pe_stack_reserve = strtoul (optarg, &end, 0);
- if (end == optarg
- || (*end != '.' && *end != '\0'))
- non_fatal (_("%s: invalid reserve value for --stack"),
- optarg);
- else if (*end != '\0')
- {
- pe_stack_commit = strtoul (end + 1, &end, 0);
- if (*end != '\0')
- non_fatal (_("%s: invalid commit value for --stack"),
- optarg);
- }
- }
+ {
+ char *end;
+ pe_stack_reserve = strtoul (optarg, &end, 0);
+ if (end == optarg
+ || (*end != '.' && *end != '\0'))
+ non_fatal (_("%s: invalid reserve value for --stack"),
+ optarg);
+ else if (*end != '\0')
+ {
+ pe_stack_commit = strtoul (end + 1, &end, 0);
+ if (*end != '\0')
+ non_fatal (_("%s: invalid commit value for --stack"),
+ optarg);
+ }
+ }
+ break;
+
+ case OPTION_VERILOG_DATA_WIDTH:
+ VerilogDataWidth = parse_vma (optarg, "--verilog-data-width");
+ if (VerilogDataWidth < 1)
+ fatal (_("verilog data width must be at least 1 byte"));
break;
case 0:
}
}
+ if (use_globalize && use_keep_global)
+ fatal(_("--globalize-symbol(s) is incompatible with -G/--keep-global-symbol(s)"));
+
if (formats_info)
{
display_info ();
else
unlink_if_ordinary (tmpname);
+ if (tmpname != output_filename)
+ free (tmpname);
+
if (change_warn)
{
struct section_list *p;
}
}
+ if (strip_specific_buffer)
+ free (strip_specific_buffer);
+
+ if (strip_unneeded_buffer)
+ free (strip_unneeded_buffer);
+
+ if (keep_specific_buffer)
+ free (keep_specific_buffer);
+
+ if (localize_specific_buffer)
+ free (globalize_specific_buffer);
+
+ if (globalize_specific_buffer)
+ free (globalize_specific_buffer);
+
+ if (keepglobal_specific_buffer)
+ free (keepglobal_specific_buffer);
+
+ if (weaken_specific_buffer)
+ free (weaken_specific_buffer);
+
return 0;
}
strip_symbols = STRIP_UNDEF;
discard_locals = LOCALS_UNDEF;
- bfd_init ();
+ if (bfd_init () != BFD_INIT_MAGIC)
+ fatal (_("fatal error: libbfd ABI mismatch"));
set_default_bfd_target ();
if (is_strip < 0)