X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-avr.c;h=9ca0c464ee31756252eee8d87671c4e0c31c3b5d;hb=f36e88862f94c15a88fa27df7af906ad75a42e7f;hp=07568a45077acadb3d8d9266b8f1b356e0221f6a;hpb=e4067dbb2a3368dbf908b39c5435c84d51abc9f3;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c index 07568a4507..9ca0c464ee 100644 --- a/bfd/elf32-avr.c +++ b/bfd/elf32-avr.c @@ -1,6 +1,5 @@ /* AVR-specific support for 32-bit ELF - Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010 Free Software Foundation, Inc. + Copyright (C) 1999-2014 Free Software Foundation, Inc. Contributed by Denis Chertykov This file is part of BFD, the Binary File Descriptor library. @@ -33,6 +32,10 @@ static bfd_boolean debug_relax = FALSE; /* Enable debugging printout at stdout with this variable. */ static bfd_boolean debug_stubs = FALSE; +static bfd_reloc_status_type +bfd_elf_avr_diff_reloc (bfd *, arelent *, asymbol *, void *, + asection *, bfd *, char **); + /* Hash table initialization and handling. Code is taken from the hppa port and adapted to the needs of AVR. */ @@ -516,6 +519,101 @@ static reloc_howto_type elf_avr_howto_table[] = 0x000000ff, /* src_mask */ 0x000000ff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* lo8-part to use in .byte lo8(sym). */ + HOWTO (R_AVR_8_LO8, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_AVR_8_LO8", /* name */ + FALSE, /* partial_inplace */ + 0xffffff, /* src_mask */ + 0xffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* hi8-part to use in .byte hi8(sym). */ + HOWTO (R_AVR_8_HI8, /* type */ + 8, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_AVR_8_HI8", /* name */ + FALSE, /* partial_inplace */ + 0xffffff, /* src_mask */ + 0xffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* hlo8-part to use in .byte hlo8(sym). */ + HOWTO (R_AVR_8_HLO8, /* type */ + 16, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_AVR_8_HLO8", /* name */ + FALSE, /* partial_inplace */ + 0xffffff, /* src_mask */ + 0xffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_AVR_DIFF8, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_avr_diff_reloc, /* special_function */ + "R_AVR_DIFF8", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_AVR_DIFF16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_avr_diff_reloc,/* special_function */ + "R_AVR_DIFF16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_AVR_DIFF32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_avr_diff_reloc,/* special_function */ + "R_AVR_DIFF32", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* 7 bit immediate for LDS/STS in Tiny core. */ + HOWTO (R_AVR_LDS_STS_16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 7, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_AVR_LDS_STS_16", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE) /* pcrel_offset */ }; /* Map BFD reloc types to AVR ELF reloc types. */ @@ -554,7 +652,14 @@ static const struct avr_reloc_map avr_reloc_map[] = { BFD_RELOC_AVR_LDI, R_AVR_LDI }, { BFD_RELOC_AVR_6, R_AVR_6 }, { BFD_RELOC_AVR_6_ADIW, R_AVR_6_ADIW }, - { BFD_RELOC_8, R_AVR_8 } + { BFD_RELOC_8, R_AVR_8 }, + { BFD_RELOC_AVR_8_LO, R_AVR_8_LO8 }, + { BFD_RELOC_AVR_8_HI, R_AVR_8_HI8 }, + { BFD_RELOC_AVR_8_HLO, R_AVR_8_HLO8 }, + { BFD_RELOC_AVR_DIFF8, R_AVR_DIFF8 }, + { BFD_RELOC_AVR_DIFF16, R_AVR_DIFF16 }, + { BFD_RELOC_AVR_DIFF32, R_AVR_DIFF32 }, + { BFD_RELOC_AVR_LDS_STS_16, R_AVR_LDS_STS_16} }; /* Meant to be filled one day with the wrap around address for the @@ -616,6 +721,24 @@ elf32_avr_link_hash_newfunc (struct bfd_hash_entry * entry, return _bfd_elf_link_hash_newfunc (entry, table, string); } +/* Free the derived linker hash table. */ + +static void +elf32_avr_link_hash_table_free (bfd *obfd) +{ + struct elf32_avr_link_hash_table *htab + = (struct elf32_avr_link_hash_table *) obfd->link.hash; + + /* Free the address mapping table. */ + if (htab->amt_stub_offsets != NULL) + free (htab->amt_stub_offsets); + if (htab->amt_destination_addr != NULL) + free (htab->amt_destination_addr); + + bfd_hash_table_free (&htab->bstab); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create the derived linker hash table. The AVR ELF port uses the derived hash table to keep information specific to the AVR ELF linker (without using static variables). */ @@ -626,7 +749,7 @@ elf32_avr_link_hash_table_create (bfd *abfd) struct elf32_avr_link_hash_table *htab; bfd_size_type amt = sizeof (*htab); - htab = bfd_malloc (amt); + htab = bfd_zmalloc (amt); if (htab == NULL) return NULL; @@ -642,38 +765,15 @@ elf32_avr_link_hash_table_create (bfd *abfd) /* Init the stub hash table too. */ if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc, sizeof (struct elf32_avr_stub_hash_entry))) - return NULL; - - htab->stub_bfd = NULL; - htab->stub_sec = NULL; - - /* Initialize the address mapping table. */ - htab->amt_stub_offsets = NULL; - htab->amt_destination_addr = NULL; - htab->amt_entry_cnt = 0; - htab->amt_max_entry_cnt = 0; + { + _bfd_elf_link_hash_table_free (abfd); + return NULL; + } + htab->etab.root.hash_table_free = elf32_avr_link_hash_table_free; return &htab->etab.root; } -/* Free the derived linker hash table. */ - -static void -elf32_avr_link_hash_table_free (struct bfd_link_hash_table *btab) -{ - struct elf32_avr_link_hash_table *htab - = (struct elf32_avr_link_hash_table *) btab; - - /* Free the address mapping table. */ - if (htab->amt_stub_offsets != NULL) - free (htab->amt_stub_offsets); - if (htab->amt_destination_addr != NULL) - free (htab->amt_destination_addr); - - bfd_hash_table_free (&htab->bstab); - _bfd_generic_link_hash_table_free (btab); -} - /* Calculates the effective distance of a pc relative jump/call. */ static int @@ -734,48 +834,6 @@ avr_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, cache_ptr->howto = &elf_avr_howto_table[r_type]; } -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -elf32_avr_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - if (info->relocatable) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - } - - return TRUE; -} - static bfd_boolean avr_stub_is_required_for_16_bit_reloc (bfd_vma relocation) { @@ -804,6 +862,22 @@ avr_get_stub_addr (bfd_vma srel, return 0x020000; } +/* Perform a diff relocation. Nothing to do, as the difference value is already + written into the section's contents. */ + +static bfd_reloc_status_type +bfd_elf_avr_diff_reloc (bfd *abfd ATTRIBUTE_UNUSED, + arelent *reloc_entry ATTRIBUTE_UNUSED, + asymbol *symbol ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED, + asection *input_section ATTRIBUTE_UNUSED, + bfd *output_bfd ATTRIBUTE_UNUSED, + char **error_message ATTRIBUTE_UNUSED) +{ + return bfd_reloc_ok; +} + + /* Perform a single relocation. By default we use the standard BFD routines, but a few relocs, we have to do them ourselves. */ @@ -1156,6 +1230,24 @@ avr_final_link_relocate (reloc_howto_type * howto, bfd_put_16 (input_bfd, (bfd_vma) srel &0x00ffff, contents); break; + case R_AVR_DIFF8: + case R_AVR_DIFF16: + case R_AVR_DIFF32: + /* Nothing to do here, as contents already contains the diff value. */ + r = bfd_reloc_ok; + break; + + case R_AVR_LDS_STS_16: + contents += rel->r_offset; + srel = (bfd_signed_vma) relocation + rel->r_addend; + if ((srel & 0xFFFF) < 0x40 || (srel & 0xFFFF) > 0xbf) + return bfd_reloc_outofrange; + srel = srel & 0x7f; + x = bfd_get_16 (input_bfd, contents); + x |= (srel & 0x0f) | ((srel & 0x30) << 5) | ((srel & 0x40) << 2); + bfd_put_16 (input_bfd, x, contents); + break; + default: r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, @@ -1221,19 +1313,19 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, } else { - bfd_boolean unresolved_reloc, warned; + bfd_boolean unresolved_reloc, warned, ignored; RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, - unresolved_reloc, warned); + unresolved_reloc, warned, ignored); name = h->root.root.string; } - if (sec != NULL && elf_discarded_section (sec)) + if (sec != NULL && discarded_section (sec)) RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, relend, howto, contents); + rel, 1, relend, howto, 0, contents); if (info->relocatable) continue; @@ -1340,6 +1432,38 @@ bfd_elf_avr_final_write_processing (bfd *abfd, case bfd_mach_avr6: val = E_AVR_MACH_AVR6; break; + + case bfd_mach_avrxmega1: + val = E_AVR_MACH_XMEGA1; + break; + + case bfd_mach_avrxmega2: + val = E_AVR_MACH_XMEGA2; + break; + + case bfd_mach_avrxmega3: + val = E_AVR_MACH_XMEGA3; + break; + + case bfd_mach_avrxmega4: + val = E_AVR_MACH_XMEGA4; + break; + + case bfd_mach_avrxmega5: + val = E_AVR_MACH_XMEGA5; + break; + + case bfd_mach_avrxmega6: + val = E_AVR_MACH_XMEGA6; + break; + + case bfd_mach_avrxmega7: + val = E_AVR_MACH_XMEGA7; + break; + + case bfd_mach_avrtiny: + val = E_AVR_MACH_AVRTINY; + break; } elf_elfheader (abfd)->e_machine = EM_AVR; @@ -1402,12 +1526,142 @@ elf32_avr_object_p (bfd *abfd) case E_AVR_MACH_AVR6: e_set = bfd_mach_avr6; break; + + case E_AVR_MACH_XMEGA1: + e_set = bfd_mach_avrxmega1; + break; + + case E_AVR_MACH_XMEGA2: + e_set = bfd_mach_avrxmega2; + break; + + case E_AVR_MACH_XMEGA3: + e_set = bfd_mach_avrxmega3; + break; + + case E_AVR_MACH_XMEGA4: + e_set = bfd_mach_avrxmega4; + break; + + case E_AVR_MACH_XMEGA5: + e_set = bfd_mach_avrxmega5; + break; + + case E_AVR_MACH_XMEGA6: + e_set = bfd_mach_avrxmega6; + break; + + case E_AVR_MACH_XMEGA7: + e_set = bfd_mach_avrxmega7; + break; + + case E_AVR_MACH_AVRTINY: + e_set = bfd_mach_avrtiny; + break; } } return bfd_default_set_arch_mach (abfd, bfd_arch_avr, e_set); } +/* Returns whether the relocation type passed is a diff reloc. */ + +static bfd_boolean +elf32_avr_is_diff_reloc (Elf_Internal_Rela *irel) +{ + return (ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF8 + ||ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF16 + || ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF32); +} + +/* Reduce the diff value written in the section by count if the shrinked + insn address happens to fall between the two symbols for which this + diff reloc was emitted. */ + +static void +elf32_avr_adjust_diff_reloc_value (bfd *abfd, + struct bfd_section *isec, + Elf_Internal_Rela *irel, + bfd_vma symval, + bfd_vma shrinked_insn_address, + int count) +{ + unsigned char *reloc_contents = NULL; + unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents; + if (isec_contents == NULL) + { + if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents)) + return; + + elf_section_data (isec)->this_hdr.contents = isec_contents; + } + + reloc_contents = isec_contents + irel->r_offset; + + /* Read value written in object file. */ + bfd_vma x = 0; + switch (ELF32_R_TYPE (irel->r_info)) + { + case R_AVR_DIFF8: + { + x = *reloc_contents; + break; + } + case R_AVR_DIFF16: + { + x = bfd_get_16 (abfd, reloc_contents); + break; + } + case R_AVR_DIFF32: + { + x = bfd_get_32 (abfd, reloc_contents); + break; + } + default: + { + BFD_FAIL(); + } + } + + /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written + into the object file at the reloc offset. sym2's logical value is + symval () + reloc addend. Compute the start and end + addresses and check if the shrinked insn falls between sym1 and sym2. */ + + bfd_vma end_address = symval + irel->r_addend; + bfd_vma start_address = end_address - x; + + /* Reduce the diff value by count bytes and write it back into section + contents. */ + + if (shrinked_insn_address >= start_address + && shrinked_insn_address <= end_address) + { + switch (ELF32_R_TYPE (irel->r_info)) + { + case R_AVR_DIFF8: + { + *reloc_contents = (x - count); + break; + } + case R_AVR_DIFF16: + { + bfd_put_16 (abfd, (x - count) & 0xFFFF, reloc_contents); + break; + } + case R_AVR_DIFF32: + { + bfd_put_32 (abfd, (x - count) & 0xFFFFFFFF, reloc_contents); + break; + } + default: + { + BFD_FAIL(); + } + } + + } +} /* Delete some bytes from a section while changing the size of an instruction. The parameter "addr" denotes the section-relative offset pointing just @@ -1489,11 +1743,18 @@ elf32_avr_relax_delete_bytes (bfd *abfd, bfd_vma symval; bfd_vma shrinked_insn_address; + if (isec->reloc_count == 0) + continue; + shrinked_insn_address = (sec->output_section->vma + sec->output_offset + addr - count); - irelend = elf_section_data (isec)->relocs + isec->reloc_count; - for (irel = elf_section_data (isec)->relocs; + irel = elf_section_data (isec)->relocs; + /* PR 12161: Read in the relocs for this section if necessary. */ + if (irel == NULL) + irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE); + + for (irelend = irel + isec->reloc_count; irel < irelend; irel++) { @@ -1539,6 +1800,14 @@ elf32_avr_relax_delete_bytes (bfd *abfd, if (symval <= shrinked_insn_address && (symval + irel->r_addend) > shrinked_insn_address) { + if (elf32_avr_is_diff_reloc (irel)) + { + elf32_avr_adjust_diff_reloc_value (abfd, isec, irel, + symval, + shrinked_insn_address, + count); + } + irel->r_addend -= count; if (debug_relax) @@ -1635,6 +1904,16 @@ elf32_avr_relax_section (bfd *abfd, Elf_Internal_Sym *isymbuf = NULL; struct elf32_avr_link_hash_table *htab; + /* If 'shrinkable' is FALSE, do not shrink by deleting bytes while + relaxing. Such shrinking can cause issues for the sections such + as .vectors and .jumptables. Instead the unused bytes should be + filled with nop instructions. */ + bfd_boolean shrinkable = TRUE; + + if (!strcmp (sec->name,".vectors") + || !strcmp (sec->name,".jumptables")) + shrinkable = FALSE; + if (link_info->relocatable) (*link_info->callbacks->einfo) (_("%P%F: --relax and -r may not be used together\n")); @@ -1699,8 +1978,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. */ @@ -1791,10 +2070,16 @@ elf32_avr_relax_section (bfd *abfd, /* Compute the distance from this insn to the branch target. */ gap = value - dot; - /* If the distance is within -4094..+4098 inclusive, then we can - relax this jump/call. +4098 because the call/jump target - will be closer after the relaxation. */ - if ((int) gap >= -4094 && (int) gap <= 4098) + /* Check if the gap falls in the range that can be accommodated + in 13bits signed (It is 12bits when encoded, as we deal with + word addressing). */ + if (!shrinkable && ((int) gap >= -4096 && (int) gap <= 4095)) + distance_short_enough = 1; + /* If shrinkable, then we can check for a range of distance which + is two bytes farther on both the directions because the call + or jump target will be closer by two bytes after the + relaxation. */ + else if (shrinkable && ((int) gap >= -4094 && (int) gap <= 4097)) distance_short_enough = 1; /* Here we handle the wrap-around case. E.g. for a 16k device @@ -1868,11 +2153,9 @@ elf32_avr_relax_section (bfd *abfd, irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_AVR_13_PCREL); - /* Check for the vector section. There we don't want to - modify the ordering! */ - - if (!strcmp (sec->name,".vectors") - || !strcmp (sec->name,".jumptables")) + /* We should not modify the ordering if 'shrinkable' is + FALSE. */ + if (!shrinkable) { /* Let's insert a nop. */ bfd_put_8 (abfd, 0x00, contents + irel->r_offset + 2); @@ -1994,10 +2277,10 @@ elf32_avr_relax_section (bfd *abfd, if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb)) { /* The next insn is a ret. We possibly could delete - this ret. First we need to check for preceeding + this ret. First we need to check for preceding sbis/sbic/sbrs or cpse "skip" instructions. */ - int there_is_preceeding_non_skip_insn = 1; + int there_is_preceding_non_skip_insn = 1; bfd_vma address_of_ret; address_of_ret = dot + insn_size; @@ -2009,51 +2292,52 @@ elf32_avr_relax_section (bfd *abfd, printf ("found jmp / ret sequence at address 0x%x\n", (int) dot); - /* We have to make sure that there is a preceeding insn. */ + /* We have to make sure that there is a preceding insn. */ if (irel->r_offset >= 2) { - unsigned char preceeding_msb; - unsigned char preceeding_lsb; - preceeding_msb = + unsigned char preceding_msb; + unsigned char preceding_lsb; + + preceding_msb = bfd_get_8 (abfd, contents + irel->r_offset - 1); - preceeding_lsb = + preceding_lsb = bfd_get_8 (abfd, contents + irel->r_offset - 2); /* sbic. */ - if (0x99 == preceeding_msb) - there_is_preceeding_non_skip_insn = 0; + if (0x99 == preceding_msb) + there_is_preceding_non_skip_insn = 0; /* sbis. */ - if (0x9b == preceeding_msb) - there_is_preceeding_non_skip_insn = 0; + if (0x9b == preceding_msb) + there_is_preceding_non_skip_insn = 0; /* sbrc */ - if ((0xfc == (preceeding_msb & 0xfe) - && (0x00 == (preceeding_lsb & 0x08)))) - there_is_preceeding_non_skip_insn = 0; + if ((0xfc == (preceding_msb & 0xfe) + && (0x00 == (preceding_lsb & 0x08)))) + there_is_preceding_non_skip_insn = 0; /* sbrs */ - if ((0xfe == (preceeding_msb & 0xfe) - && (0x00 == (preceeding_lsb & 0x08)))) - there_is_preceeding_non_skip_insn = 0; + if ((0xfe == (preceding_msb & 0xfe) + && (0x00 == (preceding_lsb & 0x08)))) + there_is_preceding_non_skip_insn = 0; /* cpse */ - if (0x10 == (preceeding_msb & 0xfc)) - there_is_preceeding_non_skip_insn = 0; + if (0x10 == (preceding_msb & 0xfc)) + there_is_preceding_non_skip_insn = 0; - if (there_is_preceeding_non_skip_insn == 0) + if (there_is_preceding_non_skip_insn == 0) if (debug_relax) - printf ("preceeding skip insn prevents deletion of" - " ret insn at addr 0x%x in section %s\n", + printf ("preceding skip insn prevents deletion of" + " ret insn at Addy 0x%x in section %s\n", (int) dot + 2, sec->name); } else { /* There is no previous instruction. */ - there_is_preceeding_non_skip_insn = 0; + there_is_preceding_non_skip_insn = 0; } - if (there_is_preceeding_non_skip_insn) + if (there_is_preceding_non_skip_insn) { /* We now only have to make sure that there is no local label defined at the address of the ret @@ -2065,6 +2349,7 @@ elf32_avr_relax_section (bfd *abfd, irel->r_offset + insn_size; Elf_Internal_Sym *isym, *isymend; unsigned int sec_shndx; + struct bfd_section *isec; sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); @@ -2115,80 +2400,85 @@ elf32_avr_relax_section (bfd *abfd, } } } + /* Now we check for relocations pointing to ret. */ - { - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; + for (isec = abfd->sections; isec && deleting_ret_is_safe; isec = isec->next) + { + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; - relend = elf_section_data (sec)->relocs - + sec->reloc_count; + rel = elf_section_data (isec)->relocs; + if (rel == NULL) + rel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE); - for (rel = elf_section_data (sec)->relocs; - rel < relend; rel++) - { - bfd_vma reloc_target = 0; + relend = rel + isec->reloc_count; - /* 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) + for (; rel && 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); 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) { @@ -2209,7 +2499,6 @@ elf32_avr_relax_section (bfd *abfd, break; } } - } } break; @@ -2566,7 +2855,7 @@ elf32_avr_setup_section_lists (bfd *output_bfd, /* Count the number of input BFDs and find the top input section id. */ for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; input_bfd != NULL; - input_bfd = input_bfd->link_next) + input_bfd = input_bfd->link.next) { bfd_count += 1; for (section = input_bfd->sections; @@ -2640,7 +2929,7 @@ get_local_syms (bfd *input_bfd, struct bfd_link_info *info) export stubs. */ for (bfd_indx = 0; input_bfd != NULL; - input_bfd = input_bfd->link_next, bfd_indx++) + input_bfd = input_bfd->link.next, bfd_indx++) { Elf_Internal_Shdr *symtab_hdr; @@ -2717,7 +3006,7 @@ elf32_avr_size_stubs (bfd *output_bfd, bfd_hash_traverse (&htab->bstab, avr_mark_stub_not_to_be_necessary, htab); for (input_bfd = info->input_bfds, bfd_indx = 0; input_bfd != NULL; - input_bfd = input_bfd->link_next, bfd_indx++) + input_bfd = input_bfd->link.next, bfd_indx++) { Elf_Internal_Shdr *symtab_hdr; asection *section; @@ -2989,16 +3278,14 @@ elf32_avr_build_stubs (struct bfd_link_info *info) #define ELF_MACHINE_ALT1 EM_AVR_OLD #define ELF_MAXPAGESIZE 1 -#define TARGET_LITTLE_SYM bfd_elf32_avr_vec +#define TARGET_LITTLE_SYM avr_elf32_vec #define TARGET_LITTLE_NAME "elf32-avr" #define bfd_elf32_bfd_link_hash_table_create elf32_avr_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_free elf32_avr_link_hash_table_free #define elf_info_to_howto avr_info_to_howto_rela #define elf_info_to_howto_rel NULL #define elf_backend_relocate_section elf32_avr_relocate_section -#define elf_backend_check_relocs elf32_avr_check_relocs #define elf_backend_can_gc_sections 1 #define elf_backend_rela_normal 1 #define elf_backend_final_write_processing \