X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Fobjcopy.c;h=61b33c7e40517d937b24bf8353453a1b7d76df17;hb=06a6207a1ab458521656f293bb1ca8fd013d6f7c;hp=d8ae1f98a10a50f640c3a40b67a6da9ed0db8b5c;hpb=de564eb5cc8c67fc38f9910937935eef5ebc17d8;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objcopy.c b/binutils/objcopy.c index d8ae1f98a1..61b33c7e40 100644 --- a/binutils/objcopy.c +++ b/binutils/objcopy.c @@ -1,5 +1,5 @@ /* objcopy.c -- copy object file from input to output, optionally massaging it. - Copyright (C) 1991-2018 Free Software Foundation, Inc. + Copyright (C) 1991-2020 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -97,8 +97,14 @@ static int deterministic = -1; /* Enable deterministic archives. */ 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 { @@ -137,16 +143,19 @@ struct section_list 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; @@ -324,6 +333,7 @@ enum command_line_switch OPTION_INTERLEAVE_WIDTH, OPTION_KEEPGLOBAL_SYMBOLS, OPTION_KEEP_FILE_SYMBOLS, + OPTION_KEEP_SECTION, OPTION_KEEP_SYMBOLS, OPTION_LOCALIZE_HIDDEN, OPTION_LOCALIZE_SYMBOLS, @@ -344,8 +354,9 @@ enum command_line_switch 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, @@ -357,6 +368,7 @@ enum command_line_switch OPTION_STRIP_UNNEEDED_SYMBOLS, OPTION_SUBSYSTEM, OPTION_UPDATE_SECTION, + OPTION_VERILOG_DATA_WIDTH, OPTION_WEAKEN, OPTION_WEAKEN_SYMBOLS, OPTION_WRITABLE_TEXT @@ -376,6 +388,7 @@ static struct option strip_options[] = {"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}, @@ -447,6 +460,7 @@ static struct option copy_options[] = {"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}, @@ -475,8 +489,9 @@ static struct option copy_options[] = {"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}, @@ -493,6 +508,7 @@ static struct option copy_options[] = {"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'}, @@ -519,6 +535,11 @@ extern unsigned int _bfd_srec_len; 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 *); @@ -572,6 +593,7 @@ copy_usage (FILE *stream, int exit_status) --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 Do not strip section \n\ -K --keep-symbol Do not strip symbol \n\ --keep-file-symbols Do not strip file symbol(s)\n\ --localize-hidden Turn all ELF hidden symbols into locals\n\ @@ -603,6 +625,8 @@ copy_usage (FILE *stream, int exit_status) Warn if a named section does not exist\n\ --set-section-flags =\n\ Set section 's properties to \n\ + --set-section-alignment =\n\ + Set section 's alignment to bytes\n\ --add-section = Add section found in to output\n\ --update-section =\n\ Update contents of section with\n\ @@ -653,6 +677,7 @@ copy_usage (FILE *stream, int exit_status) --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 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\ @@ -702,6 +727,7 @@ strip_usage (FILE *stream, int exit_status) -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= Do not copy symbol \n\ + --keep-section= Do not strip section \n\ -K --keep-symbol= Do not strip symbol \n\ --keep-file-symbols Do not strip file symbol(s)\n\ -w --wildcard Permit wildcard in symbol comparison\n\ @@ -956,6 +982,7 @@ find_section_list (const char *name, bfd_boolean add, unsigned int context) p->vma_val = 0; p->lma_val = 0; p->flags = 0; + p->alignment = 0; p->next = change_sections; change_sections = p; @@ -1240,7 +1267,7 @@ group_signature (asection *group) 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; @@ -1268,7 +1295,7 @@ is_update_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) } 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 @@ -1277,9 +1304,9 @@ is_merged_note_section (bfd * abfd, asection * sec) 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; @@ -1290,22 +1317,26 @@ is_merged_note_section (bfd * abfd, asection * sec) 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; @@ -1313,7 +1344,7 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) 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 @@ -1324,7 +1355,7 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) /* 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; } @@ -1349,7 +1380,7 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) 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; @@ -1390,16 +1421,16 @@ static bfd_boolean 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; } @@ -1450,7 +1481,7 @@ create_new_symbol (struct addsym_node *ptr, bfd *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) @@ -1488,7 +1519,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, 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) { @@ -1506,7 +1537,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, 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; } @@ -1517,7 +1548,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, || (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 = @@ -1530,14 +1561,14 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, 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) @@ -1556,7 +1587,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, } strcpy (ptr, name); - bfd_asymbol_name (sym) = n; + bfd_set_asymbol_name (sym, n); name = n; } @@ -1564,7 +1595,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, 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; @@ -1572,7 +1603,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, } 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 @@ -1583,13 +1614,13 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, 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; @@ -1622,7 +1653,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, || 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) @@ -1902,56 +1933,81 @@ copy_unknown_object (bfd *ibfd, bfd *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; + + if (pnote2->end < pnote1->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; + 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 @@ -1964,11 +2020,97 @@ is_64bit (bfd * abfd) 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; @@ -1977,18 +2119,14 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte 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) { @@ -2001,19 +2139,33 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte 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) @@ -2022,7 +2174,7 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte 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; @@ -2035,21 +2187,17 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte } 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; @@ -2155,11 +2303,18 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte 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)) { @@ -2167,271 +2322,219 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte 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 - if 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. - 6. Notes with the same start and end address can be deleted. */ - 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; + /* Skip already deleted notes. + FIXME: Can this happen ? We are scanning forwards and + deleting backwards after all. */ + if (is_deleted_note (pnote)) + continue; - /* Rule 6 - delete 0-range notes. */ + /* Rule 1 - delete 0-range notes. */ if (pnote->start == pnote->end) { - duplicate_found = TRUE; + merge_debug ("Delete note at offset %#08lx - empty range\n", + (pnote->note.namedata - (char *) contents) - 12); pnote->note.type = 0; continue; } - /* Rule 2 - preserve function notes. */ - if (! is_open_note (pnote)) - { - int iter; + int iter; + objcopy_internal_note * back; - /* Check to see if there is an identical previous function note. - This can happen with overlays for example. */ - for (iter = 0, back = pnote -1; back >= pnotes; back --) - { - if (back->start == pnote->start - && back->end == pnote->end - && back->note.namesz == pnote->note.namesz - && memcmp (back->note.namedata, pnote->note.namedata, pnote->note.namesz) == 0) - { - fprintf (stderr, "DUP FUNXC\n"); - duplicate_found = TRUE; - pnote->note.type = 0; - break; - } - - /* Don't scan too far back however. */ - if (iter ++ > 16) - break; - } - 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 2: Check to see if there is an identical previous note. */ + for (iter = 0, back = pnote - 1; back >= pnotes; back --) { - int back_type = back->note.namedata[attribute_type_byte]; - - /* 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; - - if (! is_open_note (back)) + if (is_deleted_note (back)) continue; - /* If the two notes are different then keep on searching. */ - if (back_type != note_type) - 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; + + /* 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_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) + { + 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 { - if (pnote->modified) + 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; + 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); } + free (new_contents); done: if (err) @@ -2487,7 +2590,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) return FALSE; } - if (ibfd->xvec->flavour != bfd_target_elf_flavour) + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) { if ((do_debug_sections & compress) != 0 && do_debug_sections != compress) @@ -2548,8 +2651,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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; @@ -2558,6 +2660,14 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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))) @@ -2585,7 +2695,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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; @@ -2715,7 +2825,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) } } - 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; @@ -2724,7 +2834,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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; @@ -2736,9 +2846,8 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) { 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; @@ -2763,7 +2872,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) } 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; @@ -2771,52 +2880,61 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) } } + 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; } } @@ -2835,14 +2953,14 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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, @@ -2935,7 +3053,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) + 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. */ @@ -2944,7 +3062,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) /* 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); } } } @@ -2978,18 +3096,18 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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")); @@ -3008,12 +3126,11 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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")); @@ -3087,7 +3204,14 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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; @@ -3135,23 +3259,72 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) } } - 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) { - bfd_nonfatal_message (NULL, obfd, osec, _("error: failed to copy merged notes into output")); + 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 (! 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) { @@ -3184,7 +3357,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) file_ptr off; left = gaps[i]; - off = bfd_section_size (obfd, osections[i]) - left; + off = bfd_section_size (osections[i]) - left; while (left > 0) { @@ -3269,6 +3442,27 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, 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) @@ -3563,6 +3757,14 @@ copy_file (const char *input_filename, const char *output_filename, 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); @@ -3732,18 +3934,24 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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); + if (bfd_get_flavour (ibfd) != bfd_get_flavour (obfd)) + { + flags &= bfd_applicable_section_flags (ibfd); + flags &= bfd_applicable_section_flags (obfd); + } name = find_section_rename (name, &flags); /* 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; @@ -3760,7 +3968,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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)); @@ -3769,7 +3977,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) && !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; @@ -3792,20 +4000,20 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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) { @@ -3817,14 +4025,14 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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) { @@ -3838,11 +4046,16 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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; @@ -3867,7 +4080,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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; } } @@ -3913,15 +4126,15 @@ skip_section (bfd *ibfd, sec_ptr isection, bfd_boolean skip_copy) /* 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; @@ -3946,7 +4159,7 @@ handle_remove_relocations_option (const char *section_pattern) 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); } @@ -4091,10 +4304,10 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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; @@ -4131,7 +4344,7 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) 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) @@ -4174,7 +4387,7 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) } 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) { @@ -4210,20 +4423,20 @@ get_sections (bfd *obfd ATTRIBUTE_UNUSED, asection *osection, void *secppparg) ++(*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) { @@ -4239,17 +4452,21 @@ compare_section_lma (const void *arg1, const void *arg2) } /* 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; } @@ -4329,10 +4546,10 @@ write_debugging_info (bfd *obfd, void *dhandle, 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")); @@ -4382,8 +4599,7 @@ strip_main (int argc, char *argv[]) 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) @@ -4402,6 +4618,9 @@ strip_main (int argc, char *argv[]) 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; @@ -4424,9 +4643,11 @@ strip_main (int argc, char *argv[]) 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); @@ -4478,6 +4699,16 @@ strip_main (int argc, char *argv[]) } } + /* 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 (); @@ -4816,6 +5047,10 @@ copy_main (int argc, char *argv[]) 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; @@ -5217,6 +5452,46 @@ copy_main (int argc, char *argv[]) } 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; @@ -5412,7 +5687,7 @@ copy_main (int argc, char *argv[]) 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; @@ -5439,6 +5714,12 @@ copy_main (int argc, char *argv[]) } 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; @@ -5659,7 +5940,8 @@ main (int argc, char *argv[]) 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)