/* 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.
#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;
static struct addsym_node *add_sym_list = NULL, **add_sym_tail = &add_sym_list;
static int add_symbols = 0;
+static char *strip_specific_buffer = NULL;
+static char *strip_unneeded_buffer = NULL;
+static char *keep_specific_buffer = NULL;
+static char *localize_specific_buffer = NULL;
+static char *globalize_specific_buffer = NULL;
+static char *keepglobal_specific_buffer = NULL;
+static char *weaken_specific_buffer = NULL;
+
/* If this is TRUE, we weaken global symbols (set BSF_WEAK). */
static bfd_boolean weaken = FALSE;
OPTION_REMOVE_RELOCS,
OPTION_RENAME_SECTION,
OPTION_REVERSE_BYTES,
- OPTION_SECTION_ALIGNMENT,
+ OPTION_PE_SECTION_ALIGNMENT,
OPTION_SET_SECTION_FLAGS,
+ OPTION_SET_SECTION_ALIGNMENT,
OPTION_SET_START,
OPTION_SREC_FORCES3,
OPTION_SREC_LEN,
OPTION_STRIP_UNNEEDED_SYMBOLS,
OPTION_SUBSYSTEM,
OPTION_UPDATE_SECTION,
+ OPTION_VERILOG_DATA_WIDTH,
OPTION_WEAKEN,
OPTION_WEAKEN_SYMBOLS,
OPTION_WRITABLE_TEXT
{"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
{"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
{"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
- {"section-alignment", required_argument, 0, OPTION_SECTION_ALIGNMENT},
+ {"section-alignment", required_argument, 0, OPTION_PE_SECTION_ALIGNMENT},
{"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS},
+ {"set-section-alignment", required_argument, 0, OPTION_SET_SECTION_ALIGNMENT},
{"set-start", required_argument, 0, OPTION_SET_START},
{"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3},
{"srec-len", required_argument, 0, OPTION_SREC_LEN},
{"target", required_argument, 0, 'F'},
{"update-section", required_argument, 0, OPTION_UPDATE_SECTION},
{"verbose", no_argument, 0, 'v'},
+ {"verilog-data-width", required_argument, 0, OPTION_VERILOG_DATA_WIDTH},
{"version", no_argument, 0, 'V'},
{"weaken", no_argument, 0, OPTION_WEAKEN},
{"weaken-symbol", required_argument, 0, 'W'},
on by the --srec-forceS3 command line switch. */
extern bfd_boolean _bfd_srec_forceS3;
+/* Width of data in bytes for verilog output.
+ This variable is declared in bfd/verilog.c and can be modified by
+ the --verilog-data-width parameter. */
+extern unsigned int VerilogDataWidth;
+
/* Forward declarations. */
static void setup_section (bfd *, asection *, void *);
static void setup_bfd_headers (bfd *, bfd *);
Warn if a named section does not exist\n\
--set-section-flags <name>=<flags>\n\
Set section <name>'s properties to <flags>\n\
+ --set-section-alignment <name>=<align>\n\
+ Set section <name>'s alignment to 2^<align> bytes\n\
--add-section <name>=<file> Add section <name> found in <file> to output\n\
--update-section <name>=<file>\n\
Update contents of section <name> with\n\
--decompress-debug-sections Decompress DWARF debug sections using zlib\n\
--elf-stt-common=[yes|no] Generate ELF common symbols with STT_COMMON\n\
type\n\
+ --verilog-data-width <number> Specifies data width, in bytes, for verilog output\n\
-M --merge-notes Remove redundant entries in note sections\n\
--no-merge-notes Do not attempt to remove redundant notes (default)\n\
-v --verbose List all object files modified\n\
p->vma_val = 0;
p->lma_val = 0;
p->flags = 0;
+ p->alignment = 0;
p->next = change_sections;
change_sections = p;
#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
static void
-add_specific_symbols (const char *filename, htab_t htab)
+add_specific_symbols (const char *filename, htab_t htab, char **buffer_p)
{
off_t size;
FILE * f;
line = eol;
line_count ++;
}
+
+ /* Do not free the buffer. Parts of it will have been referenced
+ in the calls to add_specific_symbol. */
+ *buffer_p = buffer;
}
/* See whether a symbol should be stripped or kept
return NULL;
ghdr = &elf_section_data (group)->this_hdr;
- if (ghdr->sh_link < elf_numsections (abfd))
+ if (ghdr->sh_link == elf_onesymtab (abfd))
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
+ Elf_Internal_Shdr *symhdr = &elf_symtab_hdr (abfd);
- if (symhdr->sh_type == SHT_SYMTAB
- && ghdr->sh_info > 0
- && ghdr->sh_info < (symhdr->sh_size / bed->s->sizeof_sym))
+ if (ghdr->sh_info > 0
+ && ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
return isympp[ghdr->sh_info - 1];
}
return NULL;
static bfd_boolean
is_dwo_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
- const char *name = bfd_get_section_name (abfd, sec);
+ const char *name = bfd_section_name (sec);
int len = strlen (name);
return strncmp (name + len - 4, ".dwo", 4) == 0;
struct section_list *p;
struct section_list *q;
- p = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
+ p = find_section_list (bfd_section_name (sec), FALSE,
SECTION_CONTEXT_REMOVE);
- q = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
+ q = find_section_list (bfd_section_name (sec), FALSE,
SECTION_CONTEXT_COPY);
if (p && q)
fatal (_("error: section %s matches both remove and copy options"),
- bfd_get_section_name (abfd, sec));
+ bfd_section_name (sec));
if (p && is_update_section (abfd, sec))
fatal (_("error: section %s matches both update and remove options"),
- bfd_get_section_name (abfd, sec));
+ bfd_section_name (sec));
if (p != NULL)
return TRUE;
return TRUE;
}
- if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0)
+ if ((bfd_section_flags (sec) & SEC_DEBUGGING) != 0)
{
if (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_UNNEEDED
/* By default we don't want to strip .reloc section.
This section has for pe-coff special meaning. See
pe-dll.c file in ld, and peXXigen.c in bfd for details. */
- if (strcmp (bfd_get_section_name (abfd, sec), ".reloc") != 0)
+ if (strcmp (bfd_section_name (sec), ".reloc") != 0)
return TRUE;
}
if (is_strip_section_1 (abfd, sec))
return TRUE;
- if ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0)
+ if ((bfd_section_flags (sec) & SEC_GROUP) != 0)
{
asymbol *gsym;
const char *gname;
asection *elt, *first;
+ gsym = group_signature (sec);
+ /* Strip groups without a valid signature. */
+ if (gsym == NULL)
+ return TRUE;
+
/* PR binutils/3181
If we are going to strip the group signature symbol, then
strip the group section too. */
- gsym = group_signature (sec);
- if (gsym != NULL)
- gname = gsym->name;
- else
- gname = sec->name;
+ gname = gsym->name;
if ((strip_symbols == STRIP_ALL
&& !is_specified_symbol (gname, keep_specific_htab))
|| is_specified_symbol (gname, strip_specific_htab))
directory", but that may be the .text section for objects produced by some
tools, which it is not sensible to keep. */
if (ibfd->xvec->flavour == bfd_target_coff_flavour)
- return (strcmp (bfd_get_section_name (ibfd, isection), ".buildid") == 0);
+ return (strcmp (bfd_section_name (isection), ".buildid") == 0);
return FALSE;
}
{
asymbol *sym = bfd_make_empty_symbol (obfd);
- bfd_asymbol_name (sym) = ptr->symdef;
+ bfd_set_asymbol_name (sym, ptr->symdef);
sym->value = ptr->symval;
sym->flags = ptr->flags;
if (ptr->section)
bfd_boolean rem_leading_char;
bfd_boolean add_leading_char;
- undefined = bfd_is_und_section (bfd_get_section (sym));
+ undefined = bfd_is_und_section (bfd_asymbol_section (sym));
if (add_sym_list)
{
if (new_name == name
&& (flags & BSF_SECTION_SYM) != 0)
new_name = (char *) find_section_rename (name, NULL);
- bfd_asymbol_name (sym) = new_name;
+ bfd_set_asymbol_name (sym, new_name);
name = new_name;
}
|| (remove_leading_char
&& ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
|| undefined
- || bfd_is_com_section (bfd_get_section (sym)))));
+ || bfd_is_com_section (bfd_asymbol_section (sym)))));
/* Check if we will add a new leading character. */
add_leading_char =
if (rem_leading_char && add_leading_char && !prefix_symbols_string)
{
name[0] = bfd_get_symbol_leading_char (obfd);
- bfd_asymbol_name (sym) = name;
+ bfd_set_asymbol_name (sym, name);
rem_leading_char = FALSE;
add_leading_char = FALSE;
}
/* Remove leading char. */
if (rem_leading_char)
- bfd_asymbol_name (sym) = ++name;
+ bfd_set_asymbol_name (sym, ++name);
/* Add new leading char and/or prefix. */
if (add_leading_char || prefix_symbols_string)
}
strcpy (ptr, name);
- bfd_asymbol_name (sym) = n;
+ bfd_set_asymbol_name (sym, n);
name = n;
}
keep = FALSE;
else if ((flags & BSF_KEEP) != 0 /* Used in relocation. */
|| ((flags & BSF_SECTION_SYM) != 0
- && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags
+ && ((*bfd_asymbol_section (sym)->symbol_ptr_ptr)->flags
& BSF_KEEP) != 0))
{
keep = TRUE;
}
else if (relocatable /* Relocatable file. */
&& ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
- || bfd_is_com_section (bfd_get_section (sym))))
+ || bfd_is_com_section (bfd_asymbol_section (sym))))
keep = TRUE;
else if (bfd_decode_symclass (sym) == 'I')
/* Global symbols in $idata sections need to be retained
else if ((flags & BSF_GLOBAL) != 0 /* Global symbol. */
|| (flags & BSF_WEAK) != 0
|| undefined
- || bfd_is_com_section (bfd_get_section (sym)))
+ || bfd_is_com_section (bfd_asymbol_section (sym)))
keep = strip_symbols != STRIP_UNNEEDED;
else if ((flags & BSF_DEBUGGING) != 0) /* Debugging symbol. */
keep = (strip_symbols != STRIP_DEBUG
&& strip_symbols != STRIP_UNNEEDED
&& ! convert_debugging);
- else if (bfd_coff_get_comdat_section (abfd, bfd_get_section (sym)))
+ else if (bfd_coff_get_comdat_section (abfd, bfd_asymbol_section (sym)))
/* COMDAT sections store special information in local
symbols, so we cannot risk stripping any of them. */
keep = TRUE;
|| is_specified_symbol (name, keep_specific_htab)))
keep = TRUE;
- if (keep && is_strip_section (abfd, bfd_get_section (sym)))
+ if (keep && is_strip_section (abfd, bfd_asymbol_section (sym)))
keep = FALSE;
if (keep)
fatal (_("%s:%d: premature end of file"), filename, lineno);
free (buf);
+ fclose (file);
}
/* Copy unknown object file IBFD onto OBFD.
return 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_notes_seen = 0;
+ 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;
- remain -= 12 + pnote->namesz + pnote->descsz;
- in += 12 + pnote->namesz + pnote->descsz;
+ pnote->start = previous_open_start;
- if (pnote->namedata[pnote->namesz - 1] != 0)
+ if (end)
+ previous_open_end = end;
+
+ pnote->end = previous_open_end;
+ }
+ else
+ {
+ if (start)
+ previous_func_start = start;
+
+ pnote->start = previous_func_start;
+
+ if (end)
+ previous_func_end = end;
+
+ pnote->end = previous_func_end;
+ }
+
+ if (pnote->note.namedata[pnote->note.namesz - 1] != 0)
{
err = _("corrupt GNU build attribute note: name not NUL terminated");
goto done;
}
-
- if (pnote->namesz > 1 && pnote->namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION)
- ++ version_notes_seen;
+
pnote ++;
}
/* Check that the notes are valid. */
if (remain != 0)
{
- err = _("corrupt GNU build attribute notes: data at end");
+ err = _("corrupt GNU build attribute notes: excess data at end");
goto done;
}
- if (version_notes_seen == 0)
+ if (version_1_seen == 0 && version_2_seen == 0 && version_3_seen == 0)
{
- err = _("bad GNU build attribute notes: no version note");
+ err = _("bad GNU build attribute notes: no known versions detected");
goto done;
}
- /* Merging is only needed if there is more than one version note... */
- if (version_notes_seen == 1)
- goto done;
-
- /* The first note should be the first version note. */
- if (pnotes[0].namedata[1] != GNU_BUILD_ATTRIBUTE_VERSION)
+ 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: first note not version note");
+ err = _("bad GNU build attribute notes: multiple different versions");
goto done;
}
- if (pnotes[0].namedata[0] != GNU_BUILD_ATTRIBUTE_TYPE_STRING
- || pnotes[0].namedata[2] != '1')
- {
- err = _("bad GNU build attribute notes: version note not v1");
- 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;
+
+ /* 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[1] == pnote->namedata[1])
+ /* 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[1] == 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 - 2, name = (unsigned char *) pnote->namedata + 2;
- bytes--;)
- {
- byte = (* name ++) & 0xff;
- note_val |= byte << shift;
- shift += 8;
- }
- for (shift = 0, back_val = 0, bytes = back->namesz - 2, name = (unsigned char *) back->namedata + 2;
- bytes--;)
- {
- byte = (* name ++) & 0xff;
- back_val |= byte << shift;
- shift += 8;
- }
- back_val += note_val;
- if (num_bytes (back_val) >= back->namesz - 2)
- {
- /* 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->namedata + 2;
- while (name < (unsigned char *) back->namedata + back->namesz)
- {
- byte = back_val & 0xff;
- * name ++ = byte;
- if (back_val == 0)
- break;
- back_val >>= 8;
- }
-
duplicate_found = TRUE;
- pnote->type = 0;
+ pnote->note.type = 0;
break;
}
-
- if (back->namesz == pnote->namesz
- && memcmp (back->namedata, pnote->namedata, back->namesz) == 0)
+
+ /* 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 --)
+ {
+ 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))
+ 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;
+ }
+
+ 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[1])
- /* Names are NUL terminated, so this is safe. */
- || strcmp (back->namedata + 2, pnote->namedata + 2) == 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;
}
}
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);
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)
+ {
+ 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
{
- 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, 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;
memcpy (contents, new_contents, new_size);
size = new_size;
free (new_contents);
-
- if (relcount > 0)
- {
- arelent ** rel;
-
- for (rel = relpp; rel < relpp + relcount; rel ++)
- if ((* rel)->howto == NULL)
- {
- /* 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:
}
}
- if (! bfd_set_section_size (obfd, padd->section, padd->size))
+ if (!bfd_set_section_size (padd->section, padd->size))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
pset = find_section_list (padd->name, FALSE,
SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA);
if (pset != NULL
- && ! bfd_set_section_vma (obfd, padd->section, pset->vma_val))
+ && !bfd_set_section_vma (padd->section, pset->vma_val))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
{
padd->section->lma = pset->lma_val;
- if (! bfd_set_section_alignment
- (obfd, padd->section,
- bfd_section_alignment (obfd, padd->section)))
+ if (!bfd_set_section_alignment
+ (padd->section, bfd_section_alignment (padd->section)))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
}
osec = pupdate->section->output_section;
- if (! bfd_set_section_size (obfd, osec, pupdate->size))
+ if (!bfd_set_section_size (osec, pupdate->size))
{
bfd_nonfatal_message (NULL, obfd, osec, NULL);
return FALSE;
{
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"));
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);
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,
continue;
}
- bfd_byte * contents = xmalloc (size);
- if (bfd_get_section_contents (ibfd, osec, contents, 0, size))
+ bfd_byte *contents;
+ if (bfd_malloc_and_get_section (ibfd, osec, &contents))
{
if (fwrite (contents, 1, size, f) != size)
{
non_fatal (_("error writing section contents to %s (error: %s)"),
pdump->filename,
strerror (errno));
+ free (contents);
+ fclose (f);
return FALSE;
}
}
+ highest_section->size,
/* FIXME: We ought to be using
COFF_PAGE_SIZE here or maybe
- bfd_get_section_alignment() (if it
+ bfd_section_alignment() (if it
was set) but since this is for PE
and we know the required alignment
it is easier just to hard code it. */
/* Umm, not sure what to do in this case. */
debuglink_vma = 0x1000;
- bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma);
+ bfd_set_section_vma (gnu_debuglink_section, debuglink_vma);
}
}
}
bfd_size_type size;
bfd_vma gap_start, gap_stop;
- flags = bfd_get_section_flags (obfd, osections[i]);
+ flags = bfd_section_flags (osections[i]);
if ((flags & SEC_HAS_CONTENTS) == 0
|| (flags & SEC_LOAD) == 0)
continue;
- size = bfd_section_size (obfd, osections[i]);
- gap_start = bfd_section_lma (obfd, osections[i]) + size;
- gap_stop = bfd_section_lma (obfd, osections[i + 1]);
+ size = bfd_section_size (osections[i]);
+ gap_start = bfd_section_lma (osections[i]) + size;
+ gap_stop = bfd_section_lma (osections[i + 1]);
if (gap_start < gap_stop)
{
- if (! bfd_set_section_size (obfd, osections[i],
- size + (gap_stop - gap_start)))
+ if (!bfd_set_section_size (osections[i],
+ size + (gap_stop - gap_start)))
{
bfd_nonfatal_message (NULL, obfd, osections[i],
_("Can't fill gap after section"));
bfd_vma lma;
bfd_size_type size;
- lma = bfd_section_lma (obfd, osections[c - 1]);
- size = bfd_section_size (obfd, osections[c - 1]);
+ lma = bfd_section_lma (osections[c - 1]);
+ size = bfd_section_size (osections[c - 1]);
if (lma + size < pad_to)
{
- if (! bfd_set_section_size (obfd, osections[c - 1],
- pad_to - lma))
+ if (!bfd_set_section_size (osections[c - 1], pad_to - lma))
{
bfd_nonfatal_message (NULL, obfd, osections[c - 1],
_("can't add padding"));
ignore input sections which have no corresponding output
section. */
if (strip_symbols != STRIP_ALL)
- bfd_map_over_sections (ibfd,
- mark_symbols_used_in_relocations,
- isympp);
+ {
+ bfd_set_error (bfd_error_no_error);
+ bfd_map_over_sections (ibfd,
+ mark_symbols_used_in_relocations,
+ isympp);
+ if (bfd_get_error () != bfd_error_no_error)
+ {
+ status = 1;
+ return FALSE;
+ }
+ }
+
osympp = (asymbol **) xmalloc ((symcount + add_symbols + 1) * sizeof (asymbol *));
symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
}
if (convert_debugging && dhandle != NULL)
{
- if (! write_debugging_info (obfd, dhandle, &symcount, &osympp))
+ bfd_boolean res;
+
+ res = write_debugging_info (obfd, dhandle, &symcount, &osympp);
+
+ free (dhandle);
+ dhandle = NULL; /* Paranoia... */
+
+ if (! res)
{
status = 1;
return FALSE;
file_ptr off;
left = gaps[i];
- off = bfd_section_size (obfd, osections[i]) - left;
+ off = bfd_section_size (osections[i]) - left;
while (left > 0)
{
off, now))
{
bfd_nonfatal_message (NULL, obfd, osections[i], NULL);
+ free (buf);
return FALSE;
}
}
}
}
+
+ free (buf);
+ free (gaps);
+ gaps = NULL;
}
/* Allow the BFD backend to copy any private data it understands
char *dir;
const char *filename;
+ /* PR 24281: It is not clear what should happen when copying a thin archive.
+ One part is straight forward - if the output archive is in a different
+ directory from the input archive then any relative paths in the library
+ should be adjusted to the new location. But if any transformation
+ options are active (eg strip, rename, add, etc) then the implication is
+ that these should be applied to the files pointed to by the archive.
+ But since objcopy is not destructive, this means that new files must be
+ created, and there is no guidance for the names of the new files. (Plus
+ this conflicts with one of the goals of thin libraries - only taking up
+ a minimal amount of space in the file system).
+
+ So for now we fail if an attempt is made to copy such libraries. */
+ if (ibfd->is_thin_archive)
+ {
+ status = 1;
+ bfd_set_error (bfd_error_invalid_operation);
+ bfd_nonfatal_message (NULL, ibfd, NULL,
+ _("sorry: copying thin archives is not currently supported"));
+ return;
+ }
+
/* Make a temp directory to hold the contents. */
dir = make_tempdir (bfd_get_filename (obfd));
if (dir == NULL)
/* If the file already exists, make another temp dir. */
if (stat (output_name, &buf) >= 0)
{
- output_name = make_tempdir (output_name);
- if (output_name == NULL)
+ char * tmpdir = make_tempdir (output_name);
+
+ free (output_name);
+ if (tmpdir == NULL)
{
non_fatal (_("cannot create tempdir for archive copying (error: %s)"),
strerror (errno));
}
l = (struct name_list *) xmalloc (sizeof (struct name_list));
- l->name = output_name;
+ l->name = tmpdir;
l->next = list;
l->obfd = NULL;
list = l;
- output_name = concat (output_name, "/",
+ output_name = concat (tmpdir, "/",
bfd_get_filename (this_element), (char *) 0);
}
cleanup_and_exit:
/* Delete all the files that we opened. */
- for (l = list; l != NULL; l = l->next)
- {
- if (l->obfd == NULL)
- rmdir (l->name);
- else
- {
- bfd_close (l->obfd);
- unlink (l->name);
- }
- }
+ {
+ struct name_list * next;
+
+ for (l = list; l != NULL; l = next)
+ {
+ if (l->obfd == NULL)
+ rmdir (l->name);
+ else
+ {
+ bfd_close (l->obfd);
+ unlink (l->name);
+ }
+ next = l->next;
+ free (l);
+ }
+ }
rmdir (dir);
}
const char * name;
char *prefix = NULL;
bfd_boolean make_nobits;
+ unsigned int alignment;
if (is_strip_section (ibfd, isection))
return;
/* Get the, possibly new, name of the output section. */
- name = bfd_section_name (ibfd, isection);
- flags = bfd_get_section_flags (ibfd, isection);
+ name = bfd_section_name (isection);
+ flags = bfd_section_flags (isection);
name = find_section_rename (name, &flags);
/* Prefix sections. */
if ((prefix_alloc_sections_string)
- && (bfd_get_section_flags (ibfd, isection) & SEC_ALLOC))
+ && (bfd_section_flags (isection) & SEC_ALLOC))
prefix = prefix_alloc_sections_string;
else if (prefix_sections_string)
prefix = prefix_sections_string;
make_nobits = FALSE;
- p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ p = find_section_list (bfd_section_name (isection), FALSE,
SECTION_CONTEXT_SET_FLAGS);
if (p != NULL)
flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
if (make_nobits)
elf_section_type (osection) = SHT_NOBITS;
- size = bfd_section_size (ibfd, isection);
+ size = bfd_section_size (isection);
size = bfd_convert_section_size (ibfd, isection, obfd, size);
if (copy_byte >= 0)
size = (size + interleave - 1) / interleave * copy_width;
else if (extract_symbol)
size = 0;
- if (! bfd_set_section_size (obfd, osection, size))
+ if (!bfd_set_section_size (osection, size))
{
err = _("failed to set size");
goto loser;
}
- vma = bfd_section_vma (ibfd, isection);
- p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ vma = bfd_section_vma (isection);
+ p = find_section_list (bfd_section_name (isection), FALSE,
SECTION_CONTEXT_ALTER_VMA | SECTION_CONTEXT_SET_VMA);
if (p != NULL)
{
else
vma += change_section_address;
- if (! bfd_set_section_vma (obfd, osection, vma))
+ if (!bfd_set_section_vma (osection, vma))
{
err = _("failed to set vma");
goto loser;
}
lma = isection->lma;
- p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
+ p = find_section_list (bfd_section_name (isection), FALSE,
SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_SET_LMA);
if (p != NULL)
{
osection->lma = lma;
+ p = find_section_list (bfd_section_name (isection), FALSE,
+ SECTION_CONTEXT_SET_ALIGNMENT);
+ if (p != NULL)
+ alignment = p->alignment;
+ else
+ alignment = bfd_section_alignment (isection);
+
/* FIXME: This is probably not enough. If we change the LMA we
may have to recompute the header for the file as well. */
- if (!bfd_set_section_alignment (obfd,
- osection,
- bfd_section_alignment (ibfd, isection)))
+ if (!bfd_set_section_alignment (osection, alignment))
{
err = _("failed to set alignment");
goto loser;
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;
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
}
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)
temp_relpp [temp_relcount++] = relpp [i];
}
relcount = temp_relcount;
- free (relpp);
+ if (isection->orelocation == NULL)
+ free (relpp);
relpp = temp_relpp;
}
ELF classes of input and output aren't the same. We can't use
the output section size since --interleave will shrink the output
section. Size will be updated if the section is converted. */
- size = bfd_get_section_size (isection);
+ size = bfd_section_size (isection);
- if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
- && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
+ if (bfd_section_flags (isection) & SEC_HAS_CONTENTS
+ && bfd_section_flags (osection) & SEC_HAS_CONTENTS)
{
bfd_byte *memhunk = NULL;
else
/* User must pad the section up in order to do this. */
fatal (_("cannot reverse bytes: length of section %s must be evenly divisible by %d"),
- bfd_section_name (ibfd, isection), reverse_bytes);
+ bfd_section_name (isection), reverse_bytes);
}
if (copy_byte >= 0)
char *end = (char *) memhunk + size;
int i;
+ /* If the section address is not exactly divisible by the interleave,
+ then we must bias the from address. If the copy_byte is less than
+ the bias, then we must skip forward one interleave, and increment
+ the final lma. */
+ int extra = isection->lma % interleave;
+ from -= extra;
+ if (copy_byte < extra)
+ from += interleave;
+
for (; from < end; from += interleave)
for (i = 0; i < copy_width; i++)
{
size = (size + interleave - 1 - copy_byte) / interleave * copy_width;
osection->lma /= interleave;
+ if (copy_byte < extra)
+ osection->lma++;
}
if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
}
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)
{
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;
long *symcountp ATTRIBUTE_UNUSED,
asymbol ***symppp ATTRIBUTE_UNUSED)
{
- if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour)
- return write_ieee_debugging_info (obfd, dhandle);
-
if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
|| bfd_get_flavour (obfd) == bfd_target_elf_flavour)
{
- bfd_byte *syms, *strings;
+ bfd_byte *syms, *strings = NULL;
bfd_size_type symsize, stringsize;
asection *stabsec, *stabstrsec;
flagword flags;
stabstrsec = bfd_make_section_with_flags (obfd, ".stabstr", flags);
if (stabsec == NULL
|| stabstrsec == NULL
- || ! bfd_set_section_size (obfd, stabsec, symsize)
- || ! bfd_set_section_size (obfd, stabstrsec, stringsize)
- || ! bfd_set_section_alignment (obfd, stabsec, 2)
- || ! bfd_set_section_alignment (obfd, stabstrsec, 0))
+ || !bfd_set_section_size (stabsec, symsize)
+ || !bfd_set_section_size (stabstrsec, stringsize)
+ || !bfd_set_section_alignment (stabsec, 2)
+ || !bfd_set_section_alignment (stabstrsec, 0))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't create debugging section"));
+ free (strings);
return FALSE;
}
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't set debugging section contents"));
+ free (strings);
return FALSE;
}
int c;
int i;
char *output_file = NULL;
+ bfd_boolean merge_notes_set = FALSE;
- merge_notes = TRUE;
-
- while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvwDU",
+ while ((c = getopt_long (argc, argv, "I:O:F:K:MN:R:o:sSpdgxXHhVvwDU",
strip_options, (int *) 0)) != EOF)
{
switch (c)
break;
case 'M':
merge_notes = TRUE;
+ merge_notes_set = TRUE;
break;
case OPTION_NO_MERGE_NOTES:
merge_notes = FALSE;
+ merge_notes_set = TRUE;
break;
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
}
}
+ /* If the user has not expressly chosen to merge/not-merge ELF notes
+ then enable the merging unless we are stripping debug or dwo info. */
+ if (! merge_notes_set
+ && (strip_symbols == STRIP_UNDEF
+ || strip_symbols == STRIP_ALL
+ || strip_symbols == STRIP_UNNEEDED
+ || strip_symbols == STRIP_NONDEBUG
+ || strip_symbols == STRIP_NONDWO))
+ merge_notes = TRUE;
+
if (formats_info)
{
display_info ();
bfd_boolean show_version = FALSE;
bfd_boolean change_warn = TRUE;
bfd_boolean formats_info = FALSE;
+ bfd_boolean use_globalize = FALSE;
+ bfd_boolean use_keep_global = FALSE;
int c;
struct stat statbuf;
const bfd_arch_info_type *input_arch = NULL;
break;
case OPTION_GLOBALIZE_SYMBOL:
+ use_globalize = TRUE;
add_specific_symbol (optarg, globalize_specific_htab);
break;
case 'G':
+ use_keep_global = TRUE;
add_specific_symbol (optarg, keepglobal_specific_htab);
break;
}
break;
+ case OPTION_SET_SECTION_ALIGNMENT:
+ {
+ struct section_list *p;
+ const char *s;
+ int len;
+ char *name;
+ int align;
+
+ s = strchr (optarg, '=');
+ if (s == NULL)
+ fatal (_("bad format for %s"), "--set-section-alignment");
+
+ align = atoi(s+1);
+ if (align < 0)
+ fatal (_("bad format for %s"), "--set-section-alignment");
+
+ 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);
+
+ p->alignment = align;
+ }
+ break;
+
case OPTION_RENAME_SECTION:
{
flagword flags;
break;
case OPTION_STRIP_SYMBOLS:
- add_specific_symbols (optarg, strip_specific_htab);
+ add_specific_symbols (optarg, strip_specific_htab,
+ &strip_specific_buffer);
break;
case OPTION_STRIP_UNNEEDED_SYMBOLS:
- add_specific_symbols (optarg, strip_unneeded_htab);
+ add_specific_symbols (optarg, strip_unneeded_htab,
+ &strip_unneeded_buffer);
break;
case OPTION_KEEP_SYMBOLS:
- add_specific_symbols (optarg, keep_specific_htab);
+ add_specific_symbols (optarg, keep_specific_htab,
+ &keep_specific_buffer);
break;
case OPTION_LOCALIZE_HIDDEN:
break;
case OPTION_LOCALIZE_SYMBOLS:
- add_specific_symbols (optarg, localize_specific_htab);
+ add_specific_symbols (optarg, localize_specific_htab,
+ &localize_specific_buffer);
break;
case OPTION_LONG_SECTION_NAMES:
break;
case OPTION_GLOBALIZE_SYMBOLS:
- add_specific_symbols (optarg, globalize_specific_htab);
+ use_globalize = TRUE;
+ add_specific_symbols (optarg, globalize_specific_htab,
+ &globalize_specific_buffer);
break;
case OPTION_KEEPGLOBAL_SYMBOLS:
- add_specific_symbols (optarg, keepglobal_specific_htab);
+ use_keep_global = TRUE;
+ add_specific_symbols (optarg, keepglobal_specific_htab,
+ &keepglobal_specific_buffer);
break;
case OPTION_WEAKEN_SYMBOLS:
- add_specific_symbols (optarg, weaken_specific_htab);
+ add_specific_symbols (optarg, weaken_specific_htab,
+ &weaken_specific_buffer);
break;
case OPTION_ALT_MACH_CODE:
pe_image_base = parse_vma (optarg, "--image-base");
break;
- case OPTION_SECTION_ALIGNMENT:
+ case OPTION_PE_SECTION_ALIGNMENT:
pe_section_alignment = parse_vma (optarg,
"--section-alignment");
break;
}
break;
+ case OPTION_VERILOG_DATA_WIDTH:
+ VerilogDataWidth = parse_vma (optarg, "--verilog-data-width");
+ if (VerilogDataWidth < 1)
+ fatal (_("verilog data width must be at least 1 byte"));
+ break;
+
case 0:
/* We've been given a long option. */
break;
}
}
+ if (use_globalize && use_keep_global)
+ fatal(_("--globalize-symbol(s) is incompatible with -G/--keep-global-symbol(s)"));
+
if (formats_info)
{
display_info ();
else
unlink_if_ordinary (tmpname);
+ if (tmpname != output_filename)
+ free (tmpname);
+
if (change_warn)
{
struct section_list *p;
}
}
+ if (strip_specific_buffer)
+ free (strip_specific_buffer);
+
+ if (strip_unneeded_buffer)
+ free (strip_unneeded_buffer);
+
+ if (keep_specific_buffer)
+ free (keep_specific_buffer);
+
+ if (localize_specific_buffer)
+ free (globalize_specific_buffer);
+
+ if (globalize_specific_buffer)
+ free (globalize_specific_buffer);
+
+ if (keepglobal_specific_buffer)
+ free (keepglobal_specific_buffer);
+
+ if (weaken_specific_buffer)
+ free (weaken_specific_buffer);
+
return 0;
}
strip_symbols = STRIP_UNDEF;
discard_locals = LOCALS_UNDEF;
- bfd_init ();
+ if (bfd_init () != BFD_INIT_MAGIC)
+ fatal (_("fatal error: libbfd ABI mismatch"));
set_default_bfd_target ();
if (is_strip < 0)