Adds code to the MSP430 linker to transform a 4-byte BR instruction into
authorNick Clifton <nickc@redhat.com>
Thu, 8 Jan 2015 16:23:16 +0000 (16:23 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 8 Jan 2015 16:23:16 +0000 (16:23 +0000)
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
bfd/elf32-msp430.c

index b6151cc33578851b602db584e3bfcb0f889f7b3c..d59075a6f36fdb5600a90b20fc20653f3440aba9 100644 (file)
@@ -1,3 +1,9 @@
+2015-01-08  Nick Clifton  <nickc@redhat.com>
+
+       * 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  <nickc@redhat.com>
 
        PR binutils/17512
index d3a7cdb24e1daaad9554197d13021245a6093d31..2157eb0c5d0eeb75089e4cd2a37d23810abd6fee 100644 (file)
@@ -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)