From 7fac7ff4ae7bb9a3cf6be14d963944805c46a755 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 1 Oct 2007 15:55:44 +0000 Subject: [PATCH] Various CR16 fixes --- bfd/ChangeLog | 10 + bfd/bfd-in2.h | 3 + bfd/elf32-cr16.c | 398 ++++++++++++++------- bfd/libbfd.h | 3 + bfd/reloc.c | 6 + gas/ChangeLog | 5 + gas/config/tc-cr16.c | 802 +++++++++++++++++++++++------------------- include/elf/ChangeLog | 4 + include/elf/cr16.h | 3 + opcodes/ChangeLog | 5 + opcodes/cr16-opc.c | 6 +- 11 files changed, 750 insertions(+), 495 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 1445a2bbcaf..45180e34a39 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,13 @@ +2007-10-01 M R Swami Reddy + + * 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 * elflink.c: Formatting. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 09432780ae6..db9cd85028d 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 46664bcfcf2..d0f7fd19bdb 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 2d5b5b3dec0..7f10f46ed55 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 cb9269b08c0..525fe35b633 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. diff --git a/gas/ChangeLog b/gas/ChangeLog index 3bee322c4af..011d29bde96 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +2007-10-01 M R Swami Reddy + + * config/tc-cr16.c: Replaced 'tabs' with white spaces and + added R_CR16_DISP8 as default reloc type for b instructions. + 2007-09-30 H.J. Lu PR gas/5080 diff --git a/gas/config/tc-cr16.c b/gas/config/tc-cr16.c index 256feed3e33..31c62157446 100644 --- a/gas/config/tc-cr16.c +++ b/gas/config/tc-cr16.c @@ -141,92 +141,92 @@ l_cons (int nbytes) expression (&exp); if (*input_line_pointer == ':') - { - /* Bitfields. */ - long value = 0; - - for (;;) - { - unsigned long width; - - if (*input_line_pointer != ':') - { - input_line_pointer = hold; - break; - } - if (exp.X_op == O_absent) - { - as_warn (_("using a bit field width of zero")); - exp.X_add_number = 0; - exp.X_op = O_constant; - } - - if (exp.X_op != O_constant) - { - *input_line_pointer = '\0'; - as_bad (_("field width \"%s\" too complex for a bitfield"), hold); - *input_line_pointer = ':'; - demand_empty_rest_of_line (); - return; - } - - if ((width = exp.X_add_number) > - (unsigned int)(BITS_PER_CHAR * nbytes)) - { - as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes)); - width = BITS_PER_CHAR * nbytes; - } /* Too big. */ - - - if (width > bits_available) - { - /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */ - input_line_pointer = hold; - exp.X_add_number = value; - break; - } - - /* Skip ':'. */ - hold = ++input_line_pointer; - - expression (&exp); - if (exp.X_op != O_constant) - { - char cache = *input_line_pointer; - - *input_line_pointer = '\0'; - as_bad (_("field value \"%s\" too complex for a bitfield"), hold); - *input_line_pointer = cache; - demand_empty_rest_of_line (); - return; - } - - value |= ((~(-1 << width) & exp.X_add_number) - << ((BITS_PER_CHAR * nbytes) - bits_available)); - - if ((bits_available -= width) == 0 - || is_it_end_of_statement () - || *input_line_pointer != ',') - break; - - hold = ++input_line_pointer; - expression (&exp); - } - - exp.X_add_number = value; - exp.X_op = O_constant; - exp.X_unsigned = 1; - } + { + /* Bitfields. */ + long value = 0; + + for (;;) + { + unsigned long width; + + if (*input_line_pointer != ':') + { + input_line_pointer = hold; + break; + } + if (exp.X_op == O_absent) + { + as_warn (_("using a bit field width of zero")); + exp.X_add_number = 0; + exp.X_op = O_constant; + } + + if (exp.X_op != O_constant) + { + *input_line_pointer = '\0'; + as_bad (_("field width \"%s\" too complex for a bitfield"), hold); + *input_line_pointer = ':'; + demand_empty_rest_of_line (); + return; + } + + if ((width = exp.X_add_number) > + (unsigned int)(BITS_PER_CHAR * nbytes)) + { + as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes)); + width = BITS_PER_CHAR * nbytes; + } /* Too big. */ + + + if (width > bits_available) + { + /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */ + input_line_pointer = hold; + exp.X_add_number = value; + break; + } + + /* Skip ':'. */ + hold = ++input_line_pointer; + + expression (&exp); + if (exp.X_op != O_constant) + { + char cache = *input_line_pointer; + + *input_line_pointer = '\0'; + as_bad (_("field value \"%s\" too complex for a bitfield"), hold); + *input_line_pointer = cache; + demand_empty_rest_of_line (); + return; + } + + value |= ((~(-1 << width) & exp.X_add_number) + << ((BITS_PER_CHAR * nbytes) - bits_available)); + + if ((bits_available -= width) == 0 + || is_it_end_of_statement () + || *input_line_pointer != ',') + break; + + hold = ++input_line_pointer; + expression (&exp); + } + + exp.X_add_number = value; + exp.X_op = O_constant; + exp.X_unsigned = 1; + } if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c')) - code_label = 1; + code_label = 1; emit_expr (&exp, (unsigned int) nbytes); ++c; if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c')) - { - input_line_pointer +=3; - break; - } + { + input_line_pointer +=3; + break; + } } while ((*input_line_pointer++ == ',')); @@ -373,8 +373,8 @@ get_index_register_pair (char *reg_name) if (reg != NULL) { if ((reg->value.reg_val != 1) || (reg->value.reg_val != 7) - || (reg->value.reg_val != 9) || (reg->value.reg_val > 10)) - return reg->value.reg_val; + || (reg->value.reg_val != 9) || (reg->value.reg_val > 10)) + return reg->value.reg_val; as_bad (_("Unknown register pair - index relative mode: `%d'"), reg->value.reg_val); } @@ -478,9 +478,7 @@ reset_vars (char *op) int cr16_force_relocation (fixS *fix) { - /* REVISIT: Check if the "SWITCH_TABLE (fix)" should be added - if (generic_force_reloc (fix) || SWITCH_TABLE (fix)) */ - if (generic_force_reloc (fix)) + if (generic_force_reloc (fix) || SWITCH_TABLE (fix)) return 1; return 0; @@ -499,12 +497,12 @@ cr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp) case 2: rtype = BFD_RELOC_CR16_NUM16; break; case 4: if (code_label) - { - rtype = BFD_RELOC_CR16_NUM32a; - code_label = 0; - } + { + rtype = BFD_RELOC_CR16_NUM32a; + code_label = 0; + } else - rtype = BFD_RELOC_CR16_NUM32; + rtype = BFD_RELOC_CR16_NUM32; break; } @@ -534,21 +532,21 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP) switch (fixP->fx_r_type) { - case BFD_RELOC_CR16_NUM8: - fixP->fx_r_type = BFD_RELOC_CR16_NUM8; - break; - case BFD_RELOC_CR16_NUM16: - fixP->fx_r_type = BFD_RELOC_CR16_NUM16; - break; - case BFD_RELOC_CR16_NUM32: - fixP->fx_r_type = BFD_RELOC_CR16_NUM32; - break; - case BFD_RELOC_CR16_NUM32a: - fixP->fx_r_type = BFD_RELOC_CR16_NUM32a; - break; - default: - abort (); - break; + case BFD_RELOC_CR16_NUM8: + fixP->fx_r_type = BFD_RELOC_CR16_SWITCH8; + break; + case BFD_RELOC_CR16_NUM16: + fixP->fx_r_type = BFD_RELOC_CR16_SWITCH16; + break; + case BFD_RELOC_CR16_NUM32: + fixP->fx_r_type = BFD_RELOC_CR16_SWITCH32; + break; + case BFD_RELOC_CR16_NUM32a: + fixP->fx_r_type = BFD_RELOC_CR16_NUM32a; + break; + default: + abort (); + break; } } else @@ -613,10 +611,41 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fragS *fragP) { /* 'opcode' points to the start of the instruction, whether we need to change the instruction's fixed encoding. */ - bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; + char *opcode = fragP->fr_literal + fragP->fr_fix; + bfd_reloc_code_real_type reloc; subseg_change (sec, 0); + switch (fragP->fr_subtype) + { + case 0: + reloc = BFD_RELOC_CR16_DISP8; + break; + case 1: + /* If the subtype is not changed due to :m operand qualifier, + then no need to update the opcode value. */ + if ((int)opcode[1] != 0x18) + { + opcode[0] = (opcode[0] & 0xf0); + opcode[1] = 0x18; + } + reloc = BFD_RELOC_CR16_DISP16; + break; + case 2: + /* If the subtype is not changed due to :l operand qualifier, + then no need to update the opcode value. */ + if ((int)opcode[1] != 0) + { + opcode[2] = opcode[0]; + opcode[0] = opcode[1]; + opcode[1] = 0x0; + } + reloc = BFD_RELOC_CR16_DISP24; + break; + default: + abort(); + } + fix_new (fragP, fragP->fr_fix, bfd_get_reloc_size (bfd_reloc_type_lookup (stdoutput, reloc)), fragP->fr_symbol, fragP->fr_offset, 1, reloc); @@ -752,8 +781,8 @@ md_pcrel_from (fixS *fixp) static void initialise_reg_hash_table (struct hash_control ** hash_table, - const reg_entry * register_table, - const unsigned int num_entries) + const reg_entry * register_table, + const unsigned int num_entries) { const reg_entry * reg; const char *hashret; @@ -767,8 +796,8 @@ initialise_reg_hash_table (struct hash_control ** hash_table, { hashret = hash_insert (* hash_table, reg->name, (char *) reg); if (hashret) - as_fatal (_("Internal Error: Can't hash %s: %s"), - reg->name, hashret); + as_fatal (_("Internal Error: Can't hash %s: %s"), + reg->name, hashret); } } @@ -790,7 +819,7 @@ md_begin (void) const char *mnemonic = cr16_instruction[i].mnemonic; hashret = hash_insert (cr16_inst_hash, mnemonic, - (char *)(cr16_instruction + i)); + (char *)(cr16_instruction + i)); if (hashret != NULL && *hashret != '\0') as_fatal (_("Can't hash `%s': %s\n"), cr16_instruction[i].mnemonic, @@ -845,7 +874,7 @@ process_label_constant (char *str, ins * cr16_ins) case O_absent: /* Missing or bad expr becomes absolute 0. */ as_bad (_("missing or invalid displacement expression `%s' taken as 0"), - str); + str); cr16_ins->exp.X_op = O_constant; cr16_ins->exp.X_add_number = 0; cr16_ins->exp.X_add_symbol = NULL; @@ -865,105 +894,105 @@ process_label_constant (char *str, ins * cr16_ins) relocatable = 1; if (strneq (input_line_pointer, "@c", 2)) - symbol_with_at = 1; + symbol_with_at = 1; if (strneq (input_line_pointer, "@l", 2) - || strneq (input_line_pointer, ":l", 2)) - symbol_with_l = 1; + || strneq (input_line_pointer, ":l", 2)) + symbol_with_l = 1; if (strneq (input_line_pointer, "@m", 2) - || strneq (input_line_pointer, ":m", 2)) - symbol_with_m = 1; + || strneq (input_line_pointer, ":m", 2)) + symbol_with_m = 1; if (strneq (input_line_pointer, "@s", 2) - || strneq (input_line_pointer, ":s", 2)) - symbol_with_s = 1; + || strneq (input_line_pointer, ":s", 2)) + symbol_with_s = 1; switch (cur_arg->type) { - case arg_cr: - if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) - { - if (cur_arg->size == 20) - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; - else - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; - } - break; - - case arg_crp: - if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) - switch (instruction->size) - { - case 1: - switch (cur_arg->size) - { - case 0: - cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; - break; - case 4: - if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb")) - cr16_ins->rtype = BFD_RELOC_CR16_REGREL4; - else - cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a; - break; - default: break; - } - break; - case 2: - cr16_ins->rtype = BFD_RELOC_CR16_REGREL16; - break; - case 3: - if (cur_arg->size == 20) - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; - else - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; - break; - default: - break; - } - break; - - case arg_idxr: - if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; - break; - - case arg_idxrp: - if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) - switch (instruction->size) - { - case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break; - case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break; - case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break; - default: break; - } - break; - - case arg_c: - if (IS_INSN_MNEMONIC ("bal")) - cr16_ins->rtype = BFD_RELOC_CR16_DISP24; - else if (IS_INSN_TYPE (BRANCH_INS)) - { - if (symbol_with_s) - cr16_ins->rtype = BFD_RELOC_CR16_DISP8; - else if (symbol_with_m) - cr16_ins->rtype = BFD_RELOC_CR16_DISP16; - else - cr16_ins->rtype = BFD_RELOC_CR16_DISP24; - } - else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS) - || IS_INSN_TYPE (CSTBIT_INS)) - { - if (symbol_with_s) - as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str); - if (symbol_with_m) - cr16_ins->rtype = BFD_RELOC_CR16_ABS20; - else /* Default to (symbol_with_l) */ - cr16_ins->rtype = BFD_RELOC_CR16_ABS24; - } - else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) - cr16_ins->rtype = BFD_RELOC_CR16_DISP4; + case arg_cr: + if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) + { + if (cur_arg->size == 20) + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; + else + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; + } + break; + + case arg_crp: + if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) + switch (instruction->size) + { + case 1: + switch (cur_arg->size) + { + case 0: + cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; + break; + case 4: + if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb")) + cr16_ins->rtype = BFD_RELOC_CR16_REGREL4; + else + cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a; + break; + default: break; + } + break; + case 2: + cr16_ins->rtype = BFD_RELOC_CR16_REGREL16; + break; + case 3: + if (cur_arg->size == 20) + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; + else + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; + break; + default: + break; + } + break; + + case arg_idxr: + if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; + break; + + case arg_idxrp: + if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) + switch (instruction->size) + { + case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break; + case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break; + case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break; + default: break; + } + break; + + case arg_c: + if (IS_INSN_MNEMONIC ("bal")) + cr16_ins->rtype = BFD_RELOC_CR16_DISP24; + else if (IS_INSN_TYPE (BRANCH_INS)) + { + if (symbol_with_l) + cr16_ins->rtype = BFD_RELOC_CR16_DISP24; + else if (symbol_with_m) + cr16_ins->rtype = BFD_RELOC_CR16_DISP16; + else + cr16_ins->rtype = BFD_RELOC_CR16_DISP8; + } + else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS) + || IS_INSN_TYPE (CSTBIT_INS)) + { + if (symbol_with_s) + as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str); + if (symbol_with_m) + cr16_ins->rtype = BFD_RELOC_CR16_ABS20; + else /* Default to (symbol_with_l) */ + cr16_ins->rtype = BFD_RELOC_CR16_ABS24; + } + else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) + cr16_ins->rtype = BFD_RELOC_CR16_DISP4; break; case arg_ic: @@ -979,13 +1008,13 @@ process_label_constant (char *str, ins * cr16_ins) cr16_ins->rtype = BFD_RELOC_CR16_IMM32; } else if (IS_INSN_TYPE (ARITH_BYTE_INS)) - { - cr16_ins->rtype = BFD_RELOC_CR16_IMM16; - } + { + cr16_ins->rtype = BFD_RELOC_CR16_IMM16; + } break; default: break; - } + } break; default: @@ -1029,9 +1058,9 @@ getreg_image (reg r) { case CR16_R_REGTYPE: if (! is_procreg) - return reg->image; + return reg->image; else - IMAGE_ERR; + IMAGE_ERR; case CR16_P_REGTYPE: return reg->image; @@ -1097,10 +1126,10 @@ set_operand (char *operand, ins * cr16_ins) /* set the arg->rp, if reg is "r12" or "r13" or "14" or "15" */ if ((cur_arg->type != arg_rbase) - && ((getreg_image (cur_arg->r) == 12) - || (getreg_image (cur_arg->r) == 13) - || (getreg_image (cur_arg->r) == 14) - || (getreg_image (cur_arg->r) == 15))) + && ((getreg_image (cur_arg->r) == 12) + || (getreg_image (cur_arg->r) == 13) + || (getreg_image (cur_arg->r) == 14) + || (getreg_image (cur_arg->r) == 15))) { cur_arg->type = arg_crp; cur_arg->rp = cur_arg->r; @@ -1137,7 +1166,7 @@ set_operand (char *operand, ins * cr16_ins) cur_arg->type = arg_idxrp; } else - cur_arg->rp = -1; + cur_arg->rp = -1; operandE = operandS; /* Set displacement constant. */ @@ -1245,9 +1274,9 @@ parse_operand (char *operand, ins * cr16_ins) { case '$': if (strchr (operand, '(') != NULL) - cur_arg->type = arg_icr; + cur_arg->type = arg_icr; else - cur_arg->type = arg_ic; + cur_arg->type = arg_ic; goto set_params; break; @@ -1439,7 +1468,7 @@ static int is_bcc_insn (char * op) { if (!(streq (op, "bal") || streq (op, "beq0b") || streq (op, "bnq0b") - || streq (op, "beq0w") || streq (op, "bnq0w"))) + || streq (op, "beq0w") || streq (op, "bnq0w"))) if ((op[0] == 'b') && (get_b_cc (op) != NULL)) return 1; return 0; @@ -1540,18 +1569,18 @@ getidxregp_image (reg r) if (reg->type == CR16_RP_REGTYPE) { switch (reg->image) - { - case 0: return 0; break; - case 2: return 1; break; - case 4: return 2; break; - case 6: return 3; break; - case 8: return 4; break; - case 10: return 5; break; - case 3: return 6; break; - case 5: return 7; break; - default: - break; - } + { + case 0: return 0; break; + case 2: return 1; break; + case 4: return 2; break; + case 6: return 3; break; + case 8: return 4; break; + case 10: return 5; break; + case 3: return 6; break; + case 5: return 7; break; + default: + break; + } } IDX_RPAIR_IMAGE_ERR; @@ -1612,17 +1641,17 @@ getprocregp_image (reg r) r = r - MAX_REG; switch (r) { - case 4: pregptab_disp = 1; break; - case 6: pregptab_disp = 2; break; - case 8: - case 9: - case 10: - pregptab_disp = 3; break; - case 12: - pregptab_disp = 4; break; - case 14: - pregptab_disp = 5; break; - default: break; + case 4: pregptab_disp = 1; break; + case 6: pregptab_disp = 2; break; + case 8: + case 9: + case 10: + pregptab_disp = 3; break; + case 12: + pregptab_disp = 4; break; + case 14: + pregptab_disp = 5; break; + default: break; } reg = &cr16_pregptab[r - pregptab_disp]; } @@ -1679,16 +1708,16 @@ print_constant (int nbits, int shift, argument *arg) case 32: case 28: /* mask the upper part of the constant, that is, the bits - going to the lowest byte of output_opcode[0]. - The upper part of output_opcode[1] is always filled, - therefore it is always masked with 0xFFFF. */ + going to the lowest byte of output_opcode[0]. + The upper part of output_opcode[1] is always filled, + therefore it is always masked with 0xFFFF. */ mask = (1 << (nbits - 16)) - 1; /* Divide the constant between two consecutive words : - 0 1 2 3 - +---------+---------+---------+---------+ - | | X X X X | x X x X | | - +---------+---------+---------+---------+ - output_opcode[0] output_opcode[1] */ + 0 1 2 3 + +---------+---------+---------+---------+ + | | X X X X | x X x X | | + +---------+---------+---------+---------+ + output_opcode[0] output_opcode[1] */ CR16_PRINT (0, (constant >> WORD_SHIFT) & mask, 0); CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); @@ -1700,70 +1729,70 @@ print_constant (int nbits, int shift, argument *arg) case 22: case 20: /* mask the upper part of the constant, that is, the bits - going to the lowest byte of output_opcode[0]. - The upper part of output_opcode[1] is always filled, - therefore it is always masked with 0xFFFF. */ + going to the lowest byte of output_opcode[0]. + The upper part of output_opcode[1] is always filled, + therefore it is always masked with 0xFFFF. */ mask = (1 << (nbits - 16)) - 1; /* Divide the constant between two consecutive words : - 0 1 2 3 - +---------+---------+---------+---------+ - | | X X X X | - X - X | | - +---------+---------+---------+---------+ - output_opcode[0] output_opcode[1] */ + 0 1 2 3 + +---------+---------+---------+---------+ + | | X X X X | - X - X | | + +---------+---------+---------+---------+ + output_opcode[0] output_opcode[1] */ if ((instruction->size > 2) && (shift == WORD_SHIFT)) - { - if (arg->type == arg_idxrp) - { - CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0); - CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); - } - else - { - CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0); - CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); - } - } + { + if (arg->type == arg_idxrp) + { + CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0); + CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); + } + else + { + CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0); + CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); + } + } else - CR16_PRINT (0, constant, shift); + CR16_PRINT (0, constant, shift); break; case 14: if (arg->type == arg_idxrp) - { - if (instruction->size == 2) - { - CR16_PRINT (0, ((constant)&0xf), shift); // 0-3 bits - CR16_PRINT (0, ((constant>>4)&0x3), (shift+20)); // 4-5 bits - CR16_PRINT (0, ((constant>>6)&0x3), (shift+14)); // 6-7 bits - CR16_PRINT (0, ((constant>>8)&0x3f), (shift+8)); // 8-13 bits - } - else - CR16_PRINT (0, constant, shift); - } + { + if (instruction->size == 2) + { + CR16_PRINT (0, ((constant) & 0xf), shift); /* 0-3 bits. */ + CR16_PRINT (0, ((constant >> 4) & 0x3), (shift + 20)); /* 4-5 bits. */ + CR16_PRINT (0, ((constant >> 6) & 0x3), (shift + 14)); /* 6-7 bits. */ + CR16_PRINT (0, ((constant >> 8) & 0x3f), (shift + 8)); /* 8-13 bits. */ + } + else + CR16_PRINT (0, constant, shift); + } break; case 16: case 12: /* When instruction size is 3 and 'shift' is 16, a 16-bit constant is - always filling the upper part of output_opcode[1]. If we mistakenly - write it to output_opcode[0], the constant prefix (that is, 'match') - will be overriden. - 0 1 2 3 - +---------+---------+---------+---------+ - | 'match' | | X X X X | | - +---------+---------+---------+---------+ - output_opcode[0] output_opcode[1] */ + always filling the upper part of output_opcode[1]. If we mistakenly + write it to output_opcode[0], the constant prefix (that is, 'match') + will be overriden. + 0 1 2 3 + +---------+---------+---------+---------+ + | 'match' | | X X X X | | + +---------+---------+---------+---------+ + output_opcode[0] output_opcode[1] */ if ((instruction->size > 2) && (shift == WORD_SHIFT)) - CR16_PRINT (1, constant, WORD_SHIFT); + CR16_PRINT (1, constant, WORD_SHIFT); else - CR16_PRINT (0, constant, shift); + CR16_PRINT (0, constant, shift); break; case 8: - CR16_PRINT (0, ((constant/2)&0xf), shift); - CR16_PRINT (0, ((constant/2)>>4), (shift+8)); + CR16_PRINT (0, ((constant / 2) & 0xf), shift); + CR16_PRINT (0, ((constant / 2) >> 4), (shift + 8)); break; default: @@ -1810,35 +1839,35 @@ print_operand (int nbits, int shift, argument *arg) +-----------------------------+ */ if (instruction->size == 3) - { - CR16_PRINT (0, getidxregp_image (arg->rp), 0); - if (getreg_image (arg->i_r) == 12) - CR16_PRINT (0, 0, 3); - else - CR16_PRINT (0, 1, 3); - } + { + CR16_PRINT (0, getidxregp_image (arg->rp), 0); + if (getreg_image (arg->i_r) == 12) + CR16_PRINT (0, 0, 3); + else + CR16_PRINT (0, 1, 3); + } else - { - CR16_PRINT (0, getidxregp_image (arg->rp), 16); - if (getreg_image (arg->i_r) == 12) - CR16_PRINT (0, 0, 19); - else - CR16_PRINT (0, 1, 19); - } + { + CR16_PRINT (0, getidxregp_image (arg->rp), 16); + if (getreg_image (arg->i_r) == 12) + CR16_PRINT (0, 0, 19); + else + CR16_PRINT (0, 1, 19); + } print_constant (nbits, shift, arg); break; case arg_idxr: if (getreg_image (arg->i_r) == 12) - if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") - || IS_INSN_MNEMONIC ("tbitb")) - CR16_PRINT (0, 0, 23); - else CR16_PRINT (0, 0, 24); + if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") + || IS_INSN_MNEMONIC ("tbitb")) + CR16_PRINT (0, 0, 23); + else CR16_PRINT (0, 0, 24); else - if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") - || IS_INSN_MNEMONIC ("tbitb")) - CR16_PRINT (0, 1, 23); - else CR16_PRINT (0, 1, 24); + if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") + || IS_INSN_MNEMONIC ("tbitb")) + CR16_PRINT (0, 1, 23); + else CR16_PRINT (0, 1, 24); print_constant (nbits, shift, arg); break; @@ -1861,16 +1890,16 @@ print_operand (int nbits, int shift, argument *arg) case arg_crp: print_constant (nbits, shift , arg); if (instruction->size > 1) - CR16_PRINT (0, getregp_image (arg->rp), (shift + 16)); + CR16_PRINT (0, getregp_image (arg->rp), (shift + 16)); else if (IS_INSN_TYPE (LD_STOR_INS) || (IS_INSN_TYPE (CSTBIT_INS))) - { - if (instruction->size == 2) - CR16_PRINT (0, getregp_image (arg->rp), (shift - 8)); - else if (instruction->size == 1) - CR16_PRINT (0, getregp_image (arg->rp), 16); - } + { + if (instruction->size == 2) + CR16_PRINT (0, getregp_image (arg->rp), (shift - 8)); + else if (instruction->size == 1) + CR16_PRINT (0, getregp_image (arg->rp), 16); + } else - CR16_PRINT (0, getregp_image (arg->rp), shift); + CR16_PRINT (0, getregp_image (arg->rp), shift); break; default: @@ -1949,11 +1978,11 @@ check_range (long *num, int bits, int unsigned flags, int update) if (value == 0xB || value == 0x9) return OP_OUT_OF_RANGE; else if (value == -1) - { - if (update) - *num = 9; - return retval; - } + { + if (update) + *num = 9; + return retval; + } } if (flags & OP_ESC1) @@ -1980,7 +2009,7 @@ check_range (long *num, int bits, int unsigned flags, int update) else if (flags & OP_NEG) { max = - 1; - min = - ((1 << (bits - 1))-1); + min = - ((1 << (bits - 1)) - 1); if ((value > max) || (value < min)) retval = OP_OUT_OF_RANGE; } @@ -2011,17 +2040,17 @@ warn_if_needed (ins *insn) unsigned int count = insn->arg[0].constant, reg_val; /* Check if count operand caused to save/retrive the RA twice - to generate warning message. */ + to generate warning message. */ if (insn->nargs > 2) { reg_val = getreg_image (insn->arg[1].r); if ( ((reg_val == 9) && (count > 7)) - || ((reg_val == 10) && (count > 6)) - || ((reg_val == 11) && (count > 5)) - || ((reg_val == 12) && (count > 4)) - || ((reg_val == 13) && (count > 2)) - || ((reg_val == 14) && (count > 0))) + || ((reg_val == 10) && (count > 6)) + || ((reg_val == 11) && (count > 5)) + || ((reg_val == 12) && (count > 4)) + || ((reg_val == 13) && (count > 2)) + || ((reg_val == 14) && (count > 0))) as_warn (_("RA register is saved twice.")); /* Check if the third operand is "RA" or "ra" */ @@ -2036,10 +2065,10 @@ warn_if_needed (ins *insn) /* If register is a register pair ie r12/r13/r14 in operand1, then the count constant should be validated. */ if (((reg_val == 11) && (count > 7)) - || ((reg_val == 12) && (count > 6)) - || ((reg_val == 13) && (count > 4)) - || ((reg_val == 14) && (count > 2)) - || ((reg_val == 15) && (count > 0))) + || ((reg_val == 12) && (count > 6)) + || ((reg_val == 13) && (count > 4)) + || ((reg_val == 14) && (count > 2)) + || ((reg_val == 15) && (count > 0))) as_bad (_("`%s' Illegal count-register combination."), ins_parse); } else @@ -2187,14 +2216,14 @@ assemble_insn (char *mnemonic, ins *insn) /* If 'bal' instruction size is '2' and reg operand is not 'ra' then goto next instruction. */ if (IS_INSN_MNEMONIC ("bal") && (i == 0) - && (instruction->size == 2) && (insn->arg[i].rp != 14)) + && (instruction->size == 2) && (insn->arg[i].rp != 14)) goto next_insn; /* If 'storb' instruction with 'sp' reg and 16-bit disp of * reg-pair, leads to undifined trap, so this should use * 20-bit disp of reg-pair. */ if (IS_INSN_MNEMONIC ("storb") && (instruction->size == 2) - && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp)) + && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp)) goto next_insn; /* Only check range - don't update the constant's value, since the @@ -2216,7 +2245,7 @@ assemble_insn (char *mnemonic, ins *insn) determined) is sufficient. */ else if ((insn->arg[i].X_op == O_symbol) && ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize - > cur_size[i])) + > cur_size[i])) goto next_insn; } found_const_within_range = 1; @@ -2241,15 +2270,15 @@ next_insn: { switch (const_err) { - case OP_OUT_OF_RANGE: - as_bad (_("Operand out of range (arg %d)"), invalid_const); - break; - case OP_NOT_EVEN: - as_bad (_("Operand has odd displacement (arg %d)"), invalid_const); - break; - default: - as_bad (_("Illegal operand (arg %d)"), invalid_const); - break; + case OP_OUT_OF_RANGE: + as_bad (_("Operand out of range (arg %d)"), invalid_const); + break; + case OP_NOT_EVEN: + as_bad (_("Operand has odd displacement (arg %d)"), invalid_const); + break; + default: + as_bad (_("Illegal operand (arg %d)"), invalid_const); + break; } } @@ -2321,28 +2350,61 @@ print_insn (ins *insn) words[j++] = output_opcode[i] & 0xFFFF; } - insn_size = instruction->size; - this_frag = frag_more (insn_size * 2); - /* Handle relocation. */ - if ((relocatable) && (insn->rtype != BFD_RELOC_NONE)) + if ((instruction->flags & RELAXABLE) && relocatable) + { + int relax_subtype; + /* Write the maximal instruction size supported. */ + insn_size = INSN_MAX_SIZE; + + if (IS_INSN_TYPE (BRANCH_INS)) + { + switch (insn->rtype) + { + case BFD_RELOC_CR16_DISP24: + relax_subtype = 2; + break; + case BFD_RELOC_CR16_DISP16: + relax_subtype = 1; + break; + default: + relax_subtype = 0; + break; + } + } + else + abort (); + + this_frag = frag_var (rs_machine_dependent, insn_size *2, + 4, relax_subtype, + insn->exp.X_add_symbol, + insn->exp.X_add_number, + 0); + } + else { - reloc_howto_type *reloc_howto; - int size; + insn_size = instruction->size; + this_frag = frag_more (insn_size * 2); - reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype); + if ((relocatable) && (insn->rtype != BFD_RELOC_NONE)) + { + reloc_howto_type *reloc_howto; + int size; - if (!reloc_howto) - abort (); + reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype); + + if (!reloc_howto) + abort (); - size = bfd_get_reloc_size (reloc_howto); + size = bfd_get_reloc_size (reloc_howto); - if (size < 1 || size > 4) - abort (); + if (size < 1 || size > 4) + abort (); - fix_new_exp (frag_now, this_frag - frag_now->fr_literal, - size, &insn->exp, reloc_howto->pc_relative, - insn->rtype); + fix_new_exp (frag_now, this_frag - frag_now->fr_literal, + size, &insn->exp, reloc_howto->pc_relative, + insn->rtype); + } } /* Verify a 2-byte code alignment. */ @@ -2410,14 +2472,14 @@ md_assemble (char *op) instruction = (const inst *) hash_find (cr16_inst_hash, op); parse_operands (&cr16_ins, param1); if (((&cr16_ins)->arg[0].type == arg_ic) - && ((&cr16_ins)->arg[0].constant >= 0)) + && ((&cr16_ins)->arg[0].constant >= 0)) { if (streq ("lshb", op)) - op = "ashub"; + op = "ashub"; else if (streq ("lshd", op)) - op = "ashud"; - else - op = "ashuw"; + op = "ashud"; + else + op = "ashuw"; } } diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index dd354e860b1..76449a274ff 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2007-10-01 M R Swami Reddy + + * cr16.h: Updated with new relocaction macros. + 2007-09-17 H.J. Lu PR binutils/3281 diff --git a/include/elf/cr16.h b/include/elf/cr16.h index e3f6c50b126..adb243dc9a6 100644 --- a/include/elf/cr16.h +++ b/include/elf/cr16.h @@ -51,6 +51,9 @@ START_RELOC_NUMBERS(elf_cr16_reloc_type) RELOC_NUMBER (R_CR16_DISP16, 23) RELOC_NUMBER (R_CR16_DISP24, 24) RELOC_NUMBER (R_CR16_DISP24a, 25) + RELOC_NUMBER (R_CR16_SWITCH8, 26) + RELOC_NUMBER (R_CR16_SWITCH16, 27) + RELOC_NUMBER (R_CR16_SWITCH32, 28) END_RELOC_NUMBERS(R_CR16_MAX) #endif /* _ELF_CR16_H */ diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index a12b90fc416..4bf8849ae30 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,8 @@ +2007-10-01 M R Swami Reddy + + * cr16-opc.c: Updated the branch on condition instructions with + RELAXABLE flag. + 2007-09-30 H.J. Lu * 386-dis.c (prefix_table): Reformat comment. diff --git a/opcodes/cr16-opc.c b/opcodes/cr16-opc.c index 081c63d8206..55c03818eb5 100644 --- a/opcodes/cr16-opc.c +++ b/opcodes/cr16-opc.c @@ -160,11 +160,11 @@ const inst cr16_instruction[] = /* Create a conditional branch instruction. */ #define BRANCH_INST(NAME, OPC) \ /* opc4 c4 dispe9 */ \ - {NAME, 1, OPC, 28, BRANCH_INS, {{cc,20}, {dispe9,16}}}, \ + {NAME, 1, OPC, 28, BRANCH_INS | RELAXABLE, {{cc,20}, {dispe9,16}}},\ /* opc4 c4 disps17 */ \ - {NAME, 2, ((OPC<<4)+0x8), 24, BRANCH_INS, {{cc,20}, {disps17,0}}}, \ + {NAME, 2, ((OPC<<4)+0x8), 24, BRANCH_INS | RELAXABLE, {{cc,20}, {disps17,0}}},\ /* opc4 c4 disps25 */ \ - {NAME, 3, (OPC<<4), 16 , BRANCH_INS, {{cc,4}, {disps25,16}}} + {NAME, 3, (OPC<<4), 16 , BRANCH_INS | RELAXABLE, {{cc,4}, {disps25,16}}} BRANCH_INST ("b", 0x1), -- 2.39.5