aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-arm.c
diff options
context:
space:
mode:
authorBarnaby Wilk s <barnaby.wilks@arm.com>2019-06-27 14:06:02 +0100
committerNick Clifton <nickc@redhat.com>2019-06-27 14:06:02 +0100
commitba85f98c42877287f45644a6d75513239c9490a5 (patch)
tree4b99cd21520a8c6a56fa4ba4e4fbe4e25d36dfe9 /gas/config/tc-arm.c
parent5ceb1f4d804b09cb8767ca704c2ba41e50a2bcdb (diff)
downloadgdb-ba85f98c42877287f45644a6d75513239c9490a5.zip
gdb-ba85f98c42877287f45644a6d75513239c9490a5.tar.gz
gdb-ba85f98c42877287f45644a6d75513239c9490a5.tar.bz2
This fixes a bug in the ARm assembler where an immediate operand larger than 4 bits (0xF) could be passed to the SMC (Secure Monitor Call) instruction.
For example, this code is invalid: smc #0x6951 The code would previously check for and encode for up to 16 bit immediate values, however this immediate should instead be only a 4 bit value (as documented herehttps://static.docs.arm.com/ddi0406/c/DDI0406C_C_arm_architecture_reference_manual.pdf ). Fixed this by adding range checks in the relevant areas and also removing code that would encode more than the first 4 bits of the immediate (code that is now redundant, as any immediate operand larger than 0xF would error now anyway). gas * config/tc-arm.c (do_smc): Add range check for immediate operand. (do_t_smc): Add range check for immediate operand. Remove obsolete immediate encoding. (md_apply_fix): Fix range check. Remove obsolete immediate encoding. * testsuite/gas/arm/arch6zk.d: Fix test. * testsuite/gas/arm/arch6zk.s: Fix test. * testsuite/gas/arm/smc-bad.d: New test. * testsuite/gas/arm/smc-bad.l: New test. * testsuite/gas/arm/smc-bad.s: New test. * testsuite/gas/arm/thumb32.d: Fix test. * testsuite/gas/arm/thumb32.s: Fix test.
Diffstat (limited to 'gas/config/tc-arm.c')
-rw-r--r--gas/config/tc-arm.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 679361d..b70028f 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -10247,6 +10247,9 @@ do_shift (void)
static void
do_smc (void)
{
+ unsigned int value = inst.relocs[0].exp.X_add_number;
+ constraint (value > 0xf, _("immediate too large (bigger than 0xF)"));
+
inst.relocs[0].type = BFD_RELOC_ARM_SMC;
inst.relocs[0].pc_rel = 0;
}
@@ -13877,10 +13880,11 @@ do_t_smc (void)
_("SMC is not permitted on this architecture"));
constraint (inst.relocs[0].exp.X_op != O_constant,
_("expression too complex"));
+ constraint (value > 0xf, _("immediate too large (bigger than 0xF)"));
+
inst.relocs[0].type = BFD_RELOC_UNUSED;
- inst.instruction |= (value & 0xf000) >> 12;
- inst.instruction |= (value & 0x0ff0);
inst.instruction |= (value & 0x000f) << 16;
+
/* PR gas/15623: SMC instructions must be last in an IT block. */
set_pred_insn_type_last ();
}
@@ -27765,11 +27769,12 @@ md_apply_fix (fixS * fixP,
break;
case BFD_RELOC_ARM_SMC:
- if (((unsigned long) value) > 0xffff)
+ if (((unsigned long) value) > 0xf)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("invalid smc expression"));
+
newval = md_chars_to_number (buf, INSN_SIZE);
- newval |= (value & 0xf) | ((value & 0xfff0) << 4);
+ newval |= (value & 0xf);
md_number_to_chars (buf, newval, INSN_SIZE);
break;