diff options
author | Nick Clifton <nickc@redhat.com> | 2007-10-01 15:55:44 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2007-10-01 15:55:44 +0000 |
commit | 7fac7ff4ae7bb9a3cf6be14d963944805c46a755 (patch) | |
tree | ee2686c90603a09908abaf74c2f458c5eeb845f8 /bfd | |
parent | fef8a650d0248ba4cb1ba7bd36ce099cd8169510 (diff) | |
download | gdb-7fac7ff4ae7bb9a3cf6be14d963944805c46a755.zip gdb-7fac7ff4ae7bb9a3cf6be14d963944805c46a755.tar.gz gdb-7fac7ff4ae7bb9a3cf6be14d963944805c46a755.tar.bz2 |
Various CR16 fixes
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 10 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 3 | ||||
-rw-r--r-- | bfd/elf32-cr16.c | 398 | ||||
-rw-r--r-- | bfd/libbfd.h | 3 | ||||
-rw-r--r-- | bfd/reloc.c | 6 |
5 files changed, 298 insertions, 122 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 1445a2b..45180e3 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,13 @@ +2007-10-01 M R Swami Reddy <MR.Swami.Reddy@nsc.com> + + * elf32-cr16.c: Fixed DISP8, DISP20 and IMM20 relocations at + final relocation phase. + Added the below relaxations: IMM32 -> IMM20/IM16 -> IMM4. + * reloc.c: Added 3 new relocations: R_CR16_SWITCH8, + R_CR16_SWITCH16, R_CR16_SWITCH32. + * libbfd.h: Regenerate. + * bfd-in2.h: Regenerate. + 2007-09-30 Alan Modra <amodra@bigpond.net.au> * elflink.c: Formatting. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 0943278..db9cd85 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -4148,6 +4148,9 @@ This is the 5 bits of a value. */ BFD_RELOC_CR16_DISP20, BFD_RELOC_CR16_DISP24, BFD_RELOC_CR16_DISP24a, + BFD_RELOC_CR16_SWITCH8, + BFD_RELOC_CR16_SWITCH16, + BFD_RELOC_CR16_SWITCH32, /* NS CRX Relocations. */ BFD_RELOC_CRX_REL4, diff --git a/bfd/elf32-cr16.c b/bfd/elf32-cr16.c index 46664bc..d0f7fd1 100644 --- a/bfd/elf32-cr16.c +++ b/bfd/elf32-cr16.c @@ -61,7 +61,10 @@ static const struct cr16_reloc_map cr16_reloc_map[R_CR16_MAX] = {BFD_RELOC_CR16_DISP8, R_CR16_DISP8}, {BFD_RELOC_CR16_DISP16, R_CR16_DISP16}, {BFD_RELOC_CR16_DISP24, R_CR16_DISP24}, - {BFD_RELOC_CR16_DISP24a, R_CR16_DISP24a} + {BFD_RELOC_CR16_DISP24a, R_CR16_DISP24a}, + {BFD_RELOC_CR16_SWITCH8, R_CR16_SWITCH8}, + {BFD_RELOC_CR16_SWITCH16, R_CR16_SWITCH16}, + {BFD_RELOC_CR16_SWITCH32, R_CR16_SWITCH32} }; static reloc_howto_type cr16_elf_howto_table[] = @@ -429,7 +432,58 @@ static reloc_howto_type cr16_elf_howto_table[] = FALSE, /* partial_inplace */ 0xffffff, /* src_mask */ 0xffffff, /* dst_mask */ - FALSE) /* pcrel_offset */ + FALSE), /* pcrel_offset */ + + /* An 8 bit switch table entry. This is generated for an expression + such as ``.byte L1 - L2''. The offset holds the difference + between the reloc address and L2. */ + HOWTO (R_CR16_SWITCH8, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_CR16_SWITCH8", /* name */ + FALSE, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A 16 bit switch table entry. This is generated for an expression + such as ``.word L1 - L2''. The offset holds the difference + between the reloc address and L2. */ + HOWTO (R_CR16_SWITCH16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_CR16_SWITCH16", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A 32 bit switch table entry. This is generated for an expression + such as ``.long L1 - L2''. The offset holds the difference + between the reloc address and L2. */ + HOWTO (R_CR16_SWITCH32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_CR16_SWITCH32", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + TRUE) /* pcrel_offset */ }; /* Retrieve a howto ptr using a BFD reloc_code. */ @@ -478,13 +532,13 @@ elf_cr16_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, static bfd_reloc_status_type cr16_elf_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, + bfd *input_bfd, bfd *output_bfd ATTRIBUTE_UNUSED, asection *input_section, - bfd_byte *contents, + bfd_byte *contents, bfd_vma offset, - bfd_vma Rvalue, - bfd_vma addend, + bfd_vma Rvalue, + bfd_vma addend, struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *sec ATTRIBUTE_UNUSED, int is_local ATTRIBUTE_UNUSED) @@ -496,9 +550,12 @@ cr16_elf_final_link_relocate (reloc_howto_type *howto, switch (r_type) { case R_CR16_IMM4: + case R_CR16_IMM20: + case R_CR16_ABS20: + break; + case R_CR16_IMM8: case R_CR16_IMM16: - case R_CR16_IMM20: case R_CR16_IMM32: case R_CR16_IMM32a: case R_CR16_REGREL4: @@ -507,7 +564,6 @@ cr16_elf_final_link_relocate (reloc_howto_type *howto, case R_CR16_REGREL14a: case R_CR16_REGREL16: case R_CR16_REGREL20: - case R_CR16_ABS20: case R_CR16_ABS24: case R_CR16_DISP16: case R_CR16_DISP24: @@ -521,11 +577,22 @@ cr16_elf_final_link_relocate (reloc_howto_type *howto, break; case R_CR16_DISP4: + if (is_local) + Rvalue += -1; + break; + case R_CR16_DISP8: case R_CR16_DISP24a: + if (is_local) + Rvalue -= -1; + break; + + case R_CR16_SWITCH8: + case R_CR16_SWITCH16: + case R_CR16_SWITCH32: /* We only care about the addend, where the difference between expressions is kept. */ - if (is_local) Rvalue -= -1; + Rvalue = 0; default: break; @@ -563,7 +630,7 @@ cr16_elf_final_link_relocate (reloc_howto_type *howto, { check |= ((bfd_vma) - 1 & ~((bfd_vma) - 1 - >> howto->rightshift)); + >> howto->rightshift)); if (((bfd_vma) check & ~reloc_bits) != (-(bfd_vma) 1 & ~reloc_bits)) @@ -582,14 +649,29 @@ cr16_elf_final_link_relocate (reloc_howto_type *howto, switch (howto->size) { case 0: - if ((r_type == R_CR16_IMM4) - || (r_type == R_CR16_DISP4) - || (r_type == R_CR16_DISP8)) + if (r_type == R_CR16_DISP8) { Rvalue1 = bfd_get_16 (input_bfd, hit_data); Rvalue = ((Rvalue1 & 0xf000) | ((Rvalue << 4) & 0xf00) - | (Rvalue1 & 0x00f0) | (Rvalue & 0xf)); - bfd_put_16 (input_bfd, Rvalue, hit_data); + | (Rvalue1 & 0x00f0) | (Rvalue & 0xf)); + bfd_put_16 (input_bfd, Rvalue, hit_data); + } + else if (r_type == R_CR16_IMM4) + { + Rvalue1 = bfd_get_16 (input_bfd, hit_data); + Rvalue = (((Rvalue1 & 0xff) << 8) | ((Rvalue << 4) & 0xf0) + | ((Rvalue1 & 0x0f00) >> 8)); + bfd_put_16 (input_bfd, Rvalue, hit_data); + } + else if (r_type == R_CR16_DISP4) + { + Rvalue1 = bfd_get_16 (input_bfd, hit_data); + Rvalue = (Rvalue1 | ((Rvalue & 0xf) << 4)); + bfd_put_16 (input_bfd, Rvalue, hit_data); + } + else + { + bfd_put_8 (input_bfd, (unsigned char) Rvalue, hit_data); } break; @@ -598,65 +680,49 @@ cr16_elf_final_link_relocate (reloc_howto_type *howto, { Rvalue |= (bfd_get_16 (input_bfd, hit_data)); Rvalue = ((Rvalue & 0xfffe) | ((Rvalue >> 16) & 0x1)); - - bfd_put_16 (input_bfd, Rvalue, hit_data); } + + bfd_put_16 (input_bfd, Rvalue, hit_data); break; case 2: - if (r_type == R_CR16_ABS20) + if ((r_type == R_CR16_ABS20) || (r_type == R_CR16_IMM20)) { - Rvalue |= (((bfd_get_16 (input_bfd, hit_data) << 16) - | (bfd_get_16 (input_bfd, hit_data + 2))) - & ~howto->dst_mask); - Rvalue |= (bfd_get_16 (input_bfd, hit_data + 2) << 16); - - /* Relocation on INSTRUCTIONS is different : Instructions are - word-addressable, that is, each word itself is arranged according - to little-endian convention, whereas the words are arranged with - respect to one another in BIG ENDIAN fashion. - When there is an immediate value that spans a word boundary, - it is split in a big-endian way with respect to the words. */ - bfd_put_16 (input_bfd, (Rvalue) & 0xffff, hit_data); - bfd_put_16 (input_bfd, (Rvalue >> 16)& 0xffff, hit_data + 2); - } - else if (r_type == R_CR16_ABS24) - { - Rvalue = ((((Rvalue >> 20)& 0xf) - | (((Rvalue >> 16) & 0xf) << 8) - | (bfd_get_16 (input_bfd, hit_data))) - | ((Rvalue & 0xffff) << 16)); - - bfd_put_32 (input_bfd, Rvalue, hit_data); + bfd_put_16 (input_bfd, (bfd_get_16 (input_bfd, hit_data)) + | ((Rvalue >> 16) & 0xf), hit_data); + bfd_put_16 (input_bfd, (Rvalue) & 0xffff, hit_data + 2); } - else if (r_type == R_CR16_DISP24) + else { - Rvalue = ((((Rvalue >> 20)& 0xf) | (((Rvalue >> 16) & 0xf)<<8) - | (bfd_get_16 (input_bfd, hit_data))) - | (((Rvalue & 0xfffE) | ((Rvalue >> 24) & 0x1)) << 16)); + if (r_type == R_CR16_ABS24) + { + Rvalue = ((((Rvalue >> 20)& 0xf) | (((Rvalue >> 16) & 0xf) << 8) + | (bfd_get_16 (input_bfd, hit_data))) + | ((Rvalue & 0xffff) << 16)); + } + if (r_type == R_CR16_DISP24) + { + Rvalue = ((((Rvalue >> 20)& 0xf) | (((Rvalue >>16) & 0xf) << 8) + | (bfd_get_16 (input_bfd, hit_data))) + | (((Rvalue & 0xfffe) + | ((Rvalue >> 24) & 0x1)) << 16)); + } + else if ((r_type == R_CR16_IMM32) ||(r_type == R_CR16_IMM32a)) + { + Rvalue = (((Rvalue >> 16)& 0xffff) + | (bfd_get_16 (input_bfd, hit_data))) + | ((Rvalue & 0xffff) << 16); + } + else if (r_type == R_CR16_DISP24a) + { + Rvalue = (((Rvalue & 0xfffffe) | (Rvalue >> 23))); + Rvalue = ((Rvalue >> 16) & 0xff) | ((Rvalue & 0xffff) << 16) + | (bfd_get_32 (input_bfd, hit_data)); + } bfd_put_32 (input_bfd, Rvalue, hit_data); } - else if ((r_type == R_CR16_IMM32) || (r_type == R_CR16_IMM32a)) - { - Rvalue = (((Rvalue >> 16)& 0xffff) - | (bfd_get_16 (input_bfd, hit_data))) - | ((Rvalue & 0xffff) << 16); - bfd_put_32 (input_bfd, Rvalue, hit_data); - } - else if (r_type == R_CR16_DISP24a) - { - Rvalue = (((Rvalue & 0xfffffe) | (Rvalue >> 23))); - Rvalue = ((Rvalue >> 16) & 0xff) | ((Rvalue & 0xffff) << 16) - | (bfd_get_32 (input_bfd, hit_data)); - - bfd_put_32 (input_bfd, Rvalue, hit_data); - } - else if ((r_type == R_CR16_NUM32) || (r_type == R_CR16_NUM32a)) - { - bfd_put_32 (input_bfd, Rvalue, hit_data); - } - break; + break; default: return bfd_reloc_notsupported; @@ -705,7 +771,7 @@ elf32_cr16_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd, for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) /* Get the new reloc address. */ if ((irel->r_offset > addr && irel->r_offset < toaddr)) - irel->r_offset -= count; + irel->r_offset -= count; /* Adjust the local symbols defined in this section. */ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -724,6 +790,12 @@ elf32_cr16_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd, Elf_Internal_Sym *rsym; bfd_vma addsym, subsym; + /* Skip if not a SWITCH relocation. */ + if (ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH8 + && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH16 + && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH32) + continue; + r_symndx = ELF32_R_SYM (irel->r_info); rsym = (Elf_Internal_Sym *) symtab_hdr->contents + r_symndx; @@ -769,10 +841,10 @@ elf32_cr16_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd, /* Loop only over the symbols whom been already checked. */ for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes; cur_sym_hashes++) - /* If the current symbol is identical to 'sym_hash', that means - the symbol was already adjusted (or at least checked). */ - if (*cur_sym_hashes == sym_hash) - break; + /* If the current symbol is identical to 'sym_hash', that means + the symbol was already adjusted (or at least checked). */ + if (*cur_sym_hashes == sym_hash) + break; /* Don't adjust the symbol again. */ if (cur_sym_hashes < sym_hashes) @@ -794,10 +866,10 @@ elf32_cr16_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd, static bfd_boolean elf32_cr16_relocate_section (bfd *output_bfd, 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) + 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; @@ -953,7 +1025,7 @@ elf32_cr16_get_relocated_section_contents (bfd *output_bfd, bfd_size_type amt; internal_relocs = _bfd_elf_link_read_relocs (input_bfd, input_section, - NULL, NULL, FALSE); + NULL, NULL, FALSE); if (internal_relocs == NULL) goto error_return; @@ -1024,8 +1096,9 @@ elf32_cr16_get_relocated_section_contents (bfd *output_bfd, There's quite a few relaxing opportunites available on the CR16: * bcond:24 -> bcond:16 2 bytes - * bcond:16 -> bcond:8 2 bytes - * arithmetic imm32 -> arithmetic imm16 2 bytes + * bcond:16 -> bcond:8 2 bytes + * arithmetic imm32 -> arithmetic imm20/imm16 2 bytes + * arithmetic imm20/imm16 -> arithmetic imm4 2 bytes Symbol- and reloc-reading infrastructure copied from elf-m10200.c. */ @@ -1055,7 +1128,7 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, /* Get a copy of the native relocations. */ internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - link_info->keep_memory); + link_info->keep_memory); if (internal_relocs == NULL) goto error_return; @@ -1068,7 +1141,10 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, /* If this isn't something that can be relaxed, then ignore this reloc. */ if (ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP16 - && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP24) + && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP24 + && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM32 + && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM20 + && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM16) continue; /* Get the section contents if we haven't done so already. */ @@ -1145,7 +1221,7 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, the linker is run. */ /* Try to turn a 24 branch/call into a 16bit relative - * branch/call. */ + branch/call. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_DISP24) { bfd_vma value = symval; @@ -1168,8 +1244,8 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, /* Verify it's a 'bcond' and fix the opcode. */ if ((code & 0xffff) == 0x0010) { - bfd_put_16 (abfd, 0x1800 | ((0xf & (code >>20))<<4), contents + irel->r_offset); - bfd_put_16 (abfd, value, contents + irel->r_offset+2); + bfd_put_16 (abfd, 0x1800 | ((0xf & (code >> 20)) << 4), contents + irel->r_offset); + bfd_put_16 (abfd, value, contents + irel->r_offset + 2); } else continue; @@ -1194,8 +1270,8 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, } } - /* Try to turn a 16bit pc-relative branch into an - 8bit pc-relative branch. */ + /* Try to turn a 16-bit pc-relative branch into an + 8-bit pc-relative branch. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_DISP16) { bfd_vma value = symval; @@ -1218,8 +1294,8 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, /* Verify it's a 'bcond' opcode. */ if ((code & 0xff00) == 0x1800) { - bfd_put_8 (abfd, 0x1 | ((0xf & (code>>4))<<4), contents + irel->r_offset); - bfd_put_8 (abfd, value, contents + irel->r_offset+2); + bfd_put_8 (abfd, 0x1 | ((0xf & (code >> 4)) << 4), contents + irel->r_offset); + bfd_put_8 (abfd, value, contents + irel->r_offset + 2); } else continue; @@ -1244,24 +1320,63 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, } } -#if 0 // REVISIT: To support IMM relaxation in CR16 target /* Try to turn a 32bit immediate address into - a 20bit immediate address. */ + a 20/16bit immediate address. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM32) { bfd_vma value = symval; + unsigned short is_add_mov = 0; /* See if the value will fit in 20 bits. */ - if ((long) value < 0x7ffff && (long) value > -0x80000) + if ((long) value < 0xfffff && (long) value > 0) { unsigned short code; /* Get the opcode. */ code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - /* Verify it's a 'arithmetic double'. */ - if ((code & 0xfff0) != 0x0070) - continue; + /* Verify it's a arithmetic ADDD or MOVD instruction. + For ADDD and MOVD only, convert to IMM32 -> IMM20. */ + if (((code & 0xfff0) != 0x0070) || ((code & 0xfff0) != 0x0020)) + is_add_mov = 1; + + if (is_add_mov) + { + /* 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 opcode. */ + if ((code & 0xfff0) == 0x0070) /* For movd. */ + bfd_put_8 (abfd, 0x05, contents + irel->r_offset + 1); + else /* code == 0x0020 for addd. */ + bfd_put_8 (abfd, 0x04, contents + irel->r_offset + 1); + + bfd_put_8 (abfd, (code & 0xf) << 4, contents + irel->r_offset); + + + /* Fix the relocation's type. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_CR16_IMM20); + /* Delete two bytes of data. */ + if (!elf32_cr16_relax_delete_bytes (link_info, 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; + } + } + /* See if the value will fit in 16 bits. */ + if ((!is_add_mov) && ((long) value < 0x7fff && (long) value > 0)) + { + unsigned short code; + + /* Get the opcode. */ + code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); /* Note that we've changed the relocs, section contents, etc. */ elf_section_data (sec)->relocs = internal_relocs; @@ -1269,40 +1384,46 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, symtab_hdr->contents = (unsigned char *) isymbuf; /* Fix the opcode. */ - bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset); + if ((code & 0xf0) == 0x70) /* For movd. */ + bfd_put_8 (abfd, 0x54, contents + irel->r_offset + 1); + else if ((code & 0xf0) == 0x20) /* For addd. */ + bfd_put_8 (abfd, 0x60, contents + irel->r_offset + 1); + else if ((code & 0xf0) == 0x90) /* For cmpd. */ + bfd_put_8 (abfd, 0x56, contents + irel->r_offset + 1); + else + continue; + + bfd_put_8 (abfd, 0xb0 | (code & 0xf), contents + irel->r_offset); /* Fix the relocation's type. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CR16_IMM20); + R_CR16_IMM16); /* Delete two bytes of data. */ if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; + 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; + *again = TRUE; } } - /* Try to turn a 20bit/16bit immediate address into + + /* Try to turn a 20/16bit immediate address into a 4bit immediate address. */ if ((ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM20) - || (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM16)) + || (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM16)) { bfd_vma value = symval; /* See if the value will fit in 4 bits. */ - if ((long) value < 0x7 && (long) value > -0x8) + if ((long) value < 0xf && (long) value > 0) { unsigned short code; /* Get the opcode. */ - code = (unsigned short) bfd_get_8 (abfd, contents + irel->r_offset); - - /* Verify it's a 'arithmetic double'. */ - if (((code & 0xff) != 0x50) || ((code & 0xff) != 0x45)) - continue; + code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); /* Note that we've changed the relocs, section contents, etc. */ elf_section_data (sec)->relocs = internal_relocs; @@ -1310,7 +1431,45 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, symtab_hdr->contents = (unsigned char *) isymbuf; /* Fix the opcode. */ - bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset); + if (((code & 0x0f00) == 0x0400) || ((code & 0x0f00) == 0x0500)) + { + if ((code & 0x0f00) == 0x0400) /* For movd imm20. */ + bfd_put_8 (abfd, 0x60, contents + irel->r_offset); + else /* For addd imm20. */ + bfd_put_8 (abfd, 0x54, contents + irel->r_offset); + bfd_put_8 (abfd, (code & 0xf0) >> 4, contents + irel->r_offset + 1); + } + else + { + if ((code & 0xfff0) == 0x56b0) /* For cmpd imm16. */ + bfd_put_8 (abfd, 0x56, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x54b0) /* For movd imm16. */ + bfd_put_8 (abfd, 0x54, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x58b0) /* For movb imm16. */ + bfd_put_8 (abfd, 0x58, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x5Ab0) /* For movw imm16. */ + bfd_put_8 (abfd, 0x5A, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x60b0) /* For addd imm16. */ + bfd_put_8 (abfd, 0x60, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x30b0) /* For addb imm16. */ + bfd_put_8 (abfd, 0x30, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x2Cb0) /* For addub imm16. */ + bfd_put_8 (abfd, 0x2C, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x32b0) /* For adduw imm16. */ + bfd_put_8 (abfd, 0x32, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x38b0) /* For subb imm16. */ + bfd_put_8 (abfd, 0x38, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x3Ab0) /* For subw imm16. */ + bfd_put_8 (abfd, 0x3A, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x50b0) /* For cmpb imm16. */ + bfd_put_8 (abfd, 0x50, contents + irel->r_offset); + else if ((code & 0xfff0) == 0x52b0) /* For cmpw imm16. */ + bfd_put_8 (abfd, 0x52, contents + irel->r_offset); + else + continue; + + bfd_put_8 (abfd, (code & 0xf), contents + irel->r_offset + 1); + } /* Fix the relocation's type. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), @@ -1318,7 +1477,7 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, /* Delete two bytes of data. */ if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) + irel->r_offset + 2, 2)) goto error_return; /* That will change things, so, we should relax again. @@ -1326,7 +1485,6 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, *again = TRUE; } } -#endif } if (isymbuf != NULL @@ -1335,10 +1493,8 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, if (! link_info->keep_memory) free (isymbuf); else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } + /* Cache the symbols for elf_link_input_bfd. */ + symtab_hdr->contents = (unsigned char *) isymbuf; } if (contents != NULL @@ -1347,10 +1503,8 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, if (! link_info->keep_memory) free (contents); else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; } if (internal_relocs != NULL @@ -1375,10 +1529,10 @@ elf32_cr16_relax_section (bfd *abfd, asection *sec, static asection * elf32_cr16_gc_mark_hook (asection *sec, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Rela *rel ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) + struct bfd_link_info *info ATTRIBUTE_UNUSED, + Elf_Internal_Rela *rel ATTRIBUTE_UNUSED, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) { if (h == NULL) return bfd_section_from_elf_index (sec->owner, sym->st_shndx); @@ -1401,9 +1555,9 @@ elf32_cr16_gc_mark_hook (asection *sec, static bfd_boolean elf32_cr16_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) + struct bfd_link_info *info ATTRIBUTE_UNUSED, + asection *sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED) { /* We don't support garbage collection of GOT and PLT relocs yet. */ return TRUE; diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 2d5b5b3d..7f10f46 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1833,6 +1833,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_CR16_DISP20", "BFD_RELOC_CR16_DISP24", "BFD_RELOC_CR16_DISP24a", + "BFD_RELOC_CR16_SWITCH8", + "BFD_RELOC_CR16_SWITCH16", + "BFD_RELOC_CR16_SWITCH32", "BFD_RELOC_CRX_REL4", "BFD_RELOC_CRX_REL8", "BFD_RELOC_CRX_REL8_CMP", diff --git a/bfd/reloc.c b/bfd/reloc.c index cb9269b..525fe35 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -4570,6 +4570,12 @@ ENUMX BFD_RELOC_CR16_DISP24 ENUMX BFD_RELOC_CR16_DISP24a +ENUMX + BFD_RELOC_CR16_SWITCH8 +ENUMX + BFD_RELOC_CR16_SWITCH16 +ENUMX + BFD_RELOC_CR16_SWITCH32 ENUMDOC NS CR16 Relocations. |