Index: bfd/elf32-avr.c |
diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c |
index 6d20aefdc21904479b9eaddf0a836f41ca9fa915..38e41df48dfd863e3b1317563684e970e49d0669 100644 |
--- a/bfd/elf32-avr.c |
+++ b/bfd/elf32-avr.c |
@@ -1,6 +1,7 @@ |
/* AVR-specific support for 32-bit ELF |
Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
- 2010, 2011 Free Software Foundation, Inc. |
+ 2010, 2011, 2012 |
+ Free Software Foundation, Inc. |
Contributed by Denis Chertykov <denisc@overta.ru> |
This file is part of BFD, the Binary File Descriptor library. |
@@ -516,6 +517,48 @@ 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 */ |
}; |
/* Map BFD reloc types to AVR ELF reloc types. */ |
@@ -554,7 +597,10 @@ 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 } |
}; |
/* Meant to be filled one day with the wrap around address for the |
@@ -1189,9 +1235,9 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, |
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; |
@@ -1503,11 +1549,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, FALSE); |
+ |
+ for (irelend = irel + isec->reloc_count; |
irel < irelend; |
irel++) |
{ |
@@ -1564,6 +1617,9 @@ elf32_avr_relax_delete_bytes (bfd *abfd, |
/* else...Reference symbol is extern. No need for adjusting |
the addend. */ |
} |
+ |
+ if (elf_section_data (isec)->relocs == NULL) |
+ free (irelend - isec->reloc_count); |
} |
} |
@@ -1649,6 +1705,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")); |
@@ -1805,10 +1871,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 |
@@ -1882,11 +1954,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); |