/* objcopy.c -- copy object file from input to output, optionally massaging it.
- Copyright (C) 1991-2017 Free Software Foundation, Inc.
+ Copyright (C) 1991-2018 Free Software Foundation, Inc.
This file is part of GNU Binutils.
OPTION_LOCALIZE_SYMBOLS,
OPTION_LONG_SECTION_NAMES,
OPTION_MERGE_NOTES,
+ OPTION_NO_MERGE_NOTES,
OPTION_NO_CHANGE_WARNINGS,
OPTION_ONLY_KEEP_DEBUG,
OPTION_PAD_TO,
{"input-target", required_argument, 0, 'I'},
{"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
{"keep-symbol", required_argument, 0, 'K'},
+ {"merge-notes", no_argument, 0, 'M'},
+ {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
{"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
{"output-file", required_argument, 0, 'o'},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
{"long-section-names", required_argument, 0, OPTION_LONG_SECTION_NAMES},
{"merge-notes", no_argument, 0, 'M'},
+ {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
{"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
{"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
{"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
--elf-stt-common=[yes|no] Generate ELF common symbols with STT_COMMON\n\
type\n\
-M --merge-notes Remove redundant entries in note sections\n\
+ --no-merge-notes Do not attempt to remove redundant notes (default)\n\
-v --verbose List all object files modified\n\
@<file> Read options from <file>\n\
-V --version Display this program's version number\n\
--strip-dwo Remove all DWO sections\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
--only-keep-debug Strip everything but the debug information\n\
+ -M --merge-notes Remove redundant entries in note sections (default)\n\
+ --no-merge-notes Do not attempt to remove redundant notes\n\
-N --strip-symbol=<name> Do not copy symbol <name>\n\
-K --keep-symbol=<name> Do not strip symbol <name>\n\
--keep-file-symbols Do not strip file symbol(s)\n\
return TRUE;
}
+/* Returns the number of bytes needed to store VAL. */
+
+static inline unsigned int
+num_bytes (unsigned long val)
+{
+ unsigned int count = 0;
+
+ /* FIXME: There must be a faster way to do this. */
+ while (val)
+ {
+ count ++;
+ val >>= 8;
+ }
+ return count;
+}
+
+typedef struct objcopy_internal_note
+{
+ Elf_Internal_Note note;
+ 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;
- /* Make a copy of the notes.
+
+ relsize = bfd_get_reloc_upper_bound (abfd, sec);
+ if (relsize > 0)
+ {
+ arelent ** relpp;
+ long relcount;
+
+ /* If there are relocs associated with this section then we
+ cannot safely merge it. */
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
+ free (relpp);
+ if (relcount != 0)
+ goto done;
+ }
+
+ /* Make a copy of the notes and convert to our internal format.
Minimum size of a note is 12 bytes. */
- pnote = pnotes = (Elf_Internal_Note *) xmalloc ((size / 12) * sizeof (Elf_Internal_Note));
+ 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;
- if (pnote->type != NT_GNU_BUILD_ATTRIBUTE_OPEN
- && pnote->type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
+ 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->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;
+
+ 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;
+ }
+
+ 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_notes_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[1] != GNU_BUILD_ATTRIBUTE_VERSION)
+ if (pnotes[0].note.namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION)
{
err = _("bad GNU build attribute notes: first note not version note");
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;
- }
-
/* 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.
- 4. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
+ of name and whose address ranges coincide.
+ IE - it there are gaps in the coverage of the notes, then these gaps
+ must be preserved.
+ 4. Combine the numeric value of any NT_GNU_BUILD_ATTRIBUTE_OPEN notes
+ of type GNU_BUILD_ATTRIBUTE_STACK_SIZE.
+ 5. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
its description field is empty then the nearest preceeding OPEN note
with a non-empty description field must also be preserved *OR* the
description field of the note must be changed to contain the starting
address to which it refers. */
for (pnote = pnotes + 1; pnote < pnotes_end; pnote ++)
{
- 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)
+ /* Rule 2 - preserve function notes. */
+ if (! is_open_note (pnote))
continue;
- /* Scan for duplicates. Clear the type field of any found - but do not
- delete them just yet. */
+ 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 --)
{
- if (back->descsz > 0
- && back->type != NT_GNU_BUILD_ATTRIBUTE_FUNC
- && prev_open == NULL)
- prev_open = 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 (back->type == pnote->type
- && back->namedata[1] == pnote->namedata[1])
+ /* 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)
{
- if (back->namesz == pnote->namesz
- && memcmp (back->namedata, pnote->namedata, back->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->note.namesz - val_start,
+ name = (unsigned char *) pnote->note.namedata + val_start;
+ bytes--;)
{
- duplicate_found = TRUE;
- pnote->type = 0;
- break;
+ byte = (* name ++) & 0xff;
+ note_val |= byte << shift;
+ shift += 8;
}
- /* If we have found an attribute match then stop searching backwards. */
- if (! ISPRINT (back->namedata[1])
- || strcmp (back->namedata + 2, pnote->namedata + 2) == 0)
+ for (shift = 0, back_val = 0,
+ bytes = back->note.namesz - val_start,
+ name = (unsigned char *) back->note.namedata + val_start;
+ bytes--;)
{
- /* Since we are keeping this note we must check to see if its
- description refers back to an earlier OPEN 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;
+ byte = (* name ++) & 0xff;
+ back_val |= byte << shift;
+ shift += 8;
+ }
- break;
+ back_val += note_val;
+ if (num_bytes (back_val) >= back->note.namesz - val_start)
+ {
+ /* We have a problem - the new value requires more bytes of
+ storage in the name field than are available. Currently
+ we have no way of fixing this, so we just preserve both
+ notes. */
+ continue;
}
+
+ /* Write the new val into back. */
+ name = (unsigned char *) back->note.namedata + val_start;
+ while (name < (unsigned char *) back->note.namedata
+ + back->note.namesz)
+ {
+ byte = back_val & 0xff;
+ * name ++ = byte;
+ if (back_val == 0)
+ break;
+ back_val >>= 8;
+ }
+
+ duplicate_found = TRUE;
+ 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)
{
- 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;
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:
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);
return FALSE;
}
}
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);
}
return FALSE;
}
}
- else
- bfd_nonfatal_message (NULL, obfd, osec, _("ICE: lost merged note section"));
+ else if (! is_strip)
+ bfd_nonfatal_message (NULL, obfd, osec, _("could not find any mergeable note sections"));
free (merged_notes);
merged_notes = NULL;
merge_notes = FALSE;
}
else
{
- 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;
}
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))
int i;
char *output_file = NULL;
- while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvwDU",
+ merge_notes = TRUE;
+
+ while ((c = getopt_long (argc, argv, "I:O:F:K:MN:R:o:sSpdgxXHhVvwDU",
strip_options, (int *) 0)) != EOF)
{
switch (c)
case 'K':
add_specific_symbol (optarg, keep_specific_htab);
break;
+ case 'M':
+ merge_notes = TRUE;
+ break;
+ case OPTION_NO_MERGE_NOTES:
+ merge_notes = FALSE;
+ break;
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
break;
case 'M':
merge_notes = TRUE;
break;
+ case OPTION_NO_MERGE_NOTES:
+ merge_notes = FALSE;
+ break;
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
else
unlink_if_ordinary (tmpname);
+ if (tmpname != output_filename)
+ free (tmpname);
+
if (change_warn)
{
struct section_list *p;