diff options
author | DJ Delorie <dj@redhat.com> | 2011-12-23 01:49:37 +0000 |
---|---|---|
committer | DJ Delorie <dj@redhat.com> | 2011-12-23 01:49:37 +0000 |
commit | 9cea966c22d3db4ed4d7008241103b05105c17d3 (patch) | |
tree | 8359d5706f5393400b3b021d84095e357fac9f81 /gas/config | |
parent | 23cb30dead402c95346474691469528cb199767b (diff) | |
download | gdb-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')
-rw-r--r-- | gas/config/rl78-defs.h | 3 | ||||
-rw-r--r-- | gas/config/rl78-parse.y | 152 | ||||
-rw-r--r-- | gas/config/tc-rl78.c | 106 | ||||
-rw-r--r-- | gas/config/tc-rl78.h | 4 |
4 files changed, 211 insertions, 54 deletions
diff --git a/gas/config/rl78-defs.h b/gas/config/rl78-defs.h index 1afbd9d..ebe19a9 100644 --- a/gas/config/rl78-defs.h +++ b/gas/config/rl78-defs.h @@ -40,8 +40,7 @@ extern void rl78_disp3 (expressionS, int); extern void rl78_field5s (expressionS); extern void rl78_field5s2 (expressionS); extern void rl78_relax (int, int); -extern void rl78_linkrelax_dsp (int); -extern void rl78_linkrelax_imm (int); +extern void rl78_linkrelax_addr16 (void); extern void rl78_linkrelax_branch (void); extern int rl78_parse (void); extern int rl78_wrap (void); diff --git a/gas/config/rl78-parse.y b/gas/config/rl78-parse.y index 4bfb3ff..d5f2ec9 100644 --- a/gas/config/rl78-parse.y +++ b/gas/config/rl78-parse.y @@ -89,6 +89,7 @@ static int rl78_in_brackets = 0; static int rl78_last_token = 0; static char * rl78_init_start; static char * rl78_last_exp_start = 0; +static int rl78_bit_insn = 0; #define YYDEBUG 1 #define YYERROR_VERBOSE 1 @@ -218,7 +219,7 @@ statement : { B1 (0x0b|$1); O1 ($4); } | addsub A ',' opt_es '!' EXPR - { B1 (0x0f|$1); O2 ($6); } + { B1 (0x0f|$1); O2 ($6); rl78_linkrelax_addr16 (); } | addsub A ',' opt_es '[' HL ']' { B1 (0x0d|$1); } @@ -238,7 +239,7 @@ statement : { if ($1 != 0x40) { rl78_error ("Only CMP takes these operands"); } else - { B1 (0x00|$1); O2 ($4); O1 ($7); } + { B1 (0x00|$1); O2 ($4); O1 ($7); rl78_linkrelax_addr16 (); } } /* ---------------------------------------------------------------------- */ @@ -253,7 +254,7 @@ statement : { B1 (0x06|$1); O1 ($4); } | addsubw AX ',' opt_es '!' EXPR - { B1 (0x02|$1); O2 ($6); } + { B1 (0x02|$1); O2 ($6); rl78_linkrelax_addr16 (); } | addsubw AX ',' opt_es '[' HL '+' EXPR ']' { B2 (0x61, 0x09|$1); O1 ($8); } @@ -336,13 +337,13 @@ statement : { B1 (0xef); PC1 ($3); } | BR '$' '!' EXPR - { B1 (0xee); PC2 ($4); } + { B1 (0xee); PC2 ($4); rl78_linkrelax_branch (); } | BR '!' EXPR - { B1 (0xed); O2 ($3); } + { B1 (0xed); O2 ($3); rl78_linkrelax_branch (); } | BR '!' '!' EXPR - { B1 (0xec); O3 ($4); } + { B1 (0xec); O3 ($4); rl78_linkrelax_branch (); } /* ---------------------------------------------------------------------- */ @@ -364,7 +365,7 @@ statement : { B1 (0xfd); O2 ($3); } | CALL '!' '!' EXPR - { B1 (0xfc); O3 ($4); } + { B1 (0xfc); O3 ($4); rl78_linkrelax_branch (); } | CALLT '[' EXPR ']' { if ($3.X_op != O_constant) @@ -406,7 +407,7 @@ statement : { B2 (0x71, 0x8a|$1); FE ($4, 9, 3); } | setclr1 opt_es '!' EXPR '.' EXPR - { B2 (0x71, 0x00+$1*0x08); FE ($6, 9, 3); O2 ($4); } + { B2 (0x71, 0x00+$1*0x08); FE ($6, 9, 3); O2 ($4); rl78_linkrelax_addr16 (); } | setclr1 opt_es '[' HL ']' '.' EXPR { B2 (0x71, 0x82|$1); FE ($7, 9, 3); } @@ -426,7 +427,7 @@ statement : { B1 (0xe4|$1); O1 ($2); } | oneclrb opt_es '!' EXPR - { B1 (0xe5|$1); O2 ($4); } + { B1 (0xe5|$1); O2 ($4); rl78_linkrelax_addr16 (); } /* ---------------------------------------------------------------------- */ @@ -453,7 +454,7 @@ statement : { B1 (0xd4); O1 ($2); } | CMP0 opt_es '!' EXPR - { B1 (0xd5); O2 ($4); } + { B1 (0xd5); O2 ($4); rl78_linkrelax_addr16 (); } /* ---------------------------------------------------------------------- */ @@ -468,7 +469,7 @@ statement : | incdec EXPR {SA($2)} { B1 (0xa4|$1); O1 ($2); } | incdec '!' EXPR - { B1 (0xa0|$1); O2 ($3); } + { B1 (0xa0|$1); O2 ($3); rl78_linkrelax_addr16 (); } | incdec ES ':' '!' EXPR { B2 (0x11, 0xa0|$1); O2 ($5); } | incdec '[' HL '+' EXPR ']' @@ -485,7 +486,7 @@ statement : { B1 (0xa6|$1); O1 ($2); } | incdecw opt_es '!' EXPR - { B1 (0xa2|$1); O2 ($4); } + { B1 (0xa2|$1); O2 ($4); rl78_linkrelax_addr16 (); } | incdecw opt_es '[' HL '+' EXPR ']' { B2 (0x61, 0x79+$1); O1 ($6); } @@ -553,7 +554,7 @@ statement : } | MOV '!' EXPR ',' '#' EXPR - { B1 (0xcf); O2 ($3); O1 ($6); } + { B1 (0xcf); O2 ($3); O1 ($6); rl78_linkrelax_addr16 (); } | MOV ES ':' '!' EXPR ',' '#' EXPR { B2 (0x11, 0xcf); O2 ($5); O1 ($8); } @@ -574,16 +575,16 @@ statement : } | MOV A ',' opt_es '!' EXPR - { B1 (0x8f); O2 ($6); } + { B1 (0x8f); O2 ($6); rl78_linkrelax_addr16 (); } | MOV '!' EXPR ',' A - { B1 (0x9f); O2 ($3); } + { B1 (0x9f); O2 ($3); rl78_linkrelax_addr16 (); } | MOV ES ':' '!' EXPR ',' A { B2 (0x11, 0x9f); O2 ($5); } | MOV regb_na ',' opt_es '!' EXPR - { B1 (0xc9|reg_xbc($2)); O2 ($6); } + { B1 (0xc9|reg_xbc($2)); O2 ($6); rl78_linkrelax_addr16 (); } | MOV A ',' opt_es EXPR {NOT_ES} { if (expr_is_saddr ($5)) @@ -712,7 +713,7 @@ statement : /* ---------------------------------------------------------------------- */ - | MOV1 CY ',' EXPR '.' EXPR + | mov1 CY ',' EXPR '.' EXPR { if (expr_is_saddr ($4)) { B2 (0x71, 0x04); FE ($6, 9, 3); O1 ($4); } else if (expr_is_sfr ($4)) @@ -721,16 +722,16 @@ statement : NOT_SFR_OR_SADDR; } - | MOV1 CY ',' A '.' EXPR + | mov1 CY ',' A '.' EXPR { B2 (0x71, 0x8c); FE ($6, 9, 3); } - | MOV1 CY ',' sfr '.' EXPR + | mov1 CY ',' sfr '.' EXPR { B3 (0x71, 0x0c, $4); FE ($6, 9, 3); } - | MOV1 CY ',' opt_es '[' HL ']' '.' EXPR + | mov1 CY ',' opt_es '[' HL ']' '.' EXPR { B2 (0x71, 0x84); FE ($9, 9, 3); } - | MOV1 EXPR '.' EXPR ',' CY + | mov1 EXPR '.' EXPR ',' CY { if (expr_is_saddr ($2)) { B2 (0x71, 0x01); FE ($4, 9, 3); O1 ($2); } else if (expr_is_sfr ($2)) @@ -739,13 +740,13 @@ statement : NOT_SFR_OR_SADDR; } - | MOV1 A '.' EXPR ',' CY + | mov1 A '.' EXPR ',' CY { B2 (0x71, 0x89); FE ($4, 9, 3); } - | MOV1 sfr '.' EXPR ',' CY + | mov1 sfr '.' EXPR ',' CY { B3 (0x71, 0x09, $2); FE ($4, 9, 3); } - | MOV1 opt_es '[' HL ']' '.' EXPR ',' CY + | mov1 opt_es '[' HL ']' '.' EXPR ',' CY { B2 (0x71, 0x81); FE ($7, 9, 3); } /* ---------------------------------------------------------------------- */ @@ -795,10 +796,10 @@ statement : { B1 (0x10); F ($2, 5, 2); } | MOVW AX ',' opt_es '!' EXPR - { B1 (0xaf); O2 ($6); WA($6); } + { B1 (0xaf); O2 ($6); WA($6); rl78_linkrelax_addr16 (); } | MOVW opt_es '!' EXPR ',' AX - { B1 (0xbf); O2 ($4); WA($4); } + { B1 (0xbf); O2 ($4); WA($4); rl78_linkrelax_addr16 (); } | MOVW AX ',' opt_es '[' DE ']' { B1 (0xa9); } @@ -864,7 +865,7 @@ statement : { B1 (0xca); F ($2, 2, 2); O1 ($4); WA($4); } | MOVW regw_na ',' opt_es '!' EXPR - { B1 (0xcb); F ($2, 2, 2); O2 ($6); WA($6); } + { B1 (0xcb); F ($2, 2, 2); O2 ($6); WA($6); rl78_linkrelax_addr16 (); } | MOVW SP ',' '#' EXPR { B2 (0xcb, 0xf8); O2 ($5); } @@ -1008,22 +1009,22 @@ statement : /* ---------------------------------------------------------------------- */ | SKC - { B2 (0x61, 0xc8); } + { B2 (0x61, 0xc8); rl78_linkrelax_branch (); } | SKH - { B2 (0x61, 0xe3); } + { B2 (0x61, 0xe3); rl78_linkrelax_branch (); } | SKNC - { B2 (0x61, 0xd8); } + { B2 (0x61, 0xd8); rl78_linkrelax_branch (); } | SKNH - { B2 (0x61, 0xf3); } + { B2 (0x61, 0xf3); rl78_linkrelax_branch (); } | SKNZ - { B2 (0x61, 0xf8); } + { B2 (0x61, 0xf8); rl78_linkrelax_branch (); } | SKZ - { B2 (0x61, 0xe8); } + { B2 (0x61, 0xe8); rl78_linkrelax_branch (); } /* ---------------------------------------------------------------------- */ @@ -1040,7 +1041,7 @@ statement : } | XCH A ',' opt_es '!' EXPR - { B2 (0x61, 0xaa); O2 ($6); } + { B2 (0x61, 0xaa); O2 ($6); rl78_linkrelax_addr16 (); } | XCH A ',' opt_es '[' DE ']' { B2 (0x61, 0xae); } @@ -1142,18 +1143,18 @@ addsubw : ADDW { $$ = 0x00; } | CMPW { $$ = 0x40; } ; -andor1 : AND1 { $$ = 0x05; } - | OR1 { $$ = 0x06; } - | XOR1 { $$ = 0x07; } +andor1 : AND1 { $$ = 0x05; rl78_bit_insn = 1; } + | OR1 { $$ = 0x06; rl78_bit_insn = 1;} + | XOR1 { $$ = 0x07; rl78_bit_insn = 1; } ; -bt_bf : BT { $$ = 0x02; } - | BF { $$ = 0x04; } - | BTCLR { $$ = 0x00; } +bt_bf : BT { $$ = 0x02; rl78_bit_insn = 1;} + | BF { $$ = 0x04; rl78_bit_insn = 1; } + | BTCLR { $$ = 0x00; rl78_bit_insn = 1; } ; -setclr1 : SET1 { $$ = 0; } - | CLR1 { $$ = 1; } +setclr1 : SET1 { $$ = 0; rl78_bit_insn = 1; } + | CLR1 { $$ = 1; rl78_bit_insn = 1; } ; oneclrb : ONEB { $$ = 0x00; } @@ -1172,6 +1173,9 @@ incdecw : INCW { $$ = 0x00; } | DECW { $$ = 0x10; } ; +mov1 : MOV1 { rl78_bit_insn = 1; } + ; + %% /* ====================================================================== */ @@ -1336,14 +1340,54 @@ rl78_lex_init (char * beginning, char * ending) rl78_in_brackets = 0; rl78_last_token = 0; + rl78_bit_insn = 0; + setbuf (stdout, 0); } +/* Return a pointer to the '.' in a bit index expression (like + foo.5), or NULL if none is found. */ +static char * +find_bit_index (char *tok) +{ + char *last_dot = NULL; + char *last_digit = NULL; + while (*tok && *tok != ',') + { + if (*tok == '.') + { + last_dot = tok; + last_digit = NULL; + } + else if (*tok >= '0' && *tok <= '7' + && last_dot != NULL + && last_digit == NULL) + { + last_digit = tok; + } + else if (ISSPACE (*tok)) + { + /* skip */ + } + else + { + last_dot = NULL; + last_digit = NULL; + } + tok ++; + } + if (last_dot != NULL + && last_digit != NULL) + return last_dot; + return NULL; +} + static int rl78_lex (void) { /*unsigned int ci;*/ char * save_input_pointer; + char * bit = NULL; while (ISSPACE (*rl78_lex_start) && rl78_lex_start != rl78_lex_end) @@ -1400,12 +1444,9 @@ rl78_lex (void) bitfields. We check for it specially so we can allow labels with '.' in them. */ - if (*rl78_lex_start == '.' - && ISDIGIT (rl78_lex_start[1]) - && (rl78_last_token == ']' - || rl78_last_token == A - || rl78_last_token == PSW - || rl78_last_token == EXPR)) + if (rl78_bit_insn + && *rl78_lex_start == '.' + && find_bit_index (rl78_lex_start) == rl78_lex_start) { rl78_last_token = *rl78_lex_start; return *rl78_lex_start ++; @@ -1418,11 +1459,26 @@ rl78_lex (void) return *rl78_lex_start ++; } + /* Again, '.' is funny. Look for '.<digit>' at the end of the line + or before a comma, which is a bitfield, not an expression. */ + + if (rl78_bit_insn) + { + bit = find_bit_index (rl78_lex_start); + if (bit) + *bit = 0; + else + bit = NULL; + } + save_input_pointer = input_line_pointer; input_line_pointer = rl78_lex_start; rl78_lval.exp.X_md = 0; expression (&rl78_lval.exp); + if (bit) + *bit = '.'; + rl78_lex_start = input_line_pointer; input_line_pointer = save_input_pointer; rl78_last_token = EXPR; 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; } diff --git a/gas/config/tc-rl78.h b/gas/config/tc-rl78.h index c4a16e9..b3ac383 100644 --- a/gas/config/tc-rl78.h +++ b/gas/config/tc-rl78.h @@ -73,3 +73,7 @@ extern void rl78_cons_fix_new (fragS *, int, int, expressionS *); #define RELOC_EXPANSION_POSSIBLE 1 #define MAX_RELOC_EXPANSION 8 + +#define MAX_MEM_FOR_RS_ALIGN_CODE 8 +#define HANDLE_ALIGN(FRAG) rl78_handle_align (FRAG) +extern void rl78_handle_align (fragS *); |