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.
This commit is contained in:
Nick Clifton 2016-08-05 11:26:13 +01:00
parent 7ea12e5c3a
commit b126985ec3
6 changed files with 89 additions and 37 deletions

View File

@ -1,5 +1,14 @@
2016-08-05 Nick Clifton <nickc@redhat.com>
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.

View File

@ -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

View File

@ -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;

View File

@ -0,0 +1,3 @@
# name: PR 20429: Too many registers in VPUSH/VPOP
# as: -mfpu=neon
# error-output: pr20429.l

View File

@ -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

View File

@ -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.