X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Fobjcopy.c;h=8f74bebae88e7cd8d60f8658b37b68fc7ba5b464;hb=03d0d46a0e60203528f8d385a4136c870ff02261;hp=e5df1a919560b8f1d161e6e25073d74e1bc78b4e;hpb=ea8fae9fe75706235ac49c507f1c5e039f4b4e1e;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objcopy.c b/binutils/objcopy.c index e5df1a9195..8f74bebae8 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-2017 Free Software Foundation, Inc. + Copyright (C) 1991-2019 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -143,10 +143,12 @@ struct section_list #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_SET_ALIGNMENT (1 << 8) /* 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; @@ -253,6 +255,14 @@ static htab_t redefine_specific_reverse_htab = NULL; static struct addsym_node *add_sym_list = NULL, **add_sym_tail = &add_sym_list; static int add_symbols = 0; +static char *strip_specific_buffer = NULL; +static char *strip_unneeded_buffer = NULL; +static char *keep_specific_buffer = NULL; +static char *localize_specific_buffer = NULL; +static char *globalize_specific_buffer = NULL; +static char *keepglobal_specific_buffer = NULL; +static char *weaken_specific_buffer = NULL; + /* If this is TRUE, we weaken global symbols (set BSF_WEAK). */ static bfd_boolean weaken = FALSE; @@ -336,8 +346,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, @@ -349,6 +360,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 @@ -467,8 +479,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}, @@ -485,6 +498,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'}, @@ -511,6 +525,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 *); @@ -595,6 +614,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\ @@ -645,6 +666,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\ @@ -948,6 +970,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; @@ -1034,7 +1057,7 @@ add_specific_symbol_node (const void *node, htab_t htab) #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; @@ -1142,6 +1165,10 @@ add_specific_symbols (const char *filename, htab_t htab) 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 @@ -1211,14 +1238,13 @@ group_signature (asection *group) 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; @@ -1229,7 +1255,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; @@ -1284,17 +1310,17 @@ is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) 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; @@ -1302,7 +1328,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 @@ -1313,7 +1339,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; } @@ -1338,20 +1364,21 @@ 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; 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)) @@ -1387,7 +1414,7 @@ is_nondebug_keep_contents_section (bfd *ibfd, asection *isection) 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; } @@ -1438,7 +1465,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) @@ -1476,7 +1503,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) { @@ -1494,7 +1521,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; } @@ -1505,7 +1532,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 = @@ -1518,14 +1545,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) @@ -1544,7 +1571,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; } @@ -1552,7 +1579,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; @@ -1560,7 +1587,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 @@ -1571,13 +1598,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; @@ -1610,7 +1637,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) @@ -1817,6 +1844,7 @@ add_redefine_syms_file (const char *filename) fatal (_("%s:%d: premature end of file"), filename, lineno); free (buf); + fclose (file); } /* Copy unknown object file IBFD onto OBFD. @@ -1905,84 +1933,229 @@ num_bytes (unsigned long val) return count; } +typedef struct objcopy_internal_note +{ + Elf_Internal_Note note; + 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. */ + +static bfd_boolean +gap_exists (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) + 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; +} + +static bfd_boolean +is_open_note (objcopy_internal_note * pnote) +{ + return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_OPEN); +} + +static bfd_boolean +is_func_note (objcopy_internal_note * pnote) +{ + return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_FUNC); +} + +static bfd_boolean +is_64bit (bfd * abfd) +{ + /* Should never happen, but let's be paranoid. */ + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + return FALSE; + + return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64; +} + /* 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) { - Elf_Internal_Note * pnotes_end; - Elf_Internal_Note * pnotes; - Elf_Internal_Note * pnote; + objcopy_internal_note * pnotes_end; + objcopy_internal_note * pnotes = NULL; + objcopy_internal_note * pnote; bfd_size_type remain = size; unsigned version_1_seen = 0; unsigned version_2_seen = 0; + unsigned version_3_seen = 0; 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) + { + arelent ** relpp; + long relcount; - /* Make a copy of the notes. - Minimum size of a note is 12 bytes. */ - pnote = pnotes = (Elf_Internal_Note *) xcalloc ((size / 12), sizeof (Elf_Internal_Note)); + /* If there are relocs associated with this section then we + cannot safely merge it. */ + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp); + free (relpp); + if (relcount != 0) + goto done; + } + + /* Make a copy of the notes and convert to our internal format. + Minimum size of a note is 12 bytes. Also locate the version + notes and check them. */ + pnote = pnotes = (objcopy_internal_note *) xcalloc ((size / 12), sizeof (* pnote)); while (remain >= 12) { - pnote->namesz = (bfd_get_32 (abfd, in ) + 3) & ~3; - pnote->descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3; - pnote->type = bfd_get_32 (abfd, in + 8); + 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); - if (pnote->type != NT_GNU_BUILD_ATTRIBUTE_OPEN - && pnote->type != NT_GNU_BUILD_ATTRIBUTE_FUNC) + if (pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_OPEN + && pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_FUNC) { err = _("corrupt GNU build attribute note: wrong note type"); goto done; } - if (pnote->namesz + pnote->descsz + 12 > remain) + if (pnote->note.namesz + pnote->note.descsz + 12 > remain) { err = _("corrupt GNU build attribute note: note too big"); goto done; } - if (pnote->namesz < 2) + if (pnote->note.namesz < 2) { err = _("corrupt GNU build attribute note: name too small"); goto done; } - if (pnote->descsz != 0 - && pnote->descsz != 4 - && pnote->descsz != 8) + pnote->note.namedata = (char *)(in + 12); + pnote->note.descdata = (char *)(in + 12 + pnote->note.namesz); + + remain -= 12 + pnote->note.namesz + pnote->note.descsz; + in += 12 + pnote->note.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) + { + if (pnote->note.namedata[4] == '2') + ++ version_2_seen; + else if (pnote->note.namedata[4] == '3') + ++ version_3_seen; + else + { + err = _("corrupt GNU build attribute note: unsupported version"); + goto done; + } + } + + switch (pnote->note.descsz) { + case 0: + start = end = 0; + break; + + case 4: + start = bfd_get_32 (abfd, pnote->note.descdata); + /* FIXME: For version 1 and 2 notes we should try to + calculate the end address by finding a symbol whose + value is START, and then adding in its size. + + For now though, since v1 and v2 was not intended to + handle gaps, we chose an artificially large end + address. */ + end = (bfd_vma) -1; + break; + + case 8: + if (! is_64bit (abfd)) + { + start = bfd_get_32 (abfd, pnote->note.descdata); + end = bfd_get_32 (abfd, pnote->note.descdata + 4); + } + else + { + start = bfd_get_64 (abfd, pnote->note.descdata); + /* FIXME: For version 1 and 2 notes we should try to + calculate the end address by finding a symbol whose + value is START, and then adding in its size. + + For now though, since v1 and v2 was not intended to + handle gaps, we chose an artificially large end + address. */ + end = (bfd_vma) -1; + } + break; + + case 16: + start = bfd_get_64 (abfd, pnote->note.descdata); + end = bfd_get_64 (abfd, pnote->note.descdata + 8); + break; + + default: err = _("corrupt GNU build attribute note: bad description size"); goto done; } - pnote->namedata = (char *)(in + 12); - pnote->descdata = (char *)(in + 12 + pnote->namesz); + if (is_open_note (pnote)) + { + if (start) + previous_open_start = start; + + pnote->start = previous_open_start; - remain -= 12 + pnote->namesz + pnote->descsz; - in += 12 + pnote->namesz + pnote->descsz; + if (end) + previous_open_end = end; - if (pnote->namedata[pnote->namesz - 1] != 0) + pnote->end = previous_open_end; + } + else + { + if (start) + previous_func_start = start; + + pnote->start = previous_func_start; + + if (end) + previous_func_end = end; + + pnote->end = previous_func_end; + } + + if (pnote->note.namedata[pnote->note.namesz - 1] != 0) { err = _("corrupt GNU build attribute note: name not NUL terminated"); goto done; } - - if (pnote->namesz > 2 - && pnote->namedata[0] == '$' - && pnote->namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION - && pnote->namedata[2] == '1') - ++ version_1_seen; - else if (pnote->namesz > 4 - && pnote->namedata[0] == 'G' - && pnote->namedata[1] == 'A' - && pnote->namedata[2] == '$' - && pnote->namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION - && pnote->namedata[4] == '2') - ++ version_2_seen; + pnote ++; } @@ -1995,144 +2168,209 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte goto done; } - if (version_1_seen == 0 && version_2_seen == 0) + if (version_1_seen == 0 && version_2_seen == 0 && version_3_seen == 0) { err = _("bad GNU build attribute notes: no known versions detected"); goto done; } - 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)) { err = _("bad GNU build attribute notes: multiple different versions"); goto done; } /* Merging is only needed if there is more than one version note... */ - if (version_1_seen == 1 || version_2_seen == 1) + 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].namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION) - { - err = _("bad GNU build attribute notes: first note not version note"); - goto done; - } + /* We used to require that the first note be a version note, + but this is no longer enforced. Due to the problems with + linking sections with the same name (eg .gnu.build.note.hot) + we cannot guarantee that the first note will be a version note. */ /* 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. + 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. */ - for (pnote = pnotes + 1; pnote < pnotes_end; pnote ++) + address to which it refers. + 6. Notes with the same start and end address can be deleted. + 7. FIXME: Elminate duplicate version notes - even function specific ones ? */ + for (pnote = pnotes; pnote < pnotes_end; pnote ++) { - Elf_Internal_Note * back; - Elf_Internal_Note * prev_open = NULL; + int note_type; + objcopy_internal_note * back; + objcopy_internal_note * prev_open_with_range = NULL; - if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC) - continue; + /* Rule 6 - delete 0-range notes. */ + if (pnote->start == pnote->end) + { + duplicate_found = TRUE; + pnote->note.type = 0; + continue; + } - /* Scan 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 - preserve function notes. */ + if (! is_open_note (pnote)) { - if (back->descsz > 0 - && back->type != NT_GNU_BUILD_ATTRIBUTE_FUNC - && prev_open == NULL) - prev_open = back; + int iter; - if (back->type == pnote->type - && back->namedata[attribute_type_byte] == pnote->namedata[attribute_type_byte]) + /* 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->namedata[attribute_type_byte] == GNU_BUILD_ATTRIBUTE_STACK_SIZE) + 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) { - 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->namesz - val_start, - name = (unsigned char *) pnote->namedata + val_start; - bytes--;) - { - byte = (* name ++) & 0xff; - note_val |= byte << shift; - shift += 8; - } + duplicate_found = TRUE; + pnote->note.type = 0; + break; + } - for (shift = 0, back_val = 0, - bytes = back->namesz - val_start, - name = (unsigned char *) back->namedata + val_start; - bytes--;) - { - byte = (* name ++) & 0xff; - back_val |= byte << shift; - shift += 8; - } + /* Don't scan too far back however. */ + if (iter ++ > 16) + break; + } + continue; + } - back_val += note_val; - if (num_bytes (back_val) >= back->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; - } + note_type = pnote->note.namedata[attribute_type_byte]; - /* Write the new val into back. */ - name = (unsigned char *) back->namedata + val_start; - while (name < (unsigned char *) back->namedata + back->namesz) - { - byte = back_val & 0xff; - * name ++ = byte; - if (back_val == 0) - break; - back_val >>= 8; - } + /* 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 --) + { + int back_type = back->note.namedata[attribute_type_byte]; - duplicate_found = TRUE; - pnote->type = 0; - break; + /* 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)) + 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) + { + 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; } - - if (back->namesz == pnote->namesz - && memcmp (back->namedata, pnote->namedata, back->namesz) == 0) + + for (shift = 0, back_val = 0, + bytes = back->note.namesz - val_start, + name = (unsigned char *) back->note.namedata + val_start; + bytes--;) { - duplicate_found = TRUE; - pnote->type = 0; - break; + byte = (* name ++) & 0xff; + back_val |= byte << shift; + shift += 8; } - /* If we have found an attribute match then stop searching backwards. */ - if (! ISPRINT (back->namedata[attribute_type_byte]) - /* Names are NUL terminated, so this is safe. */ - || strcmp (back->namedata + val_start, pnote->namedata + val_start) == 0) + back_val += note_val; + if (num_bytes (back_val) >= back->note.namesz - val_start) { - /* Since we are keeping this note we must check to see if its - description refers back to an earlier OPEN version note. If so - then we must make sure that version note is also preserved. */ - if (pnote->descsz == 0 - && prev_open != NULL - && prev_open->type == 0) - prev_open->type = NT_GNU_BUILD_ATTRIBUTE_FUNC; + /* 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; + } - break; + /* 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; + 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)) + { + duplicate_found = TRUE; + 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) + { + /* 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; + } + else + { + 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; + } + + /* We have found a similar attribute but the details do not match. + Stop searching backwards. */ + break; } } @@ -2142,22 +2380,8 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte bfd_byte * old; bfd_byte * new; bfd_size_type new_size; - arelent ** relpp = NULL; - long relsize; - long relcount = 0; - - relsize = bfd_get_reloc_upper_bound (abfd, sec); - if (relsize > 0) - { - /* If there are relocs associated with this section then we may - have to adjust them as well, as we remove notes. */ - relpp = (arelent **) xmalloc (relsize); - relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp); - if (relcount < 0) - /* Do not bother complaining here - copy_relocations_in_section - will do that for us. */ - relcount = 0; - } + bfd_vma prev_start = 0; + bfd_vma prev_end = 0; /* Eliminate the duplicates. */ new = new_contents = xmalloc (size); @@ -2165,36 +2389,52 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte pnote < pnotes_end; pnote ++) { - bfd_size_type note_size = 12 + pnote->namesz + pnote->descsz; + bfd_size_type note_size = 12 + pnote->note.namesz + pnote->note.descsz; - if (pnote->type == 0) + if (pnote->note.type != 0) { - if (relcount > 0) + if (pnote->modified) { - arelent ** rel; - - /* If there is a reloc at the current offset, delete it. - Adjust the location of any relocs above the current - location downwards by the size of the note being deleted. - FIXME: We could optimize this loop by retaining a pointer to - the last reloc below the current note. */ - for (rel = relpp; rel < relpp + relcount; rel ++) + /* 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) { - if ((* rel)->howto == NULL) - continue; - if ((* rel)->address < (bfd_vma) (new - new_contents)) - continue; - if ((* rel)->address >= (bfd_vma) ((new + note_size) - new_contents)) - (* rel)->address -= note_size; + 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 - (* rel)->howto = NULL; + { + bfd_put_32 (abfd, pnote->start, new); + bfd_put_32 (abfd, pnote->end, new + 4); + new += 8; + } } } - } - else - { - memcpy (new, old, note_size); - new += note_size; + else + { + memcpy (new, old, note_size); + new += note_size; + } + prev_start = pnote->start; + prev_end = pnote->end; } old += note_size; @@ -2204,24 +2444,6 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte memcpy (contents, new_contents, new_size); size = new_size; free (new_contents); - - if (relcount > 0) - { - arelent **rel = relpp; - - while (rel < relpp + relcount) - if ((*rel)->howto != NULL) - rel++; - else - { - /* Delete eliminated relocs. - FIXME: There are better ways to do this. */ - memmove (rel, rel + 1, - ((relcount - (rel - relpp)) - 1) * sizeof (*rel)); - relcount--; - } - bfd_set_reloc (abfd, sec, relpp, relcount); - } } done: @@ -2506,7 +2728,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; @@ -2515,7 +2737,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; @@ -2527,9 +2749,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; @@ -2554,7 +2775,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; @@ -2571,7 +2792,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) { bfd_size_type size; - size = bfd_get_section_size (osec); + size = bfd_section_size (osec); if (size == 0) { bfd_nonfatal_message (NULL, ibfd, osec, _("warning: note section is empty")); @@ -2598,7 +2819,8 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) else { if (osec->output_section == NULL - || ! bfd_set_section_size (obfd, osec->output_section, merged_size)) + || !bfd_set_section_size (osec->output_section, + merged_size)) { bfd_nonfatal_message (NULL, obfd, osec, _("warning: failed to set merged notes size")); free (merged_notes); @@ -2626,14 +2848,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, @@ -2659,6 +2881,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) pdump->filename, strerror (errno)); free (contents); + fclose (f); return FALSE; } } @@ -2725,7 +2948,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. */ @@ -2734,7 +2957,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); } } } @@ -2768,18 +2991,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")); @@ -2798,12 +3021,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")); @@ -2859,16 +3081,32 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) 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; @@ -2965,7 +3203,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) { @@ -2980,6 +3218,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) off, now)) { bfd_nonfatal_message (NULL, obfd, osections[i], NULL); + free (buf); return FALSE; } @@ -2988,6 +3227,10 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) } } } + + free (buf); + free (gaps); + gaps = NULL; } /* Allow the BFD backend to copy any private data it understands @@ -3045,6 +3288,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) @@ -3098,8 +3362,10 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, /* 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)); @@ -3108,11 +3374,11 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, } 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); } @@ -3219,16 +3485,22 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, 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); } @@ -3500,18 +3772,19 @@ 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); 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; @@ -3528,7 +3801,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)); @@ -3560,20 +3833,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) { @@ -3585,14 +3858,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) { @@ -3606,11 +3879,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; @@ -3684,12 +3962,12 @@ skip_section (bfd *ibfd, sec_ptr isection, bfd_boolean skip_copy) if (skip_copy && is_merged_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; @@ -3714,27 +3992,28 @@ 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); } /* 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 @@ -3785,14 +4064,24 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg) } else { - relpp = (arelent **) xmalloc (relsize); - relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp); - if (relcount < 0) + if (isection->orelocation != NULL) { - status = 1; - bfd_nonfatal_message (NULL, ibfd, isection, - _("relocation count is negative")); - return; + /* Some other function has already set up the output relocs + for us, so scan those instead of the default relocs. */ + relcount = isection->reloc_count; + relpp = isection->orelocation; + } + else + { + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp); + if (relcount < 0) + { + status = 1; + bfd_nonfatal_message (NULL, ibfd, isection, + _("relocation count is negative")); + return; + } } if (strip_symbols == STRIP_ALL) @@ -3815,7 +4104,8 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg) temp_relpp [temp_relcount++] = relpp [i]; } relcount = temp_relcount; - free (relpp); + if (isection->orelocation == NULL) + free (relpp); relpp = temp_relpp; } @@ -3847,10 +4137,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; @@ -3887,7 +4177,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) @@ -3898,6 +4188,15 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) char *end = (char *) memhunk + size; int i; + /* If the section address is not exactly divisible by the interleave, + then we must bias the from address. If the copy_byte is less than + the bias, then we must skip forward one interleave, and increment + the final lma. */ + int extra = isection->lma % interleave; + from -= extra; + if (copy_byte < extra) + from += interleave; + for (; from < end; from += interleave) for (i = 0; i < copy_width; i++) { @@ -3908,6 +4207,8 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg) size = (size + interleave - 1 - copy_byte) / interleave * copy_width; osection->lma /= interleave; + if (copy_byte < extra) + osection->lma++; } if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size)) @@ -3919,7 +4220,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) { @@ -3990,9 +4291,9 @@ compare_section_lma (const void *arg1, const void *arg2) 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)) + else if (bfd_section_size (*sec1) < bfd_section_size (*sec2)) return -1; return 0; @@ -4056,13 +4357,10 @@ write_debugging_info (bfd *obfd, void *dhandle, 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; @@ -4077,13 +4375,14 @@ 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")); + free (strings); return FALSE; } @@ -4097,6 +4396,7 @@ write_debugging_info (bfd *obfd, void *dhandle, { bfd_nonfatal_message (NULL, obfd, NULL, _("can't set debugging section contents")); + free (strings); return FALSE; } @@ -4128,8 +4428,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) @@ -4170,9 +4469,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); @@ -4224,6 +4525,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 (); @@ -4499,6 +4810,8 @@ copy_main (int argc, char *argv[]) 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; @@ -4617,10 +4930,12 @@ copy_main (int argc, char *argv[]) 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; @@ -4959,6 +5274,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; @@ -5017,15 +5372,18 @@ copy_main (int argc, char *argv[]) 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: @@ -5033,7 +5391,8 @@ copy_main (int argc, char *argv[]) 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: @@ -5048,15 +5407,20 @@ copy_main (int argc, char *argv[]) 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: @@ -5145,7 +5509,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; @@ -5172,6 +5536,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; @@ -5185,6 +5555,9 @@ copy_main (int argc, char *argv[]) } } + if (use_globalize && use_keep_global) + fatal(_("--globalize-symbol(s) is incompatible with -G/--keep-global-symbol(s)")); + if (formats_info) { display_info (); @@ -5301,6 +5674,9 @@ copy_main (int argc, char *argv[]) else unlink_if_ordinary (tmpname); + if (tmpname != output_filename) + free (tmpname); + if (change_warn) { struct section_list *p; @@ -5340,6 +5716,27 @@ copy_main (int argc, char *argv[]) } } + 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; } @@ -5365,7 +5762,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)