diff options
author | Nick Clifton <nickc@redhat.com> | 2015-01-08 16:23:16 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2015-01-08 16:23:16 +0000 |
commit | 23d4663e222cbb2b9776150677683516bb7135b7 (patch) | |
tree | 252ae9c68ed8ed8a67fb907c39b18768ba441eda /bfd/elf32-msp430.c | |
parent | 063bb0250defafcc55544474a2961ecbc153882e (diff) | |
download | gdb-23d4663e222cbb2b9776150677683516bb7135b7.zip gdb-23d4663e222cbb2b9776150677683516bb7135b7.tar.gz gdb-23d4663e222cbb2b9776150677683516bb7135b7.tar.bz2 |
Adds code to the MSP430 linker to transform a 4-byte BR instruction into
a 2-byte JMP instruction, when this can be done safely.
* elf32-msp430.c (msp430_elf_relax_section): Add relaxation of
16-bit absolute BR instructions to 10-bit pc-relative JMP
instructions.
Diffstat (limited to 'bfd/elf32-msp430.c')
-rw-r--r-- | bfd/elf32-msp430.c | 64 |
1 files changed, 58 insertions, 6 deletions
diff --git a/bfd/elf32-msp430.c b/bfd/elf32-msp430.c index d3a7cdb..2157eb0 100644 --- a/bfd/elf32-msp430.c +++ b/bfd/elf32-msp430.c @@ -1768,7 +1768,6 @@ msp430_elf_relax_section (bfd * abfd, asection * sec, bfd_byte * contents = NULL; Elf_Internal_Sym * isymbuf = NULL; - /* Assume nothing changes. */ *again = FALSE; @@ -1966,10 +1965,6 @@ msp430_elf_relax_section (bfd * abfd, asection * sec, *again = TRUE; } - if (! uses_msp430x_relocs (abfd)) - /* Now perform the relocations that shrink the code size. - We only do this for non msp430x as gas only generates the RL - reloc for the msp430. */ for (irel = internal_relocs; irel < irelend; irel++) { bfd_vma symval; @@ -2048,7 +2043,8 @@ msp430_elf_relax_section (bfd * abfd, asection * sec, /* Try to turn a 16bit pc-relative branch into a 10bit pc-relative branch. */ /* Paranoia? paranoia... */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MSP430_RL_PCREL) + if (! uses_msp430x_relocs (abfd) + && ELF32_R_TYPE (irel->r_info) == (int) R_MSP430_RL_PCREL) { bfd_vma value = symval; @@ -2158,6 +2154,62 @@ msp430_elf_relax_section (bfd * abfd, asection * sec, *again = TRUE; } } + + /* Try to turn a 16-bit absolute branch into a 10-bit pc-relative + branch. */ + if (uses_msp430x_relocs (abfd) + && ELF32_R_TYPE (irel->r_info) == R_MSP430X_ABS16) + { + bfd_vma value = symval; + + value -= irel->r_offset; + value += irel->r_addend; + + /* See if the value will fit in 10 bits, note the high value is + 1016 as the target will be two bytes closer if we are + able to relax. */ + if ((long) value < 1016 && (long) value > -1016) + { + int code2; + + /* Get the opcode. */ + code2 = bfd_get_16 (abfd, contents + irel->r_offset - 2); + if (code2 != 0x4030) + continue; + /* FIXME: check r4 and r3 ? */ + /* FIXME: Handle 0x4010 as well ? */ + + /* Note that we've changed the relocs, section contents, etc. */ + elf_section_data (sec)->relocs = internal_relocs; + elf_section_data (sec)->this_hdr.contents = contents; + symtab_hdr->contents = (unsigned char *) isymbuf; + + /* Fix the relocation's type. */ + if (uses_msp430x_relocs (abfd)) + { + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_MSP430X_10_PCREL); + } + else + { + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_MSP430_10_PCREL); + } + + /* Fix the opcode right way. */ + bfd_put_16 (abfd, 0x3c00, contents + irel->r_offset - 2); + irel->r_offset -= 2; + + /* Delete bytes. */ + if (!msp430_elf_relax_delete_bytes (abfd, sec, + irel->r_offset + 2, 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; + } + } } if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) |