2015-12-08 DJ Delorie <dj@redhat.com>
+ * elf32-rl78.c (rl78_offset_for_reloc): Add more relocs.
+ (rl78_elf_relax_section): Add bc/bz/bnc/bnz/bh/bnh. Fix reloc
+ choices.
+
* elf32-rx.c (rx_elf_object_p): Ignore empty and nobits sections.
2015-12-07 Nick Clifton <nickc@redhat.com>
default:
reloc_computes_value:
- symval = rl78_compute_complex_reloc (r_type, 0, input_section);
+ symval = rl78_compute_complex_reloc (r_type, symval, input_section);
+ case R_RL78_DIR32:
+ case R_RL78_DIR24S:
+ case R_RL78_DIR16:
+ case R_RL78_DIR16U:
+ case R_RL78_DIR16S:
+ case R_RL78_DIR24S_PCREL:
+ case R_RL78_DIR16S_PCREL:
+ case R_RL78_DIR8S_PCREL:
if (lrel)
*lrel = rel;
return symval;
switch (insn[0])
{
+ case 0xdc: /* BC */
+ case 0xdd: /* BZ */
+ case 0xde: /* BNC */
+ case 0xdf: /* BNZ */
+ if (insn[1] == 0x03 && insn[2] == 0xee /* BR */
+ && (srel->r_offset - irel->r_offset) > 1) /* a B<c> without its own reloc */
+ {
+ /* This is a "long" conditional as generated by gas:
+ DC 03 EE ad.dr */
+ if (pcrel < 127
+ && pcrel > -127)
+ {
+ insn[0] ^= 0x02; /* invert conditional */
+ SNIPNR (4, 1);
+ SNIP (1, 2, R_RL78_DIR8S_PCREL);
+ insn[1] = pcrel;
+ *again = TRUE;
+ }
+ }
+ break;
+
case 0xec: /* BR !!abs20 */
if (pcrel < 127
insn[0] = 0xed;
insn[1] = symval & 0xff;
insn[2] = symval >> 8;
- SNIP (2, 1, R_RL78_DIR16S);
+ SNIP (2, 1, R_RL78_DIR16U);
*again = TRUE;
}
else if (pcrel < 32767
insn[0] = 0xfd;
insn[1] = symval & 0xff;
insn[2] = symval >> 8;
- SNIP (2, 1, R_RL78_DIR16S);
+ SNIP (2, 1, R_RL78_DIR16U);
*again = TRUE;
}
else if (pcrel < 32767
here anyway. */
switch (insn[1])
{
+ case 0xd3: /* BNH */
+ case 0xc3: /* BH */
+ if (insn[2] == 0x03 && insn[3] == 0xee
+ && (srel->r_offset - irel->r_offset) > 2) /* a B<c> without its own reloc */
+ {
+ /* Another long branch by gas:
+ 61 D3 03 EE ad.dr */
+ if (pcrel < 127
+ && pcrel > -127)
+ {
+ insn[1] ^= 0x10; /* invert conditional */
+ SNIPNR (5, 1);
+ SNIP (2, 2, R_RL78_DIR8S_PCREL);
+ insn[2] = pcrel;
+ *again = TRUE;
+ }
+ }
+ break;
+
case 0xc8: /* SKC */
if (insn[2] == 0xef)
{
+2015-12-08 DJ Delorie <dj@redhat.com>
+
+ * config/rl78-parse.y: Make all branches relaxable via
+ rl78_linkrelax_branch().
+ * config/tc-rl78.c (rl78_linkrelax_branch): Mark all relaxable
+ branches with relocs.
+ (options): Add OPTION_NORELAX.
+ (md_longopts): Add -mnorelax.
+ (md_parse_option): Support OPTION_NORELAX.
+ (op_type_T): Add bh, sk, call, and br.
+ (rl78_opcode_type): Likewise.
+ (rl78_relax_frag): Fix not-relaxing logic. Add sk.
+ (md_convert_frag): Fix relocation handling.
+ (tc_gen_reloc): Strip relax relocs when not linker relaxing.
+ (md_apply_fix): Defer overflow handling for anything that needs a
+ PLT, to the linker.
+ * config/tc-rl78.h (TC_FORCE_RELOCATION): Force all relocations to
+ the linker when linker relaxing.
+ * doc/c-rl78.texi (norelax): Add.
+
2015-12-07 Alan Modra <amodra@gmail.com>
* config/tc-ppc.c (md_apply_fix): Localize variables. Reduce casts.
/* ---------------------------------------------------------------------- */
| BC '$' EXPR
- { B1 (0xdc); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+ { B1 (0xdc); PC1 ($3); rl78_linkrelax_branch (); }
| BNC '$' EXPR
- { B1 (0xde); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+ { B1 (0xde); PC1 ($3); rl78_linkrelax_branch (); }
| BZ '$' EXPR
- { B1 (0xdd); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+ { B1 (0xdd); PC1 ($3); rl78_linkrelax_branch (); }
| BNZ '$' EXPR
- { B1 (0xdf); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+ { B1 (0xdf); PC1 ($3); rl78_linkrelax_branch (); }
| BH '$' EXPR
- { B2 (0x61, 0xc3); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+ { B2 (0x61, 0xc3); PC1 ($3); rl78_linkrelax_branch (); }
| BNH '$' EXPR
- { B2 (0x61, 0xd3); PC1 ($3); rl78_relax (RL78_RELAX_BRANCH, 0); }
+ { B2 (0x61, 0xd3); PC1 ($3); rl78_linkrelax_branch (); }
/* ---------------------------------------------------------------------- */
{ B2 (0x61, 0xcb); }
| BR '$' EXPR
- { B1 (0xef); PC1 ($3); }
+ { B1 (0xef); PC1 ($3); rl78_linkrelax_branch (); }
| BR '$' '!' EXPR
{ B1 (0xee); PC2 ($4); rl78_linkrelax_branch (); }
/* ---------------------------------------------------------------------- */
| SKC
- { B2 (0x61, 0xc8); rl78_linkrelax_branch (); }
+ { B2 (0x61, 0xc8); rl78_relax (RL78_RELAX_BRANCH, 0); }
| SKH
- { B2 (0x61, 0xe3); rl78_linkrelax_branch (); }
+ { B2 (0x61, 0xe3); rl78_relax (RL78_RELAX_BRANCH, 0); }
| SKNC
- { B2 (0x61, 0xd8); rl78_linkrelax_branch (); }
+ { B2 (0x61, 0xd8); rl78_relax (RL78_RELAX_BRANCH, 0); }
| SKNH
- { B2 (0x61, 0xf3); rl78_linkrelax_branch (); }
+ { B2 (0x61, 0xf3); rl78_relax (RL78_RELAX_BRANCH, 0); }
| SKNZ
- { B2 (0x61, 0xf8); rl78_linkrelax_branch (); }
+ { B2 (0x61, 0xf8); rl78_relax (RL78_RELAX_BRANCH, 0); }
| SKZ
- { B2 (0x61, 0xe8); rl78_linkrelax_branch (); }
+ { B2 (0x61, 0xe8); rl78_relax (RL78_RELAX_BRANCH, 0); }
/* ---------------------------------------------------------------------- */
| XOR1 { $$ = 0x07; rl78_bit_insn = 1; }
;
-bt_bf : BT { $$ = 0x02; rl78_bit_insn = 1; rl78_relax (RL78_RELAX_BRANCH, 0); }
- | BF { $$ = 0x04; rl78_bit_insn = 1; rl78_relax (RL78_RELAX_BRANCH, 0); }
+bt_bf : BT { $$ = 0x02; rl78_bit_insn = 1; rl78_linkrelax_branch (); }
+ | BF { $$ = 0x04; rl78_bit_insn = 1; rl78_linkrelax_branch (); }
| BTCLR { $$ = 0x00; rl78_bit_insn = 1; }
;
void
rl78_linkrelax_branch (void)
{
+ rl78_relax (RL78_RELAX_BRANCH, 0);
rl78_bytes.link_relax |= RL78_RELAXA_BRA;
}
enum options
{
OPTION_RELAX = OPTION_MD_BASE,
+ OPTION_NORELAX,
OPTION_G10,
OPTION_G13,
OPTION_G14,
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},
case OPTION_RELAX:
linkrelax = 1;
return 1;
+ case OPTION_NORELAX:
+ linkrelax = 0;
+ return 1;
case OPTION_G10:
elf_flags &= ~ E_FLAG_RL78_CPU_MASK;
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:
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))
&& (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;
}
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 OT_bh:
newsize = 6;
break;
- case OT_other:
+ case OT_sk:
+ newsize = 2;
+ break;
+ default:
newsize = oldsize;
break;
}
else
newsize = 6;
break;
- case OT_other:
+ case OT_sk:
+ newsize = 2;
+ break;
+ default:
newsize = oldsize;
break;
}
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. */
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. */
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. */
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. */
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. */
reloc_adjust = 2;
break;
- default:
- fprintf(stderr, "Missed case %d %d at 0x%lx\n",
- rl78_opcode_type (fragP->fr_opcode), fragP->fr_subtype, mypc);
- abort ();
+ case OPCODE (OT_sk, 2): /* SK<cond> - 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;
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)
{
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))
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:
break;
}
- if (f->fx_addsy == NULL)
- f->fx_done = 1;
}
valueT
|| TC_FORCE_RELOCATION (FIX))
#define DWARF2_USE_FIXED_ADVANCE_PC 1
+
+#define TC_FORCE_RELOCATION(FIX) (linkrelax)
@item relax
Enable support for link-time relaxation.
+@item norelax
+Disable support for link-time relaxation (default).
+
@item mg10
Mark the generated binary as targeting the G10 variant of the RL78
architecture.