diff options
author | DJ Delorie <dj@redhat.com> | 2015-12-08 01:29:25 -0500 |
---|---|---|
committer | DJ Delorie <dj@redhat.com> | 2015-12-08 01:29:25 -0500 |
commit | e896287c1643b8b47080c4a8ddbe9a92d9fa585b (patch) | |
tree | cbab9e88d6c15d508f6498f7050089895fa9e5e3 /bfd/elf32-rl78.c | |
parent | 7859afc4fa05f6876c4e6b95cfb8fc252efd96bc (diff) | |
download | fsf-binutils-gdb-e896287c1643b8b47080c4a8ddbe9a92d9fa585b.zip fsf-binutils-gdb-e896287c1643b8b47080c4a8ddbe9a92d9fa585b.tar.gz fsf-binutils-gdb-e896287c1643b8b47080c4a8ddbe9a92d9fa585b.tar.bz2 |
rl78: relaxation fixes
Various fixes to linker relaxation. In general, we need to support
relaxing every branch, even if we don't relax it in the assembler,
so we can optionally defer relaxation to the linker.
* elf32-rl78.c (rl78_offset_for_reloc): Add more relocs.
(rl78_elf_relax_section): Add bc/bz/bnc/bnz/bh/bnh. Fix reloc
choices.
* 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.
Diffstat (limited to 'bfd/elf32-rl78.c')
-rw-r--r-- | bfd/elf32-rl78.c | 54 |
1 files changed, 51 insertions, 3 deletions
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) { |