diff options
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-cris.c | 70 |
1 files changed, 67 insertions, 3 deletions
diff --git a/gas/config/tc-cris.c b/gas/config/tc-cris.c index 736261c..e725b88 100644 --- a/gas/config/tc-cris.c +++ b/gas/config/tc-cris.c @@ -58,7 +58,7 @@ Note that some prefix-insns might be assembled as CRIS_INSN_NORMAL. */ enum cris_insn_kind { - CRIS_INSN_NORMAL, CRIS_INSN_NONE, CRIS_INSN_BRANCH + CRIS_INSN_NORMAL, CRIS_INSN_NONE, CRIS_INSN_BRANCH, CRIS_INSN_MUL }; /* An instruction will have one of these prefixes. @@ -187,6 +187,10 @@ const pseudo_typeS md_pseudo_table[] = static int warn_for_branch_expansion = 0; +/* Whether to emit error when a MULS/MULU could be located last on a + cache-line. */ +static int err_for_dangerous_mul_placement = 1; + const char cris_comment_chars[] = ";"; /* This array holds the chars that only start a comment at the beginning of @@ -219,10 +223,16 @@ const char FLT_CHARS[] = ""; length: byte, word, 10-byte expansion 2. BDAP - length: byte, word, dword */ + length: byte, word, dword + + 3. MULS/MULU + Not really a relaxation (no infrastructure to get delay-slots + right), just an alignment and placement checker for the v10 + multiply/cache-bug. */ #define STATE_CONDITIONAL_BRANCH (1) #define STATE_BASE_PLUS_DISP_PREFIX (2) +#define STATE_MUL (3) #define STATE_LENGTH_MASK (3) #define STATE_BYTE (0) @@ -282,7 +292,13 @@ const relax_typeS md_cris_relax_table[] = {BDAP_WF, BDAP_WB, 2, ENCODE_RELAX (2, 2)}, /* BDAP.d [PC+] (2, 2). */ - {0, 0, 4, 0} + {0, 0, 4, 0}, + + /* Unused (2, 3). */ + {0, 0, 0, 0}, + + /* MULS/MULU (3, 0). Positions (3, 1..3) are unused. */ + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} }; #undef BRANCH_BF @@ -304,6 +320,10 @@ struct option md_longopts[] = {"underscore", no_argument, NULL, OPTION_US}, #define OPTION_PIC (OPTION_MD_BASE + 2) {"pic", no_argument, NULL, OPTION_PIC}, +#define OPTION_MULBUG_ABORT_ON (OPTION_MD_BASE + 3) + {"mul-bug-abort", no_argument, NULL, OPTION_MULBUG_ABORT_ON}, +#define OPTION_MULBUG_ABORT_OFF (OPTION_MD_BASE + 4) + {"no-mul-bug-abort", no_argument, NULL, OPTION_MULBUG_ABORT_OFF}, {NULL, no_argument, NULL, 0} }; @@ -392,6 +412,10 @@ cris_relax_frag (seg, fragP, stretch) aim = S_GET_VALUE (symbolP); break; + case ENCODE_RELAX (STATE_MUL, STATE_BYTE): + /* Nothing to do here. */ + return 0; + default: as_fatal (_("internal inconsistency problem in %s: fr_subtype %d"), __FUNCTION__, fragP->fr_subtype); @@ -558,6 +582,10 @@ md_estimate_size_before_relax (fragP, segment_type) fragP->fr_var = md_cris_relax_table[fragP->fr_subtype].rlx_length; break; + case ENCODE_RELAX (STATE_MUL, STATE_BYTE): + /* Nothing to do here. */ + break; + default: BAD_CASE (fragP->fr_subtype); } @@ -679,6 +707,24 @@ md_convert_frag (abfd, sec, fragP) var_part_size = 4; break; + case ENCODE_RELAX (STATE_MUL, STATE_BYTE): + /* This is the only time we check position and aligmnent of the + placement-tracking frag. */ + if (sec->alignment_power < 2) + as_bad_where (fragP->fr_file, fragP->fr_line, + _("section alignment must be >= 4 bytes to check MULS/MULU safeness")); + else + { + /* If the address after the MULS/MULU has alignment which is + that of the section and may be that of a cache-size of the + buggy versions, then the MULS/MULU can be placed badly. */ + if ((address_of_var_part + & ((1 << sec->alignment_power) - 1) & 31) == 0) + as_bad_where (fragP->fr_file, fragP->fr_line, + _("dangerous MULS/MULU location; give it higher alignment")); + } + break; + default: BAD_CASE (fragP->fr_subtype); break; @@ -967,6 +1013,13 @@ md_assemble (str) output_instruction.expr.X_add_number); } } + else if (output_instruction.insn_type == CRIS_INSN_MUL + && err_for_dangerous_mul_placement) + /* Create a frag which which we track the location of the mul insn + (in the last two bytes before the mul-frag). */ + frag_variant (rs_machine_dependent, 0, 0, + ENCODE_RELAX (STATE_MUL, STATE_BYTE), + NULL, 0, opcodep); else { if (output_instruction.imm_oprnd_size > 0) @@ -1572,6 +1625,9 @@ cris_process_instruction (insn_text, out_insnp, prefixp) != (unsigned int) out_insnp->imm_oprnd_size)) as_bad (_("PIC relocation size does not match operand size")); } + else if (instruction->op == cris_muls_op + || instruction->op == cris_mulu_op) + out_insnp->insn_type = CRIS_INSN_MUL; } break; } @@ -2947,6 +3003,14 @@ md_parse_option (arg, argp) pic = TRUE; return 1; + case OPTION_MULBUG_ABORT_OFF: + err_for_dangerous_mul_placement = 0; + return 1; + + case OPTION_MULBUG_ABORT_ON: + err_for_dangerous_mul_placement = 1; + return 1; + default: return 0; } |