aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog4
-rw-r--r--bfd/elf32-rl78.c54
-rw-r--r--gas/ChangeLog20
-rw-r--r--gas/config/rl78-parse.y30
-rw-r--r--gas/config/tc-rl78.c77
-rw-r--r--gas/config/tc-rl78.h2
-rw-r--r--gas/doc/c-rl78.texi3
7 files changed, 161 insertions, 29 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 180f363..2473d6e 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,9 @@
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>
diff --git a/bfd/elf32-rl78.c b/bfd/elf32-rl78.c
index 723cb4b..cf192bf 100644
--- a/bfd/elf32-rl78.c
+++ b/bfd/elf32-rl78.c
@@ -1974,7 +1974,15 @@ rl78_offset_for_reloc (bfd * abfd,
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;
@@ -2316,6 +2324,27 @@ rl78_elf_relax_section
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
@@ -2331,7 +2360,7 @@ rl78_elf_relax_section
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
@@ -2363,7 +2392,7 @@ rl78_elf_relax_section
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
@@ -2386,6 +2415,25 @@ rl78_elf_relax_section
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)
{
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 8a50708..6fb81a1 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,23 @@
+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.
diff --git a/gas/config/rl78-parse.y b/gas/config/rl78-parse.y
index b879581..ff017cf 100644
--- a/gas/config/rl78-parse.y
+++ b/gas/config/rl78-parse.y
@@ -294,22 +294,22 @@ statement :
/* ---------------------------------------------------------------------- */
| 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 (); }
/* ---------------------------------------------------------------------- */
@@ -337,7 +337,7 @@ statement :
{ 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 (); }
@@ -1022,22 +1022,22 @@ statement :
/* ---------------------------------------------------------------------- */
| 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); }
/* ---------------------------------------------------------------------- */
@@ -1161,8 +1161,8 @@ andor1 : AND1 { $$ = 0x05; rl78_bit_insn = 1; }
| 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; }
;
diff --git a/gas/config/tc-rl78.c b/gas/config/tc-rl78.c
index 9fbaa42..ad04795 100644
--- a/gas/config/tc-rl78.c
+++ b/gas/config/tc-rl78.c
@@ -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;
}
@@ -280,6 +281,7 @@ rl78_field (int val, int pos, int sz)
enum options
{
OPTION_RELAX = OPTION_MD_BASE,
+ OPTION_NORELAX,
OPTION_G10,
OPTION_G13,
OPTION_G14,
@@ -294,6 +296,7 @@ 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},
@@ -312,6 +315,9 @@ md_parse_option (int c, char * arg ATTRIBUTE_UNUSED)
case OPTION_RELAX:
linkrelax = 1;
return 1;
+ case OPTION_NORELAX:
+ linkrelax = 0;
+ return 1;
case OPTION_G10:
elf_flags &= ~ E_FLAG_RL78_CPU_MASK;
@@ -757,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:
@@ -780,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))
@@ -805,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;
}
@@ -901,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)
{
@@ -920,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;
}
@@ -967,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;
}
@@ -1062,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. */
@@ -1079,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. */
@@ -1096,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. */
@@ -1113,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. */
@@ -1130,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. */
@@ -1144,11 +1185,13 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
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;
@@ -1215,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)
{
@@ -1376,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))
@@ -1384,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:
@@ -1461,8 +1518,6 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
break;
}
- if (f->fx_addsy == NULL)
- f->fx_done = 1;
}
valueT
diff --git a/gas/config/tc-rl78.h b/gas/config/tc-rl78.h
index b9ede61..82f798e 100644
--- a/gas/config/tc-rl78.h
+++ b/gas/config/tc-rl78.h
@@ -99,3 +99,5 @@ extern void rl78_elf_final_processing (void);
|| TC_FORCE_RELOCATION (FIX))
#define DWARF2_USE_FIXED_ADVANCE_PC 1
+
+#define TC_FORCE_RELOCATION(FIX) (linkrelax)
diff --git a/gas/doc/c-rl78.texi b/gas/doc/c-rl78.texi
index 5cb568f..49e4ee4 100644
--- a/gas/doc/c-rl78.texi
+++ b/gas/doc/c-rl78.texi
@@ -28,6 +28,9 @@
@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.