aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-avr.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf32-avr.c')
-rw-r--r--bfd/elf32-avr.c91
1 files changed, 60 insertions, 31 deletions
diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c
index 0f6c188..f140aa7 100644
--- a/bfd/elf32-avr.c
+++ b/bfd/elf32-avr.c
@@ -1854,6 +1854,40 @@ elf32_avr_adjust_reloc_if_spans_insn (bfd *abfd,
}
}
+static bfd_boolean
+avr_should_move_sym (symvalue symval,
+ bfd_vma start,
+ bfd_vma end,
+ bfd_boolean did_pad)
+{
+ bfd_boolean sym_within_boundary =
+ did_pad ? symval < end : symval <= end;
+ return (symval > start && sym_within_boundary);
+}
+
+static bfd_boolean
+avr_should_reduce_sym_size (symvalue symval,
+ symvalue symend,
+ bfd_vma start,
+ bfd_vma end,
+ bfd_boolean did_pad)
+{
+ bfd_boolean sym_end_within_boundary =
+ did_pad ? symend < end : symend <= end;
+ return (symval <= start && symend > start && sym_end_within_boundary);
+}
+
+static bfd_boolean
+avr_should_increase_sym_size (symvalue symval,
+ symvalue symend,
+ bfd_vma start,
+ bfd_vma end,
+ bfd_boolean did_pad)
+{
+ return avr_should_move_sym (symval, start, end, did_pad)
+ && symend >= end && did_pad;
+}
+
/* 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
@@ -1875,13 +1909,14 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
Elf_Internal_Rela *irel, *irelend;
Elf_Internal_Sym *isym;
Elf_Internal_Sym *isymbuf = NULL;
- bfd_vma toaddr, reloc_toaddr;
+ bfd_vma toaddr;
struct elf_link_hash_entry **sym_hashes;
struct elf_link_hash_entry **end_hashes;
unsigned int symcount;
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);
@@ -1912,17 +1947,6 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
}
}
- /* We need to look at all relocs with offsets less than toaddr. prop
- records handling adjusts toaddr downwards to avoid moving syms at the
- address of the property record, but all relocs with offsets between addr
- and the current value of toaddr need to have their offsets adjusted.
- Assume addr = 0, toaddr = 4 and count = 2. After prop records handling,
- toaddr becomes 2, but relocs with offsets 2 and 3 still need to be
- adjusted (to 0 and 1 respectively), as the first 2 bytes are now gone.
- So record the current value of toaddr here, and use it when adjusting
- reloc offsets. */
- reloc_toaddr = toaddr;
-
irel = elf_section_data (sec)->relocs;
irelend = irel + sec->reloc_count;
@@ -1962,10 +1986,7 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
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);
-
- /* Adjust the TOADDR to avoid moving symbols located at the address
- of the property record, which has not moved. */
- toaddr -= count;
+ did_pad = TRUE;
}
if (!did_shrink)
@@ -1981,7 +2002,7 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
/* Get the new reloc address. */
if ((irel->r_offset > addr
- && irel->r_offset < reloc_toaddr))
+ && irel->r_offset < toaddr))
{
if (debug_relax)
printf ("Relocation at address 0x%x needs to be moved.\n"
@@ -2059,7 +2080,7 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
{
/* If there is an alignment boundary, we only need to
adjust addends that end up below the boundary. */
- bfd_vma shrink_boundary = (reloc_toaddr
+ bfd_vma shrink_boundary = (toaddr
+ sec->output_section->vma
+ sec->output_offset);
@@ -2102,12 +2123,10 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
{
if (isym->st_shndx == sec_shndx)
{
- if (isym->st_value > addr
- && isym->st_value <= toaddr)
- isym->st_value -= count;
-
- if (isym->st_value <= addr
- && isym->st_value + isym->st_size > addr)
+ symvalue symval = isym->st_value;
+ symvalue symend = symval + isym->st_size;
+ if (avr_should_reduce_sym_size (symval, symend,
+ addr, toaddr, did_pad))
{
/* If this assert fires then we have a symbol that ends
part way through an instruction. Does that make
@@ -2115,6 +2134,12 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
isym->st_size -= count;
}
+ else if (avr_should_increase_sym_size (symval, symend,
+ addr, toaddr, did_pad))
+ isym->st_size += count;
+
+ if (avr_should_move_sym (symval, addr, toaddr, did_pad))
+ isym->st_value -= count;
}
}
}
@@ -2131,20 +2156,24 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
|| sym_hash->root.type == bfd_link_hash_defweak)
&& sym_hash->root.u.def.section == sec)
{
- if (sym_hash->root.u.def.value > addr
- && sym_hash->root.u.def.value <= toaddr)
- sym_hash->root.u.def.value -= count;
+ symvalue symval = sym_hash->root.u.def.value;
+ symvalue symend = symval + sym_hash->size;
- if (sym_hash->root.u.def.value <= addr
- && (sym_hash->root.u.def.value + sym_hash->size > addr))
+ if (avr_should_reduce_sym_size (symval, symend,
+ addr, toaddr, did_pad))
{
/* If this assert fires then we have a symbol that ends
part way through an instruction. Does that make
sense? */
- BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
- >= addr + count);
+ BFD_ASSERT (symend >= addr + count);
sym_hash->size -= count;
}
+ else if (avr_should_increase_sym_size (symval, symend,
+ addr, toaddr, did_pad))
+ sym_hash->size += count;
+
+ if (avr_should_move_sym (symval, addr, toaddr, did_pad))
+ sym_hash->root.u.def.value -= count;
}
}