* elf32-mn10200.c (mn10200_elf_final_link_relocate): Simplify
authorJeff Law <law@redhat.com>
Fri, 21 Feb 1997 23:19:34 +0000 (23:19 +0000)
committerJeff Law <law@redhat.com>
Fri, 21 Feb 1997 23:19:34 +0000 (23:19 +0000)
        somewhat.
        (mn10200_elf_relax_section): Correctly compute a symbol's value
        when the symbol is local, but not in the same section as we are
        relaxing.  Implement abs24 -> abs16, imm24 -> imm16 and d24 -> d16
        relaxing.
Another 1.3% size reduction for hello world.  Only relaxing left todo is
imm16 -> imm8 and d16 -> d8 where applicable.

bfd/ChangeLog
bfd/elf32-mn10200.c

index 4fd8c410778b1e970e37a5d91a8ddb42848aaec4..5ca5f5e6269754a1872accaaef781f14d4f6f1fb 100644 (file)
@@ -1,3 +1,12 @@
+Fri Feb 21 16:15:18 1997  Jeffrey A Law  (law@cygnus.com)
+
+       * elf32-mn10200.c (mn10200_elf_final_link_relocate): Simplify
+       somewhat.
+       (mn10200_elf_relax_section): Correctly compute a symbol's value
+       when the symbol is local, but not in the same section as we are
+       relaxing.  Implement abs24 -> abs16, imm24 -> imm16 and d24 -> d16
+       relaxing.
+
 start-sanitize-m32r
 Fri Feb 21 13:55:14 1997  Doug Evans  <dje@seba.cygnus.com>
 
index 1006dda020487a25c130cceb254f3503959e8b0e..4d1e1af112a44a6dfc4ad7e83870353444e2ed3f 100644 (file)
@@ -243,13 +243,11 @@ mn10200_elf_final_link_relocate (howto, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_MN10200_32:
-      value += bfd_get_32 (input_bfd, hit_data);
       value += addend;
       bfd_put_32 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
 
     case R_MN10200_16:
-      value += (short)bfd_get_16 (input_bfd, hit_data);
       value += addend;
 
       if ((long)value > 0x7fff || (long)value < -0x8000)
@@ -259,7 +257,6 @@ mn10200_elf_final_link_relocate (howto, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_MN10200_8:
-      value += (char)bfd_get_8 (input_bfd, hit_data);
       value += addend;
 
       if ((long)value > 0x7fff || (long)value < -0x8000)
@@ -269,7 +266,6 @@ mn10200_elf_final_link_relocate (howto, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_MN10200_24:
-      value += (bfd_get_32 (input_bfd, hit_data) & 0xffffff);
       value += addend;
 
       if ((long)value > 0x7fffff || (long)value < -0x800000)
@@ -617,25 +613,17 @@ mn10200_elf_relax_section (abfd, sec, link_info, again)
       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
          Elf_Internal_Sym isym;
+         asection *sym_sec;
 
          /* A local symbol.  */
          bfd_elf32_swap_symbol_in (abfd,
                                    extsyms + ELF32_R_SYM (irel->r_info),
                                    &isym);
 
-#if 0
-         if (isym.st_shndx != _bfd_elf_section_from_bfd_section (abfd, sec))
-           {
-             ((*_bfd_error_handler)
-              ("%s: 0x%lx: warning: symbol in unexpected section",
-               bfd_get_filename (abfd), (unsigned long) 0));
-             continue;
-           }
-#endif
-
+         sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
          symval = (isym.st_value
-                   + sec->output_section->vma
-                   + sec->output_offset);
+                   + sym_sec->output_section->vma
+                   + sym_sec->output_offset);
        }
       else
        {
@@ -939,6 +927,274 @@ mn10200_elf_relax_section (abfd, sec, link_info, again)
          *again = true;
        }
 
+      /* Try to turn a 24bit immediate, displacement or absolute address
+        into a 16bit immediate, displacement or absolute address.  */
+      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_24)
+       {
+         bfd_vma value = symval;
+
+         /* See if the value will fit in 16 bits. 
+            We allow any 16bit match here.  We prune those we can't
+            handle below.  */
+         if ((long)value < 0x7fff && (long)value > -0x8000)
+           {
+             unsigned char code;
+
+             /* All insns which have 24bit operands are 5 bytes long,
+                the first byte will always be 0xf4, but we double check
+                it just in case.  */
+
+             /* Get the first opcode.  */
+             code = bfd_get_8 (abfd, contents + irel->r_offset - 2);
+
+             if (code != 0xf4)
+               continue;
+
+             /* Get the second opcode.  */
+             code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
+
+             switch (code & 0xfc)
+               {
+               /* mov imm24,dn -> mov imm16,dn */
+               case 0x70:
+                 /* Not safe if the high bit is on as relaxing may
+                    move the value out of high mem and thus not fit
+                    in a signed 16bit value.  */
+                 if (value & 0x8000)
+                   continue;
+
+                 /* Note that we've changed the reldection contents, etc.  */
+                 elf_section_data (sec)->relocs = internal_relocs;
+                 free_relocs = NULL;
+
+                 elf_section_data (sec)->this_hdr.contents = contents;
+                 free_contents = NULL;
+
+                 symtab_hdr->contents = (bfd_byte *) extsyms;
+                 free_extsyms = NULL;
+
+                 /* Fix the opcode.  */
+                 bfd_put_8 (abfd, 0xf8 + (code & 0x03),
+                            contents + irel->r_offset - 2);
+
+                 /* Fix the relocation's type.  */
+                 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                              R_MN10200_16);
+
+                 /* The opcode got shorter too, so we have to fix the
+                    addend and offset too!  */
+                 irel->r_offset -= 1;
+
+                 /* Delete two bytes of data.  */
+                 if (!mn10200_elf_relax_delete_bytes (abfd, sec,
+                                                      irel->r_offset + 1, 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;
+                 break;
+
+               /* mov imm24,an -> mov imm16,an 
+                  cmp imm24,an -> cmp imm16,an
+                  mov (abs24),dn -> mov (abs16),dn
+                  mov dn,(abs24) -> mov dn,(abs16)
+                  movb dn,(abs24) -> movb dn,(abs16)
+                  movbu (abs24),dn -> movbu (abs16),dn */
+               case 0x74:
+               case 0x7c:
+               case 0xc0:
+               case 0x40:
+               case 0x44:
+               case 0xc8:
+                 /* Note that we've changed the reldection contents, etc.  */
+                 elf_section_data (sec)->relocs = internal_relocs;
+                 free_relocs = NULL;
+
+                 elf_section_data (sec)->this_hdr.contents = contents;
+                 free_contents = NULL;
+
+                 symtab_hdr->contents = (bfd_byte *) extsyms;
+                 free_extsyms = NULL;
+
+                 if ((code & 0xfc) == 0x74)
+                   code = 0xdc + (code & 0x03);
+                 else if ((code & 0xfc) == 0x7c)
+                   code = 0xec + (code & 0x03);
+                 else if ((code & 0xfc) == 0xc0)
+                   code = 0xc8 + (code & 0x03);
+                 else if ((code & 0xfc) == 0x40)
+                   code = 0xc0 + (code & 0x03);
+                 else if ((code & 0xfc) == 0x44)
+                   code = 0xc4 + (code & 0x03);
+                 else if ((code & 0xfc) == 0xc8)
+                   code = 0xcc + (code & 0x03);
+
+                 /* Fix the opcode.  */
+                 bfd_put_8 (abfd, code, contents + irel->r_offset - 2);
+
+                 /* Fix the relocation's type.  */
+                 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                              R_MN10200_16);
+
+                 /* The opcode got shorter too, so we have to fix the
+                    addend and offset too!  */
+                 irel->r_offset -= 1;
+
+                 /* Delete two bytes of data.  */
+                 if (!mn10200_elf_relax_delete_bytes (abfd, sec,
+                                                      irel->r_offset + 1, 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;
+                 break;
+
+               /* cmp imm24,dn -> cmp imm16,dn
+                  mov (abs24),an -> mov (abs16),an
+                  mov an,(abs24) -> mov an,(abs16)
+                  add imm24,dn -> add imm16,dn
+                  add imm24,an -> add imm16,an
+                  sub imm24,dn -> sub imm16,dn
+                  sub imm24,an -> sub imm16,an 
+                  And all d24->d16 in memory ops.  */
+               case 0x78:
+               case 0xd0:
+               case 0x50:
+               case 0x60:
+               case 0x64:
+               case 0x68:
+               case 0x6c:
+               case 0x80:
+               case 0xf0:
+               case 0x00:
+               case 0x10:
+               case 0xb0:
+               case 0x30:
+               case 0xa0:
+               case 0x20:
+               case 0x90:
+                 /* Not safe if the high bit is on as relaxing may
+                    move the value out of high mem and thus not fit
+                    in a signed 16bit value.  */
+                 if (((code & 0xfc) == 0x78
+                       || (code & 0xfc) == 0x60
+                       || (code & 0xfc) == 0x64
+                       || (code & 0xfc) == 0x68
+                       || (code & 0xfc) == 0x6c
+                       || (code & 0xfc) == 0x80
+                       || (code & 0xfc) == 0xf0
+                       || (code & 0xfc) == 0x00
+                       || (code & 0xfc) == 0x10
+                       || (code & 0xfc) == 0xb0
+                       || (code & 0xfc) == 0x30
+                       || (code & 0xfc) == 0xa0
+                       || (code & 0xfc) == 0x20
+                       || (code & 0xfc) == 0x90)
+                      && (value & 0x8000) != 0)
+                   continue;
+
+                 /* Note that we've changed the reldection contents, etc.  */
+                 elf_section_data (sec)->relocs = internal_relocs;
+                 free_relocs = NULL;
+
+                 elf_section_data (sec)->this_hdr.contents = contents;
+                 free_contents = NULL;
+
+                 symtab_hdr->contents = (bfd_byte *) extsyms;
+                 free_extsyms = NULL;
+
+                 /* Fix the opcode.  */
+                 bfd_put_8 (abfd, 0xf7, contents + irel->r_offset - 2);
+
+                 if ((code & 0xfc) == 0x78)
+                   code = 0x48 + (code & 0x03);
+                 else if ((code & 0xfc) == 0xd0)
+                   code = 0x30 + (code & 0x03);
+                 else if ((code & 0xfc) == 0x50)
+                   code = 0x20 + (code & 0x03);
+                 else if ((code & 0xfc) == 0x60)
+                   code = 0x18 + (code & 0x03);
+                 else if ((code & 0xfc) == 0x64)
+                   code = 0x08 + (code & 0x03);
+                 else if ((code & 0xfc) == 0x68)
+                   code = 0x1c + (code & 0x03);
+                 else if ((code & 0xfc) == 0x6c)
+                   code = 0x0c + (code & 0x03);
+                 else if ((code & 0xfc) == 0x80)
+                   code = 0xc0 + (code & 0x07);
+                 else if ((code & 0xfc) == 0xf0)
+                   code = 0xb0 + (code & 0x07);
+                 else if ((code & 0xfc) == 0x00)
+                   code = 0x80 + (code & 0x07);
+                 else if ((code & 0xfc) == 0x10)
+                   code = 0xa0 + (code & 0x07);
+                 else if ((code & 0xfc) == 0xb0)
+                   code = 0x70 + (code & 0x07);
+                 else if ((code & 0xfc) == 0x30)
+                   code = 0x60 + (code & 0x07);
+                 else if ((code & 0xfc) == 0xa0)
+                   code = 0xd0 + (code & 0x07);
+                 else if ((code & 0xfc) == 0x20)
+                   code = 0x90 + (code & 0x07);
+                 else if ((code & 0xfc) == 0x90)
+                   code = 0x50 + (code & 0x07);
+
+                 bfd_put_8 (abfd, code, contents + irel->r_offset - 1);
+
+                 /* Fix the relocation's type.  */
+                 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                              R_MN10200_16);
+
+                 /* Delete one bytes of data.  */
+                 if (!mn10200_elf_relax_delete_bytes (abfd, sec,
+                                                      irel->r_offset + 2, 1))
+                   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;
+                 break;
+
+               /* movb (abs24),dn ->movbu (abs16),dn extxb bn */
+               case 0xc4:
+                 /* Note that we've changed the reldection contents, etc.  */
+                 elf_section_data (sec)->relocs = internal_relocs;
+                 free_relocs = NULL;
+
+                 elf_section_data (sec)->this_hdr.contents = contents;
+                 free_contents = NULL;
+
+                 symtab_hdr->contents = (bfd_byte *) extsyms;
+                 free_extsyms = NULL;
+
+                 bfd_put_8 (abfd, 0xcc + (code & 0x03),
+                            contents + irel->r_offset - 2);
+
+                 bfd_put_8 (abfd, 0xb8 + (code & 0x03),
+                            contents + irel->r_offset - 1);
+
+                 /* Fix the relocation's type.  */
+                 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                              R_MN10200_16);
+
+                 /* The reloc will be applied one byte in front of its
+                    current location.  */
+                 irel->r_offset -= 1;
+
+                 /* Delete one bytes of data.  */
+                 if (!mn10200_elf_relax_delete_bytes (abfd, sec,
+                                                      irel->r_offset + 2, 1))
+                   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;
+                 break;
+               }
+           }
+       }
     }
 
   if (free_relocs != NULL)