From b126985ec3f922f86a9fa164cc0f443b1aa9e0bb Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 5 Aug 2016 11:26:13 +0100 Subject: [PATCH] Ensure ARM VPUSH and VPOP instructions do not affect more than 16 registers. PR gas/20429 * config/tc-arm.c (do_vfp_nsyn_push): Check that no more than 16 registers are pushed. (do_vfp_nsyn_pop): Check that no more than 16 registers are popped. * testsuite/gas/arm/pr20429.s: New test. * testsuite/gas/arm/pr20429.d: New test driver. * testsuite/gas/arm/pr20429.1: Expected error output. --- gas/ChangeLog | 9 +++++ gas/config/tc-arm.c | 10 ++++++ gas/config/tc-xgate.c | 80 ++++++++++++++++++++++------------------- gas/testsuite/gas/arm/pr20429.d | 3 ++ gas/testsuite/gas/arm/pr20429.l | 11 ++++++ gas/testsuite/gas/arm/pr20429.s | 13 +++++++ 6 files changed, 89 insertions(+), 37 deletions(-) create mode 100644 gas/testsuite/gas/arm/pr20429.d create mode 100644 gas/testsuite/gas/arm/pr20429.l create mode 100644 gas/testsuite/gas/arm/pr20429.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 9634ea8..792ba87 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,14 @@ 2016-08-05 Nick Clifton + PR gas/20429 + * config/tc-arm.c (do_vfp_nsyn_push): Check that no more than 16 + registers are pushed. + (do_vfp_nsyn_pop): Check that no more than 16 registers are + popped. + * testsuite/gas/arm/pr20429.s: New test. + * testsuite/gas/arm/pr20429.d: New test driver. + * testsuite/gas/arm/pr20429.1: Expected error output. + PR gas/20364 * config/tc-aarch64.c (s_ltorg): Change the mapping state after aligning the frag. diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 73d0531..a8d9556 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -14390,6 +14390,11 @@ static void do_vfp_nsyn_push (void) { nsyn_insert_sp (); + + constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16, + _("register list must contain at least 1 and at most 16 " + "registers")); + if (inst.operands[1].issingle) do_vfp_nsyn_opcode ("fstmdbs"); else @@ -14400,6 +14405,11 @@ static void do_vfp_nsyn_pop (void) { nsyn_insert_sp (); + + constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16, + _("register list must contain at least 1 and at most 16 " + "registers")); + if (inst.operands[1].issingle) do_vfp_nsyn_opcode ("fldmias"); else diff --git a/gas/config/tc-xgate.c b/gas/config/tc-xgate.c index 769d158..521fe44 100644 --- a/gas/config/tc-xgate.c +++ b/gas/config/tc-xgate.c @@ -108,7 +108,7 @@ static int cmp_opcode (struct xgate_opcode *, struct xgate_opcode *); static void xgate_print_table (void); static unsigned int xgate_get_operands (char *, s_operand []); static register_id reg_name_search (char *); -static op_modifiers xgate_determine_modifiers(char **); +static op_modifiers xgate_determine_modifiers (char **); static void xgate_scan_operands (struct xgate_opcode *opcode, s_operand []); static unsigned int xgate_parse_operand (struct xgate_opcode *, int *, int, char **, s_operand); @@ -191,7 +191,7 @@ struct option md_longopts[] = { NULL, no_argument, NULL, 0 } }; -size_t md_longopts_size = sizeof(md_longopts); +size_t md_longopts_size = sizeof (md_longopts); const char * md_atof (int type, char *litP, int *sizeP) @@ -301,13 +301,13 @@ md_begin (void) xgate_op_table = XNEWVEC (struct xgate_opcode, xgate_num_opcodes); memset (xgate_op_table, 0, - sizeof(struct xgate_opcode) * (xgate_num_opcodes)); + sizeof (struct xgate_opcode) * (xgate_num_opcodes)); for (xgate_opcode_ptr = (struct xgate_opcode*) xgate_opcodes, i = 0; i < xgate_num_opcodes; i++) xgate_op_table[i] = xgate_opcode_ptr[i]; - qsort (xgate_op_table, xgate_num_opcodes, sizeof(struct xgate_opcode), + qsort (xgate_op_table, xgate_num_opcodes, sizeof (struct xgate_opcode), (int (*)(const void *, const void *)) cmp_opcode); /* Calculate number of handles since this will be @@ -457,7 +457,7 @@ xgate_listing_header (void) symbolS * md_undefined_symbol (char *name ATTRIBUTE_UNUSED) { - return 0; + return NULL; } /* GAS will call this function for each section at the end of the assembly, @@ -486,7 +486,7 @@ md_assemble (char *input_line) fixup_required = 0; oper_check = 0; /* set error flags */ - input_line = extract_word (input_line, op_name, sizeof(op_name)); + input_line = extract_word (input_line, op_name, sizeof (op_name)); /* Check to make sure we are not reading a bogus line. */ if (!op_name[0]) @@ -552,10 +552,10 @@ md_assemble (char *input_line) } else { - operandCount = xgate_get_operands(input_line, new_operands); + operandCount = xgate_get_operands (input_line, new_operands); macro_opcode = xgate_find_match (opcode_handle, opcode_handle->number_of_modes, new_operands, - operandCount); + operandCount); xgate_scan_operands (macro_opcode, new_operands); } } @@ -889,7 +889,8 @@ static char * xgate_parse_exp (char *s, expressionS * op) { input_line_pointer = s; - expression(op); + + expression (op); if (op->X_op == O_absent) as_bad (_("missing operand")); return input_line_pointer; @@ -915,51 +916,55 @@ xgate_find_match (struct xgate_opcode_handle *opcode_handle, switch (operandCount) { case 0: - if (!strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_INH)) + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_INH)) return opcode_handle->opc0[i]; break; case 1: if (oprs[0].reg >= REG_R0 && oprs[0].reg <= REG_R7) - if (!strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_MON)) - return opcode_handle->opc0[i]; - if (!strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_DYA_MON)) - return opcode_handle->opc0[i]; + { + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_MON)) + return opcode_handle->opc0[i]; + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_DYA_MON)) + return opcode_handle->opc0[i]; + } if (oprs[0].reg == REG_NONE) - if (!strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_IMM3)) + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM3)) return opcode_handle->opc0[i]; break; case 2: if (oprs[0].reg >= REG_R0 && oprs[0].reg <= REG_R7) { if (oprs[1].reg >= REG_R0 && oprs[1].reg <= REG_R7) - if (!strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_DYA)) - return opcode_handle->opc0[i]; + { + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_DYA)) + return opcode_handle->opc0[i]; + } if (oprs[1].reg == REG_CCR) - if (!strcmp(opcode_handle->opc0[i]->constraints, + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_MON_R_C)) return opcode_handle->opc0[i]; if (oprs[1].reg == REG_PC) - if (!strcmp(opcode_handle->opc0[i]->constraints, + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_MON_R_P)) return opcode_handle->opc0[i]; if (oprs[1].reg == REG_NONE) - if (!strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_IMM16) - || !strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_IMM8) - || !strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_IMM4) - || !strcmp(opcode_handle->opc0[i]->constraints, + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM16) + || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM8) + || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM4) + || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM16mADD) - || !strcmp(opcode_handle->opc0[i]->constraints, + || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM16mAND) - || !strcmp(opcode_handle->opc0[i]->constraints, + || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM16mCPC) - || !strcmp(opcode_handle->opc0[i]->constraints, + || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM16mSUB) - || !strcmp(opcode_handle->opc0[i]->constraints, + || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM16mLDW)) return opcode_handle->opc0[i]; } if (oprs[0].reg == REG_CCR) - if (!strcmp(opcode_handle->opc0[i]->constraints, XGATE_OP_MON_C_R)) + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_MON_C_R)) return opcode_handle->opc0[i]; break; case 3: @@ -969,22 +974,22 @@ xgate_find_match (struct xgate_opcode_handle *opcode_handle, { if (oprs[2].reg >= REG_R0 && oprs[2].reg <= REG_R7) { - if (!strcmp(opcode_handle->opc0[i]->constraints, + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IDR) - || !strcmp(opcode_handle->opc0[i]->constraints, + || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_TRI)) return opcode_handle->opc0[i]; } if (oprs[2].reg == REG_NONE) - if (!strcmp(opcode_handle->opc0[i]->constraints, + if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IDO5)) return opcode_handle->opc0[i]; } } break; default: - as_bad(_("unknown operand count")); + as_bad (_("unknown operand count")); break; } } @@ -1004,7 +1009,7 @@ xgate_frob_symbol (symbolS *sym) bfdsym = symbol_get_bfdsym (sym); elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); - gas_assert(elfsym); + gas_assert (elfsym); /* Mark the symbol as being *from XGATE */ elfsym->internal_elf_sym.st_target_internal = 1; @@ -1051,6 +1056,7 @@ xgate_get_operands (char *line, s_operand oprs[]) /* reg_name_search() finds the register number given its name. Returns the register number or REG_NONE on failure. */ + static register_id reg_name_search (char *name) { @@ -1080,7 +1086,7 @@ reg_name_search (char *name) /* Parse operand modifiers such as inc/dec/hi/low. */ static op_modifiers -xgate_determine_modifiers(char **line) +xgate_determine_modifiers (char **line) { char *local_line = line[0]; @@ -1149,7 +1155,7 @@ xgate_scan_operands (struct xgate_opcode *opcode, s_operand oprs[]) ++op; bin = xgate_apply_operand (operand, &oper_mask, bin, operand_bit_length); - if(first_operand_equals_second) + if (first_operand_equals_second) bin = xgate_apply_operand (operand, &oper_mask, bin, operand_bit_length); /* Parse second operand. */ @@ -1229,9 +1235,9 @@ xgate_parse_operand (struct xgate_opcode *opcode, if (operand.reg == REG_NONE) as_bad (_(": expected register name r0-r7 ") ); op_mask = operand.reg; - if(operand.mod == MOD_POSTINC) + if (operand.mod == MOD_POSTINC) pp_fix = INCREMENT; - if(operand.mod == MOD_PREDEC) + if (operand.mod == MOD_PREDEC) pp_fix = DECREMENT; op_mask <<= 2; op_mask |= pp_fix; diff --git a/gas/testsuite/gas/arm/pr20429.d b/gas/testsuite/gas/arm/pr20429.d new file mode 100644 index 0000000..8837537 --- /dev/null +++ b/gas/testsuite/gas/arm/pr20429.d @@ -0,0 +1,3 @@ +# name: PR 20429: Too many registers in VPUSH/VPOP +# as: -mfpu=neon +# error-output: pr20429.l diff --git a/gas/testsuite/gas/arm/pr20429.l b/gas/testsuite/gas/arm/pr20429.l new file mode 100644 index 0000000..73886dd --- /dev/null +++ b/gas/testsuite/gas/arm/pr20429.l @@ -0,0 +1,11 @@ +[^:]*: Assembler messages: +[^:]*:5: Error: register list must contain at least 1 and at most 16 registers -- `vpush {d0-d31}' +[^:]*:6: Error: register list must contain at least 1 and at most 16 registers -- `vpush {d1-d17}' +[^:]*:7: Error: register list must contain at least 1 and at most 16 registers -- `vpop {d1-d17}' +[^:]*:8: Error: register list must contain at least 1 and at most 16 registers -- `vpop {d0-d31}' +[^:]*:10: Error: register list must contain at least 1 and at most 16 registers -- `vpush {q0-q15}' +[^:]*:11: Error: register list must contain at least 1 and at most 16 registers -- `vpush {q1-q9}' +[^:]*:12: Error: register list must contain at least 1 and at most 16 registers -- `vpop {q1-q9}' +[^:]*:13: Error: register list must contain at least 1 and at most 16 registers -- `vpop {q0-q15}' +#pass + diff --git a/gas/testsuite/gas/arm/pr20429.s b/gas/testsuite/gas/arm/pr20429.s new file mode 100644 index 0000000..02195c9 --- /dev/null +++ b/gas/testsuite/gas/arm/pr20429.s @@ -0,0 +1,13 @@ +.syntax unified +.arm + +.text + vpush {d0-d31} // 32 > 16, not catched. + vpush {d1-d17} // 17 > 16, not catched. + vpop {d1-d17} // 17 > 16, not catched. + vpop {d0-d31} // 32 > 16, not catched. + + vpush {q0-q15} // 32 > 16, not catched. + vpush {q1-q9} // 18 > 16, not catched. + vpop {q1-q9} // 18 > 16, not catched. + vpop {q0-q15} // 32 > 16, not catched. -- 2.7.4