diff options
author | Nick Clifton <nickc@redhat.com> | 1997-08-14 19:55:03 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 1997-08-14 19:55:03 +0000 |
commit | 035d8553d764f2b1084c6ee9aaf4c78fd1a7c29e (patch) | |
tree | bc767c99a9cf3721130abe019c2108c9bf5642e5 /gas | |
parent | 052d7984df2f032ca3dfaaa1b581f8b8f30f63f7 (diff) | |
download | gdb-035d8553d764f2b1084c6ee9aaf4c78fd1a7c29e.zip gdb-035d8553d764f2b1084c6ee9aaf4c78fd1a7c29e.tar.gz gdb-035d8553d764f2b1084c6ee9aaf4c78fd1a7c29e.tar.bz2 |
Fixed typo in previous delta and added more sanitization.
Diffstat (limited to 'gas')
-rw-r--r-- | gas/config/tc-v850.c | 353 |
1 files changed, 289 insertions, 64 deletions
diff --git a/gas/config/tc-v850.c b/gas/config/tc-v850.c index 5ee6528..d4dcaa9 100644 --- a/gas/config/tc-v850.c +++ b/gas/config/tc-v850.c @@ -60,15 +60,17 @@ const relax_typeS md_relax_table[] = { {0x1fffff, -0x200000, 6, 0}, }; +/* start-sanitize-v850e */ +static boolean support_v850e = false; +/* end-sanitize-v850e */ +/* start-sanitize-v850eq */ +static boolean support_v850eq = false; +/* end-sanitize-v850eq */ + /* local functions */ static unsigned long v850_insert_operand PARAMS ((unsigned long insn, const struct v850_operand *operand, offsetT val, char *file, unsigned int line)); -static int reg_name_search PARAMS ((const struct reg_name *, int, const char *)); -static boolean register_name PARAMS ((expressionS *expressionP)); -static boolean system_register_name PARAMS ((expressionS *expressionP)); -static boolean cc_name PARAMS ((expressionS *expressionP)); -static bfd_reloc_code_real_type v850_reloc_prefix PARAMS ((void)); /* fixups */ @@ -82,12 +84,6 @@ struct v850_fixup struct v850_fixup fixups[MAX_INSN_FIXUPS]; static int fc; -const char *md_shortopts = ""; -struct option md_longopts[] = { - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof(md_longopts); - /* The target specific pseudo-ops which we support. */ const pseudo_typeS md_pseudo_table[] = { @@ -349,19 +345,141 @@ cc_name (expressionP) } } +/* start-sanitize-v850e */ +/* Summary of parse_register_list (). + * + * in: Input_line_pointer points to 1st char of a list of registers. + * insn is the partially constructed instruction. + * operand is the operand being inserted. + * + * out: True if the parse completed successfully, False otherwise. + * If the parse completes the correct bit fields in the + * instruction will be filled in. + */ +static boolean +parse_register_list +( + unsigned long * insn, + const struct v850_operand * operand +) +{ + static int type1_regs[ 32 ] = { 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 }; +/* start-sanitize-v850eq */ + static int type2_regs[ 32 ] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 }; + static int type3_regs[ 32 ] = { 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 13, 12, 7, 6, 5, 4, 11, 10, 9, 8 }; +/* end-sanitize-v850eq */ + int * regs; + + /* Select a register array to parse. */ + switch (operand->shift) + { + case 0xffe00001: regs = type1_regs; break; +/* start-sanitize-v850eq */ + case 0xfff8000f: regs = type2_regs; break; + case 0xfff8001f: regs = type3_regs; break; +/* end-sanitize-v850eq */ + default: + fprintf (stderr, "unknown operand shift: %x\n", operand->shift ); + return false; + } + + /* Parse the register list until a terminator (comma or new-line) is found. */ + for (;;) + { + expressionS exp; + int i; + + if (register_name (& exp)) + { + /* Locate the given register in the list, and if it is there, insert the corresponding bit into the instruction. */ + for (i = 0; i < 32; i++) + { + if (regs[ i ] == exp.X_add_number) + { + * insn |= (1 << i); + break; + } + } + + if (i == 32) + { + as_bad( "unable to insert register r%d into list\n", exp.X_add_number ); + return false; + } + } + else if (system_register_name (& exp)) + { + if (regs == type1_regs) + { + as_bad ("system registers cannot be included in this register list" ); + return false; + } + else if (exp.X_add_number == 5) + { + if (regs == type2_regs) + as_bad ("PSW cannot be included in this register list" ); + else + * insn |= 0x8; + } + else + * insn |= 0x80000; + } + else + break; + + /* Skip white space. */ + while (* input_line_pointer == ' ' || * input_line_pointer == '\t') + ++ input_line_pointer; + } + + return true; +} +/* end-sanitize-v850e */ + +CONST char * md_shortopts = "m:"; + +struct option md_longopts[] = +{ + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof md_longopts; + + void md_show_usage (stream) FILE *stream; { - fprintf(stream, "V850 options:\n\ -none yet\n"); + fprintf (stream, "V850 options:\n"); +/* start-sanitize-v850e */ + fprintf (stream, " -mcpu=v850e target the V850E processor\n"); +/* end-sanitize-v850e */ +/* start-sanitize-v850eq */ + fprintf (stream, " -mcpu=v850eq target the V850E processor with Quantum's extensions\n"); +/* end-sanitize-v850eq */ } int md_parse_option (c, arg) - int c; - char *arg; + int c; + char * arg; { +/* start-sanitize-v850e */ + if ((c == 'm') && arg != NULL && (strcmp (arg, "cpu=v850e") == 0)) + { + support_v850e = true; + return 1; + } +/* end-sanitize-v850e */ + +/* start-sanitize-v850eq */ + if ((c == 'm') && arg != NULL && (strcmp (arg, "cpu=v850eq") == 0)) + { + support_v850e = true; + support_v850eq = true; + return 1; + } +/* end-sanitize-v850eq */ + return 0; } @@ -487,7 +605,7 @@ md_begin () } static bfd_reloc_code_real_type -v850_reloc_prefix() +v850_reloc_prefix () { if (strncmp(input_line_pointer, "hi0(", 4) == 0) { @@ -563,22 +681,30 @@ v850_reloc_prefix() void md_assemble (str) - char *str; + char * str; { - char *s; - struct v850_opcode *opcode; - struct v850_opcode *next_opcode; - const unsigned char *opindex_ptr; - int next_opindex, relaxable; - unsigned long insn, insn_size; - char *f; - int i; - int match; - bfd_reloc_code_real_type reloc; + char * s; + char * start_of_operands; + struct v850_opcode * opcode; + struct v850_opcode * next_opcode; + const unsigned char * opindex_ptr; + int next_opindex; + int relaxable; + unsigned long insn; + unsigned long insn_size; + char * f; + int i; + int match; + bfd_reloc_code_real_type reloc; + boolean extra_data_after_insn = false; + unsigned extra_data_len; + unsigned long extra_data; + /* Get the opcode. */ for (s = str; *s != '\0' && ! isspace (*s); s++) - ; + continue; + if (*s != '\0') *s++ = '\0'; @@ -587,6 +713,7 @@ md_assemble (str) if (opcode == NULL) { as_bad ("Unrecognized opcode: `%s'", str); + ignore_rest_of_line (); return; } @@ -594,22 +721,42 @@ md_assemble (str) while (isspace (*str)) ++str; - input_line_pointer = str; + start_of_operands = str; - for(;;) + for (;;) { - const char *errmsg = NULL; + const char * errmsg = NULL; relaxable = 0; fc = 0; match = 0; next_opindex = 0; insn = opcode->opcode; + extra_data_after_insn = false; + + input_line_pointer = str = start_of_operands; + +/* start-sanitize-v850e */ + if ((opcode->flags & V850E_INSTRUCTION) && ! support_v850e) + { + errmsg = "V850E instructions not allowed"; + goto error; + } +/* end-sanitize-v850e */ + +/* start-sanitize-v850eq */ + if ((opcode->flags & V850EQ_INSTRUCTION) && ! support_v850eq) + { + errmsg = "V850EQ instructions not allowed"; + goto error; + } +/* end-sanitize-v850eq */ + for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) { - const struct v850_operand *operand; - char *hold; - expressionS ex; + const struct v850_operand * operand; + char * hold; + expressionS ex; if (next_opindex == 0) { @@ -632,12 +779,13 @@ md_assemble (str) /* Gather the operand. */ hold = input_line_pointer; input_line_pointer = str; - + +// fprintf (stderr, "operand: %s index = %d, opcode = %s\n", input_line_pointer, opindex_ptr - opcode->operands, opcode->name ); /* lo(), hi(), hi0(), etc... */ if ((reloc = v850_reloc_prefix()) != BFD_RELOC_UNUSED) { - expression(&ex); + expression (& ex); if (ex.X_op == O_constant) { @@ -702,26 +850,27 @@ md_assemble (str) } else { + errmsg = NULL; + if ((operand->flags & V850_OPERAND_REG) != 0) { - if (!register_name(&ex)) + if (!register_name (& ex)) { errmsg = "invalid register name"; - goto error; } } else if ((operand->flags & V850_OPERAND_SRG) != 0) { - if (!system_register_name(&ex)) + if (!system_register_name (& ex)) { errmsg = "invalid system register name"; - goto error; } } else if ((operand->flags & V850_OPERAND_EP) != 0) { - char *start = input_line_pointer; - char c = get_symbol_end (); + char * start = input_line_pointer; + char c = get_symbol_end (); + if (strcmp (start, "ep") != 0 && strcmp (start, "r30") != 0) { /* Put things back the way we found them. */ @@ -730,6 +879,7 @@ md_assemble (str) errmsg = "expected EP register"; goto error; } + *input_line_pointer = c; str = input_line_pointer; input_line_pointer = hold; @@ -740,35 +890,92 @@ md_assemble (str) } else if ((operand->flags & V850_OPERAND_CC) != 0) { - if (!cc_name(&ex)) + if (!cc_name (& ex)) { errmsg = "invalid condition code name"; - goto error; } } + else if (operand->flags & V850E_PUSH_POP) + { + if (! parse_register_list (& insn, operand)) + { + errmsg = "invalid register list"; + } + + /* The parse_register_list() function has already done everything, so fake a dummy expression. */ + ex.X_op = O_constant; + ex.X_add_number = 0; + } + else if (operand->flags & V850E_IMMEDIATE16) + { + expression (& ex); + + if (ex.X_op != O_constant) + errmsg = "constant expression expected"; + else if (ex.X_add_number & 0xffff0000) + { + if (ex.X_add_number & 0xffff) + errmsg = "constant too big to fit into instruction"; + else if ((insn & 0x001fffc0) == 0x00130780) + ex.X_add_number >>= 16; + else + errmsg = "constant too big to fit into instruction"; + } + + extra_data_after_insn = true; + extra_data_len = 2; + extra_data = ex.X_add_number; + ex.X_add_number = 0; + } + else if (operand->flags & V850E_IMMEDIATE32) + { + expression (& ex); + + if (ex.X_op != O_constant) + errmsg = "constant expression expected"; + + extra_data_after_insn = true; + extra_data_len = 4; + extra_data = ex.X_add_number; + ex.X_add_number = 0; + } else if (register_name (&ex) && (operand->flags & V850_OPERAND_REG) == 0) { errmsg = "syntax error: register not expected"; - goto error; } else if (system_register_name (&ex) && (operand->flags & V850_OPERAND_SRG) == 0) { errmsg = "syntax error: system register not expected"; - goto error; } else if (cc_name (&ex) && (operand->flags & V850_OPERAND_CC) == 0) { errmsg = "syntax error: condition code not expected"; - goto error; } else { - expression(&ex); + expression (& ex); +/* start-sanitize-v850e */ + /* Special case: + If we are assembling a MOV instruction (or a CALLT.... :-) + and the immediate value does not fit into the bits available + and we are supporting V850e instructions + then create a fake error so that the next MOV instruction + will be selected. This one has a 32 bit immediate field. */ + + if (((insn & 0x07e0) == 0x0200) + && ex.X_op == O_constant + && (ex.X_add_number < (- (1 << (operand->bits - 1))) || ex.X_add_number > ((1 << operand->bits) - 1)) + && support_v850e) + errmsg = "use bigger instruction"; +/* end-sanitize-v850e */ } + if (errmsg) + goto error; + switch (ex.X_op) { case O_illegal: @@ -783,7 +990,13 @@ md_assemble (str) errmsg = "invalid operand"; goto error; } - +#if 0 + if (ex.X_add_number == 0 + && (operand->shift == 11)) + { + as_warn ("register 0 being used as destination of instruction" ); + } +#endif insn = v850_insert_operand (insn, operand, ex.X_add_number, (char *) NULL, 0); break; @@ -803,7 +1016,6 @@ md_assemble (str) ++fc; break; } - } str = input_line_pointer; @@ -826,6 +1038,7 @@ md_assemble (str) } as_bad ("%s", errmsg); + ignore_rest_of_line (); return; } break; @@ -853,17 +1066,28 @@ md_assemble (str) md_number_to_chars (f + 2, 0, 4); fc = 0; } - else if ((insn & 0x0600) == 0x0600) - { - insn_size = 4; - f = frag_more (insn_size); - md_number_to_chars (f, insn, insn_size); - } - else + else { - insn_size = 2; + if ((insn & 0x0600) == 0x0600) + insn_size = 4; + else + insn_size = 2; + + /* Special case: 32 bit MOV */ + if ((insn & 0xffe0) == 0x0620) + insn_size = 2; + f = frag_more (insn_size); + md_number_to_chars (f, insn, insn_size); + + if (extra_data_after_insn) + { + f = frag_more (extra_data_len); + md_number_to_chars (f, extra_data, extra_data_len); + + extra_data_after_insn = false; + } } /* Create any fixups. At this point we do not use a @@ -1072,7 +1296,7 @@ md_apply_fix3 (fixp, valuep, seg) static unsigned long v850_insert_operand (insn, operand, val, file, line) unsigned long insn; - const struct v850_operand *operand; + const struct v850_operand * operand; offsetT val; char *file; unsigned int line; @@ -1084,7 +1308,7 @@ v850_insert_operand (insn, operand, val, file, line) if ((operand->flags & V850_OPERAND_SIGNED) != 0) { - max = (1 << (operand->bits - 1)) - 1; + max = (1 << (operand->bits - 1)) - 1; min = - (1 << (operand->bits - 1)); } else @@ -1095,10 +1319,9 @@ v850_insert_operand (insn, operand, val, file, line) test = val; - if (test < (offsetT) min || test > (offsetT) max) { - const char *err = + const char * err = "operand out of range (%s not between %ld and %ld)"; char buf[100]; @@ -1112,8 +1335,9 @@ v850_insert_operand (insn, operand, val, file, line) if (operand->insert) { - const char *message = NULL; - insn = (*operand->insert) (insn, val, &message); + const char * message = NULL; + + insn = (*operand->insert) (insn, val, & message); if (message != NULL) { if (file == (char *) NULL) @@ -1124,6 +1348,7 @@ v850_insert_operand (insn, operand, val, file, line) } else insn |= (((long) val & ((1 << operand->bits) - 1)) << operand->shift); + return insn; } |