/* objcopy.c -- copy object file from input to output, optionally massaging it.
- Copyright (C) 1991-2018 Free Software Foundation, Inc.
+ Copyright (C) 1991-2019 Free Software Foundation, Inc.
This file is part of GNU Binutils.
static int status = 0; /* Exit status. */
static bfd_boolean merge_notes = FALSE; /* Merge note sections. */
-static bfd_byte * merged_notes = NULL; /* Contents on note section undergoing a merge. */
-static bfd_size_type merged_size = 0; /* New, smaller size of the merged note section. */
+
+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_REMOVE_RELOCS (1 << 7) /* Remove relocations for this section. */
+#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;
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_INTERLEAVE_WIDTH,
OPTION_KEEPGLOBAL_SYMBOLS,
OPTION_KEEP_FILE_SYMBOLS,
+ OPTION_KEEP_SECTION,
OPTION_KEEP_SYMBOLS,
OPTION_LOCALIZE_HIDDEN,
OPTION_LOCALIZE_SYMBOLS,
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},
{"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},
{"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'},
on by the --srec-forceS3 command line switch. */
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 setup_bfd_headers (bfd *, bfd *);
--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\
--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\
-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\
p->vma_val = 0;
p->lma_val = 0;
p->flags = 0;
+ p->alignment = 0;
p->next = change_sections;
change_sections = p;
#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
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
- && ghdr->sh_info > 0
- && ghdr->sh_info < (symhdr->sh_size / bed->s->sizeof_sym))
+ if (ghdr->sh_info > 0
+ && ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
return isympp[ghdr->sh_info - 1];
}
return NULL;
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;
}
static bfd_boolean
-is_merged_note_section (bfd * abfd, asection * sec)
+is_mergeable_note_section (bfd * abfd, asection * sec)
{
if (merge_notes
&& bfd_get_flavour (abfd) == bfd_target_elf_flavour
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 with the
- expected name. */
- || (strcmp (sec->name, GNU_BUILD_ATTRS_SECTION_NAME) == 0)))
+ 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;
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));
+ 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))
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);
+ return (strcmp (bfd_section_name (isection), ".buildid") == 0);
return FALSE;
}
{
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)
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)
{
if (new_name == name
&& (flags & BSF_SECTION_SYM) != 0)
new_name = (char *) find_section_rename (name, NULL);
- bfd_asymbol_name (sym) = new_name;
+ bfd_set_asymbol_name (sym, new_name);
name = new_name;
}
|| (remove_leading_char
&& ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
|| undefined
- || bfd_is_com_section (bfd_get_section (sym)))));
+ || bfd_is_com_section (bfd_asymbol_section (sym)))));
/* Check if we will add a new leading character. */
add_leading_char =
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)
}
strcpy (ptr, name);
- bfd_asymbol_name (sym) = n;
+ bfd_set_asymbol_name (sym, n);
name = n;
}
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)
fatal (_("%s:%d: premature end of file"), filename, lineno);
free (buf);
+ fclose (file);
}
/* Copy unknown object file IBFD onto OBFD.
return TRUE;
}
-/* Returns the number of bytes needed to store VAL. */
-
-static inline unsigned int
-num_bytes (unsigned long val)
-{
- unsigned int count = 0;
-
- /* FIXME: There must be a faster way to do this. */
- while (val)
- {
- count ++;
- val >>= 8;
- }
- return count;
-}
-
typedef struct objcopy_internal_note
{
Elf_Internal_Note note;
+ unsigned long padded_namesz;
bfd_vma start;
bfd_vma end;
- bfd_boolean modified;
} objcopy_internal_note;
-/* Returns TRUE if a gap does, or could, exist between the address range
- covered by PNOTE1 and PNOTE2. */
+#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
-gap_exists (objcopy_internal_note * pnote1,
- objcopy_internal_note * pnote2)
+overlaps_or_adjoins (objcopy_internal_note * pnote1,
+ objcopy_internal_note * pnote2)
{
- /* Without range end notes, we assume that a gap might exist. */
- if (pnote1->end == 0 || pnote2->end == 0)
+ 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;
- /* 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 < 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);
+ 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);
+ 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
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;
+
+ /* 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)
+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;
unsigned version_1_seen = 0;
unsigned version_2_seen = 0;
unsigned version_3_seen = 0;
- bfd_boolean duplicate_found = FALSE;
const char * err = NULL;
bfd_byte * in = contents;
- int attribute_type_byte;
- int val_start;
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)
{
relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
free (relpp);
if (relcount != 0)
- goto done;
+ {
+ 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. */
- pnote = pnotes = (objcopy_internal_note *) xcalloc ((size / 12), sizeof (* pnote));
+ 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 ) + 3) & ~3;
- pnote->note.descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
- pnote->note.type = bfd_get_32 (abfd, in + 8);
+ 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)
goto done;
}
- if (pnote->note.namesz + pnote->note.descsz + 12 > remain)
+ if (pnote->padded_namesz + pnote->note.descsz + 12 > remain)
{
err = _("corrupt GNU build attribute note: note too big");
goto done;
}
pnote->note.namedata = (char *)(in + 12);
- pnote->note.descdata = (char *)(in + 12 + pnote->note.namesz);
+ pnote->note.descdata = (char *)(in + 12 + pnote->padded_namesz);
- remain -= 12 + pnote->note.namesz + pnote->note.descsz;
- in += 12 + pnote->note.namesz + pnote->note.descsz;
+ 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 (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)
+ else if (is_version_note (pnote))
{
if (pnote->note.namedata[4] == '2')
++ version_2_seen;
For now though, since v1 and v2 was not intended to
handle gaps, we chose an artificially large end
address. */
- end = 0x7ffffffffffffffUL;
+ end = (bfd_vma) -1;
break;
case 8:
For now though, since v1 and v2 was not intended to
handle gaps, we chose an artificially large end
address. */
- end = 0x7ffffffffffffffUL;
+ end = (bfd_vma) -1;
}
break;
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)
+ 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))
{
goto done;
}
- /* Merging is only needed if there is more than one version note... */
- if (version_1_seen == 1 || version_2_seen == 1 || version_3_seen == 1)
- goto done;
-
- attribute_type_byte = version_1_seen ? 1 : 3;
- val_start = attribute_type_byte + 1;
-
- /* The first note should be the first version note. */
- if (pnotes[0].note.namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION)
+ /* We are now only supporting the merging v3+ notes
+ - it makes things much simpler. */
+ if (version_3_seen == 0)
{
- err = _("bad GNU build attribute notes: first note not version note");
+ 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. Preserve the ordering of the notes.
- 2. Preserve any NT_GNU_BUILD_ATTRIBUTE_FUNC notes.
- 3. Eliminate any NT_GNU_BUILD_ATTRIBUTE_OPEN notes that have the same
- full name field as the immediately preceeding note with the same type
- of name and whose address ranges coincide.
- IE - it there are gaps in the coverage of the notes, then these gaps
- must be preserved.
- 4. Combine the numeric value of any NT_GNU_BUILD_ATTRIBUTE_OPEN notes
- of type GNU_BUILD_ATTRIBUTE_STACK_SIZE.
- 5. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
- its description field is empty then the nearest preceeding OPEN note
- with a non-empty description field must also be preserved *OR* the
- description field of the note must be changed to contain the starting
- address to which it refers. */
- for (pnote = pnotes + 1; pnote < pnotes_end; pnote ++)
+ 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 ++)
{
- int note_type;
- objcopy_internal_note * back;
- objcopy_internal_note * prev_open_with_range = NULL;
-
- /* Rule 2 - preserve function notes. */
- if (! is_open_note (pnote))
+ /* Skip already deleted notes.
+ FIXME: Can this happen ? We are scanning forwards and
+ deleting backwards after all. */
+ if (is_deleted_note (pnote))
continue;
- note_type = pnote->note.namedata[attribute_type_byte];
-
- /* Scan backwards from pnote, looking for duplicates.
- Clear the type field of any found - but do not delete them just yet. */
- for (back = pnote - 1; back >= pnotes; back --)
+ /* Rule 1 - delete 0-range notes. */
+ if (pnote->start == pnote->end)
{
- int back_type = back->note.namedata[attribute_type_byte];
+ merge_debug ("Delete note at offset %#08lx - empty range\n",
+ (pnote->note.namedata - (char *) contents) - 12);
+ pnote->note.type = 0;
+ continue;
+ }
- /* If this is the first open note with an address
- range that we have encountered then record it. */
- if (prev_open_with_range == NULL
- && back->note.descsz > 0
- && ! is_func_note (back))
- prev_open_with_range = back;
+ int iter;
+ objcopy_internal_note * back;
- if (! is_open_note (back))
- continue;
-
- /* If the two notes are different then keep on searching. */
- if (back_type != note_type)
+ /* 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;
- /* Rule 4 - combine stack size notes. */
- if (back_type == GNU_BUILD_ATTRIBUTE_STACK_SIZE)
+ /* 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)
{
- unsigned char * name;
- unsigned long note_val;
- unsigned long back_val;
- unsigned int shift;
- unsigned int bytes;
- unsigned long byte;
-
- for (shift = 0, note_val = 0,
- bytes = pnote->note.namesz - val_start,
- name = (unsigned char *) pnote->note.namedata + val_start;
- bytes--;)
- {
- byte = (* name ++) & 0xff;
- note_val |= byte << shift;
- shift += 8;
- }
-
- for (shift = 0, back_val = 0,
- bytes = back->note.namesz - val_start,
- name = (unsigned char *) back->note.namedata + val_start;
- bytes--;)
- {
- byte = (* name ++) & 0xff;
- back_val |= byte << shift;
- shift += 8;
- }
-
- back_val += note_val;
- if (num_bytes (back_val) >= back->note.namesz - val_start)
- {
- /* We have a problem - the new value requires more bytes of
- storage in the name field than are available. Currently
- we have no way of fixing this, so we just preserve both
- notes. */
- continue;
- }
-
- /* Write the new val into back. */
- name = (unsigned char *) back->note.namedata + val_start;
- while (name < (unsigned char *) back->note.namedata
- + back->note.namesz)
- {
- byte = back_val & 0xff;
- * name ++ = byte;
- if (back_val == 0)
- break;
- back_val >>= 8;
- }
-
- duplicate_found = TRUE;
+ 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 3 - combine identical open notes. */
- if (back->note.namesz == pnote->note.namesz
- && memcmp (back->note.namedata,
- pnote->note.namedata, back->note.namesz) == 0
- && ! gap_exists (back, pnote))
+ /* Rule 2a. */
+ if (contained_by (pnote, back))
{
- duplicate_found = TRUE;
+ 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;
-
- if (pnote->end > back->end)
- back->end = pnote->end;
-
- if (version_3_seen)
- back->modified = TRUE;
break;
}
- /* Rule 5 - Since we are keeping this note we must check to see
- if its description refers back to an earlier OPEN version
- note that has been scheduled for deletion. If so then we
- must make sure that version note is also preserved. */
- if (version_3_seen)
+#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))
{
- /* As of version 3 we can just
- move the range into the note. */
- pnote->modified = TRUE;
- pnote->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
- back->modified = TRUE;
- back->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+ 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;
}
- else
+
+ /* Don't scan too far back however. */
+ if (iter ++ > 16)
{
- if (pnote->note.descsz == 0
- && prev_open_with_range != NULL
- && prev_open_with_range->note.type == 0)
- prev_open_with_range->note.type = NT_GNU_BUILD_ATTRIBUTE_OPEN;
+ /* FIXME: Not sure if this can ever be triggered. */
+ merge_debug ("ITERATION LIMIT REACHED\n");
+ break;
}
-
- /* We have found a similar attribute but the details do not match.
- Stop searching backwards. */
- 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
}
- if (duplicate_found)
+ /* 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;
+
+ new = new_contents = xmalloc (size);
+ for (pnote = pnotes, old = contents;
+ pnote < pnotes_end;
+ pnote ++)
{
- 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;
-
- /* Eliminate the duplicates. */
- new = new_contents = xmalloc (size);
- for (pnote = pnotes, old = contents;
- pnote < pnotes_end;
- pnote ++)
- {
- bfd_size_type note_size = 12 + pnote->note.namesz + pnote->note.descsz;
+ bfd_size_type note_size = 12 + pnote->padded_namesz + pnote->note.descsz;
- if (pnote->note.type != 0)
+ 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)
{
- if (pnote->modified)
+ 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))
{
- /* If the note has been modified then we must copy it by
- hand, potentially adding in a new description field. */
- 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);
- new += pnote->note.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);
- new += pnote->note.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;
- }
- }
+ bfd_put_64 (abfd, pnote->start, new);
+ bfd_put_64 (abfd, pnote->end, new + 8);
+ new += 16;
}
else
{
- memcpy (new, old, note_size);
- new += note_size;
+ 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;
}
- new_size = new - new_contents;
- memcpy (contents, new_contents, new_size);
- size = new_size;
- free (new_contents);
+ 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;
+ memcpy (contents, new_contents, new_size);
+ size = new_size;
+ free (new_contents);
+
done:
if (err)
{
}
}
- 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;
}
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. */
- osec = bfd_get_section_by_name (ibfd, GNU_BUILD_ATTRS_SECTION_NAME);
- if (osec && is_merged_note_section (ibfd, osec))
+ for (osec = ibfd->sections; osec != NULL; osec = osec->next)
{
- bfd_size_type size;
-
- size = bfd_get_section_size (osec);
+ 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"));
- merge_notes = FALSE;
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("warning: note section is empty"));
+ continue;
}
- else if (! bfd_get_full_section_contents (ibfd, osec, & merged_notes))
+
+ 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_notes);
- merged_notes = NULL;
- merge_notes = FALSE;
+ bfd_nonfatal_message (NULL, ibfd, osec,
+ _("warning: could not load note section"));
+ free (merged);
+ continue;
}
- else
+
+ 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))
{
- merged_size = merge_gnu_build_notes (ibfd, osec, size, merged_notes);
- if (merged_size == size)
- {
- /* Merging achieves nothing. */
- free (merged_notes);
- merged_notes = NULL;
- merge_notes = FALSE;
- merged_size = 0;
- }
- else
- {
- if (osec->output_section == NULL
- || ! bfd_set_section_size (obfd, osec->output_section, merged_size))
- {
- bfd_nonfatal_message (NULL, obfd, osec, _("warning: failed to set merged notes size"));
- free (merged_notes);
- merged_notes = NULL;
- merge_notes = FALSE;
- merged_size = 0;
- }
- }
+ 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;
}
}
continue;
}
- if ((bfd_get_section_flags (ibfd, osec) & SEC_HAS_CONTENTS) == 0)
+ if ((bfd_section_flags (osec) & SEC_HAS_CONTENTS) == 0)
{
bfd_nonfatal_message (NULL, ibfd, osec,
_("can't dump section - it has no contents"));
continue;
}
- bfd_size_type size = bfd_get_section_size (osec);
+ bfd_size_type size = bfd_section_size (osec);
if (size == 0)
{
bfd_nonfatal_message (NULL, ibfd, osec,
pdump->filename,
strerror (errno));
free (contents);
+ fclose (f);
return FALSE;
}
}
+ 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);
}
}
}
bfd_size_type size;
bfd_vma gap_start, gap_stop;
- 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]) + size;
+ gap_stop = bfd_section_lma (osections[i + 1]);
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"));
bfd_vma lma;
bfd_size_type size;
- lma = bfd_section_lma (obfd, osections[c - 1]);
- size = bfd_section_size (obfd, osections[c - 1]);
+ lma = bfd_section_lma (osections[c - 1]);
+ size = bfd_section_size (osections[c - 1]);
if (lma + size < pad_to)
{
- if (! bfd_set_section_size (obfd, osections[c - 1],
- pad_to - lma))
+ if (!bfd_set_section_size (osections[c - 1], pad_to - lma))
{
bfd_nonfatal_message (NULL, obfd, osections[c - 1],
_("can't add padding"));
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;
}
}
- if (merge_notes)
+ if (merged_note_sections != NULL)
{
- osec = bfd_get_section_by_name (obfd, GNU_BUILD_ATTRS_SECTION_NAME);
- if (osec && is_merged_note_section (obfd, osec))
+ merged_note_section * merged = NULL;
+
+ for (osec = obfd->sections; osec != NULL; osec = osec->next)
{
- if (! bfd_set_section_contents (obfd, osec, merged_notes, 0, merged_size))
+ 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"));
+ 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 (! is_strip)
- bfd_nonfatal_message (NULL, obfd, osec, _("could not find any mergeable note sections"));
- free (merged_notes);
- merged_notes = NULL;
- merge_notes = FALSE;
}
+ 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)
{
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)
/* 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);
}
const char * 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 = bfd_section_name (ibfd, isection);
- flags = bfd_get_section_flags (ibfd, isection);
+ name = bfd_section_name (isection);
+ flags = bfd_section_flags (isection);
name = find_section_rename (name, &flags);
/* Prefix sections. */
if ((prefix_alloc_sections_string)
- && (bfd_get_section_flags (ibfd, isection) & SEC_ALLOC))
+ && (bfd_section_flags (isection) & SEC_ALLOC))
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));
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;
/* 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_merged_note_section (ibfd, isection))
+ if (skip_copy && is_mergeable_note_section (ibfd, isection))
return TRUE;
- flags = bfd_get_section_flags (ibfd, isection);
+ 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;
static bfd_boolean
discard_relocations (bfd *ibfd ATTRIBUTE_UNUSED, asection *isection)
{
- return (find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ 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. */
+ 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)
{
- if (strncmp (section_pattern, ".rela.", 6) == 0)
- handle_remove_relocations_option (section_pattern + 5);
- else if (strncmp (section_pattern, ".rel.", 5) == 0)
- handle_remove_relocations_option (section_pattern + 4);
- else
+ find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE);
+ if (strncmp (section_pattern, ".rel", 4) == 0)
{
- find_section_list (section_pattern, TRUE, SECTION_CONTEXT_REMOVE);
- sections_removed = TRUE;
+ 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
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;
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)
}
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)
{
++(*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;
}
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;
}
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't set debugging section contents"));
+ free (strings);
return FALSE;
}
int c;
int i;
char *output_file = NULL;
-
- merge_notes = TRUE;
+ bfd_boolean merge_notes_set = FALSE;
while ((c = getopt_long (argc, argv, "I:O:F:K:MN:R:o:sSpdgxXHhVvwDU",
strip_options, (int *) 0)) != EOF)
case 'R':
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;
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);
}
}
+ /* 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 ();
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;
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;
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_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_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:
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_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:
/* We've been given a long option. */
break;
}
}
+ if (use_globalize && use_keep_global)
+ fatal(_("--globalize-symbol(s) is incompatible with -G/--keep-global-symbol(s)"));
+
if (formats_info)
{
display_info ();
}
}
+ 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)