X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-rl78.c;h=8ab35ec146ccbe9859233f95e709b436746c9f19;hb=add39d2344036db9334bdeb1ec20a90beaa3ca49;hp=f2382b7b06a2b4c84f0fa6a08bc31f6d058f0fae;hpb=e57e6ddc2e768323732a7eed6a5d25d3ee350638;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-rl78.c b/gas/config/tc-rl78.c index f2382b7b06..8ab35ec146 100644 --- a/gas/config/tc-rl78.c +++ b/gas/config/tc-rl78.c @@ -1,5 +1,5 @@ /* tc-rl78.c -- Assembler for the Renesas RL78 - Copyright (C) 2011-2014 Free Software Foundation, Inc. + Copyright (C) 2011-2016 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -102,6 +102,7 @@ rl78_linkrelax_addr16 (void) void rl78_linkrelax_branch (void) { + rl78_relax (RL78_RELAX_BRANCH, 0); rl78_bytes.link_relax |= RL78_RELAXA_BRA; } @@ -130,7 +131,7 @@ rl78_prefix (int p) } int -rl78_has_prefix () +rl78_has_prefix (void) { return rl78_bytes.n_prefix; } @@ -280,7 +281,10 @@ rl78_field (int val, int pos, int sz) enum options { OPTION_RELAX = OPTION_MD_BASE, + OPTION_NORELAX, OPTION_G10, + OPTION_G13, + OPTION_G14, OPTION_32BIT_DOUBLES, OPTION_64BIT_DOUBLES, }; @@ -292,7 +296,11 @@ const char * md_shortopts = RL78_SHORTOPTS; struct option md_longopts[] = { {"relax", no_argument, NULL, OPTION_RELAX}, + {"norelax", no_argument, NULL, OPTION_NORELAX}, {"mg10", no_argument, NULL, OPTION_G10}, + {"mg13", no_argument, NULL, OPTION_G13}, + {"mg14", no_argument, NULL, OPTION_G14}, + {"mrl78", no_argument, NULL, OPTION_G14}, {"m32bit-doubles", no_argument, NULL, OPTION_32BIT_DOUBLES}, {"m64bit-doubles", no_argument, NULL, OPTION_64BIT_DOUBLES}, {NULL, no_argument, NULL, 0} @@ -300,18 +308,32 @@ struct option md_longopts[] = size_t md_longopts_size = sizeof (md_longopts); int -md_parse_option (int c, char * arg ATTRIBUTE_UNUSED) +md_parse_option (int c, const char * arg ATTRIBUTE_UNUSED) { switch (c) { case OPTION_RELAX: linkrelax = 1; return 1; + case OPTION_NORELAX: + linkrelax = 0; + return 1; case OPTION_G10: + elf_flags &= ~ E_FLAG_RL78_CPU_MASK; elf_flags |= E_FLAG_RL78_G10; return 1; + case OPTION_G13: + elf_flags &= ~ E_FLAG_RL78_CPU_MASK; + elf_flags |= E_FLAG_RL78_G13; + return 1; + + case OPTION_G14: + elf_flags &= ~ E_FLAG_RL78_CPU_MASK; + elf_flags |= E_FLAG_RL78_G14; + return 1; + case OPTION_32BIT_DOUBLES: elf_flags &= ~ E_FLAG_RL78_64BIT_DOUBLES; return 1; @@ -323,13 +345,35 @@ md_parse_option (int c, char * arg ATTRIBUTE_UNUSED) return 0; } +int +rl78_isa_g10 (void) +{ + return (elf_flags & E_FLAG_RL78_CPU_MASK) == E_FLAG_RL78_G10; +} + +int +rl78_isa_g13 (void) +{ + return (elf_flags & E_FLAG_RL78_CPU_MASK) == E_FLAG_RL78_G13; +} + +int +rl78_isa_g14 (void) +{ + return (elf_flags & E_FLAG_RL78_CPU_MASK) == E_FLAG_RL78_G14; +} + void -md_show_usage (FILE * stream ATTRIBUTE_UNUSED) +md_show_usage (FILE * stream) { fprintf (stream, _(" RL78 specific command line options:\n")); + fprintf (stream, _(" --mrelax Enable link time relaxation\n")); fprintf (stream, _(" --mg10 Enable support for G10 variant\n")); + fprintf (stream, _(" --mg13 Selects the G13 core.\n")); + fprintf (stream, _(" --mg14 Selects the G14 core [default]\n")); + fprintf (stream, _(" --mrl78 Alias for --mg14\n")); fprintf (stream, _(" --m32bit-doubles [default]\n")); - fprintf (stream, _(" --m64bit-doubles\n")); + fprintf (stream, _(" --m64bit-doubles Source code uses 64-bit doubles\n")); } static void @@ -364,9 +408,12 @@ const pseudo_typeS md_pseudo_table[] = { NULL, NULL, 0 } }; +static symbolS * rl78_abs_sym = NULL; + void md_begin (void) { + rl78_abs_sym = symbol_make ("__rl78_abs__"); } void @@ -389,7 +436,7 @@ md_number_to_chars (char * buf, valueT val, int n) } static void -require_end_of_expr (char *fname) +require_end_of_expr (const char *fname) { while (* input_line_pointer == ' ' || * input_line_pointer == '\t') @@ -407,7 +454,7 @@ require_end_of_expr (char *fname) static struct { - char * fname; + const char * fname; int reloc; } reloc_functions[] = @@ -455,7 +502,7 @@ rl78_frag_init (fragS * fragP) { if (rl78_bytes.n_relax || rl78_bytes.link_relax) { - fragP->tc_frag_data = malloc (sizeof (rl78_bytesT)); + fragP->tc_frag_data = XNEW (rl78_bytesT); memcpy (fragP->tc_frag_data, & rl78_bytes, sizeof (rl78_bytesT)); } else @@ -486,7 +533,7 @@ rl78_handle_align (fragS * frag) } } -char * +const char * md_atof (int type, char * litP, int * sizeP) { return ieee_md_atof (type, litP, sizeP, target_big_endian); @@ -643,13 +690,23 @@ rl78_cons_fix_new (fragS * frag, case BFD_RELOC_RL78_LO16: case BFD_RELOC_RL78_HI16: if (size != 2) - as_bad (_("%%hi16/%%lo16 only applies to .short or .hword")); - type = exp->X_md; + { + /* Fixups to assembler generated expressions do not use %hi or %lo. */ + if (frag->fr_file) + as_bad (_("%%hi16/%%lo16 only applies to .short or .hword")); + } + else + type = exp->X_md; break; case BFD_RELOC_RL78_HI8: if (size != 1) - as_bad (_("%%hi8 only applies to .byte")); - type = exp->X_md; + { + /* Fixups to assembler generated expressions do not use %hi or %lo. */ + if (frag->fr_file) + as_bad (_("%%hi8 only applies to .byte")); + } + else + type = exp->X_md; break; default: break; @@ -706,7 +763,10 @@ typedef enum OT_bt_sfr, OT_bt_es, OT_bc, - OT_bh + OT_bh, + OT_sk, + OT_call, + OT_br, } op_type_T; /* We're looking for these types of relaxations: @@ -729,8 +789,10 @@ typedef enum a different size later. */ static op_type_T -rl78_opcode_type (char * op) +rl78_opcode_type (char * ops) { + unsigned char *op = (unsigned char *)ops; + if (op[0] == 0x31 && ((op[1] & 0x0f) == 0x05 || (op[1] & 0x0f) == 0x03)) @@ -754,6 +816,20 @@ rl78_opcode_type (char * op) && (op[1] & 0xef) == 0xc3) return OT_bh; + if (op[0] == 0x61 + && (op[1] & 0xcf) == 0xc8) + return OT_sk; + + if (op[0] == 0x61 + && (op[1] & 0xef) == 0xe3) + return OT_sk; + + if (op[0] == 0xfc) + return OT_call; + + if ((op[0] & 0xec) == 0xec) + return OT_br; + return OT_other; } @@ -804,7 +880,7 @@ rl78_frag_fix_value (fragS * fragP, /* Estimate how big the opcode is after this relax pass. The return value is the difference between fr_fix and the actual size. We compute the total size in rl78_relax_frag and store it in fr_subtype, - sowe only need to subtract fx_fix and return it. */ + so we only need to subtract fx_fix and return it. */ int md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED) @@ -850,6 +926,11 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch) fragP->tc_frag_data->relax[ri].type != RL78_RELAX_BRANCH, & sym_addr)) { + /* If we don't expect the linker to do relaxing, don't emit + expanded opcodes that only the linker will relax. */ + if (!linkrelax) + return newsize - oldsize; + /* If we don't, we must use the maximum size for the linker. */ switch (fragP->tc_frag_data->relax[ri].type) { @@ -869,7 +950,10 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch) case OT_bh: newsize = 6; break; - case OT_other: + case OT_sk: + newsize = 2; + break; + default: newsize = oldsize; break; } @@ -916,7 +1000,10 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch) else newsize = 6; break; - case OT_other: + case OT_sk: + newsize = 2; + break; + default: newsize = oldsize; break; } @@ -941,8 +1028,8 @@ rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch) fragP->fr_subtype = newsize; tprintf (" -> new %d old %d delta %d\n", newsize, oldsize, newsize-oldsize); return newsize - oldsize; - } - +} + /* This lets us test for the opcode type and the desired size in a switch statement. */ #define OPCODE(type,size) ((type) * 16 + (size)) @@ -976,12 +1063,12 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, /* We used a new frag for this opcode, so the opcode address should be the frag address. */ mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal); - tprintf("\033[32mmypc: 0x%x\033[0m\n", (int)mypc); + tprintf ("\033[32mmypc: 0x%x\033[0m\n", (int)mypc); /* Try to get the target address. If we fail here, we just use the largest format. */ if (rl78_frag_fix_value (fragP, segment, 0, & addr0, - fragP->tc_frag_data->relax[ri].type != RL78_RELAX_BRANCH, 0)) + fragP->tc_frag_data->relax[ri].type != RL78_RELAX_BRANCH, 0)) { /* We don't know the target address. */ keep_reloc = 1; @@ -1011,6 +1098,7 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, case OPCODE (OT_bt, 3): /* BT A,$ - no change. */ disp -= 3; op[2] = disp; + reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE; break; case OPCODE (OT_bt, 6): /* BT A,$ - long version. */ @@ -1028,6 +1116,7 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, case OPCODE (OT_bt_sfr, 4): /* BT PSW,$ - no change. */ disp -= 4; op[3] = disp; + reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE; break; case OPCODE (OT_bt_sfr, 7): /* BT PSW,$ - long version. */ @@ -1045,6 +1134,7 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, case OPCODE (OT_bt_es, 4): /* BT ES:[HL],$ - no change. */ disp -= 4; op[3] = disp; + reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE; break; case OPCODE (OT_bt_es, 7): /* BT PSW,$ - long version. */ @@ -1062,6 +1152,7 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, case OPCODE (OT_bc, 2): /* BC $ - no change. */ disp -= 2; op[1] = disp; + reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE; break; case OPCODE (OT_bc, 5): /* BC $ - long version. */ @@ -1079,6 +1170,7 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, case OPCODE (OT_bh, 3): /* BH $ - no change. */ disp -= 3; op[2] = disp; + reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE; break; case OPCODE (OT_bh, 6): /* BC $ - long version. */ @@ -1093,11 +1185,13 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, reloc_adjust = 2; break; + case OPCODE (OT_sk, 2): /* SK - no change */ + reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE; + break; + default: - fprintf(stderr, "Missed case %d %d at 0x%lx\n", - rl78_opcode_type (fragP->fr_opcode), fragP->fr_subtype, mypc); - abort (); - + reloc_type = fix ? fix->fx_r_type : BFD_RELOC_NONE; + break; } break; @@ -1164,6 +1258,12 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) return reloc; } + if (fixp->fx_r_type == BFD_RELOC_RL78_RELAX && !linkrelax) + { + reloc[0] = NULL; + return reloc; + } + if (fixp->fx_subsy && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) { @@ -1171,8 +1271,8 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) fixp->fx_subsy = NULL; } - reloc[0] = (arelent *) xmalloc (sizeof (arelent)); - reloc[0]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc[0] = XNEW (arelent); + reloc[0]->sym_ptr_ptr = XNEW (asymbol *); * reloc[0]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc[0]->address = fixp->fx_frag->fr_address + fixp->fx_where; reloc[0]->addend = fixp->fx_offset; @@ -1184,15 +1284,25 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) } #define OPX(REL,SYM,ADD) \ - reloc[rp] = (arelent *) xmalloc (sizeof (arelent)); \ - reloc[rp]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); \ + reloc[rp] = XNEW (arelent); \ + reloc[rp]->sym_ptr_ptr = XNEW (asymbol *); \ reloc[rp]->howto = bfd_reloc_type_lookup (stdoutput, REL); \ reloc[rp]->addend = ADD; \ * reloc[rp]->sym_ptr_ptr = SYM; \ reloc[rp]->address = fixp->fx_frag->fr_address + fixp->fx_where; \ reloc[++rp] = NULL #define OPSYM(SYM) OPX(BFD_RELOC_RL78_SYM, SYM, 0) -#define OPIMM(IMM) OPX(BFD_RELOC_RL78_SYM, abs_symbol.bsym, IMM) + + /* FIXME: We cannot do the normal thing for an immediate value reloc, + ie creating a RL78_SYM reloc in the *ABS* section with an offset + equal to the immediate value we want to store. This fails because + the reloc processing in bfd_perform_relocation and bfd_install_relocation + will short circuit such relocs and never pass them on to the special + reloc processing code. So instead we create a RL78_SYM reloc against + the __rl78_abs__ symbol and arrange for the linker scripts to place + this symbol at address 0. */ +#define OPIMM(IMM) OPX (BFD_RELOC_RL78_SYM, symbol_get_bfdsym (rl78_abs_sym), IMM) + #define OP(OP) OPX(BFD_RELOC_RL78_##OP, *reloc[0]->sym_ptr_ptr, 0) #define SYM0() reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RL78_SYM) @@ -1315,6 +1425,11 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED, char * op; unsigned long val; + /* We always defer overflow checks for these to the linker, as it + needs to do PLT stuff. */ + if (f->fx_r_type == BFD_RELOC_RL78_CODE) + f->fx_no_overflow = 1; + if (f->fx_addsy && S_FORCE_RELOC (f->fx_addsy, 1)) return; if (f->fx_subsy && S_FORCE_RELOC (f->fx_subsy, 1)) @@ -1323,13 +1438,16 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED, op = f->fx_frag->fr_literal + f->fx_where; val = (unsigned long) * t; + if (f->fx_addsy == NULL) + f->fx_done = 1; + switch (f->fx_r_type) { case BFD_RELOC_NONE: break; case BFD_RELOC_RL78_RELAX: - f->fx_done = 1; + f->fx_done = 0; break; case BFD_RELOC_8_PCREL: @@ -1339,6 +1457,7 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED, val); /* Fall through. */ case BFD_RELOC_8: + case BFD_RELOC_RL78_SADDR: /* We need to store the 8 LSB, but this works. */ op[0] = val; break; @@ -1361,13 +1480,22 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED, break; case BFD_RELOC_32: - case BFD_RELOC_RL78_DIFF: op[0] = val; op[1] = val >> 8; op[2] = val >> 16; op[3] = val >> 24; break; + case BFD_RELOC_RL78_DIFF: + op[0] = val; + if (f->fx_size > 1) + op[1] = val >> 8; + if (f->fx_size > 2) + op[2] = val >> 16; + if (f->fx_size > 3) + op[3] = val >> 24; + break; + case BFD_RELOC_RL78_HI8: val = val >> 16; op[0] = val; @@ -1390,13 +1518,11 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED, break; } - if (f->fx_addsy == NULL) - f->fx_done = 1; } valueT md_section_align (segT segment, valueT size) { int align = bfd_get_section_alignment (stdoutput, segment); - return ((size + (1 << align) - 1) & (-1 << align)); + return ((size + (1 << align) - 1) & -(1 << align)); }