/* Delete some bytes from a section while changing the size of an instruction.
The parameter "addr" denotes the section-relative offset pointing just
behind the shrinked instruction. "addr+count" point at the first
- byte just behind the original unshrinked instruction. */
+ byte just behind the original unshrinked instruction. If delete_shrinks_insn
+ is FALSE, we are deleting redundant padding bytes from relax_info prop
+ record handling. In that case, addr is section-relative offset of start
+ of padding, and count is the number of padding bytes to delete. */
static bfd_boolean
elf32_avr_relax_delete_bytes (bfd *abfd,
asection *sec,
bfd_vma addr,
- int count)
+ int count,
+ bfd_boolean delete_shrinks_insn)
{
Elf_Internal_Shdr *symtab_hdr;
unsigned int sec_shndx;
struct avr_relax_info *relax_info;
struct avr_property_record *prop_record = NULL;
bfd_boolean did_shrink = FALSE;
+ bfd_boolean did_pad = FALSE;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
to remember we didn't delete anything i.e. don't set did_shrink,
so that we don't corrupt reloc offsets or symbol values.*/
memset (contents + toaddr - count, fill, count);
+ did_pad = TRUE;
/* Adjust the TOADDR to avoid moving symbols located at the address
of the property record, which has not moved. */
continue;
shrinked_insn_address = (sec->output_section->vma
- + sec->output_offset + addr - count);
+ + sec->output_offset + addr);
+ if (delete_shrinks_insn)
+ shrinked_insn_address -= count;
irel = elf_section_data (isec)->relocs;
/* PR 12161: Read in the relocs for this section if necessary. */
a symbol or section associated with it. */
if (sym_sec == sec)
{
+ /* If there is an alignment boundary, we only need to
+ adjust addends that end up below the boundary. */
+ bfd_vma shrink_boundary = (reloc_toaddr
+ + sec->output_section->vma
+ + sec->output_offset);
+ bfd_boolean addend_within_shrink_boundary = FALSE;
+
symval += sym_sec->output_section->vma
+ sym_sec->output_offset;
(unsigned int) (symval + irel->r_addend),
(unsigned int) shrinked_insn_address);
+ /* If we padded bytes, then the boundary didn't change,
+ so there's no need to adjust addends pointing at the boundary.
+ If we didn't pad, then we actually shrank the boundary, so
+ addends pointing at the boundary need to be adjusted too. */
+ addend_within_shrink_boundary = did_pad
+ ? ((symval + irel->r_addend) < shrink_boundary)
+ : ((symval + irel->r_addend) <= shrink_boundary);
+
if (symval <= shrinked_insn_address
- && (symval + irel->r_addend) > shrinked_insn_address)
+ && (symval + irel->r_addend) > shrinked_insn_address
+ && addend_within_shrink_boundary)
{
if (elf32_avr_is_diff_reloc (irel))
{
{
/* Delete two bytes of data. */
if (!elf32_avr_relax_delete_bytes (abfd, sec,
- irel->r_offset + 2, 2))
+ irel->r_offset + 2, 2,
+ TRUE))
goto error_return;
/* That will change things, so, we should relax again.
/* Delete two bytes of data. */
if (!elf32_avr_relax_delete_bytes (abfd, sec,
- irel->r_offset + insn_size, 2))
+ irel->r_offset + insn_size, 2,
+ TRUE))
goto error_return;
/* That will change things, so, we should relax
record->offset -= count;
elf32_avr_relax_delete_bytes (abfd, sec,
addr - count,
- count);
+ count, FALSE);
*again = TRUE;
}
}