From 6772dd07c44296695b6b99e7a007ebb99948a364 Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Feb 24 2006 22:10:36 +0000 Subject: [include/elf] * m32c.h: Add relax relocs. [cpu] * m32c.cpu (RL_TYPE): New attribute, with macros. (Lab-8-24): Add RELAX. (unary-insn-defn-g, binary-arith-imm-dst-defn, binary-arith-imm4-dst-defn): Add 1ADDR attribute. (binary-arith-src-dst-defn): Add 2ADDR attribute. (jcnd16-5, jcnd16, jcnd32, jmp16.s, jmp16.b, jmp16.w, jmp16.a, jmp32.s, jmp32.b, jmp32.w, jmp32.a, jsr16.w, jsr16.a): Add JUMP attribute. (jsri16, jsri32): Add 1ADDR attribute. (jsr32.w, jsr32.a): Add JUMP attribute. [opcodes] * m32c-desc.c: Regenerate with linker relaxation attributes. * m32c-desc.h: Likewise. * m32c-dis.c: Likewise. * m32c-opc.c: Likewise. [gas] * config/tc-m32c.h (md_apply_fix): Define to m32c_apply_fix. (tc_gen_reloc): Don't define. * config/tc-m32c.c (rl_for, relaxable): New convenience macros. (OPTION_LINKRELAX): New. (md_longopts): Add it. (m32c_relax): New. (md_parse_options): Set it. (md_assemble): Emit relaxation relocs as needed. (md_convert_frag): Emit relaxation relocs as needed. (md_cgen_lookup_reloc): Add LAB_8_8 and LAB_8_16. (m32c_apply_fix): New. (tc_gen_reloc): New. (m32c_force_relocation): Force out jump relocs when relaxing. (m32c_fix_adjustable): Return false if relaxing. [bfd] * elf32-m32c.c (m32c_elf_howto_table): Add relaxation relocs. (m32c_elf_relocate_section): Don't relocate them. (compare_reloc): New. (relax_reloc): Remove. (m32c_offset_for_reloc): New. (m16c_addr_encodings): New. (m16c_jmpaddr_encodings): New. (m32c_addr_encodings): New. (m32c_elf_relax_section): Relax jumps and address displacements. (m32c_elf_relax_delete_bytes): Adjust for internal syms. Fix up short jumps. * reloc.c: Add m32c relax relocs. * libbfd.h: Regenerate. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 89077f8..646a849 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,21 @@ +2006-02-24 DJ Delorie + + * elf32-m32c.c (m32c_elf_howto_table): Add relaxation relocs. + (m32c_elf_relocate_section): Don't relocate them. + (compare_reloc): New. + (relax_reloc): Remove. + (m32c_offset_for_reloc): New. + (m16c_addr_encodings): New. + (m16c_jmpaddr_encodings): New. + (m32c_addr_encodings): New. + (m32c_elf_relax_section): Relax jumps and address displacements. + (m32c_elf_relax_delete_bytes): Adjust for internal syms. Fix up + short jumps. + + * reloc.c: Add m32c relax relocs. + * libbfd.h: Regenerate. + * bfd-in2.h: Regenerate. + 2006-02-24 H.J. Lu PR ld/2218 diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 6095ce5..195e8a0 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -8,8 +8,7 @@ /* Main header file for the bfd library -- portable access to object files. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Cygnus Support. @@ -3217,6 +3216,9 @@ of the container. */ /* Renesas M16C/M32C Relocations. */ BFD_RELOC_M32C_HI8, + BFD_RELOC_M32C_RL_JUMP, + BFD_RELOC_M32C_RL_1ADDR, + BFD_RELOC_M32C_RL_2ADDR, /* Renesas M32R (formerly Mitsubishi M32R) relocs. This is a 24 bit absolute address. */ diff --git a/bfd/elf32-m32c.c b/bfd/elf32-m32c.c index 35136af..8004795 100644 --- a/bfd/elf32-m32c.c +++ b/bfd/elf32-m32c.c @@ -1,5 +1,5 @@ /* M16C/M32C specific support for 32-bit ELF. - Copyright (C) 2005 + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -74,7 +74,7 @@ static reloc_howto_type m32c_elf_howto_table [] = "R_M32C_16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ + 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_M32C_24, /* type */ @@ -88,7 +88,7 @@ static reloc_howto_type m32c_elf_howto_table [] = "R_M32C_24", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0x00ffffff, /* dst_mask */ + 0xffffff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_M32C_32, /* type */ @@ -116,7 +116,7 @@ static reloc_howto_type m32c_elf_howto_table [] = "R_M32C_8_PCREL", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0x000000ff, /* dst_mask */ + 0xff, /* dst_mask */ TRUE), /* pcrel_offset */ HOWTO (R_M32C_16_PCREL, /* type */ @@ -130,7 +130,7 @@ static reloc_howto_type m32c_elf_howto_table [] = "R_M32C_16_PCREL", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0, /* dst_mask */ + 0xffff, /* dst_mask */ TRUE), /* pcrel_offset */ HOWTO (R_M32C_8, /* type */ @@ -144,7 +144,7 @@ static reloc_howto_type m32c_elf_howto_table [] = "R_M32C_8", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0x000000ff, /* dst_mask */ + 0xff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_M32C_LO16, /* type */ @@ -158,7 +158,7 @@ static reloc_howto_type m32c_elf_howto_table [] = "R_M32C_LO16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ + 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_M32C_HI8, /* type */ @@ -172,7 +172,7 @@ static reloc_howto_type m32c_elf_howto_table [] = "R_M32C_HI8", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0x000000ff, /* dst_mask */ + 0xff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_M32C_HI16, /* type */ @@ -186,8 +186,51 @@ static reloc_howto_type m32c_elf_howto_table [] = "R_M32C_HI16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ + 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ + + HOWTO (R_M32C_RL_JUMP, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_M32C_RL_JUMP", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_M32C_RL_1ADDR, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_M32C_RL_1ADDR", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_M32C_RL_2ADDR, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_M32C_RL_2ADDR", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + }; /* Map BFD reloc types to M32C ELF reloc types. */ @@ -209,7 +252,10 @@ static const struct m32c_reloc_map m32c_reloc_map [] = { BFD_RELOC_8, R_M32C_8 }, { BFD_RELOC_LO16, R_M32C_LO16 }, { BFD_RELOC_HI16, R_M32C_HI16 }, - { BFD_RELOC_M32C_HI8, R_M32C_HI8 } + { BFD_RELOC_M32C_HI8, R_M32C_HI8 }, + { BFD_RELOC_M32C_RL_JUMP, R_M32C_RL_JUMP }, + { BFD_RELOC_M32C_RL_1ADDR, R_M32C_RL_1ADDR }, + { BFD_RELOC_M32C_RL_2ADDR, R_M32C_RL_2ADDR } }; static reloc_howto_type * @@ -316,6 +362,13 @@ m32c_elf_relocate_section int r_type; r_type = ELF32_R_TYPE (rel->r_info); + + /* These are only used for relaxing; we don't actually relocate + anything with them, so skip them. */ + if (r_type == R_M32C_RL_JUMP + || r_type == R_M32C_RL_1ADDR + || r_type == R_M32C_RL_2ADDR) + continue; r_symndx = ELF32_R_SYM (rel->r_info); @@ -344,7 +397,7 @@ m32c_elf_relocate_section h = NULL; sym = NULL; sec = NULL; - + if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; @@ -355,7 +408,7 @@ m32c_elf_relocate_section name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; + name = (sym->st_name == 0) ? bfd_section_name (input_bfd, sec) : name; } else { @@ -439,6 +492,17 @@ m32c_elf_relocate_section break; } +#if 0 + printf("relocate %s at %06lx relocation %06lx addend %ld ", + m32c_elf_howto_table[ELF32_R_TYPE(rel->r_info)].name, + rel->r_offset, relocation, rel->r_addend); + { + int i; + for (i=0; i<4; i++) + printf(" %02x", contents[rel->r_offset+i]); + printf("\n"); + } +#endif r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, relocation, rel->r_addend); @@ -1143,169 +1207,166 @@ m32c_elf_relax_plt_section (bfd *dynobj, return TRUE; } -struct relax_reloc_s +static int +compare_reloc (const void *e1, const void *e2) { - int machine; - int opcode_mask; - bfd_vma opcode; /* original opcode or insn part */ - int relax_backward; /* lbound */ - int relax_forward; /* hbound */ - int value_shift; - int mask; - int new_opcode; /* new opcode */ - int old_reloc; /* old relocation */ - int new_reloc; /* new relocation */ - int use_pcrel; - int delete_n; /* # bytes differ between original and new */ -}; -static struct relax_reloc_s relax_reloc [] = - { -#if 0 - { - bfd_mach_m16c, - 0xff, - 0xfc, /* jmp.a */ - -32768, - 32767, - 2, - 0xffffff00, - 0xf4, /* jmp.w */ - R_M32C_8_ELABEL24, - R_M32C_8_PCREL16, - 1, - 1, - }, - { - bfd_mach_m32c, - 0xff, - 0xcc, /* jmp.a */ - -32768, - 32767, - 2, - 0xffffff00, - 0xce, /* jmp.w */ - R_M32C_8_ELABEL24, - R_M32C_8_PCREL16, - 1, - 1, - }, - { - bfd_mach_m32c, - 0xff, - 0xcd, /* jsr.a */ - -32768, - 32767, - 2, - 0xffffff00, - 0xcf, /* jsr.w */ - R_M32C_8_ELABEL24, - R_M32C_8_PCREL16, - 1, - 1, - }, - { - bfd_mach_m16c, - 0xff, - 0xf4, /* jmp.w */ - -128, - 127, - 2, - 0xffffff00, - 0xfe, /* jmp.b */ - R_M32C_8_PCREL16, - R_M32C_8_PCREL8, - 1, - 1, - }, - { - bfd_mach_m32c, - 0xff, - 0xce, /* jmp.w */ - -128, - 127, - 2, - 0xffffff00, - 0xbb, /* jmp.b */ - R_M32C_8_PCREL16, - R_M32C_8_PCREL8, - 1, - 1, - }, - { - bfd_mach_m32c, - 0xc0f6, - 0x8096, /* dest */ - 0, - 0xffff, - 3, - 0xffff3fff, - 0xc000, /* abs16 */ - R_M32C_24_ABS24, - R_M32C_24_ABS16, - 0, - 1, - }, - { - bfd_mach_m32c, - 0xc0f6, - 0x80a6, /* dest */ - 0, - 0xffff, - 4, - 0xffff3fff, - 0xc000, /* abs16 */ - R_M32C_32_ABS24, - R_M32C_32_ABS16, - 0, - 1, - }, - { - bfd_mach_m32c, - 0xc0f6, - 0x80b6, /* dest */ - 0, - 0xffff, - 5, - 0xffff3fff, - 0xc000, /* abs16 */ - R_M32C_40_ABS24, - R_M32C_40_ABS16, - 0, - 1, - }, - { - bfd_mach_m32c, - 0x30f0, - 0x20b0, /* src */ - 0, - 0xffff, - 2, - 0xffffcfff, - 0x3000, /* abs16 */ - R_M32C_16_ABS24, - R_M32C_16_ABS16, - 0, - 1, - }, + const Elf_Internal_Rela *i1 = (const Elf_Internal_Rela *) e1; + const Elf_Internal_Rela *i2 = (const Elf_Internal_Rela *) e2; + + if (i1->r_offset == i2->r_offset) + return 0; + else + return i1->r_offset < i2->r_offset ? -1 : 1; +} + +#define OFFSET_FOR_RELOC(rel) m32c_offset_for_reloc (abfd, sec, rel, symtab_hdr, shndx_buf, intsyms) +static bfd_vma +m32c_offset_for_reloc (bfd *abfd, + asection * sec, + Elf_Internal_Rela *rel, + Elf_Internal_Shdr *symtab_hdr, + Elf_External_Sym_Shndx *shndx_buf, + Elf_Internal_Sym *intsyms) +{ + bfd_vma symval; + + /* Get the value of the symbol referred to by the reloc. */ + if (ELF32_R_SYM (rel->r_info) < symtab_hdr->sh_info) { - bfd_mach_m32c, - 0xc086, - 0x8086, /* dest */ - 0, - 0xffff, - 2, - 0xffff3fff, - 0xc000, /* abs16 */ - R_M32C_16_ABS24, - R_M32C_16_ABS16, - 0, - 1, - }, -#endif + /* A local symbol. */ + Elf_Internal_Sym *isym; + Elf_External_Sym_Shndx *shndx; + + isym = intsyms + ELF32_R_SYM (rel->r_info); + shndx = shndx_buf + (shndx_buf ? ELF32_R_SYM (rel->r_info) : 0); + + symval = (isym->st_value + + sec->output_section->vma + + sec->output_offset); + } + else { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + unsigned long indx; + struct elf_link_hash_entry *h; + + /* An external symbol. */ + indx = ELF32_R_SYM (rel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + /* This appears to be a reference to an undefined + symbol. Just ignore it--it will be caught by the + regular reloc processing. */ + return 0; + + symval = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); } - }; + return symval; +} + +static int bytes_saved = 0; + +static int bytes_to_reloc[] = { + R_M32C_NONE, + R_M32C_8, + R_M32C_16, + R_M32C_24, + R_M32C_32 +}; + +/* What we use the bits in a relax reloc addend (R_M32C_RL_*) for. */ + +/* Mask for the number of relocs associated with this insn. */ +#define RLA_RELOCS 0x0000000f +/* Number of bytes gas emitted (before gas's relaxing) */ +#define RLA_NBYTES 0x00000ff0 + +/* If the displacement is within the given range and the new encoding + differs from the old encoding (the index), then the insn can be + relaxed to the new encoding. */ +typedef struct { + int bytes; + unsigned int max_disp; + unsigned char new_encoding; +} EncodingTable; + +static EncodingTable m16c_addr_encodings[] = { + { 0, 0, 0 }, /* R0 */ + { 0, 0, 1 }, /* R1 */ + { 0, 0, 2 }, /* R2 */ + { 0, 0, 3 }, /* R3 */ + { 0, 0, 4 }, /* A0 */ + { 0, 0, 5 }, /* A1 */ + { 0, 0, 6 }, /* [A0] */ + { 0, 0, 7 }, /* [A1] */ + { 1, 0, 6 }, /* udsp:8[A0] */ + { 1, 0, 7 }, /* udsp:8[A1] */ + { 1, 0, 10 }, /* udsp:8[SB] */ + { 1, 0, 11 }, /* sdsp:8[FB] */ + { 2, 255, 8 }, /* udsp:16[A0] */ + { 2, 255, 9 }, /* udsp:16[A1] */ + { 2, 255, 10 }, /* udsp:16[SB] */ + { 2, 0, 15 }, /* abs:16 */ +}; + +static EncodingTable m16c_jmpaddr_encodings[] = { + { 0, 0, 0 }, /* R0 */ + { 0, 0, 1 }, /* R1 */ + { 0, 0, 2 }, /* R2 */ + { 0, 0, 3 }, /* R3 */ + { 0, 0, 4 }, /* A0 */ + { 0, 0, 5 }, /* A1 */ + { 0, 0, 6 }, /* [A0] */ + { 0, 0, 7 }, /* [A1] */ + { 1, 0, 6 }, /* udsp:8[A0] */ + { 1, 0, 7 }, /* udsp:8[A1] */ + { 1, 0, 10 }, /* udsp:8[SB] */ + { 1, 0, 11 }, /* sdsp:8[FB] */ + { 3, 255, 8 }, /* udsp:20[A0] */ + { 3, 255, 9 }, /* udsp:20[A1] */ + { 2, 255, 10 }, /* udsp:16[SB] */ + { 2, 0, 15 }, /* abs:16 */ +}; + +static EncodingTable m32c_addr_encodings[] = { + { 0, 0, 0 }, /* [A0] */ + { 0, 0, 1 }, /* [A1] */ + { 0, 0, 2 }, /* A0 */ + { 0, 0, 3 }, /* A1 */ + { 1, 0, 0 }, /* udsp:8[A0] */ + { 1, 0, 1 }, /* udsp:8[A1] */ + { 1, 0, 6 }, /* udsp:8[SB] */ + { 1, 0, 7 }, /* sdsp:8[FB] */ + { 2, 255, 4 }, /* udsp:16[A0] */ + { 2, 255, 5 }, /* udsp:16[A1] */ + { 2, 255, 6 }, /* udsp:16[SB] */ + { 2, 127, 7 }, /* sdsp:16[FB] */ + { 3, 65535, 8 }, /* udsp:24[A0] */ + { 3, 65535, 9 }, /* udsp:24[A1] */ + { 3, 65535, 15 }, /* abs24 */ + { 2, 0, 15 }, /* abs16 */ + { 0, 0, 16 }, /* R2 */ + { 0, 0, 17 }, /* R3 */ + { 0, 0, 18 }, /* R0 */ + { 0, 0, 19 }, /* R1 */ + { 0, 0, 20 }, /* */ + { 0, 0, 21 }, /* */ + { 0, 0, 22 }, /* */ + { 0, 0, 23 }, /* */ + { 0, 0, 24 }, /* */ + { 0, 0, 25 }, /* */ + { 0, 0, 26 }, /* */ + { 0, 0, 27 }, /* */ + { 0, 0, 28 }, /* */ + { 0, 0, 29 }, /* */ + { 0, 0, 30 }, /* */ + { 0, 0, 31 }, /* */ +}; + static bfd_boolean m32c_elf_relax_section (bfd * abfd, @@ -1317,11 +1378,11 @@ m32c_elf_relax_section Elf_Internal_Shdr *shndx_hdr; Elf_Internal_Rela *internal_relocs; Elf_Internal_Rela *free_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; + Elf_Internal_Rela *irel, *irelend, *srel; bfd_byte * contents = NULL; bfd_byte * free_contents = NULL; - Elf32_External_Sym *extsyms = NULL; - Elf32_External_Sym *free_extsyms = NULL; + Elf_Internal_Sym *intsyms = NULL; + Elf_Internal_Sym *free_intsyms = NULL; Elf_External_Sym_Shndx *shndx_buf = NULL; int machine; @@ -1343,12 +1404,43 @@ m32c_elf_relax_section || (sec->flags & SEC_CODE) == 0) return TRUE; - /* Relaxing doesn't quite work right yet. */ - return TRUE; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; + /* Get the section contents. */ + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + /* Go get them off disk. */ + else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) + goto error_return; + + /* Read this BFD's symbols. */ + /* Get cached copy if it exists. */ + if (symtab_hdr->contents != NULL) + { + intsyms = (Elf_Internal_Sym *) symtab_hdr->contents; + } + else + { + intsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr, symtab_hdr->sh_info, 0, NULL, NULL, NULL); + symtab_hdr->contents = (bfd_byte *) intsyms; + } + + if (shndx_hdr->sh_size != 0) + { + bfd_size_type amt; + + amt = symtab_hdr->sh_info; + amt *= sizeof (Elf_External_Sym_Shndx); + shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt); + if (shndx_buf == NULL) + goto error_return; + if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0 + || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt) + goto error_return; + shndx_hdr->contents = (bfd_byte *) shndx_buf; + } + /* Get a copy of the native relocations. */ internal_relocs = (_bfd_elf_link_read_relocs (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL, @@ -1358,188 +1450,388 @@ m32c_elf_relax_section if (! link_info->keep_memory) free_relocs = internal_relocs; + /* The RL_ relocs must be just before the operand relocs they go + with, so we must sort them to guarantee this. */ + qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), + compare_reloc); + /* Walk through them looking for relaxing opportunities. */ irelend = internal_relocs + sec->reloc_count; for (irel = internal_relocs; irel < irelend; irel++) { bfd_vma symval; - bfd_vma insn; + unsigned char *insn, *gap, *einsn; bfd_vma pc; - bfd_signed_vma pcrel_value; - bfd_vma addend; - int to_delete; - int i; + bfd_signed_vma pcrel; + int relax_relocs; + int gap_size; + int new_type; + int posn; + int enc; + EncodingTable *enctbl; + EncodingTable *e; + + if (ELF32_R_TYPE(irel->r_info) != R_M32C_RL_JUMP + && ELF32_R_TYPE(irel->r_info) != R_M32C_RL_1ADDR + && ELF32_R_TYPE(irel->r_info) != R_M32C_RL_2ADDR) + continue; - /* Get the section contents. */ - if (contents == NULL) - { - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - /* Go get them off disk. */ - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } + srel = irel; - /* Read this BFD's symbols if we haven't done so already. */ - if (extsyms == NULL) + /* There will always be room for the relaxed insn, since it is smaller + than the one it would replace. */ + BFD_ASSERT (irel->r_offset < sec->size); + + insn = contents + irel->r_offset; + relax_relocs = irel->r_addend % 16; + + /* Ok, we only have three relocs we care about, and they're all + fake. The lower four bits of the addend is always the number + of following relocs (hence the qsort above) that are assigned + to this opcode. The next 8 bits of the addend indicates the + number of bytes in the insn. We use the rest of them + ourselves as flags for the more expensive operations (defines + above). The three relocs are: + + RL_JUMP: This marks all direct jump insns. We check the + displacement and replace them with shorter jumps if + they're in range. We also use this to find JMP.S + insns and manually shorten them when we delete bytes. + We have to decode these insns to figure out what to + do. + + RL_1ADDR: This is a :G or :Q insn, which has a single + "standard" operand. We have to extract the type + field, see if it's a wide displacement, then figure + out if we can replace it with a narrow displacement. + We don't have to decode these insns. + + RL_2ADDR: Similarly, but two "standard" operands. Note that + r_addend may still be 1, as standard operands don't + always have displacements. Gas shouldn't give us one + with zero operands, but since we don't know which one + has the displacement, we check them both anyway. + + These all point to the beginning of the insn itself, not the + operands. + + Note that we only relax one step at a time, relying on the + linker to call us repeatedly. Thus, there is no code for + JMP.A->JMP.B although that will happen in two steps. + Likewise, for 2ADDR relaxes, we do one operand per cycle. + */ + + /* Get the value of the symbol referred to by the reloc. Just + in case this is the last reloc in the list, use the RL's + addend to choose between this reloc (no addend) or the next + (yes addend, which means at least one following reloc). */ + srel = irel + (relax_relocs ? 1 : 0); + symval = OFFSET_FOR_RELOC (srel); + + /* Setting gap_size nonzero is the flag which means "something + shrunk". */ + gap_size = 0; + new_type = ELF32_R_TYPE(srel->r_info); + + pc = sec->output_section->vma + sec->output_offset + + srel->r_offset; + pcrel = symval - pc + srel->r_addend; + + if (machine == bfd_mach_m16c) { - /* Get cached copy if it exists. */ - if (symtab_hdr->contents != NULL) - extsyms = (Elf32_External_Sym *) symtab_hdr->contents; - else - { - bfd_size_type amt = symtab_hdr->sh_size; - - /* Go get them off disk. */ - extsyms = (Elf32_External_Sym *) bfd_malloc (amt); - if (extsyms == NULL) - goto error_return; - free_extsyms = extsyms; - if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0 - || bfd_bread (extsyms, amt, abfd) != amt) - goto error_return; - symtab_hdr->contents = (bfd_byte *) extsyms; - } + /* R8C / M16C */ - if (shndx_hdr->sh_size != 0) + switch (ELF32_R_TYPE(irel->r_info)) { - bfd_size_type amt; - - amt = symtab_hdr->sh_info; - amt *= sizeof (Elf_External_Sym_Shndx); - shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt); - if (shndx_buf == NULL) - goto error_return; - if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0 - || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt) - goto error_return; - shndx_hdr->contents = (bfd_byte *) shndx_buf; - } - } - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf32_External_Sym *esym; - Elf_External_Sym_Shndx *shndx; - Elf_Internal_Sym isym; - - esym = extsyms + ELF32_R_SYM (irel->r_info); - shndx = shndx_buf + (shndx_buf ? ELF32_R_SYM (irel->r_info) : 0); - bfd_elf32_swap_symbol_in (abfd, esym, shndx, &isym); - - symval = (isym.st_value - + sec->output_section->vma - + sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; + case R_M32C_RL_JUMP: + switch (insn[0]) + { + case 0xfe: /* jmp.b */ + if (pcrel >= 2 && pcrel <= 9) + { + /* Relax JMP.B -> JMP.S. We need to get rid of + the following reloc though. */ + insn[0] = 0x60 | (pcrel - 2); + new_type = R_M32C_NONE; + irel->r_addend = 0x10; + gap_size = 1; + gap = insn + 1; + } + break; + + case 0xf4: /* jmp.w */ + /* 128 is allowed because it will be one byte closer + after relaxing. Likewise for all other pc-rel + jumps. */ + if (pcrel <= 128 && pcrel >= -128) + { + /* Relax JMP.W -> JMP.B */ + insn[0] = 0xfe; + insn[1] = 0; + new_type = R_M32C_8_PCREL; + gap_size = 1; + gap = insn + 2; + } + break; + + case 0xfc: /* jmp.a */ + if (pcrel <= 32768 && pcrel >= -32768) + { + /* Relax JMP.A -> JMP.W */ + insn[0] = 0xf4; + insn[1] = 0; + insn[2] = 0; + new_type = R_M32C_16_PCREL; + gap_size = 1; + gap = insn + 3; + } + break; + + case 0xfd: /* jsr.a */ + if (pcrel <= 32768 && pcrel >= -32768) + { + /* Relax JSR.A -> JSR.W */ + insn[0] = 0xf5; + insn[1] = 0; + insn[2] = 0; + new_type = R_M32C_16_PCREL; + gap_size = 1; + gap = insn + 3; + } + break; + } + break; - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } + case R_M32C_RL_2ADDR: + /* xxxx xxxx srce dest [src-disp] [dest-disp]*/ - /* There will always be room for the relaxed insn, since it is smaller - than the one it would replace. */ - BFD_ASSERT (irel->r_offset <= sec->size - 2); + enctbl = m16c_addr_encodings; + posn = 2; + enc = (insn[1] >> 4) & 0x0f; + e = & enctbl[enc]; + + if (srel->r_offset == irel->r_offset + posn + && e->new_encoding != enc + && symval <= e->max_disp) + { + insn[1] &= 0x0f; + insn[1] |= e->new_encoding << 4; + gap_size = e->bytes - enctbl[e->new_encoding].bytes; + gap = insn + posn + enctbl[e->new_encoding].bytes; + new_type = bytes_to_reloc[enctbl[e->new_encoding].bytes]; + break; + } + if (relax_relocs == 2) + srel ++; + posn += e->bytes; + + goto try_1addr_16; - insn = bfd_get_16 (abfd, contents + irel->r_offset + 0); + case R_M32C_RL_1ADDR: + /* xxxx xxxx xxxx dest [disp] */ - addend = irel->r_addend; - for (i = 0; relax_reloc[i].machine; i++) + enctbl = m16c_addr_encodings; + posn = 2; + + /* Check the opcode for jumps. We know it's safe to + do this because all 2ADDR insns are at least two + bytes long. */ + enc = insn[0] * 256 + insn[1]; + enc &= 0xfff0; + if (enc == 0x7d20 + || enc == 0x7d00 + || enc == 0x7d30 + || enc == 0x7d10) + { + enctbl = m16c_jmpaddr_encodings; + } + + try_1addr_16: + /* srel, posn, and enc must be set here. */ + + symval = OFFSET_FOR_RELOC (srel); + enc = insn[1] & 0x0f; + e = & enctbl[enc]; + + if (srel->r_offset == irel->r_offset + posn + && e->new_encoding != enc + && symval <= e->max_disp) + { + insn[1] &= 0xf0; + insn[1] |= e->new_encoding; + gap_size = e->bytes - enctbl[e->new_encoding].bytes; + gap = insn + posn + enctbl[e->new_encoding].bytes; + new_type = bytes_to_reloc[enctbl[e->new_encoding].bytes]; + break; + } + + break; + + } /* Ends switch (reloc type) for m16c. */ + } + else /* machine == bfd_mach_m32c */ { -#ifdef DEBUG - _bfd_error_handler ("insn %x %d mask %x opcode %x =%x\n", - insn, i, relax_reloc[i].opcode_mask, - relax_reloc[i].opcode, - (insn & relax_reloc[i].opcode_mask) == relax_reloc[i].opcode); -#endif - if (!(machine == relax_reloc[i].machine - && (insn & relax_reloc[i].opcode_mask) == relax_reloc[i].opcode - && (relax_reloc[i].old_reloc - == (int) ELF32_R_TYPE(irel->r_info)))) - continue; + /* M32CM / M32C */ - /* At this point we've confirmed we have a matching insn. Now - ensure the operand is in range. */ - if (relax_reloc[i].use_pcrel) + switch (ELF32_R_TYPE(irel->r_info)) { - pc = sec->output_section->vma + sec->output_offset - + irel->r_offset; - pcrel_value = symval - pc; -#ifndef USE_REL /* put in for learning purposes */ - pcrel_value += addend; -#else - addend = bfd_get_signed_16 (abfd, contents + irel->r_offset + 2); - pcrel_value += addend; -#endif - } - else - pcrel_value = symval; - if (pcrel_value >= relax_reloc[i].relax_backward - && pcrel_value < relax_reloc[i].relax_forward + 2) - { - /* We can relax to a shorter operand. */ - insn = (insn & relax_reloc[i].mask) | relax_reloc[i].new_opcode; + case R_M32C_RL_JUMP: + switch (insn[0]) + { + case 0xbb: /* jmp.b */ + if (pcrel >= 2 && pcrel <= 9) + { + int p = pcrel - 2; + /* Relax JMP.B -> JMP.S. We need to get rid of + the following reloc though. */ + insn[0] = 0x4a | ((p << 3) & 0x30) | (p & 1); + new_type = R_M32C_NONE; + irel->r_addend = 0x10; + gap_size = 1; + gap = insn + 1; + } + break; + + case 0xce: /* jmp.w */ + if (pcrel <= 128 && pcrel >= -128) + { + /* Relax JMP.W -> JMP.B */ + insn[0] = 0xbb; + insn[1] = 0; + new_type = R_M32C_8_PCREL; + gap_size = 1; + gap = insn + 2; + } + break; + + case 0xcc: /* jmp.a */ + if (pcrel <= 32768 && pcrel >= -32768) + { + /* Relax JMP.A -> JMP.W */ + insn[0] = 0xce; + insn[1] = 0; + insn[2] = 0; + new_type = R_M32C_16_PCREL; + gap_size = 1; + gap = insn + 3; + } + break; + + case 0xcd: /* jsr.a */ + if (pcrel <= 32768 && pcrel >= -32768) + { + /* Relax JSR.A -> JSR.W */ + insn[0] = 0xcf; + insn[1] = 0; + insn[2] = 0; + new_type = R_M32C_16_PCREL; + gap_size = 1; + gap = insn + 3; + } + break; + } + break; - to_delete = relax_reloc[i].delete_n; + case R_M32C_RL_2ADDR: + /* xSSS DDDx DDSS xxxx [src-disp] [dest-disp]*/ - /* Rewrite the insn. */ - bfd_put_16 (abfd, insn, contents + irel->r_offset); + einsn = insn; + posn = 2; + if (einsn[0] == 1) + { + /* prefix; remove it as far as the RL reloc is concerned. */ + einsn ++; + posn ++; + } - /* Set the new reloc type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - relax_reloc[i].new_reloc); - irel->r_addend = pcrel_value; - } - else - continue; + enctbl = m32c_addr_encodings; + enc = ((einsn[0] & 0x70) >> 2) | ((einsn[1] & 0x30) >> 4); + e = & enctbl[enc]; -#ifdef DEBUG - _bfd_error_handler ("insn %x pc %x index %d mask %x shift %d delete %d\n" - "old reloc %s new reloc %s", - insn, sec->output_section->vma - + sec->output_offset + irel->r_offset + 2, - i, relax_reloc[i].opcode_mask, - relax_reloc[i].value_shift, to_delete, - m32c_get_reloc (relax_reloc[i].old_reloc), - m32c_get_reloc (relax_reloc[i].new_reloc)); -#endif + if (srel->r_offset == irel->r_offset + posn + && e->new_encoding != enc + && symval <= e->max_disp) + { + einsn[0] &= 0x8f; + einsn[0] |= (e->new_encoding & 0x1c) << 2; + einsn[1] &= 0xcf; + einsn[1] |= (e->new_encoding & 0x03) << 4; + gap_size = e->bytes - enctbl[e->new_encoding].bytes; + gap = insn + posn + enctbl[e->new_encoding].bytes; + new_type = bytes_to_reloc[enctbl[e->new_encoding].bytes]; + break; + } + if (relax_relocs == 2) + srel ++; + posn += e->bytes; + + goto try_1addr_32; + + case R_M32C_RL_1ADDR: + /* xxxx DDDx DDxx xxxx [disp] */ + + einsn = insn; + posn = 2; + if (einsn[0] == 1) + { + /* prefix; remove it as far as the RL reloc is concerned. */ + einsn ++; + posn ++; + } + + enctbl = m32c_addr_encodings; - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - free_relocs = NULL; + try_1addr_32: + /* srel, posn, and enc must be set here. */ - elf_section_data (sec)->this_hdr.contents = contents; - free_contents = NULL; + symval = OFFSET_FOR_RELOC (srel); + enc = ((einsn[0] & 0x0e) << 1) | ((einsn[1] & 0xc0) >> 6); + e = & enctbl[enc]; - symtab_hdr->contents = (bfd_byte *) extsyms; - free_extsyms = NULL; + if (srel->r_offset == irel->r_offset + posn + && e->new_encoding != enc + && symval <= e->max_disp) + { + einsn[0] &= 0xf1; + einsn[0] |= (e->new_encoding & 0x1c) >> 1; + einsn[1] &= 0x3f; + einsn[1] |= (e->new_encoding & 0x03) << 6; + gap_size = e->bytes - enctbl[e->new_encoding].bytes; + gap = insn + posn + enctbl[e->new_encoding].bytes; + new_type = bytes_to_reloc[enctbl[e->new_encoding].bytes]; + break; + } + + break; + + } /* Ends switch (reloc type) for m32c. */ + } + + if (gap_size == 0) + continue; + + *again = TRUE; + + srel->r_info = ELF32_R_INFO (ELF32_R_SYM (srel->r_info), new_type); + + /* Note that we've changed the relocs, section 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 *) intsyms; + free_intsyms = NULL; + + bytes_saved += gap_size; + + if (! m32c_elf_relax_delete_bytes(abfd, sec, gap - contents, gap_size)) + goto error_return; - /* Delete TO_DELETE bytes of data. */ - if (! m32c_elf_relax_delete_bytes - (abfd, sec, irel->r_offset + relax_reloc[i].value_shift, - to_delete)) - goto error_return; - } /* next relax_reloc */ } /* next relocation */ if (free_relocs != NULL) @@ -1565,18 +1857,18 @@ m32c_elf_relax_section free (shndx_buf); } - if (free_extsyms != NULL) + if (free_intsyms != NULL) { if (! link_info->keep_memory) - free (free_extsyms); + free (free_intsyms); /* Cache the symbols for elf_link_input_bfd. */ else - symtab_hdr->contents = NULL /* (unsigned char *) extsyms*/; + { + symtab_hdr->contents = NULL /* (unsigned char *) intsyms*/; + } - free_extsyms = NULL; + free_intsyms = NULL; } - /* elf_link_input_bfd expects internal syms. */ - symtab_hdr->contents = NULL; return TRUE; @@ -1590,8 +1882,8 @@ m32c_elf_relax_section shndx_hdr->contents = NULL; free (shndx_buf); } - if (free_extsyms != NULL) - free (free_extsyms); + if (free_intsyms != NULL) + free (free_intsyms); return FALSE; } @@ -1612,20 +1904,15 @@ m32c_elf_relax_delete_bytes Elf_Internal_Rela *irelend; Elf_Internal_Rela *irelalign; bfd_vma toaddr; - Elf32_External_Sym *esym; - Elf32_External_Sym *esymend; - Elf32_External_Sym *extsyms; + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + Elf_Internal_Sym *intsyms; Elf_External_Sym_Shndx *shndx_buf; Elf_External_Sym_Shndx *shndx; struct elf_link_hash_entry ** sym_hashes; struct elf_link_hash_entry ** end_hashes; unsigned int symcount; - - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - extsyms = (Elf32_External_Sym *) symtab_hdr->contents; - shndx_hdr = & elf_tdata (abfd)->symtab_shndx_hdr; - shndx_buf = (Elf_External_Sym_Shndx *) shndx_hdr->contents; - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + contents = elf_section_data (sec)->this_hdr.contents; /* The deletion must stop at the next ALIGN reloc for an aligment @@ -1646,27 +1933,62 @@ m32c_elf_relax_delete_bytes /* Get the new reloc address. */ if (irel->r_offset > addr && irel->r_offset < toaddr) irel->r_offset -= count; - if (irel->r_addend > addr && irel->r_addend < toaddr) - irel->r_addend -= count; + + if (ELF32_R_TYPE(irel->r_info) == R_M32C_RL_JUMP + && irel->r_addend == 0x10 /* one byte insn, no relocs */ + && irel->r_offset + 1 < addr + && irel->r_offset + 7 > addr) + { + bfd_vma disp; + unsigned char *insn = &contents[irel->r_offset]; + disp = *insn; + /* This is a JMP.S, which we have to manually update. */ + if (elf32_m32c_machine (abfd) == bfd_mach_m16c) + { + if ((*insn & 0xf8) != 0x60) + continue; + disp = (disp & 7); + } + else + { + if ((*insn & 0xce) != 0x4a) + continue; + disp = ((disp & 0x30) >> 3) | (disp & 1); + } + if (irel->r_offset + disp + 2 >= addr+count) + { + disp -= count; + if (elf32_m32c_machine (abfd) == bfd_mach_m16c) + { + *insn = (*insn & 0xf8) | disp; + } + else + { + *insn = (*insn & 0xce) | ((disp & 6) << 3) | (disp & 1); + } + } + } } /* Adjust the local symbols defined in this section. */ + symtab_hdr = & elf_tdata (abfd)->symtab_hdr; + intsyms = (Elf_Internal_Sym *) symtab_hdr->contents; + isym = intsyms; + isymend = isym + symtab_hdr->sh_info; + + sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + shndx_hdr = & elf_tdata (abfd)->symtab_shndx_hdr; + shndx_buf = (Elf_External_Sym_Shndx *) shndx_hdr->contents; shndx = shndx_buf; - esym = extsyms; - esymend = esym + symtab_hdr->sh_info; - for (; esym < esymend; esym++, shndx = (shndx ? shndx + 1 : NULL)) - { - Elf_Internal_Sym isym; - Elf_External_Sym_Shndx dummy; - bfd_elf32_swap_symbol_in (abfd, esym, shndx, &isym); + for (; isym < isymend; isym++, shndx = (shndx ? shndx + 1 : NULL)) + { - if ((int) isym.st_shndx == sec_shndx - && isym.st_value > addr - && isym.st_value < toaddr) + if ((int) isym->st_shndx == sec_shndx + && isym->st_value > addr + && isym->st_value < toaddr) { - isym.st_value -= count; - bfd_elf32_swap_symbol_out (abfd, &isym, (PTR) esym, (PTR) & dummy); + isym->st_value -= count; } } @@ -1687,7 +2009,9 @@ m32c_elf_relax_delete_bytes && sym_hash->root.u.def.section == sec && sym_hash->root.u.def.value > addr && sym_hash->root.u.def.value < toaddr) - sym_hash->root.u.def.value -= count; + { + sym_hash->root.u.def.value -= count; + } } return TRUE; diff --git a/bfd/libbfd.h b/bfd/libbfd.h index bcc35b1..0b13b6e 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1374,6 +1374,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_DLX_LO16", "BFD_RELOC_DLX_JMP26", "BFD_RELOC_M32C_HI8", + "BFD_RELOC_M32C_RL_JUMP", + "BFD_RELOC_M32C_RL_1ADDR", + "BFD_RELOC_M32C_RL_2ADDR", "BFD_RELOC_M32R_24", "BFD_RELOC_M32R_10_PCREL", "BFD_RELOC_M32R_18_PCREL", diff --git a/bfd/reloc.c b/bfd/reloc.c index 5a66c38..b621217 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -3202,6 +3202,12 @@ ENUMDOC ENUM BFD_RELOC_M32C_HI8 +ENUMX + BFD_RELOC_M32C_RL_JUMP +ENUMX + BFD_RELOC_M32C_RL_1ADDR +ENUMX + BFD_RELOC_M32C_RL_2ADDR ENUMDOC Renesas M16C/M32C Relocations. diff --git a/cpu/ChangeLog b/cpu/ChangeLog index 0efd530..9e30be7 100644 --- a/cpu/ChangeLog +++ b/cpu/ChangeLog @@ -1,3 +1,16 @@ +2006-02-24 DJ Delorie + + * m32c.cpu (RL_TYPE): New attribute, with macros. + (Lab-8-24): Add RELAX. + (unary-insn-defn-g, binary-arith-imm-dst-defn, + binary-arith-imm4-dst-defn): Add 1ADDR attribute. + (binary-arith-src-dst-defn): Add 2ADDR attribute. + (jcnd16-5, jcnd16, jcnd32, jmp16.s, jmp16.b, jmp16.w, jmp16.a, + jmp32.s, jmp32.b, jmp32.w, jmp32.a, jsr16.w, jsr16.a): Add JUMP + attribute. + (jsri16, jsri32): Add 1ADDR attribute. + (jsr32.w, jsr32.a): Add JUMP attribute. + 2006-02-17 Shrirang Khisti Anil Paranjape Shilin Shakti diff --git a/cpu/m32c.cpu b/cpu/m32c.cpu index a70124e..725b2d5 100644 --- a/cpu/m32c.cpu +++ b/cpu/m32c.cpu @@ -1,6 +1,6 @@ ; Renesas M32C CPU description. -*- Scheme -*- ; -; Copyright 2005 Free Software Foundation, Inc. +; Copyright 2005, 2006 Free Software Foundation, Inc. ; ; Contributed by Red Hat Inc; developed under contract from Renesas. ; @@ -139,6 +139,13 @@ ) ) +(define-attr + (type enum) + (name RL_TYPE) + (values NONE JUMP 1ADDR 2ADDR) + (default NONE) + ) + ; Macros to simplify MACH attribute specification. (define-pmacro all-isas () (ISA m16c,m32c)) @@ -150,6 +157,11 @@ (define-pmacro (machine size) (MACH (.sym m size c)) (ISA (.sym m size c))) + +(define-pmacro RL_JUMP (RL_TYPE JUMP)) +(define-pmacro RL_1ADDR (RL_TYPE 1ADDR)) +(define-pmacro RL_2ADDR (RL_TYPE 2ADDR)) + ;============================================================= ; Fields @@ -2097,7 +2109,7 @@ (dnop Lab-8-8 "8 bit label" (all-isas RELAX) h-iaddr f-lab-8-8) (dnop Lab-8-16 "16 bit label" (all-isas RELAX) h-iaddr f-lab-8-16) -(dnop Lab-8-24 "24 bit label" (all-isas) h-iaddr f-lab-8-24) +(dnop Lab-8-24 "24 bit label" (all-isas RELAX) h-iaddr f-lab-8-24) (dnop Lab-16-8 "8 bit label" (all-isas RELAX) h-iaddr f-lab-16-8) (dnop Lab-24-8 "8 bit label" (all-isas) h-iaddr f-lab-24-8) (dnop Lab-32-8 "8 bit label" (all-isas) h-iaddr f-lab-32-8) @@ -5859,7 +5871,7 @@ (define-pmacro (unary-insn-defn-g mach group mode wstr op encoding sem opg) (dni (.sym op mach wstr - group) (.str op wstr opg " dst" mach "-" group "-" mode) - ((machine mach)) + ((machine mach) RL_1ADDR) (.str op wstr opg " ${dst" mach "-" group "-" mode "}") encoding (sem mode (.sym dst mach - group - mode)) @@ -6075,7 +6087,7 @@ (define-pmacro (binary-arith-imm-dst-defn mach src dstgroup dmode wstr op suffix encoding sem) (dni (.sym op mach wstr - imm-G - dstgroup) (.str op wstr " " mach "-imm-G-" dstgroup "-" dmode) - ((machine mach)) + ((machine mach) RL_1ADDR) (.str op wstr "$"suffix " #${" src "},${dst" mach "-" dstgroup "-" dmode "}") encoding (sem dmode src (.sym dst mach - dstgroup - dmode)) @@ -6185,7 +6197,7 @@ (define-pmacro (binary-arith-imm4-dst-defn mach src dstgroup mode wstr op encoding sem) (dni (.sym op mach wstr - imm4-Q - dstgroup) (.str op wstr " " mach "-imm4-Q-" dstgroup "-" mode) - ((machine mach)) + ((machine mach) RL_1ADDR) (.str op wstr "$Q #${" src "},${dst" mach "-" dstgroup "-" mode "}") encoding (sem mode src (.sym dst mach - dstgroup - mode)) @@ -6261,7 +6273,7 @@ (define-pmacro (binary-arith-src-dst-defn mach srcgroup dstgroup smode dmode wstr op suffix encoding sem) (dni (.sym op mach wstr - srcgroup - dstgroup) (.str op wstr " dst" mach "-" srcgroup "-" dstgroup "-" dmode) - ((machine mach)) + ((machine mach) RL_2ADDR) (.str op wstr "$" suffix " ${src" mach "-" srcgroup "-" smode "},${dst" mach "-" dstgroup "-" dmode "}") encoding (sem dmode (.sym src mach - srcgroup - smode) (.sym dst mach - dstgroup - dmode)) @@ -8058,7 +8070,7 @@ (dni jcnd16-5 "jCnd label" - (RELAXABLE (machine 16)) + (RL_JUMP RELAXABLE (machine 16)) "j$cond16j5 ${Lab-8-8}" (+ (f-0-4 #x6) (f-4-1 1) cond16j5 Lab-8-8) (jcnd16-sem cond16j5 Lab-8-8) @@ -8067,7 +8079,7 @@ (dni jcnd16 "jCnd label" - (RELAXABLE (machine 16)) + (RL_JUMP RELAXABLE (machine 16)) "j$cond16j ${Lab-16-8}" (+ (f-0-4 #x7) (f-4-4 #xD) (f-8-4 #xC) cond16j Lab-16-8) (jcnd16-sem cond16j Lab-16-8) @@ -8076,7 +8088,7 @@ (dni jcnd32 "jCnd label" - (RELAXABLE (machine 32)) + (RL_JUMP RELAXABLE (machine 32)) "j$cond32j ${Lab-8-8}" (+ (f-0-1 1) (f-4-3 5) cond32j Lab-8-8) (jcnd32-sem cond32j Lab-8-8) @@ -8088,25 +8100,25 @@ ;------------------------------------------------------------- ; jmp.s label3 (m16 #1) -(dni jmp16.s "jmp.s Lab-5-3" (RELAXABLE (machine 16)) +(dni jmp16.s "jmp.s Lab-5-3" (RL_JUMP RELAXABLE (machine 16)) ("jmp.s ${Lab-5-3}") (+ (f-0-4 6) (f-4-1 0) Lab-5-3) (sequence () (set pc Lab-5-3)) ()) ; jmp.b label8 (m16 #2) -(dni jmp16.b "jmp.b Lab-8-8" (RELAXABLE (machine 16)) +(dni jmp16.b "jmp.b Lab-8-8" (RL_JUMP RELAXABLE (machine 16)) ("jmp.b ${Lab-8-8}") (+ (f-0-4 #xF) (f-4-4 #xE) Lab-8-8) (sequence () (set pc Lab-8-8)) ()) ; jmp.w label16 (m16 #3) -(dni jmp16.w "jmp.w Lab-8-16" (RELAXABLE (machine 16)) +(dni jmp16.w "jmp.w Lab-8-16" (RL_JUMP RELAXABLE (machine 16)) ("jmp.w ${Lab-8-16}") (+ (f-0-4 #xF) (f-4-4 4) Lab-8-16) (sequence () (set pc Lab-8-16)) ()) ; jmp.a label24 (m16 #4) -(dni jmp16.a "jmp.a Lab-8-24" ((machine 16)) +(dni jmp16.a "jmp.a Lab-8-24" (RL_JUMP RELAXABLE (machine 16)) ("jmp.a ${Lab-8-24}") (+ (f-0-4 #xF) (f-4-4 #xC) Lab-8-24) (sequence () (set pc Lab-8-24)) @@ -8133,32 +8145,32 @@ ; jmp.s label3 (m32 #1) (dni jmp32.s "jmp.s label" - (RELAXABLE (machine 32)) + (RL_JUMP RELAXABLE (machine 32)) "jmp.s ${Lab32-jmp-s}" (+ (f-0-2 1) (f-4-3 5) Lab32-jmp-s) (set pc Lab32-jmp-s) () ) ; jmp.b label8 (m32 #2) -(dni jmp32.b "jmp.b Lab-8-8" (RELAXABLE (machine 32)) +(dni jmp32.b "jmp.b Lab-8-8" (RL_JUMP RELAXABLE (machine 32)) ("jmp.b ${Lab-8-8}") (+ (f-0-4 #xB) (f-4-4 #xB) Lab-8-8) (set pc Lab-8-8) ()) ; jmp.w label16 (m32 #3) -(dni jmp32.w "jmp.w Lab-8-16" (RELAXABLE (machine 32)) +(dni jmp32.w "jmp.w Lab-8-16" (RL_JUMP RELAXABLE (machine 32)) ("jmp.w ${Lab-8-16}") (+ (f-0-4 #xC) (f-4-4 #xE) Lab-8-16) (set pc Lab-8-16) ()) ; jmp.a label24 (m32 #4) -(dni jmp32.a "jmp.a Lab-8-24" ((machine 32)) +(dni jmp32.a "jmp.a Lab-8-24" (RL_JUMP RELAXABLE (machine 32)) ("jmp.a ${Lab-8-24}") (+ (f-0-4 #xC) (f-4-4 #xC) Lab-8-24) (set pc Lab-8-24) ()) ; jmp.s imm8 (m32 #1) -(dni jmps32 "jmps Imm-8-QI" ((machine 32)) +(dni jmps32 "jmps Imm-8-QI" (RL_JUMP (machine 32)) ("jmps #${Imm-8-QI}") (+ (f-0-4 #xD) (f-4-4 #xC) Imm-8-QI) (set pc Imm-8-QI) @@ -8190,13 +8202,13 @@ ) ; jsr.w label16 (m16 #1) -(dni jsr16.w "jsr.w Lab-8-16" (RELAXABLE (machine 16)) +(dni jsr16.w "jsr.w Lab-8-16" (RL_JUMP RELAXABLE (machine 16)) ("jsr.w ${Lab-8-16}") (+ (f-0-4 #xF) (f-4-4 5) Lab-8-16) (jsr16-sem 3 Lab-8-16) ()) ; jsr.a label24 (m16 #2) -(dni jsr16.a "jsr.a Lab-8-24" ((machine 16)) +(dni jsr16.a "jsr.a Lab-8-24" (RL_JUMP RELAXABLE (machine 16)) ("jsr.a ${Lab-8-24}") (+ (f-0-4 #xF) (f-4-4 #xD) Lab-8-24) (jsr16-sem 4 Lab-8-24) @@ -8206,14 +8218,14 @@ (begin (dni (.sym jsri16 mode - op16) (.str "jsri." mode " " op16) - ((machine 16)) + (RL_1ADDR (machine 16)) (.str "jsri." mode " ${" op16 "}") (+ op16-1 op16-2 op16-3 op16) (op16-sem len op16) ()) (dni (.sym jsri32 mode - op32) (.str "jsri." mode " " op32) - ((machine 32)) + (RL_1ADDR (machine 32)) (.str "jsri." mode " ${" op32 "}") (+ op32-1 op32-2 op32-3 op32-4 op32) (op32-sem len op32) @@ -8227,7 +8239,7 @@ dst32-16-16-Unprefixed-HI (f-0-4 #xC) (f-7-1 1) (f-10-2 #x1) (f-12-4 #xF) jsr32-sem 4) (jsri-defn w dst16-basic-HI (f-0-4 #x7) (f-4-4 #xD) (f-8-4 #x3) jsr16-sem dst32-basic-Unprefixed-HI (f-0-4 #xC) (f-7-1 1) (f-10-2 #x1) (f-12-4 #xF) jsr32-sem 2) -(dni jsri32.w "jsr.w dst32-16-24-Unprefixed-HI" ((machine 32)) +(dni jsri32.w "jsr.w dst32-16-24-Unprefixed-HI" (RL_1ADDR (machine 32)) ("jsri.w ${dst32-16-24-Unprefixed-HI}") (+ (f-0-4 #xC) (f-7-1 1) dst32-16-24-Unprefixed-HI (f-10-2 #x1) (f-12-4 #xF)) (jsr32-sem 6 dst32-16-24-Unprefixed-HI) @@ -8241,19 +8253,19 @@ (jsri-defn a dst16-basic-SI (f-0-4 #x7) (f-4-4 #xD) (f-8-4 #x1) jsr16-sem dst32-basic-Unprefixed-SI (f-0-4 #x9) (f-7-1 0) (f-10-2 #x0) (f-12-4 #x1) jsr32-sem 2) -(dni jsri32.a "jsr.w dst32-16-24-Unprefixed-HI" ((machine 32)) +(dni jsri32.a "jsr.w dst32-16-24-Unprefixed-HI" (RL_1ADDR (machine 32)) ("jsri.w ${dst32-16-24-Unprefixed-SI}") (+ (f-0-4 #x9) (f-7-1 0) dst32-16-24-Unprefixed-SI (f-10-2 #x0) (f-12-4 #x1)) (jsr32-sem 6 dst32-16-24-Unprefixed-SI) ()) ; jsr.w label16 (m32 #1) -(dni jsr32.w "jsr.w label" (RELAXABLE (machine 32)) +(dni jsr32.w "jsr.w label" (RL_JUMP RELAXABLE (machine 32)) ("jsr.w ${Lab-8-16}") (+ (f-0-4 #xC) (f-4-4 #xF) Lab-8-16) (jsr32-sem 3 Lab-8-16) ()) ; jsr.a label16 (m32 #2) -(dni jsr32.a "jsr.a label" ((machine 32)) +(dni jsr32.a "jsr.a label" (RL_JUMP (machine 32)) ("jsr.a ${Lab-8-24}") (+ (f-0-4 #xC) (f-4-4 #xD) Lab-8-24) (jsr32-sem 4 Lab-8-24) diff --git a/gas/ChangeLog b/gas/ChangeLog index 307c531..a484a9f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,20 @@ +2006-02-24 DJ Delorie + + * config/tc-m32c.h (md_apply_fix): Define to m32c_apply_fix. + (tc_gen_reloc): Don't define. + * config/tc-m32c.c (rl_for, relaxable): New convenience macros. + (OPTION_LINKRELAX): New. + (md_longopts): Add it. + (m32c_relax): New. + (md_parse_options): Set it. + (md_assemble): Emit relaxation relocs as needed. + (md_convert_frag): Emit relaxation relocs as needed. + (md_cgen_lookup_reloc): Add LAB_8_8 and LAB_8_16. + (m32c_apply_fix): New. + (tc_gen_reloc): New. + (m32c_force_relocation): Force out jump relocs when relaxing. + (m32c_fix_adjustable): Return false if relaxing. + 2006-02-24 Paul Brook * config/arm/tc-arm.c (arm_ext_v6_notm, arm_ext_div, arm_ext_v7, diff --git a/gas/config/tc-m32c.c b/gas/config/tc-m32c.c index 8f4f502..5f174d3 100644 --- a/gas/config/tc-m32c.c +++ b/gas/config/tc-m32c.c @@ -55,6 +55,9 @@ typedef struct } m32c_insn; +#define rl_for(insn) (CGEN_ATTR_CGEN_INSN_RL_TYPE_VALUE (&(insn.insn->base->attrs))) +#define relaxable(insn) (CGEN_ATTR_CGEN_INSN_RELAXABLE_VALUE (&(insn.insn->base->attrs))) + const char comment_chars[] = ";"; const char line_comment_chars[] = "#"; const char line_separator_chars[] = "|"; @@ -67,11 +70,13 @@ const char * md_shortopts = M32C_SHORTOPTS; /* assembler options */ #define OPTION_CPU_M16C (OPTION_MD_BASE) #define OPTION_CPU_M32C (OPTION_MD_BASE + 1) +#define OPTION_LINKRELAX (OPTION_MD_BASE + 2) struct option md_longopts[] = { { "m16c", no_argument, NULL, OPTION_CPU_M16C }, { "m32c", no_argument, NULL, OPTION_CPU_M32C }, + { "relax", no_argument, NULL, OPTION_LINKRELAX }, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); @@ -84,6 +89,7 @@ size_t md_longopts_size = sizeof (md_longopts); static unsigned long m32c_mach = bfd_mach_m16c; static int cpu_mach = (1 << MACH_M16C); static int insn_size; +static int m32c_relax = 0; /* Flags to set in the elf header */ static flagword m32c_flags = DEFAULT_FLAGS; @@ -118,6 +124,10 @@ md_parse_option (int c, char * arg ATTRIBUTE_UNUSED) set_isa (ISA_M32C); break; + case OPTION_LINKRELAX: + m32c_relax = 1; + break; + default: return 0; } @@ -153,7 +163,7 @@ void md_begin (void) { /* Initialize the `cgen' interface. */ - + /* Set the machine number and endian. */ gas_cgen_cpu_desc = m32c_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, cpu_mach, CGEN_CPU_OPEN_ENDIAN, @@ -320,6 +330,8 @@ md_assemble (char * str) static int last_insn_had_delay_slot = 0; m32c_insn insn; char * errmsg; + finished_insnS results; + int rl_type; if (m32c_mach == bfd_mach_m32c && m32c_indirect_operand (str)) return; @@ -336,13 +348,46 @@ md_assemble (char * str) return; } + results.num_fixups = 0; /* Doesn't really matter what we pass for RELAX_P here. */ gas_cgen_finish_insn (insn.insn, insn.buffer, - CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); + CGEN_FIELDS_BITSIZE (& insn.fields), 1, &results); last_insn_had_delay_slot = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT); insn_size = CGEN_INSN_BITSIZE(insn.insn); + + rl_type = rl_for (insn); + + /* We have to mark all the jumps, because we need to adjust them + when we delete bytes, but we only need to mark the displacements + if they're symbolic - if they're not, we've already picked the + shortest opcode by now. The linker, however, will still have to + check any operands to see if they're the displacement type, since + we don't know (nor record) *which* operands are relaxable. */ + if (m32c_relax + && rl_type != RL_TYPE_NONE + && (rl_type == RL_TYPE_JUMP || results.num_fixups) + && !relaxable (insn)) + { + int reloc = 0; + int addend = results.num_fixups + 16 * insn_size/8; + + switch (rl_for (insn)) + { + case RL_TYPE_JUMP: reloc = BFD_RELOC_M32C_RL_JUMP; break; + case RL_TYPE_1ADDR: reloc = BFD_RELOC_M32C_RL_1ADDR; break; + case RL_TYPE_2ADDR: reloc = BFD_RELOC_M32C_RL_2ADDR; break; + } + if (insn.insn->base->num == M32C_INSN_JMP16_S + || insn.insn->base->num == M32C_INSN_JMP32_S) + addend = 0x10; + + fix_new (results.frag, + results.addr - results.frag->fr_literal, + 0, abs_section_sym, addend, 0, + reloc); + } } /* The syntax in the manual says constants begin with '#'. @@ -551,18 +596,26 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, int operand; int new_insn; int where = fragP->fr_opcode - fragP->fr_literal; + int rl_where = fragP->fr_opcode - fragP->fr_literal; unsigned char *op = (unsigned char *)fragP->fr_opcode; + int op_base = 0; + int op_op = 0; + int rl_addend = 0; addend = target_address_for (fragP) - (fragP->fr_address + where); new_insn = subtype_mappings[fragP->fr_subtype].insn; fragP->fr_fix = where + subtype_mappings[fragP->fr_subtype].bytes; + op_base = 0; + switch (subtype_mappings[fragP->fr_subtype].insn) { case M32C_INSN_JCND16_5: op[1] = addend - 1; operand = M32C_OPERAND_LAB_8_8; + op_op = 1; + rl_addend = 0x21; break; case -M32C_MACRO_JCND16_5_W: @@ -574,6 +627,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, operand = M32C_OPERAND_LAB_8_16; where += 2; new_insn = M32C_INSN_JMP16_W; + op_base = 2; + op_op = 3; + rl_addend = 0x51; break; case -M32C_MACRO_JCND16_5_A: @@ -583,12 +639,18 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, operand = M32C_OPERAND_LAB_8_24; where += 2; new_insn = M32C_INSN_JMP16_A; + op_base = 2; + op_op = 3; + rl_addend = 0x61; break; case M32C_INSN_JCND16: op[2] = addend - 2; operand = M32C_OPERAND_LAB_16_8; + op_base = 0; + op_op = 2; + rl_addend = 0x31; break; case -M32C_MACRO_JCND16_W: @@ -600,6 +662,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, operand = M32C_OPERAND_LAB_8_16; where += 3; new_insn = M32C_INSN_JMP16_W; + op_base = 3; + op_op = 4; + rl_addend = 0x61; break; case -M32C_MACRO_JCND16_A: @@ -609,17 +674,26 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, operand = M32C_OPERAND_LAB_8_24; where += 3; new_insn = M32C_INSN_JMP16_A; + op_base = 3; + op_op = 4; + rl_addend = 0x71; break; case M32C_INSN_JMP16_S: op[0] = 0x60 | ((addend-2) & 0x07); operand = M32C_OPERAND_LAB_5_3; + op_base = 0; + op_op = 0; + rl_addend = 0x10; break; case M32C_INSN_JMP16_B: op[0] = 0xfe; op[1] = addend - 1; operand = M32C_OPERAND_LAB_8_8; + op_base = 0; + op_op = 1; + rl_addend = 0x21; break; case M32C_INSN_JMP16_W: @@ -627,6 +701,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[1] = addend - 1; op[2] = (addend - 1) >> 8; operand = M32C_OPERAND_LAB_8_16; + op_base = 0; + op_op = 1; + rl_addend = 0x31; break; case M32C_INSN_JMP16_A: @@ -635,11 +712,17 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[2] = 0; op[3] = 0; operand = M32C_OPERAND_LAB_8_24; + op_base = 0; + op_op = 1; + rl_addend = 0x41; break; case M32C_INSN_JCND32: op[1] = addend - 1; operand = M32C_OPERAND_LAB_8_8; + op_base = 0; + op_op = 1; + rl_addend = 0x21; break; case -M32C_MACRO_JCND32_W: @@ -651,6 +734,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, operand = M32C_OPERAND_LAB_8_16; where += 2; new_insn = M32C_INSN_JMP32_W; + op_base = 2; + op_op = 3; + rl_addend = 0x51; break; case -M32C_MACRO_JCND32_A: @@ -660,6 +746,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, operand = M32C_OPERAND_LAB_8_24; where += 2; new_insn = M32C_INSN_JMP32_A; + op_base = 2; + op_op = 3; + rl_addend = 0x61; break; @@ -668,12 +757,18 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, addend = ((addend-2) & 0x07); op[0] = 0x4a | (addend & 0x01) | ((addend << 3) & 0x30); operand = M32C_OPERAND_LAB32_JMP_S; + op_base = 0; + op_op = 0; + rl_addend = 0x10; break; case M32C_INSN_JMP32_B: op[0] = 0xbb; op[1] = addend - 1; operand = M32C_OPERAND_LAB_8_8; + op_base = 0; + op_op = 1; + rl_addend = 0x21; break; case M32C_INSN_JMP32_W: @@ -681,6 +776,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[1] = addend - 1; op[2] = (addend - 1) >> 8; operand = M32C_OPERAND_LAB_8_16; + op_base = 0; + op_op = 1; + rl_addend = 0x31; break; case M32C_INSN_JMP32_A: @@ -689,6 +787,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[2] = 0; op[3] = 0; operand = M32C_OPERAND_LAB_8_24; + op_base = 0; + op_op = 1; + rl_addend = 0x41; break; @@ -697,6 +798,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[1] = addend - 1; op[2] = (addend - 1) >> 8; operand = M32C_OPERAND_LAB_8_16; + op_base = 0; + op_op = 1; + rl_addend = 0x31; break; case M32C_INSN_JSR16_A: @@ -705,6 +809,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[2] = 0; op[3] = 0; operand = M32C_OPERAND_LAB_8_24; + op_base = 0; + op_op = 1; + rl_addend = 0x41; break; case M32C_INSN_JSR32_W: @@ -712,6 +819,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[1] = addend - 1; op[2] = (addend - 1) >> 8; operand = M32C_OPERAND_LAB_8_16; + op_base = 0; + op_op = 1; + rl_addend = 0x31; break; case M32C_INSN_JSR32_A: @@ -720,6 +830,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[2] = 0; op[3] = 0; operand = M32C_OPERAND_LAB_8_24; + op_base = 0; + op_op = 1; + rl_addend = 0x41; break; @@ -731,8 +844,21 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, abort(); } + if (m32c_relax) + { + if (operand != M32C_OPERAND_LAB_8_24) + fragP->fr_offset = (fragP->fr_address + where); + + fix_new (fragP, + rl_where, + 0, abs_section_sym, rl_addend, 0, + BFD_RELOC_M32C_RL_JUMP); + } + if (S_GET_SEGMENT (fragP->fr_symbol) != sec - || operand == M32C_OPERAND_LAB_8_24) + || operand == M32C_OPERAND_LAB_8_24 + || (m32c_relax && (operand != M32C_OPERAND_LAB_5_3 + && operand != M32C_OPERAND_LAB32_JMP_S))) { assert (fragP->fr_cgen.insn != 0); gas_cgen_record_fixup (fragP, @@ -786,11 +912,15 @@ md_cgen_lookup_reloc (const CGEN_INSN * insn ATTRIBUTE_UNUSED, } op_reloc_table[] = { /* PC-REL relocs for 8-bit fields. */ + { M32C_OPERAND_LAB_8_8, BFD_RELOC_8_PCREL, 1 }, { M32C_OPERAND_LAB_16_8, BFD_RELOC_8_PCREL, 2 }, { M32C_OPERAND_LAB_24_8, BFD_RELOC_8_PCREL, 3 }, { M32C_OPERAND_LAB_32_8, BFD_RELOC_8_PCREL, 4 }, { M32C_OPERAND_LAB_40_8, BFD_RELOC_8_PCREL, 5 }, + /* PC-REL relocs for 16-bit fields. */ + { M32C_OPERAND_LAB_8_16, BFD_RELOC_16_PCREL, 1 }, + /* Absolute relocs for 8-bit fields. */ { M32C_OPERAND_IMM_8_QI, BFD_RELOC_8, 1 }, { M32C_OPERAND_IMM_16_QI, BFD_RELOC_8, 2 }, @@ -890,6 +1020,38 @@ md_cgen_lookup_reloc (const CGEN_INSN * insn ATTRIBUTE_UNUSED, return BFD_RELOC_NONE; } +void +m32c_apply_fix (struct fix *f, valueT *t, segT s) +{ + if (f->fx_r_type == BFD_RELOC_M32C_RL_JUMP + || f->fx_r_type == BFD_RELOC_M32C_RL_1ADDR + || f->fx_r_type == BFD_RELOC_M32C_RL_2ADDR) + return; + gas_cgen_md_apply_fix (f, t, s); +} + +arelent * +tc_gen_reloc (asection *sec, fixS *fx) +{ + if (fx->fx_r_type == BFD_RELOC_M32C_RL_JUMP + || fx->fx_r_type == BFD_RELOC_M32C_RL_1ADDR + || fx->fx_r_type == BFD_RELOC_M32C_RL_2ADDR) + { + arelent * reloc; + + reloc = xmalloc (sizeof (* reloc)); + + reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fx->fx_addsy); + reloc->address = fx->fx_frag->fr_address + fx->fx_where; + reloc->howto = bfd_reloc_type_lookup (stdoutput, fx->fx_r_type); + reloc->addend = fx->fx_offset; + return reloc; + + } + return gas_cgen_tc_gen_reloc (sec, fx); +} + /* See whether we need to force a relocation into the output file. This is used to force out switch and PC relative relocations when relaxing. */ @@ -914,12 +1076,40 @@ m32c_force_relocation (fixS * fixp) case M32C_OPERAND_DSP_24_U16: case M32C_OPERAND_IMM_24_HI: return 1; + + /* If we're doing linker relaxing, we need to keep all the + pc-relative jumps in case we need to fix them due to + deleted bytes between the jump and its destination. */ + case M32C_OPERAND_LAB_8_8: + case M32C_OPERAND_LAB_8_16: + case M32C_OPERAND_LAB_8_24: + case M32C_OPERAND_LAB_16_8: + case M32C_OPERAND_LAB_24_8: + case M32C_OPERAND_LAB_32_8: + case M32C_OPERAND_LAB_40_8: + if (m32c_relax) + return 1; + default: + break; } } else { - if (fixp->fx_r_type == BFD_RELOC_16) - return 1; + switch (fixp->fx_r_type) + { + case BFD_RELOC_16: + return 1; + + case BFD_RELOC_M32C_RL_JUMP: + case BFD_RELOC_M32C_RL_1ADDR: + case BFD_RELOC_M32C_RL_2ADDR: + case BFD_RELOC_8_PCREL: + case BFD_RELOC_16_PCREL: + if (m32c_relax) + return 1; + default: + break; + } } return generic_force_reloc (fixp); @@ -1065,6 +1255,9 @@ m32c_fix_adjustable (fixS * fixP) if (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) return 0; + if (m32c_relax) + return 0; + return 1; } diff --git a/gas/config/tc-m32c.h b/gas/config/tc-m32c.h index 971b59d..3cdd1a1 100644 --- a/gas/config/tc-m32c.h +++ b/gas/config/tc-m32c.h @@ -47,7 +47,8 @@ long md_pcrel_from_section PARAMS ((struct fix *, segT)); /* We don't need to handle .word strangely. */ #define WORKING_DOT_WORD -#define md_apply_fix gas_cgen_md_apply_fix +#define md_apply_fix m32c_apply_fix +extern void m32c_apply_fix PARAMS ((struct fix *, valueT *, segT)); #define tc_fix_adjustable(fixP) m32c_fix_adjustable (fixP) extern bfd_boolean m32c_fix_adjustable PARAMS ((struct fix *)); @@ -66,8 +67,6 @@ extern void m32c_prepare_relax_scan PARAMS ((fragS *, offsetT *, relax_substateT /* Values passed to md_apply_fix don't include the symbol value. */ #define MD_APPLY_SYM_VALUE(FIX) 0 -#define tc_gen_reloc gas_cgen_tc_gen_reloc - /* Call md_pcrel_from_section(), not md_pcrel_from(). */ #define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section (FIXP, SEC) extern long md_pcrel_from_section PARAMS ((struct fix *, segT)); diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index bf759f2..9977e9f 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2006-02-24 DJ Delorie + + * m32c.h: Add relax relocs. + 2006-02-17 Shrirang Khisti Anil Paranjape Shilin Shakti diff --git a/include/elf/m32c.h b/include/elf/m32c.h index 8054173..143773b 100644 --- a/include/elf/m32c.h +++ b/include/elf/m32c.h @@ -40,6 +40,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., /* Bits 16..31 of an address, for LDE's A1A0 etc. */ RELOC_NUMBER (R_M32C_HI16, 9) + /* These are relocs we need when relaxing. */ + /* Marks various jump opcodes. */ + RELOC_NUMBER (R_M32C_RL_JUMP, 10) + /* Marks standard one-address form. */ + RELOC_NUMBER (R_M32C_RL_1ADDR, 11) + /* Marks standard two-address form. */ + RELOC_NUMBER (R_M32C_RL_2ADDR, 12) + END_RELOC_NUMBERS (R_M32C_max) #define EF_M32C_CPU_M16C 0x00000075 /* default */ diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 6aad194..4400057 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,10 @@ +2006-02-24 DJ Delorie + + * m32c-desc.c: Regenerate with linker relaxation attributes. + * m32c-desc.h: Likewise. + * m32c-dis.c: Likewise. + * m32c-opc.c: Likewise. + 2006-02-24 Paul Brook * arm-dis.c (arm_opcodes): Add V7 instructions. diff --git a/opcodes/m32c-desc.c b/opcodes/m32c-desc.c index e38828e..850c168 100644 --- a/opcodes/m32c-desc.c +++ b/opcodes/m32c-desc.c @@ -60,10 +60,20 @@ static const CGEN_ATTR_ENTRY ISA_attr[] ATTRIBUTE_UNUSED = { 0, 0 } }; +static const CGEN_ATTR_ENTRY RL_TYPE_attr[] ATTRIBUTE_UNUSED = +{ + { "NONE", RL_TYPE_NONE }, + { "JUMP", RL_TYPE_JUMP }, + { "1ADDR", RL_TYPE_1ADDR }, + { "2ADDR", RL_TYPE_2ADDR }, + { 0, 0 } +}; + const CGEN_ATTR_TABLE m32c_cgen_ifield_attr_table[] = { { "MACH", & MACH_attr[0], & MACH_attr[0] }, { "ISA", & ISA_attr[0], & ISA_attr[0] }, + { "RL_TYPE", & RL_TYPE_attr[0], & RL_TYPE_attr[0] }, { "VIRTUAL", &bool_attr[0], &bool_attr[0] }, { "PCREL-ADDR", &bool_attr[0], &bool_attr[0] }, { "ABS-ADDR", &bool_attr[0], &bool_attr[0] }, @@ -77,6 +87,7 @@ const CGEN_ATTR_TABLE m32c_cgen_hardware_attr_table[] = { { "MACH", & MACH_attr[0], & MACH_attr[0] }, { "ISA", & ISA_attr[0], & ISA_attr[0] }, + { "RL_TYPE", & RL_TYPE_attr[0], & RL_TYPE_attr[0] }, { "VIRTUAL", &bool_attr[0], &bool_attr[0] }, { "CACHE-ADDR", &bool_attr[0], &bool_attr[0] }, { "PC", &bool_attr[0], &bool_attr[0] }, @@ -88,6 +99,7 @@ const CGEN_ATTR_TABLE m32c_cgen_operand_attr_table[] = { { "MACH", & MACH_attr[0], & MACH_attr[0] }, { "ISA", & ISA_attr[0], & ISA_attr[0] }, + { "RL_TYPE", & RL_TYPE_attr[0], & RL_TYPE_attr[0] }, { "VIRTUAL", &bool_attr[0], &bool_attr[0] }, { "PCREL-ADDR", &bool_attr[0], &bool_attr[0] }, { "ABS-ADDR", &bool_attr[0], &bool_attr[0] }, @@ -103,6 +115,7 @@ const CGEN_ATTR_TABLE m32c_cgen_insn_attr_table[] = { { "MACH", & MACH_attr[0], & MACH_attr[0] }, { "ISA", & ISA_attr[0], & ISA_attr[0] }, + { "RL_TYPE", & RL_TYPE_attr[0], & RL_TYPE_attr[0] }, { "ALIAS", &bool_attr[0], &bool_attr[0] }, { "VIRTUAL", &bool_attr[0], &bool_attr[0] }, { "UNCOND-CTI", &bool_attr[0], &bool_attr[0] }, @@ -692,82 +705,82 @@ CGEN_KEYWORD m32c_cgen_opval_h_shimm = const CGEN_HW_ENTRY m32c_cgen_hw_table[] = { - { "h-memory", HW_H_MEMORY, CGEN_ASM_NONE, 0, { 0, { { { (1<nonbool[CGEN_IFLD_MACH-CGEN_IFLD_START_NBOOLS-1].nonbitset) #define CGEN_ATTR_CGEN_IFLD_ISA_VALUE(attrs) ((attrs)->nonbool[CGEN_IFLD_ISA-CGEN_IFLD_START_NBOOLS-1].bitset) +#define CGEN_ATTR_CGEN_IFLD_RL_TYPE_VALUE(attrs) ((attrs)->nonbool[CGEN_IFLD_RL_TYPE-CGEN_IFLD_START_NBOOLS-1].nonbitset) #define CGEN_ATTR_CGEN_IFLD_VIRTUAL_VALUE(attrs) (((attrs)->bool & (1 << CGEN_IFLD_VIRTUAL)) != 0) #define CGEN_ATTR_CGEN_IFLD_PCREL_ADDR_VALUE(attrs) (((attrs)->bool & (1 << CGEN_IFLD_PCREL_ADDR)) != 0) #define CGEN_ATTR_CGEN_IFLD_ABS_ADDR_VALUE(attrs) (((attrs)->bool & (1 << CGEN_IFLD_ABS_ADDR)) != 0) @@ -156,7 +162,7 @@ typedef enum ifield_type { typedef enum cgen_hw_attr { CGEN_HW_VIRTUAL, CGEN_HW_CACHE_ADDR, CGEN_HW_PC, CGEN_HW_PROFILE , CGEN_HW_END_BOOLS, CGEN_HW_START_NBOOLS = 31, CGEN_HW_MACH, CGEN_HW_ISA - , CGEN_HW_END_NBOOLS + , CGEN_HW_RL_TYPE, CGEN_HW_END_NBOOLS } CGEN_HW_ATTR; /* Number of non-boolean elements in cgen_hw_attr. */ @@ -165,6 +171,7 @@ typedef enum cgen_hw_attr { /* cgen_hw attribute accessor macros. */ #define CGEN_ATTR_CGEN_HW_MACH_VALUE(attrs) ((attrs)->nonbool[CGEN_HW_MACH-CGEN_HW_START_NBOOLS-1].nonbitset) #define CGEN_ATTR_CGEN_HW_ISA_VALUE(attrs) ((attrs)->nonbool[CGEN_HW_ISA-CGEN_HW_START_NBOOLS-1].bitset) +#define CGEN_ATTR_CGEN_HW_RL_TYPE_VALUE(attrs) ((attrs)->nonbool[CGEN_HW_RL_TYPE-CGEN_HW_START_NBOOLS-1].nonbitset) #define CGEN_ATTR_CGEN_HW_VIRTUAL_VALUE(attrs) (((attrs)->bool & (1 << CGEN_HW_VIRTUAL)) != 0) #define CGEN_ATTR_CGEN_HW_CACHE_ADDR_VALUE(attrs) (((attrs)->bool & (1 << CGEN_HW_CACHE_ADDR)) != 0) #define CGEN_ATTR_CGEN_HW_PC_VALUE(attrs) (((attrs)->bool & (1 << CGEN_HW_PC)) != 0) @@ -202,7 +209,7 @@ typedef enum cgen_operand_attr { CGEN_OPERAND_VIRTUAL, CGEN_OPERAND_PCREL_ADDR, CGEN_OPERAND_ABS_ADDR, CGEN_OPERAND_SIGN_OPT , CGEN_OPERAND_SIGNED, CGEN_OPERAND_NEGATIVE, CGEN_OPERAND_RELAX, CGEN_OPERAND_SEM_ONLY , CGEN_OPERAND_END_BOOLS, CGEN_OPERAND_START_NBOOLS = 31, CGEN_OPERAND_MACH, CGEN_OPERAND_ISA - , CGEN_OPERAND_END_NBOOLS + , CGEN_OPERAND_RL_TYPE, CGEN_OPERAND_END_NBOOLS } CGEN_OPERAND_ATTR; /* Number of non-boolean elements in cgen_operand_attr. */ @@ -211,6 +218,7 @@ typedef enum cgen_operand_attr { /* cgen_operand attribute accessor macros. */ #define CGEN_ATTR_CGEN_OPERAND_MACH_VALUE(attrs) ((attrs)->nonbool[CGEN_OPERAND_MACH-CGEN_OPERAND_START_NBOOLS-1].nonbitset) #define CGEN_ATTR_CGEN_OPERAND_ISA_VALUE(attrs) ((attrs)->nonbool[CGEN_OPERAND_ISA-CGEN_OPERAND_START_NBOOLS-1].bitset) +#define CGEN_ATTR_CGEN_OPERAND_RL_TYPE_VALUE(attrs) ((attrs)->nonbool[CGEN_OPERAND_RL_TYPE-CGEN_OPERAND_START_NBOOLS-1].nonbitset) #define CGEN_ATTR_CGEN_OPERAND_VIRTUAL_VALUE(attrs) (((attrs)->bool & (1 << CGEN_OPERAND_VIRTUAL)) != 0) #define CGEN_ATTR_CGEN_OPERAND_PCREL_ADDR_VALUE(attrs) (((attrs)->bool & (1 << CGEN_OPERAND_PCREL_ADDR)) != 0) #define CGEN_ATTR_CGEN_OPERAND_ABS_ADDR_VALUE(attrs) (((attrs)->bool & (1 << CGEN_OPERAND_ABS_ADDR)) != 0) @@ -456,7 +464,7 @@ typedef enum cgen_insn_attr { CGEN_INSN_ALIAS, CGEN_INSN_VIRTUAL, CGEN_INSN_UNCOND_CTI, CGEN_INSN_COND_CTI , CGEN_INSN_SKIP_CTI, CGEN_INSN_DELAY_SLOT, CGEN_INSN_RELAXABLE, CGEN_INSN_RELAXED , CGEN_INSN_NO_DIS, CGEN_INSN_PBB, CGEN_INSN_END_BOOLS, CGEN_INSN_START_NBOOLS = 31 - , CGEN_INSN_MACH, CGEN_INSN_ISA, CGEN_INSN_END_NBOOLS + , CGEN_INSN_MACH, CGEN_INSN_ISA, CGEN_INSN_RL_TYPE, CGEN_INSN_END_NBOOLS } CGEN_INSN_ATTR; /* Number of non-boolean elements in cgen_insn_attr. */ @@ -465,6 +473,7 @@ typedef enum cgen_insn_attr { /* cgen_insn attribute accessor macros. */ #define CGEN_ATTR_CGEN_INSN_MACH_VALUE(attrs) ((attrs)->nonbool[CGEN_INSN_MACH-CGEN_INSN_START_NBOOLS-1].nonbitset) #define CGEN_ATTR_CGEN_INSN_ISA_VALUE(attrs) ((attrs)->nonbool[CGEN_INSN_ISA-CGEN_INSN_START_NBOOLS-1].bitset) +#define CGEN_ATTR_CGEN_INSN_RL_TYPE_VALUE(attrs) ((attrs)->nonbool[CGEN_INSN_RL_TYPE-CGEN_INSN_START_NBOOLS-1].nonbitset) #define CGEN_ATTR_CGEN_INSN_ALIAS_VALUE(attrs) (((attrs)->bool & (1 << CGEN_INSN_ALIAS)) != 0) #define CGEN_ATTR_CGEN_INSN_VIRTUAL_VALUE(attrs) (((attrs)->bool & (1 << CGEN_INSN_VIRTUAL)) != 0) #define CGEN_ATTR_CGEN_INSN_UNCOND_CTI_VALUE(attrs) (((attrs)->bool & (1 << CGEN_INSN_UNCOND_CTI)) != 0) diff --git a/opcodes/m32c-dis.c b/opcodes/m32c-dis.c index 43f93e2..cfe5cb7 100644 --- a/opcodes/m32c-dis.c +++ b/opcodes/m32c-dis.c @@ -694,7 +694,7 @@ m32c_cgen_print_operand (CGEN_CPU_DESC cd, print_address (cd, info, fields->f_lab_8_16, 0|(1<f_lab_8_24, 0|(1<f_lab_8_24, 0|(1<f_lab_8_8, 0|(1<