X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-rl78.c;h=8ab35ec146ccbe9859233f95e709b436746c9f19;hb=3d207518c117df7a6c58f20bc2693171b7690650;hp=04c9b2c845263efdccb7501fba1fb252f7a64bb7;hpb=4b95cf5c0c75d6efc1b2f96af72317aecca079f1;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-rl78.c b/gas/config/tc-rl78.c index 04c9b2c845..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. @@ -20,7 +20,6 @@ #include "as.h" #include "struc-symbol.h" -#include "obstack.h" #include "safe-ctype.h" #include "dwarf2dbg.h" #include "libbfd.h" @@ -85,6 +84,15 @@ typedef struct rl78_bytesT static rl78_bytesT rl78_bytes; +void +rl78_relax (int type, int pos) +{ + rl78_bytes.relax[rl78_bytes.n_relax].type = type; + rl78_bytes.relax[rl78_bytes.n_relax].field_pos = pos; + rl78_bytes.relax[rl78_bytes.n_relax].val_ofs = rl78_bytes.n_base + rl78_bytes.n_ops; + rl78_bytes.n_relax ++; +} + void rl78_linkrelax_addr16 (void) { @@ -94,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; } @@ -122,7 +131,7 @@ rl78_prefix (int p) } int -rl78_has_prefix () +rl78_has_prefix (void) { return rl78_bytes.n_prefix; } @@ -199,6 +208,16 @@ rl78_op (expressionS exp, int nbytes, int type) if (nbytes > 2 && exp.X_md == BFD_RELOC_RL78_CODE) exp.X_md = 0; + + if (nbytes == 1 + && (exp.X_md == BFD_RELOC_RL78_LO16 + || exp.X_md == BFD_RELOC_RL78_HI16)) + as_bad (_("16-bit relocation used in 8-bit operand")); + + if (nbytes == 2 + && exp.X_md == BFD_RELOC_RL78_HI8) + as_bad (_("8-bit relocation used in 16-bit operand")); + rl78_op_fixup (exp, rl78_bytes.n_ops * 8, nbytes * 8, type); memset (rl78_bytes.ops + rl78_bytes.n_ops, 0, nbytes); rl78_bytes.n_ops += nbytes; @@ -262,7 +281,12 @@ 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, }; #define RL78_SHORTOPTS "" @@ -272,32 +296,85 @@ 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} }; 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; + + case OPTION_64BIT_DOUBLES: + elf_flags |= E_FLAG_RL78_64BIT_DOUBLES; + return 1; } return 0; } -void -md_show_usage (FILE * stream ATTRIBUTE_UNUSED) +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) +{ + 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 Source code uses 64-bit doubles\n")); +} static void s_bss (int ignore ATTRIBUTE_UNUSED) @@ -309,23 +386,34 @@ s_bss (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +static void +rl78_float_cons (int ignore ATTRIBUTE_UNUSED) +{ + if (elf_flags & E_FLAG_RL78_64BIT_DOUBLES) + return float_cons ('d'); + return float_cons ('f'); +} + /* The target specific pseudo-ops which we support. */ const pseudo_typeS md_pseudo_table[] = { - /* Our "standard" pseudos. */ - { "double", float_cons, 'd' }, - { "bss", s_bss, 0 }, - { "3byte", cons, 3 }, - { "int", cons, 4 }, - { "word", cons, 4 }, + /* Our "standard" pseudos. */ + { "double", rl78_float_cons, 'd' }, + { "bss", s_bss, 0 }, + { "3byte", cons, 3 }, + { "int", cons, 4 }, + { "word", cons, 4 }, /* End of list marker. */ { NULL, NULL, 0 } }; +static symbolS * rl78_abs_sym = NULL; + void md_begin (void) { + rl78_abs_sym = symbol_make ("__rl78_abs__"); } void @@ -348,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') @@ -366,7 +454,7 @@ require_end_of_expr (char *fname) static struct { - char * fname; + const char * fname; int reloc; } reloc_functions[] = @@ -414,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 @@ -445,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); @@ -486,12 +574,13 @@ md_assemble (char * str) rl78_parse (); /* This simplifies the relaxation code. */ - if (rl78_bytes.link_relax) + if (rl78_bytes.n_relax || rl78_bytes.link_relax) { int olen = rl78_bytes.n_prefix + rl78_bytes.n_base + rl78_bytes.n_ops; /* We do it this way because we want the frag to have the - rl78_bytes in it, which we initialize above. */ - bytes = frag_more (olen); + rl78_bytes in it, which we initialize above. The extra bytes + are for relaxing. */ + bytes = frag_more (olen + 3); frag_then = frag_now; frag_variant (rs_machine_dependent, olen /* max_chars */, @@ -601,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; @@ -638,13 +737,515 @@ rl78_cons_fix_new (fragS * frag, } } -/* No relaxation just yet */ + +/*----------------------------------------------------------------------*/ +/* To recap: we estimate everything based on md_estimate_size, then + adjust based on rl78_relax_frag. When it all settles, we call + md_convert frag to update the bytes. The relaxation types and + relocations are in fragP->tc_frag_data, which is a copy of that + rl78_bytes. + + Our scheme is as follows: fr_fix has the size of the smallest + opcode (like BRA.S). We store the number of total bytes we need in + fr_subtype. When we're done relaxing, we use fr_subtype and the + existing opcode bytes to figure out what actual opcode we need to + put in there. If the fixup isn't resolvable now, we use the + maximal size. */ + +#define TRACE_RELAX 0 +#define tprintf if (TRACE_RELAX) printf + + +typedef enum +{ + OT_other, + OT_bt, + OT_bt_sfr, + OT_bt_es, + OT_bc, + OT_bh, + OT_sk, + OT_call, + OT_br, +} op_type_T; + +/* We're looking for these types of relaxations: + + BT 00110001 sbit0cc1 addr---- (cc is 10 (BF) or 01 (BT)) + B~T 00110001 sbit0cc1 00000011 11101110 pcrel16- -------- (BR $!pcrel20) + + BT sfr 00110001 sbit0cc0 sfr----- addr---- + BT ES: 00010001 00101110 sbit0cc1 addr---- + + BC 110111cc addr---- + B~C 110111cc 00000011 11101110 pcrel16- -------- (BR $!pcrel20) + + BH 01100001 110c0011 00000011 11101110 pcrel16- -------- (BR $!pcrel20) + B~H 01100001 110c0011 00000011 11101110 pcrel16- -------- (BR $!pcrel20) +*/ + +/* Given the opcode bytes at OP, figure out which opcode it is and + return the type of opcode. We use this to re-encode the opcode as + a different size later. */ + +static op_type_T +rl78_opcode_type (char * ops) +{ + unsigned char *op = (unsigned char *)ops; + + if (op[0] == 0x31 + && ((op[1] & 0x0f) == 0x05 + || (op[1] & 0x0f) == 0x03)) + return OT_bt; + + if (op[0] == 0x31 + && ((op[1] & 0x0f) == 0x04 + || (op[1] & 0x0f) == 0x02)) + return OT_bt_sfr; + + if (op[0] == 0x11 + && op[1] == 0x31 + && ((op[2] & 0x0f) == 0x05 + || (op[2] & 0x0f) == 0x03)) + return OT_bt_es; + + if ((op[0] & 0xfc) == 0xdc) + return OT_bc; + + if (op[0] == 0x61 + && (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; +} + +/* Returns zero if *addrP has the target address. Else returns nonzero + if we cannot compute the target address yet. */ + +static int +rl78_frag_fix_value (fragS * fragP, + segT segment, + int which, + addressT * addrP, + int need_diff, + addressT * sym_addr) +{ + addressT addr = 0; + rl78_bytesT * b = fragP->tc_frag_data; + expressionS * exp = & b->fixups[which].exp; + + if (need_diff && exp->X_op != O_subtract) + return 1; + + if (exp->X_add_symbol) + { + if (S_FORCE_RELOC (exp->X_add_symbol, 1)) + return 1; + if (S_GET_SEGMENT (exp->X_add_symbol) != segment) + return 1; + addr += S_GET_VALUE (exp->X_add_symbol); + } + + if (exp->X_op_symbol) + { + if (exp->X_op != O_subtract) + return 1; + if (S_FORCE_RELOC (exp->X_op_symbol, 1)) + return 1; + if (S_GET_SEGMENT (exp->X_op_symbol) != segment) + return 1; + addr -= S_GET_VALUE (exp->X_op_symbol); + } + if (sym_addr) + * sym_addr = addr; + addr += exp->X_add_number; + * addrP = addr; + return 0; +} + +/* 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, + 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) { - return 0; + int opfixsize; + int delta; + + /* This is the size of the opcode that's accounted for in fr_fix. */ + opfixsize = fragP->fr_fix - (fragP->fr_opcode - fragP->fr_literal); + /* This is the size of the opcode that isn't. */ + delta = (fragP->fr_subtype - opfixsize); + + tprintf (" -> opfixsize %d delta %d\n", opfixsize, delta); + return delta; +} + +/* Given the new addresses for this relax pass, figure out how big + each opcode must be. We store the total number of bytes needed in + fr_subtype. The return value is the difference between the size + after the last pass and the size after this pass, so we use the old + fr_subtype to calculate the difference. */ + +int +rl78_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch) +{ + addressT addr0, sym_addr; + addressT mypc; + int disp; + int oldsize = fragP->fr_subtype; + int newsize = oldsize; + op_type_T optype; + int ri; + + mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal); + + /* If we ever get more than one reloc per opcode, this is the one + we're relaxing. */ + ri = 0; + + optype = rl78_opcode_type (fragP->fr_opcode); + /* Try to get the target address. */ + if (rl78_frag_fix_value (fragP, segment, ri, & addr0, + 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) + { + case RL78_RELAX_BRANCH: + switch (optype) + { + case OT_bt: + newsize = 6; + break; + case OT_bt_sfr: + case OT_bt_es: + newsize = 7; + break; + case OT_bc: + newsize = 5; + break; + case OT_bh: + newsize = 6; + break; + case OT_sk: + newsize = 2; + break; + default: + newsize = oldsize; + break; + } + break; + + } + fragP->fr_subtype = newsize; + tprintf (" -> new %d old %d delta %d (external)\n", newsize, oldsize, newsize-oldsize); + return newsize - oldsize; + } + + if (sym_addr > mypc) + addr0 += stretch; + + switch (fragP->tc_frag_data->relax[ri].type) + { + case RL78_RELAX_BRANCH: + disp = (int) addr0 - (int) mypc; + + switch (optype) + { + case OT_bt: + if (disp >= -128 && (disp - (oldsize-2)) <= 127) + newsize = 3; + else + newsize = 6; + break; + case OT_bt_sfr: + case OT_bt_es: + if (disp >= -128 && (disp - (oldsize-3)) <= 127) + newsize = 4; + else + newsize = 7; + break; + case OT_bc: + if (disp >= -128 && (disp - (oldsize-1)) <= 127) + newsize = 2; + else + newsize = 5; + break; + case OT_bh: + if (disp >= -128 && (disp - (oldsize-2)) <= 127) + newsize = 3; + else + newsize = 6; + break; + case OT_sk: + newsize = 2; + break; + default: + newsize = oldsize; + break; + } + break; + } + + /* This prevents infinite loops in align-heavy sources. */ + if (newsize < oldsize) + { + if (fragP->tc_frag_data->times_shrank > 10 + && fragP->tc_frag_data->times_grown > 10) + newsize = oldsize; + if (fragP->tc_frag_data->times_shrank < 20) + fragP->tc_frag_data->times_shrank ++; + } + else if (newsize > oldsize) + { + if (fragP->tc_frag_data->times_grown < 20) + fragP->tc_frag_data->times_grown ++; + } + + 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)) + +/* Given the opcode stored in fr_opcode and the number of bytes we + think we need, encode a new opcode. We stored a pointer to the + fixup for this opcode in the tc_frag_data structure. If we can do + the fixup here, we change the relocation type to "none" (we test + for that in tc_gen_reloc) else we change it to the right type for + the new (biggest) opcode. */ + +void +md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, + segT segment ATTRIBUTE_UNUSED, + fragS * fragP ATTRIBUTE_UNUSED) +{ + rl78_bytesT * rl78b = fragP->tc_frag_data; + addressT addr0, mypc; + int disp; + int reloc_type, reloc_adjust; + char * op = fragP->fr_opcode; + int keep_reloc = 0; + int ri; + int fi = (rl78b->n_fixups > 1) ? 1 : 0; + fixS * fix = rl78b->fixups[fi].fixP; + + /* If we ever get more than one reloc per opcode, this is the one + we're relaxing. */ + ri = 0; + + /* 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); + + /* 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)) + { + /* We don't know the target address. */ + keep_reloc = 1; + addr0 = 0; + disp = 0; + tprintf ("unknown addr ? - %x = ?\n", (int)mypc); + } + else + { + /* We know the target address, and it's in addr0. */ + disp = (int) addr0 - (int) mypc; + tprintf ("known addr %x - %x = %d\n", (int)addr0, (int)mypc, disp); + } + + if (linkrelax) + keep_reloc = 1; + + reloc_type = BFD_RELOC_NONE; + reloc_adjust = 0; + + switch (fragP->tc_frag_data->relax[ri].type) + { + case RL78_RELAX_BRANCH: + switch (OPCODE (rl78_opcode_type (fragP->fr_opcode), fragP->fr_subtype)) + { + + 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. */ + disp -= 3; + op[1] ^= 0x06; /* toggle conditional. */ + op[2] = 3; /* displacement over long branch. */ + disp -= 3; + op[3] = 0xEE; /* BR $!addr20 */ + op[4] = disp & 0xff; + op[5] = disp >> 8; + reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE; + reloc_adjust = 2; + break; + + 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. */ + disp -= 4; + op[1] ^= 0x06; /* toggle conditional. */ + op[3] = 3; /* displacement over long branch. */ + disp -= 3; + op[4] = 0xEE; /* BR $!addr20 */ + op[5] = disp & 0xff; + op[6] = disp >> 8; + reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE; + reloc_adjust = 2; + break; + + 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. */ + disp -= 4; + op[2] ^= 0x06; /* toggle conditional. */ + op[3] = 3; /* displacement over long branch. */ + disp -= 3; + op[4] = 0xEE; /* BR $!addr20 */ + op[5] = disp & 0xff; + op[6] = disp >> 8; + reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE; + reloc_adjust = 2; + break; + + 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. */ + disp -= 2; + op[0] ^= 0x02; /* toggle conditional. */ + op[1] = 3; + disp -= 3; + op[2] = 0xEE; /* BR $!addr20 */ + op[3] = disp & 0xff; + op[4] = disp >> 8; + reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE; + reloc_adjust = 2; + break; + + 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. */ + disp -= 3; + op[1] ^= 0x10; /* toggle conditional. */ + op[2] = 3; + disp -= 3; + op[3] = 0xEE; /* BR $!addr20 */ + op[4] = disp & 0xff; + op[5] = disp >> 8; + reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE; + 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: + reloc_type = fix ? fix->fx_r_type : BFD_RELOC_NONE; + break; + } + break; + + default: + if (rl78b->n_fixups) + { + reloc_type = fix->fx_r_type; + reloc_adjust = 0; + } + break; + } + + if (rl78b->n_fixups) + { + + fix->fx_r_type = reloc_type; + fix->fx_where += reloc_adjust; + switch (reloc_type) + { + case BFD_RELOC_NONE: + fix->fx_size = 0; + break; + case BFD_RELOC_8: + fix->fx_size = 1; + break; + case BFD_RELOC_16_PCREL: + fix->fx_size = 2; + break; + } + } + + fragP->fr_fix = fragP->fr_subtype + (fragP->fr_opcode - fragP->fr_literal); + tprintf ("fragP->fr_fix now %ld (%d + (%p - %p)\n", (long) fragP->fr_fix, + fragP->fr_subtype, fragP->fr_opcode, fragP->fr_literal); + fragP->fr_var = 0; + + tprintf ("compare 0x%lx vs 0x%lx - 0x%lx = 0x%lx (%p)\n", + (long)fragP->fr_fix, + (long)fragP->fr_next->fr_address, (long)fragP->fr_address, + (long)(fragP->fr_next->fr_address - fragP->fr_address), + fragP->fr_next); + + if (fragP->fr_next != NULL + && ((offsetT) (fragP->fr_next->fr_address - fragP->fr_address) + != fragP->fr_fix)) + as_bad (_("bad frag at %p : fix %ld addr %ld %ld \n"), fragP, + (long) fragP->fr_fix, + (long) fragP->fr_address, (long) fragP->fr_next->fr_address); } +/* End of relaxation code. + ----------------------------------------------------------------------*/ + + arelent ** tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) { @@ -657,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) { @@ -664,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; @@ -677,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) @@ -722,8 +1339,8 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) break; case BFD_RELOC_RL78_CODE: - SYM0 (); - OP (ABS16); + reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RL78_16U); + reloc[1] = NULL; break; case BFD_RELOC_RL78_LO16: @@ -808,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)) @@ -816,22 +1438,36 @@ 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: case BFD_RELOC_8_PCREL: + if ((long)val < -128 || (long)val > 127) + as_bad_where (f->fx_file, f->fx_line, + _("value of %ld too large for 8-bit branch"), + 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; - case BFD_RELOC_16: case BFD_RELOC_16_PCREL: + if ((long)val < -32768 || (long)val > 32767) + as_bad_where (f->fx_file, f->fx_line, + _("value of %ld too large for 16-bit branch"), + val); + /* Fall through. */ + case BFD_RELOC_16: case BFD_RELOC_RL78_CODE: op[0] = val; op[1] = val >> 8; @@ -844,35 +1480,49 @@ 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; + break; + + case BFD_RELOC_RL78_HI16: + val = val >> 16; + op[0] = val; + op[1] = val >> 8; + break; + + case BFD_RELOC_RL78_LO16: + op[0] = val; + op[1] = val >> 8; + break; + default: as_bad (_("Unknown reloc in md_apply_fix: %s"), bfd_get_reloc_code_name (f->fx_r_type)); 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)); -} - -void -md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, - segT segment ATTRIBUTE_UNUSED, - fragS * fragP ATTRIBUTE_UNUSED) -{ - /* No relaxation yet */ - fragP->fr_var = 0; + return ((size + (1 << align) - 1) & -(1 << align)); }