aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-rl78.c
diff options
context:
space:
mode:
authorDJ Delorie <dj@redhat.com>2011-12-23 01:49:37 +0000
committerDJ Delorie <dj@redhat.com>2011-12-23 01:49:37 +0000
commit9cea966c22d3db4ed4d7008241103b05105c17d3 (patch)
tree8359d5706f5393400b3b021d84095e357fac9f81 /gas/config/tc-rl78.c
parent23cb30dead402c95346474691469528cb199767b (diff)
downloadgdb-9cea966c22d3db4ed4d7008241103b05105c17d3.zip
gdb-9cea966c22d3db4ed4d7008241103b05105c17d3.tar.gz
gdb-9cea966c22d3db4ed4d7008241103b05105c17d3.tar.bz2
[bfd]
* elf32-rl78.c (rl78_elf_howto_table): Add R_RL78_RH_RELAX. (rl78_reloc_map): Add BFD_RELOC_RL78_RELAX. (rl78_elf_relocate_section): Add R_RL78_RH_RELAX, R_RL78_RH_SFR, and R_RL78_RH_SADDR. (rl78_elf_finish_dynamic_sections): Only validate PLT section if we didn't relax anything, as relaxing might remove a PLT reference after we've set up the table. (elf32_rl78_relax_delete_bytes): New. (reloc_bubblesort): New. (rl78_offset_for_reloc): New. (relax_addr16): New. (rl78_elf_relax_section): Add support for relaxing long instructions into short ones. [gas] * config/rl78-defs.h (rl78_linkrelax_addr16): Add. (rl78_linkrelax_dsp, rl78_linkrelax_imm): Remove. * config/rl78-parse.y: Tag all addr16 and branch patterns with relaxation markers. * config/tc-rl78.c (rl78_linkrelax_addr16): New. (rl78_linkrelax_branch): New. (OPTION_RELAX): New. (md_longopts): Add relax option. (md_parse_option): Add OPTION_RELAX. (rl78_frag_init): Support relaxation. (rl78_handle_align): New. (md_assemble): Support relaxation. (md_apply_fix): Likewise. (md_convert_frag): Likewise. * config/tc-rl78.h (MAX_MEM_FOR_RS_ALIGN_CODE): New. (HANDLE_ALIGN): New. (rl78_handle_align): Declare. * config/rl78-parse.y (rl78_bit_insn): New. Set it for all bit insn patterns. (find_bit_index): New. Strip .BIT suffix off relevent expressions for bit insns. (rl78_lex): Exclude bit suffixes from expression parsing. [include/elf] * rl78.h (R_RL78_RH_RELAX, R_RL78_RH_SFR, R_RL78_RH_SADDR): New. (RL78_RELAXA_BRA, RL78_RELAXA_ADDR16: New.
Diffstat (limited to 'gas/config/tc-rl78.c')
-rw-r--r--gas/config/tc-rl78.c106
1 files changed, 102 insertions, 4 deletions
diff --git a/gas/config/tc-rl78.c b/gas/config/tc-rl78.c
index fe0f977..1d9fb2e 100644
--- a/gas/config/tc-rl78.c
+++ b/gas/config/tc-rl78.c
@@ -81,6 +81,18 @@ typedef struct rl78_bytesT
static rl78_bytesT rl78_bytes;
+void
+rl78_linkrelax_addr16 (void)
+{
+ rl78_bytes.link_relax |= RL78_RELAXA_ADDR16;
+}
+
+void
+rl78_linkrelax_branch (void)
+{
+ rl78_bytes.link_relax |= RL78_RELAXA_BRA;
+}
+
static void
rl78_fixup (expressionS exp, int offsetbits, int nbits, int type)
{
@@ -240,19 +252,32 @@ rl78_field (int val, int pos, int sz)
/*------------------------------------------------------------------*/
+enum options
+{
+ OPTION_RELAX = OPTION_MD_BASE,
+};
+
#define RL78_SHORTOPTS ""
const char * md_shortopts = RL78_SHORTOPTS;
/* Assembler options. */
struct option md_longopts[] =
{
+ {"relax", no_argument, NULL, OPTION_RELAX},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
int
-md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
+md_parse_option (int c, char * arg ATTRIBUTE_UNUSED)
{
+ switch (c)
+ {
+ case OPTION_RELAX:
+ linkrelax = 1;
+ return 1;
+
+ }
return 0;
}
@@ -348,7 +373,37 @@ md_operand (expressionS * exp ATTRIBUTE_UNUSED)
void
rl78_frag_init (fragS * fragP)
{
- fragP->tc_frag_data = 0;
+ if (rl78_bytes.n_relax || rl78_bytes.link_relax)
+ {
+ fragP->tc_frag_data = malloc (sizeof (rl78_bytesT));
+ memcpy (fragP->tc_frag_data, & rl78_bytes, sizeof (rl78_bytesT));
+ }
+ else
+ fragP->tc_frag_data = 0;
+}
+
+/* When relaxing, we need to output a reloc for any .align directive
+ so that we can retain this alignment as we adjust opcode sizes. */
+void
+rl78_handle_align (fragS * frag)
+{
+ if (linkrelax
+ && (frag->fr_type == rs_align
+ || frag->fr_type == rs_align_code)
+ && frag->fr_address + frag->fr_fix > 0
+ && frag->fr_offset > 0
+ && now_seg != bss_section)
+ {
+ fix_new (frag, frag->fr_fix, 0,
+ &abs_symbol, RL78_RELAXA_ALIGN + frag->fr_offset,
+ 0, BFD_RELOC_RL78_RELAX);
+ /* For the purposes of relaxation, this relocation is attached
+ to the byte *after* the alignment - i.e. the byte that must
+ remain aligned. */
+ fix_new (frag->fr_next, 0, 0,
+ &abs_symbol, RL78_RELAXA_ELIGN + frag->fr_offset,
+ 0, BFD_RELOC_RL78_RELAX);
+ }
}
char *
@@ -391,13 +446,50 @@ md_assemble (char * str)
rl78_parse ();
- bytes = frag_more (rl78_bytes.n_prefix + rl78_bytes.n_base + rl78_bytes.n_ops);
- frag_then = frag_now;
+ /* This simplifies the relaxation code. */
+ if (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);
+ frag_then = frag_now;
+ frag_variant (rs_machine_dependent,
+ olen /* max_chars */,
+ 0 /* var */,
+ olen /* subtype */,
+ 0 /* symbol */,
+ 0 /* offset */,
+ 0 /* opcode */);
+ frag_then->fr_opcode = bytes;
+ frag_then->fr_fix = olen + (bytes - frag_then->fr_literal);
+ frag_then->fr_subtype = olen;
+ frag_then->fr_var = 0;
+ }
+ else
+ {
+ bytes = frag_more (rl78_bytes.n_prefix + rl78_bytes.n_base + rl78_bytes.n_ops);
+ frag_then = frag_now;
+ }
APPEND (prefix, n_prefix);
APPEND (base, n_base);
APPEND (ops, n_ops);
+ if (rl78_bytes.link_relax)
+ {
+ fixS * f;
+
+ f = fix_new (frag_then,
+ (char *) bytes - frag_then->fr_literal,
+ 0,
+ abs_section_sym,
+ rl78_bytes.link_relax | rl78_bytes.n_fixups,
+ 0,
+ BFD_RELOC_RL78_RELAX);
+ frag_then->tc_frag_data->link_relax_fixP = f;
+ }
+
for (i = 0; i < rl78_bytes.n_fixups; i ++)
{
/* index: [nbytes][type] */
@@ -477,6 +569,7 @@ md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTR
{
return 0;
}
+
arelent **
tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
{
@@ -648,6 +741,10 @@ md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
case BFD_RELOC_NONE:
break;
+ case BFD_RELOC_RL78_RELAX:
+ f->fx_done = 1;
+ break;
+
case BFD_RELOC_8:
case BFD_RELOC_8_PCREL:
op[0] = val;
@@ -696,4 +793,5 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
fragS * fragP ATTRIBUTE_UNUSED)
{
/* No relaxation yet */
+ fragP->fr_var = 0;
}