diff options
Diffstat (limited to 'bfd/elf32-avr.c')
-rw-r--r-- | bfd/elf32-avr.c | 360 |
1 files changed, 177 insertions, 183 deletions
diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c index cc06360..804033e 100644 --- a/bfd/elf32-avr.c +++ b/bfd/elf32-avr.c @@ -775,14 +775,14 @@ static bfd_vma avr_get_stub_addr (bfd_vma srel, struct elf32_avr_link_hash_table *htab) { - unsigned int index; + unsigned int sindex; bfd_vma stub_sec_addr = (htab->stub_sec->output_section->vma + htab->stub_sec->output_offset); - for (index = 0; index < htab->amt_max_entry_cnt; index ++) - if (htab->amt_destination_addr[index] == srel) - return htab->amt_stub_offsets[index] + stub_sec_addr; + for (sindex = 0; sindex < htab->amt_max_entry_cnt; sindex ++) + if (htab->amt_destination_addr[sindex] == srel) + return htab->amt_stub_offsets[sindex] + stub_sec_addr; /* Return an address that could not be reached by 16 bit relocs. */ return 0x020000; @@ -1510,7 +1510,6 @@ elf32_avr_relax_delete_bytes (bfd *abfd, if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) { /* A local symbol. */ - Elf_Internal_Sym *isym; asection *sym_sec; isym = isymbuf + ELF32_R_SYM (irel->r_info); @@ -1703,8 +1702,8 @@ elf32_avr_relax_section (bfd *abfd, bfd_vma symval; if ( ELF32_R_TYPE (irel->r_info) != R_AVR_13_PCREL - && ELF32_R_TYPE (irel->r_info) != R_AVR_7_PCREL - && ELF32_R_TYPE (irel->r_info) != R_AVR_CALL) + && ELF32_R_TYPE (irel->r_info) != R_AVR_7_PCREL + && ELF32_R_TYPE (irel->r_info) != R_AVR_CALL) continue; /* Get the section contents if we haven't done so already. */ @@ -1721,7 +1720,7 @@ elf32_avr_relax_section (bfd *abfd, } } - /* Read this BFD's local symbols if we haven't done so already. */ + /* Read this BFD's local symbols if we haven't done so already. */ if (isymbuf == NULL && symtab_hdr->sh_info != 0) { isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; @@ -1780,9 +1779,9 @@ elf32_avr_relax_section (bfd *abfd, the linker is run. */ switch (ELF32_R_TYPE (irel->r_info)) { - /* Try to turn a 22-bit absolute call/jump into an 13-bit - pc-relative rcall/rjmp. */ - case R_AVR_CALL: + /* Try to turn a 22-bit absolute call/jump into an 13-bit + pc-relative rcall/rjmp. */ + case R_AVR_CALL: { bfd_vma value = symval + irel->r_addend; bfd_vma dot, gap; @@ -1807,27 +1806,27 @@ elf32_avr_relax_section (bfd *abfd, vaiable avr_pc_wrap_around with the appropriate value. I.e. 0x4000 for a 16k device. */ { - /* Shrinking the code size makes the gaps larger in the - case of wrap-arounds. So we use a heuristical safety - margin to avoid that during relax the distance gets - again too large for the short jumps. Let's assume - a typical code-size reduction due to relax for a - 16k device of 600 bytes. So let's use twice the - typical value as safety margin. */ - int rgap; - int safety_margin; - - int assumed_shrink = 600; - if (avr_pc_wrap_around > 0x4000) - assumed_shrink = 900; - - safety_margin = 2 * assumed_shrink; - - rgap = avr_relative_distance_considering_wrap_around (gap); - - if (rgap >= (-4092 + safety_margin) - && rgap <= (4094 - safety_margin)) - distance_short_enough = 1; + /* Shrinking the code size makes the gaps larger in the + case of wrap-arounds. So we use a heuristical safety + margin to avoid that during relax the distance gets + again too large for the short jumps. Let's assume + a typical code-size reduction due to relax for a + 16k device of 600 bytes. So let's use twice the + typical value as safety margin. */ + int rgap; + int safety_margin; + + int assumed_shrink = 600; + if (avr_pc_wrap_around > 0x4000) + assumed_shrink = 900; + + safety_margin = 2 * assumed_shrink; + + rgap = avr_relative_distance_considering_wrap_around (gap); + + if (rgap >= (-4092 + safety_margin) + && rgap <= (4094 - safety_margin)) + distance_short_enough = 1; } if (distance_short_enough) @@ -1921,9 +1920,9 @@ elf32_avr_relax_section (bfd *abfd, if (irel->r_offset + 3 < sec->size) { next_insn_msb = - bfd_get_8 (abfd, contents + irel->r_offset + 3); + bfd_get_8 (abfd, contents + irel->r_offset + 3); next_insn_lsb = - bfd_get_8 (abfd, contents + irel->r_offset + 2); + bfd_get_8 (abfd, contents + irel->r_offset + 2); } if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb)) @@ -1951,9 +1950,9 @@ elf32_avr_relax_section (bfd *abfd, if (irel->r_offset + 5 < sec->size) { next_insn_msb = - bfd_get_8 (abfd, contents + irel->r_offset + 5); + bfd_get_8 (abfd, contents + irel->r_offset + 5); next_insn_lsb = - bfd_get_8 (abfd, contents + irel->r_offset + 4); + bfd_get_8 (abfd, contents + irel->r_offset + 4); } if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb)) @@ -1988,11 +1987,11 @@ elf32_avr_relax_section (bfd *abfd, if (irel->r_offset + insn_size + 1 < sec->size) { next_insn_msb = - bfd_get_8 (abfd, contents + irel->r_offset - + insn_size + 1); + bfd_get_8 (abfd, contents + irel->r_offset + + insn_size + 1); next_insn_lsb = - bfd_get_8 (abfd, contents + irel->r_offset - + insn_size); + bfd_get_8 (abfd, contents + irel->r_offset + + insn_size); } if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb)) @@ -2019,9 +2018,9 @@ elf32_avr_relax_section (bfd *abfd, unsigned char preceeding_msb; unsigned char preceeding_lsb; preceeding_msb = - bfd_get_8 (abfd, contents + irel->r_offset - 1); + bfd_get_8 (abfd, contents + irel->r_offset - 1); preceeding_lsb = - bfd_get_8 (abfd, contents + irel->r_offset - 2); + bfd_get_8 (abfd, contents + irel->r_offset - 2); /* sbic. */ if (0x99 == preceeding_msb) @@ -2033,12 +2032,12 @@ elf32_avr_relax_section (bfd *abfd, /* sbrc */ if ((0xfc == (preceeding_msb & 0xfe) - && (0x00 == (preceeding_lsb & 0x08)))) + && (0x00 == (preceeding_lsb & 0x08)))) there_is_preceeding_non_skip_insn = 0; /* sbrs */ if ((0xfe == (preceeding_msb & 0xfe) - && (0x00 == (preceeding_lsb & 0x08)))) + && (0x00 == (preceeding_lsb & 0x08)))) there_is_preceeding_non_skip_insn = 0; /* cpse */ @@ -2066,7 +2065,7 @@ elf32_avr_relax_section (bfd *abfd, int deleting_ret_is_safe = 1; unsigned int section_offset_of_ret_insn = - irel->r_offset + insn_size; + irel->r_offset + insn_size; Elf_Internal_Sym *isym, *isymend; unsigned int sec_shndx; @@ -2078,145 +2077,140 @@ elf32_avr_relax_section (bfd *abfd, isymend = isym + symtab_hdr->sh_info; /* PR 6019: There may not be any local symbols. */ for (; isym != NULL && isym < isymend; isym++) - { - if (isym->st_value == section_offset_of_ret_insn - && isym->st_shndx == sec_shndx) - { - deleting_ret_is_safe = 0; - if (debug_relax) - printf ("local label prevents deletion of ret " - "insn at address 0x%x\n", - (int) dot + insn_size); - } - } - - /* Now check for global symbols. */ - { - int symcount; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - - symcount = (symtab_hdr->sh_size - / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = - *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == + { + if (isym->st_value == section_offset_of_ret_insn + && isym->st_shndx == sec_shndx) + { + deleting_ret_is_safe = 0; + if (debug_relax) + printf ("local label prevents deletion of ret " + "insn at address 0x%x\n", + (int) dot + insn_size); + } + } + + /* Now check for global symbols. */ + { + int symcount; + struct elf_link_hash_entry **sym_hashes; + struct elf_link_hash_entry **end_hashes; + + symcount = (symtab_hdr->sh_size + / sizeof (Elf32_External_Sym) + - symtab_hdr->sh_info); + sym_hashes = elf_sym_hashes (abfd); + end_hashes = sym_hashes + symcount; + for (; sym_hashes < end_hashes; sym_hashes++) + { + struct elf_link_hash_entry *sym_hash = + *sym_hashes; + if ((sym_hash->root.type == bfd_link_hash_defined + || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value == section_offset_of_ret_insn) - { - deleting_ret_is_safe = 0; - if (debug_relax) - printf ("global label prevents deletion of " - "ret insn at address 0x%x\n", - (int) dot + insn_size); - } - } - } - /* Now we check for relocations pointing to ret. */ - { - Elf_Internal_Rela *irel; - Elf_Internal_Rela *relend; - Elf_Internal_Shdr *symtab_hdr; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - relend = elf_section_data (sec)->relocs - + sec->reloc_count; - - for (irel = elf_section_data (sec)->relocs; - irel < relend; irel++) - { - bfd_vma reloc_target = 0; - bfd_vma symval; - Elf_Internal_Sym *isymbuf = NULL; - - /* Read this BFD's local symbols if we haven't - done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) - symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms - (abfd, - symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - break; - } - - /* Get the value of the symbol referred to - by the reloc. */ - if (ELF32_R_SYM (irel->r_info) - < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf - + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index - (abfd, isym->st_shndx); - symval = isym->st_value; - - /* If the reloc is absolute, it will not - have a symbol or section associated - with it. */ - - if (sym_sec) - { - symval += - sym_sec->output_section->vma - + sym_sec->output_offset; - reloc_target = symval + irel->r_addend; - } - else - { - reloc_target = symval + irel->r_addend; - /* Reference symbol is absolute. */ - } - } - /* else ... reference symbol is extern. */ - - if (address_of_ret == reloc_target) - { - deleting_ret_is_safe = 0; - if (debug_relax) - printf ("ret from " - "rjmp/jmp ret sequence at address" - " 0x%x could not be deleted. ret" - " is target of a relocation.\n", - (int) address_of_ret); - } - } - } - - if (deleting_ret_is_safe) - { - if (debug_relax) - printf ("unreachable ret instruction " - "at address 0x%x deleted.\n", - (int) dot + insn_size); - - /* Delete two bytes of data. */ - if (!elf32_avr_relax_delete_bytes (abfd, sec, - irel->r_offset + insn_size, 2)) - goto error_return; - - /* That will change things, so, we should relax - again. Note that this is not required, and it - may be slow. */ - *again = TRUE; - break; - } + && sym_hash->root.u.def.section == sec + && sym_hash->root.u.def.value == section_offset_of_ret_insn) + { + deleting_ret_is_safe = 0; + if (debug_relax) + printf ("global label prevents deletion of " + "ret insn at address 0x%x\n", + (int) dot + insn_size); + } + } + } + /* Now we check for relocations pointing to ret. */ + { + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + relend = elf_section_data (sec)->relocs + + sec->reloc_count; + + for (rel = elf_section_data (sec)->relocs; + rel < relend; rel++) + { + bfd_vma reloc_target = 0; + + /* Read this BFD's local symbols if we haven't + done so already. */ + if (isymbuf == NULL && symtab_hdr->sh_info != 0) + { + isymbuf = (Elf_Internal_Sym *) + symtab_hdr->contents; + if (isymbuf == NULL) + isymbuf = bfd_elf_get_elf_syms + (abfd, + symtab_hdr, + symtab_hdr->sh_info, 0, + NULL, NULL, NULL); + if (isymbuf == NULL) + break; + } + + /* Get the value of the symbol referred to + by the reloc. */ + if (ELF32_R_SYM (rel->r_info) + < symtab_hdr->sh_info) + { + /* A local symbol. */ + asection *sym_sec; + + isym = isymbuf + + ELF32_R_SYM (rel->r_info); + sym_sec = bfd_section_from_elf_index + (abfd, isym->st_shndx); + symval = isym->st_value; + + /* If the reloc is absolute, it will not + have a symbol or section associated + with it. */ + + if (sym_sec) + { + symval += + sym_sec->output_section->vma + + sym_sec->output_offset; + reloc_target = symval + rel->r_addend; + } + else + { + reloc_target = symval + rel->r_addend; + /* Reference symbol is absolute. */ + } + } + /* else ... reference symbol is extern. */ + + if (address_of_ret == reloc_target) + { + deleting_ret_is_safe = 0; + if (debug_relax) + printf ("ret from " + "rjmp/jmp ret sequence at address" + " 0x%x could not be deleted. ret" + " is target of a relocation.\n", + (int) address_of_ret); + } + } + } + + if (deleting_ret_is_safe) + { + if (debug_relax) + printf ("unreachable ret instruction " + "at address 0x%x deleted.\n", + (int) dot + insn_size); + + /* Delete two bytes of data. */ + if (!elf32_avr_relax_delete_bytes (abfd, sec, + irel->r_offset + insn_size, 2)) + goto error_return; + + /* That will change things, so, we should relax + again. Note that this is not required, and it + may be slow. */ + *again = TRUE; + break; + } } } |