From 23d4663e222cbb2b9776150677683516bb7135b7 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 8 Jan 2015 16:23:16 +0000 Subject: [PATCH] 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. --- bfd/ChangeLog | 6 +++++ bfd/elf32-msp430.c | 64 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index b6151cc335..d59075a6f3 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2015-01-08 Nick Clifton + + * elf32-msp430.c (msp430_elf_relax_section): Add relaxation of + 16-bit absolute BR instructions to 10-bit pc-relative JMP + instructions. + 2015-01-08 Nick Clifton PR binutils/17512 diff --git a/bfd/elf32-msp430.c b/bfd/elf32-msp430.c index d3a7cdb24e..2157eb0c5d 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)