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.c689
1 files changed, 318 insertions, 371 deletions
diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c
index 32268cc..ec42bb3 100644
--- a/bfd/elf32-avr.c
+++ b/bfd/elf32-avr.c
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
#include "bfd.h"
@@ -26,37 +26,6 @@
#include "elf-bfd.h"
#include "elf/avr.h"
-static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
- PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
-static void avr_info_to_howto_rela
- PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
-static asection *elf32_avr_gc_mark_hook
- PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
- struct elf_link_hash_entry *, Elf_Internal_Sym *));
-static bfd_boolean elf32_avr_gc_sweep_hook
- PARAMS ((bfd *, struct bfd_link_info *, asection *,
- const Elf_Internal_Rela *));
-static bfd_boolean elf32_avr_check_relocs
- PARAMS ((bfd *, struct bfd_link_info *, asection *,
- const Elf_Internal_Rela *));
-static bfd_reloc_status_type avr_final_link_relocate
- PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
- Elf_Internal_Rela *, bfd_vma));
-static bfd_boolean elf32_avr_relocate_section
- PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
- Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
-static void bfd_elf_avr_final_write_processing PARAMS ((bfd *, bfd_boolean));
-static bfd_boolean elf32_avr_object_p PARAMS ((bfd *));
-
-/* Relaxing stuff */
-static bfd_boolean elf32_avr_relax_section
- PARAMS((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
-static bfd_boolean elf32_avr_relax_delete_bytes
- PARAMS((bfd *, asection *, bfd_vma, int));
-static bfd_byte *elf32_avr_get_relocated_section_contents
- PARAMS((bfd *, struct bfd_link_info *, struct bfd_link_order *,
- bfd_byte *, bfd_boolean, asymbol **));
-
static reloc_howto_type elf_avr_howto_table[] =
{
HOWTO (R_AVR_NONE, /* type */
@@ -177,7 +146,7 @@ static reloc_howto_type elf_avr_howto_table[] =
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A high 6 bit absolute relocation of 22 bit address.
- For LDI command. As well second most significant 8 bit value of
+ For LDI command. As well second most significant 8 bit value of
a 32 bit link-time constant. */
HOWTO (R_AVR_HH8_LDI, /* type */
16, /* rightshift */
@@ -453,25 +422,24 @@ struct avr_reloc_map
};
/* Meant to be filled one day with the wrap around address for the
- specific device. I.e. should get the value 0x4000 for 16k devices,
+ specific device. I.e. should get the value 0x4000 for 16k devices,
0x8000 for 32k devices and so on.
-
+
We initialize it here with a value of 0x1000000 resulting in
- that we will never suggest a wrap-around jump during relaxation.
- The logic of the source code later on assumes that in
+ that we will never suggest a wrap-around jump during relaxation.
+ The logic of the source code later on assumes that in
avr_pc_wrap_around one single bit is set. */
-
+
unsigned int avr_pc_wrap_around = 0x10000000;
/* Calculates the effective distance of a pc relative jump/call. */
static int
avr_relative_distance_considering_wrap_around (unsigned int distance)
-{
+{
unsigned int wrap_around_mask = avr_pc_wrap_around - 1;
-
int dist_with_wrap_around = distance & wrap_around_mask;
- if (dist_with_wrap_around > ((int) (avr_pc_wrap_around >> 1)) )
+ if (dist_with_wrap_around > ((int) (avr_pc_wrap_around >> 1)))
dist_with_wrap_around -= avr_pc_wrap_around;
return dist_with_wrap_around;
@@ -479,9 +447,8 @@ avr_relative_distance_considering_wrap_around (unsigned int distance)
static reloc_howto_type *
-bfd_elf32_bfd_reloc_type_lookup (abfd, code)
- bfd *abfd ATTRIBUTE_UNUSED;
- bfd_reloc_code_real_type code;
+bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ bfd_reloc_code_real_type code)
{
unsigned int i;
@@ -499,10 +466,9 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
/* Set the howto pointer for an AVR ELF reloc. */
static void
-avr_info_to_howto_rela (abfd, cache_ptr, dst)
- bfd *abfd ATTRIBUTE_UNUSED;
- arelent *cache_ptr;
- Elf_Internal_Rela *dst;
+avr_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *cache_ptr,
+ Elf_Internal_Rela *dst)
{
unsigned int r_type;
@@ -512,12 +478,11 @@ avr_info_to_howto_rela (abfd, cache_ptr, dst)
}
static asection *
-elf32_avr_gc_mark_hook (sec, info, rel, h, sym)
- asection *sec;
- struct bfd_link_info *info ATTRIBUTE_UNUSED;
- Elf_Internal_Rela *rel;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
+elf32_avr_gc_mark_hook (asection *sec,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ Elf_Internal_Rela *rel,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
{
if (h != NULL)
{
@@ -545,11 +510,10 @@ elf32_avr_gc_mark_hook (sec, info, rel, h, sym)
}
static bfd_boolean
-elf32_avr_gc_sweep_hook (abfd, info, sec, relocs)
- bfd *abfd ATTRIBUTE_UNUSED;
- struct bfd_link_info *info ATTRIBUTE_UNUSED;
- asection *sec ATTRIBUTE_UNUSED;
- const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
+elf32_avr_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ asection *sec ATTRIBUTE_UNUSED,
+ const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
{
/* We don't use got and plt entries for avr. */
return TRUE;
@@ -560,11 +524,10 @@ elf32_avr_gc_sweep_hook (abfd, info, sec, relocs)
virtual table relocs for gc. */
static bfd_boolean
-elf32_avr_check_relocs (abfd, info, sec, relocs)
- bfd *abfd;
- struct bfd_link_info *info;
- asection *sec;
- const Elf_Internal_Rela *relocs;
+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, **sym_hashes_end;
@@ -576,7 +539,7 @@ elf32_avr_check_relocs (abfd, info, sec, relocs)
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
- sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
+ sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
if (!elf_bad_symtab (abfd))
sym_hashes_end -= symtab_hdr->sh_info;
@@ -605,14 +568,12 @@ elf32_avr_check_relocs (abfd, info, sec, relocs)
routines, but a few relocs, we have to do them ourselves. */
static bfd_reloc_status_type
-avr_final_link_relocate (howto, input_bfd, input_section,
- contents, rel, relocation)
- reloc_howto_type * howto;
- bfd * input_bfd;
- asection * input_section;
- bfd_byte * contents;
- Elf_Internal_Rela * rel;
- bfd_vma relocation;
+avr_final_link_relocate (reloc_howto_type * howto,
+ bfd * input_bfd,
+ asection * input_section,
+ bfd_byte * contents,
+ Elf_Internal_Rela * rel,
+ bfd_vma relocation)
{
bfd_reloc_status_type r = bfd_reloc_ok;
bfd_vma x;
@@ -688,8 +649,8 @@ avr_final_link_relocate (howto, input_bfd, input_section,
case R_AVR_LDI:
contents += rel->r_offset;
srel = (bfd_signed_vma) relocation + rel->r_addend;
- if ( ((srel > 0) && (srel & 0xffff) > 255)
- || ((srel < 0) && ( (-srel) & 0xffff) > 128))
+ if (((srel > 0) && (srel & 0xffff) > 255)
+ || ((srel < 0) && ((-srel) & 0xffff) > 128))
/* Remove offset for data/eeprom section. */
return bfd_reloc_overflow;
@@ -705,7 +666,7 @@ avr_final_link_relocate (howto, input_bfd, input_section,
/* Remove offset for data/eeprom section. */
return bfd_reloc_overflow;
x = bfd_get_16 (input_bfd, contents);
- x = (x & 0xd3f8) | ((srel & 7) | ((srel & (3 << 3)) << 7)
+ x = (x & 0xd3f8) | ((srel & 7) | ((srel & (3 << 3)) << 7)
| ((srel & (1 << 5)) << 8));
bfd_put_16 (input_bfd, x, contents);
break;
@@ -717,7 +678,7 @@ avr_final_link_relocate (howto, input_bfd, input_section,
/* Remove offset for data/eeprom section. */
return bfd_reloc_overflow;
x = bfd_get_16 (input_bfd, contents);
- x = (x & 0xff30) | (srel & 0xf) | ((srel & 0x30) << 2);
+ x = (x & 0xff30) | (srel & 0xf) | ((srel & 0x30) << 2);
bfd_put_16 (input_bfd, x, contents);
break;
@@ -882,17 +843,16 @@ avr_final_link_relocate (howto, input_bfd, input_section,
}
/* Relocate an AVR ELF section. */
+
static bfd_boolean
-elf32_avr_relocate_section (output_bfd, info, input_bfd, input_section,
- contents, relocs, local_syms, local_sections)
- bfd *output_bfd ATTRIBUTE_UNUSED;
- struct bfd_link_info *info;
- bfd *input_bfd;
- asection *input_section;
- bfd_byte *contents;
- Elf_Internal_Rela *relocs;
- Elf_Internal_Sym *local_syms;
- asection **local_sections;
+elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info,
+ bfd *input_bfd,
+ asection *input_section,
+ bfd_byte *contents,
+ Elf_Internal_Rela *relocs,
+ Elf_Internal_Sym *local_syms,
+ asection **local_sections)
{
Elf_Internal_Shdr * symtab_hdr;
struct elf_link_hash_entry ** sym_hashes;
@@ -1003,9 +963,8 @@ elf32_avr_relocate_section (output_bfd, info, input_bfd, input_section,
number. */
static void
-bfd_elf_avr_final_write_processing (abfd, linker)
- bfd *abfd;
- bfd_boolean linker ATTRIBUTE_UNUSED;
+bfd_elf_avr_final_write_processing (bfd *abfd,
+ bfd_boolean linker ATTRIBUTE_UNUSED)
{
unsigned long val;
@@ -1042,14 +1001,15 @@ bfd_elf_avr_final_write_processing (abfd, linker)
/* Set the right machine number. */
static bfd_boolean
-elf32_avr_object_p (abfd)
- bfd *abfd;
+elf32_avr_object_p (bfd *abfd)
{
unsigned int e_set = bfd_mach_avr2;
+
if (elf_elfheader (abfd)->e_machine == EM_AVR
|| elf_elfheader (abfd)->e_machine == EM_AVR_OLD)
{
int e_mach = elf_elfheader (abfd)->e_flags & EF_AVR_MACH;
+
switch (e_mach)
{
default:
@@ -1082,12 +1042,177 @@ elf32_avr_object_p (abfd)
/* Enable debugging printout at stdout with a value of 1. */
#define DEBUG_RELAX 0
+/* 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. */
+
+static bfd_boolean
+elf32_avr_relax_delete_bytes (bfd *abfd,
+ asection *sec,
+ bfd_vma addr,
+ int count)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned int sec_shndx;
+ bfd_byte *contents;
+ Elf_Internal_Rela *irel, *irelend;
+ Elf_Internal_Rela *irelalign;
+ Elf_Internal_Sym *isym;
+ Elf_Internal_Sym *isymbuf = NULL;
+ Elf_Internal_Sym *isymend;
+ bfd_vma toaddr;
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_link_hash_entry **end_hashes;
+ unsigned int symcount;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+ contents = elf_section_data (sec)->this_hdr.contents;
+
+ /* The deletion must stop at the next ALIGN reloc for an aligment
+ power larger than the number of bytes we are deleting. */
+
+ irelalign = NULL;
+ toaddr = sec->size;
+
+ irel = elf_section_data (sec)->relocs;
+ irelend = irel + sec->reloc_count;
+
+ /* Actually delete the bytes. */
+ if (toaddr - addr - count > 0)
+ memmove (contents + addr, contents + addr + count,
+ (size_t) (toaddr - addr - count));
+ sec->size -= count;
+
+ /* Adjust all the relocs. */
+ for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+ {
+ bfd_vma symval;
+ bfd_vma old_reloc_address;
+ bfd_vma shrinked_insn_address;
+
+ old_reloc_address = (sec->output_section->vma
+ + sec->output_offset + irel->r_offset);
+ shrinked_insn_address = (sec->output_section->vma
+ + sec->output_offset + addr - count);
+
+ /* Get the new reloc address. */
+ if ((irel->r_offset > addr
+ && irel->r_offset < toaddr))
+ {
+ if (DEBUG_RELAX)
+ printf ("Relocation at address 0x%x needs to be moved.\n"
+ "Old section offset: 0x%x, New section offset: 0x%x \n",
+ (unsigned int) old_reloc_address,
+ (unsigned int) irel->r_offset,
+ (unsigned int) ((irel->r_offset) - count));
+
+ irel->r_offset -= count;
+ }
+
+ /* The reloc's own addresses are now ok. However, we need to readjust
+ the reloc's addend if two conditions are met:
+ 1.) the reloc is relative to a symbol in this section that
+ is located in front of the shrinked instruction
+ 2.) symbol plus addend end up behind the shrinked instruction.
+
+ This should happen only for local symbols that are progmem related. */
+
+ /* 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)
+ return FALSE;
+ }
+
+ /* 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;
+
+ if (DEBUG_RELAX)
+ printf ("Checking if the relocation's "
+ "addend needs corrections.\n"
+ "Address of anchor symbol: 0x%x \n"
+ "Address of relocation target: 0x%x \n"
+ "Address of relaxed insn: 0x%x \n",
+ (unsigned int) symval,
+ (unsigned int) (symval + irel->r_addend),
+ (unsigned int) shrinked_insn_address);
+
+ if (symval <= shrinked_insn_address
+ && (symval + irel->r_addend) > shrinked_insn_address)
+ {
+ irel->r_addend -= count;
+
+ if (DEBUG_RELAX)
+ printf ("Anchor symbol and relocation target bracket "
+ "shrinked insn address.\n"
+ "Need for new addend : 0x%x\n",
+ (unsigned int) irel->r_addend);
+ }
+ }
+ /* else ... Reference symbol is absolute. No adjustment needed. */
+ }
+ /* else ... Reference symbol is extern. No need for adjusting the addend. */
+ }
+
+ /* Adjust the local symbols defined in this section. */
+ isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+ isymend = isym + symtab_hdr->sh_info;
+ for (; isym < isymend; isym++)
+ {
+ if (isym->st_shndx == sec_shndx
+ && isym->st_value > addr
+ && isym->st_value < toaddr)
+ isym->st_value -= count;
+ }
+
+ /* Now adjust the global symbols defined in this section. */
+ 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 > addr
+ && sym_hash->root.u.def.value < toaddr)
+ {
+ sym_hash->root.u.def.value -= count;
+ }
+ }
+
+ return TRUE;
+}
+
/* This function handles relaxing for the avr.
Many important relaxing opportunities within functions are already
realized by the compiler itself.
Here we try to replace call (4 bytes) -> rcall (2 bytes)
- and jump -> rjmp (safes also 2 bytes).
- As well we now optimize seqences of
+ and jump -> rjmp (safes also 2 bytes).
+ As well we now optimize seqences of
- call/rcall function
- ret
to yield
@@ -1101,20 +1226,21 @@ elf32_avr_object_p (abfd)
is not the target of a branch or jump within the same section, it is checked
that there is no skip instruction before the jmp/rjmp and that there
is no local or global label place at the address of the ret.
-
+
We refrain from relaxing within sections ".vectors" and
- ".jumptables" in order to maintain the position of the instructions.
+ ".jumptables" in order to maintain the position of the instructions.
There, however, we substitute jmp/call by a sequence rjmp,nop/rcall,nop
- if possible. (In future one could possibly use the space of the nop
+ if possible. (In future one could possibly use the space of the nop
for the first instruction of the irq service function.
The .jumptables sections is meant to be used for a future tablejump variant
for the devices with 3-byte program counter where the table itself
- contains 4-byte jump instructions whose relative offset must not
+ contains 4-byte jump instructions whose relative offset must not
be changed. */
-
+
static bfd_boolean
-elf32_avr_relax_section (bfd *abfd, asection *sec,
+elf32_avr_relax_section (bfd *abfd,
+ asection *sec,
struct bfd_link_info *link_info,
bfd_boolean *again)
{
@@ -1137,20 +1263,17 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
|| sec->reloc_count == 0
|| (sec->flags & SEC_CODE) == 0)
return TRUE;
-
+
/* Check if the object file to relax uses internal symbols so that we
could fix up the relocations. */
-
if (!(elf_elfheader (abfd)->e_flags & EF_AVR_LINKRELAX_PREPARED))
return TRUE;
-
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
/* Get a copy of the native relocations. */
internal_relocs = (_bfd_elf_link_read_relocs
- (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
- link_info->keep_memory));
+ (abfd, sec, NULL, NULL, link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
@@ -1165,11 +1288,11 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
{
bfd_vma symval;
- if (ELF32_R_TYPE (irel->r_info) != R_AVR_13_PCREL
+ 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)
continue;
-
+
/* Get the section contents if we haven't done so already. */
if (contents == NULL)
{
@@ -1179,7 +1302,7 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
else
{
/* Go get them off disk. */
- if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+ if (! bfd_malloc_and_get_section (abfd, sec, &contents))
goto error_return;
}
}
@@ -1224,12 +1347,11 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
BFD_ASSERT (h != NULL);
if (h->root.type != bfd_link_hash_defined
&& h->root.type != bfd_link_hash_defweak)
- {
- /* This appears to be a reference to an undefined
- symbol. Just ignore it--it will be caught by the
- regular reloc processing. */
- continue;
- }
+ /* This appears to be a reference to an undefined
+ symbol. Just ignore it--it will be caught by the
+ regular reloc processing. */
+ continue;
+
symval = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
@@ -1261,12 +1383,12 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
/* 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. */
+ will be closer after the relaxation. */
if ((int) gap >= -4094 && (int) gap <= 4098)
distance_short_enough = 1;
/* Here we handle the wrap-around case. E.g. for a 16k device
- we could use a rjmp to jump from address 0x100 to 0x3d00!
+ we could use a rjmp to jump from address 0x100 to 0x3d00!
In order to make this work properly, we need to fill the
vaiable avr_pc_wrap_around with the appropriate value.
I.e. 0x4000 for a 16k device. */
@@ -1277,23 +1399,22 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
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. */
-
+ 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)
+
+ if (rgap >= (-4092 + safety_margin)
&& rgap <= (4094 - safety_margin))
- distance_short_enough = 1;
- }
+ distance_short_enough = 1;
+ }
if (distance_short_enough)
{
@@ -1330,7 +1451,7 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
bfd_put_8 (abfd, 0x00, contents + irel->r_offset);
bfd_put_8 (abfd, 0xC0, contents + irel->r_offset + 1);
}
- else
+ else
abort ();
/* Fix the relocation's type. */
@@ -1360,6 +1481,7 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
}
}
}
+
default:
{
unsigned char code_msb;
@@ -1372,8 +1494,8 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
/* Get the address of this instruction. */
dot = (sec->output_section->vma
+ sec->output_offset + irel->r_offset);
-
- /* Here we look for rcall/ret or call/ret sequences that could be
+
+ /* Here we look for rcall/ret or call/ret sequences that could be
safely replaced by rjmp/ret or jmp/ret */
if (0xd0 == (code_msb & 0xf0))
{
@@ -1383,16 +1505,16 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
if (irel->r_offset + 3 < sec->size)
{
- next_insn_msb =
+ next_insn_msb =
bfd_get_8 (abfd, contents + irel->r_offset + 3);
- next_insn_lsb =
+ next_insn_lsb =
bfd_get_8 (abfd, contents + irel->r_offset + 2);
}
- if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
+
+ if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
{
/* The next insn is a ret. We now convert the rcall insn
into a rjmp instruction. */
-
code_msb &= 0xef;
bfd_put_8 (abfd, code_msb, contents + irel->r_offset + 1);
if (DEBUG_RELAX)
@@ -1417,6 +1539,7 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
next_insn_lsb =
bfd_get_8 (abfd, contents + irel->r_offset + 4);
}
+
if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
{
/* The next insn is a ret. We now convert the call insn
@@ -1432,11 +1555,11 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
break;
}
}
- else if ((0xc0 == (code_msb & 0xf0))
- || ((0x94 == (code_msb & 0xfe))
+ else if ((0xc0 == (code_msb & 0xf0))
+ || ((0x94 == (code_msb & 0xfe))
&& (0x0c == (code_lsb & 0x0e))))
{
- /* this insn is a rjmp or a jmp. */
+ /* This insn is a rjmp or a jmp. */
unsigned char next_insn_msb = 0;
unsigned char next_insn_lsb = 0;
int insn_size;
@@ -1448,11 +1571,11 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
if (irel->r_offset + insn_size + 1 < sec->size)
{
- next_insn_msb =
- bfd_get_8 (abfd, contents + irel->r_offset
+ next_insn_msb =
+ bfd_get_8 (abfd, contents + irel->r_offset
+ insn_size + 1);
- next_insn_lsb =
- bfd_get_8 (abfd, contents + irel->r_offset
+ next_insn_lsb =
+ bfd_get_8 (abfd, contents + irel->r_offset
+ insn_size);
}
@@ -1468,12 +1591,10 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
address_of_ret = dot + insn_size;
if (DEBUG_RELAX && (insn_size == 2))
- printf ("found rjmp / ret sequence at "
- "address 0x%x\n",
+ printf ("found rjmp / ret sequence at address 0x%x\n",
(int) dot);
if (DEBUG_RELAX && (insn_size == 4))
- printf ("found jmp / ret sequence at "
- "address 0x%x\n",
+ printf ("found jmp / ret sequence at address 0x%x\n",
(int) dot);
/* We have to make sure that there is a preceeding insn. */
@@ -1481,17 +1602,17 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
{
unsigned char preceeding_msb;
unsigned char preceeding_lsb;
- preceeding_msb =
+ preceeding_msb =
bfd_get_8 (abfd, contents + irel->r_offset - 1);
- preceeding_lsb =
+ preceeding_lsb =
bfd_get_8 (abfd, contents + irel->r_offset - 2);
/* sbic. */
- if (0x99 == preceeding_msb)
+ if (0x99 == preceeding_msb)
there_is_preceeding_non_skip_insn = 0;
/* sbis. */
- if (0x9b == preceeding_msb)
+ if (0x9b == preceeding_msb)
there_is_preceeding_non_skip_insn = 0;
/* sbrc */
@@ -1499,15 +1620,15 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
&& (0x00 == (preceeding_lsb & 0x08))))
there_is_preceeding_non_skip_insn = 0;
- /* sbrs */
+ /* sbrs */
if ((0xfe == (preceeding_msb & 0xfe)
&& (0x00 == (preceeding_lsb & 0x08))))
there_is_preceeding_non_skip_insn = 0;
-
+
/* cpse */
if (0x10 == (preceeding_msb & 0xfc))
there_is_preceeding_non_skip_insn = 0;
-
+
if (there_is_preceeding_non_skip_insn == 0)
if (DEBUG_RELAX)
printf ("preceeding skip insn prevents deletion of"
@@ -1518,7 +1639,7 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
{
/* There is no previous instruction. */
there_is_preceeding_non_skip_insn = 0;
- }
+ }
if (there_is_preceeding_non_skip_insn)
{
@@ -1528,13 +1649,13 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
in this section pointing to the ret. */
int deleting_ret_is_safe = 1;
- unsigned int section_offset_of_ret_insn =
+ unsigned int section_offset_of_ret_insn =
irel->r_offset + insn_size;
Elf_Internal_Sym *isym, *isymend;
unsigned int sec_shndx;
-
- sec_shndx =
- _bfd_elf_section_from_bfd_section (abfd, sec);
+
+ sec_shndx =
+ _bfd_elf_section_from_bfd_section (abfd, sec);
/* Check for local symbols. */
isym = (Elf_Internal_Sym *) symtab_hdr->contents;
@@ -1558,21 +1679,20 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
struct elf_link_hash_entry **sym_hashes;
struct elf_link_hash_entry **end_hashes;
- symcount = (symtab_hdr->sh_size
+ 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 =
+ 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.type ==
+ bfd_link_hash_defweak)
&& sym_hash->root.u.def.section == sec
- && sym_hash->root.u.def.value ==
- section_offset_of_ret_insn)
+ && sym_hash->root.u.def.value == section_offset_of_ret_insn)
{
deleting_ret_is_safe = 0;
if (DEBUG_RELAX)
@@ -1588,55 +1708,55 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
Elf_Internal_Rela *relend;
Elf_Internal_Shdr *symtab_hdr;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- relend = elf_section_data (sec)->relocs
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ relend = elf_section_data (sec)->relocs
+ sec->reloc_count;
- for (irel = elf_section_data (sec)->relocs;
+ 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
+
+ /* 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 *)
+ 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);
+ 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
+
+ /* Get the value of the symbol referred to
by the reloc. */
- if (ELF32_R_SYM (irel->r_info)
+ if (ELF32_R_SYM (irel->r_info)
< symtab_hdr->sh_info)
{
/* A local symbol. */
Elf_Internal_Sym *isym;
asection *sym_sec;
- isym = isymbuf
+ 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
+ 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 +=
+ {
+ symval +=
sym_sec->output_section->vma
+ sym_sec->output_offset;
reloc_target = symval + irel->r_addend;
@@ -1644,16 +1764,13 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
else
{
reloc_target = symval + irel->r_addend;
- /* reference symbol is absolute. */
+ /* Reference symbol is absolute. */
}
}
- else
- {
- /* reference symbol is extern. */
- }
-
+ /* else ... reference symbol is extern. */
+
if (address_of_ret == reloc_target)
- {
+ {
deleting_ret_is_safe = 0;
if (DEBUG_RELAX)
printf ("ret from "
@@ -1671,23 +1788,22 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
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
+ /* That will change things, so, we should relax
+ again. Note that this is not required, and it
may be slow. */
-
*again = TRUE;
break;
}
}
-
- }
- }
+
+ }
+ }
break;
}
}
@@ -1722,183 +1838,15 @@ elf32_avr_relax_section (bfd *abfd, asection *sec,
&& elf_section_data (sec)->relocs != internal_relocs)
free (internal_relocs);
- return FALSE;
-}
-
-/* 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. */
-static bfd_boolean
-elf32_avr_relax_delete_bytes (bfd *abfd, asection *sec,
- bfd_vma addr, int count)
-{
- Elf_Internal_Shdr *symtab_hdr;
- unsigned int sec_shndx;
- bfd_byte *contents;
- Elf_Internal_Rela *irel, *irelend;
- Elf_Internal_Rela *irelalign;
- Elf_Internal_Sym *isym;
- Elf_Internal_Sym *isymbuf = NULL;
- Elf_Internal_Sym *isymend;
- bfd_vma toaddr;
- struct elf_link_hash_entry **sym_hashes;
- struct elf_link_hash_entry **end_hashes;
- unsigned int symcount;
-
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
- contents = elf_section_data (sec)->this_hdr.contents;
-
- /* The deletion must stop at the next ALIGN reloc for an aligment
- power larger than the number of bytes we are deleting. */
-
- irelalign = NULL;
- toaddr = sec->size;
-
- irel = elf_section_data (sec)->relocs;
- irelend = irel + sec->reloc_count;
-
- /* Actually delete the bytes. */
- if (toaddr - addr - count > 0)
- memmove (contents + addr, contents + addr + count,
- (size_t) (toaddr - addr - count));
- sec->size -= count;
-
- /* Adjust all the relocs. */
- for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
- {
- bfd_vma symval;
- bfd_vma old_reloc_address;
- bfd_vma shrinked_insn_address;
-
- old_reloc_address = (sec->output_section->vma
- + sec->output_offset + irel->r_offset);
- shrinked_insn_address = (sec->output_section->vma
- + sec->output_offset + addr - count);
-
- /* Get the new reloc address. */
- if ((irel->r_offset > addr
- && irel->r_offset < toaddr))
- {
- if (DEBUG_RELAX)
- printf ("Relocation at address 0x%x needs to be moved.\n"
- "Old section offset: 0x%x, New section offset: 0x%x \n",
- (unsigned int) old_reloc_address,
- (unsigned int) irel->r_offset,
- (unsigned int) ((irel->r_offset) - count));
-
- irel->r_offset -= count;
- }
-
- /* The reloc's own addresses are now ok. However, we need to readjust
- the reloc's addend if two conditions are met:
- 1.) the reloc is relative to a symbol in this section that
- is located in front of the shrinked instruction
- 2.) symbol plus addend end up behind the shrinked instruction.
-
- This should happen only for local symbols that are progmem related. */
-
- /* 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)
- return FALSE;
- }
-
- /* 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;
-
- if (DEBUG_RELAX)
- printf ("Checking if the relocation's "
- "addend needs corrections.\n"
- "Address of anchor symbol: 0x%x \n"
- "Address of relocation target: 0x%x \n"
- "Address of relaxed insn: 0x%x \n",
- (unsigned int) symval,
- (unsigned int) (symval + irel->r_addend),
- (unsigned int) shrinked_insn_address);
-
- if ( symval <= shrinked_insn_address
- && (symval + irel->r_addend) > shrinked_insn_address)
- {
- irel->r_addend -= count;
-
- if (DEBUG_RELAX)
- printf ("Anchor symbol and relocation target bracket "
- "shrinked insn address.\n"
- "Need for new addend : 0x%x\n",
- (unsigned int) irel->r_addend);
- }
- }
- else
- {
- /* Reference symbol is absolute. No adjustment needed. */
- }
- }
- else
- {
- /* Reference symbol is extern. No need for adjusting the addend. */
- }
- }
-
- /* Adjust the local symbols defined in this section. */
- isym = (Elf_Internal_Sym *) symtab_hdr->contents;
- isymend = isym + symtab_hdr->sh_info;
- for (; isym < isymend; isym++)
- {
- if (isym->st_shndx == sec_shndx
- && isym->st_value > addr
- && isym->st_value < toaddr)
- isym->st_value -= count;
- }
-
- /* Now adjust the global symbols defined in this section. */
- 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 > addr
- && sym_hash->root.u.def.value < toaddr)
- {
- sym_hash->root.u.def.value -= count;
- }
- }
-
- return TRUE;
+ return FALSE;
}
/* This is a version of bfd_generic_get_relocated_section_contents
- which uses elf32_avr_relocate_section.
+ which uses elf32_avr_relocate_section.
- For avr it's essentially a cut and paste taken from the H8300 port.
+ For avr it's essentially a cut and paste taken from the H8300 port.
The author of the relaxation support patch for avr had absolutely no
- clue what is happening here but found out that this part of the code
+ clue what is happening here but found out that this part of the code
seems to be important. */
static bfd_byte *
@@ -1937,8 +1885,7 @@ elf32_avr_get_relocated_section_contents (bfd *output_bfd,
bfd_size_type amt;
internal_relocs = (_bfd_elf_link_read_relocs
- (input_bfd, input_section, (PTR) NULL,
- (Elf_Internal_Rela *) NULL, FALSE));
+ (input_bfd, input_section, NULL, NULL, FALSE));
if (internal_relocs == NULL)
goto error_return;
@@ -1955,7 +1902,7 @@ elf32_avr_get_relocated_section_contents (bfd *output_bfd,
amt = symtab_hdr->sh_info;
amt *= sizeof (asection *);
- sections = (asection **) bfd_malloc (amt);
+ sections = bfd_malloc (amt);
if (sections == NULL && amt != 0)
goto error_return;