diff options
author | Barnaby Wilk s <barnaby.wilks@arm.com> | 2019-06-27 14:06:02 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2019-06-27 14:06:02 +0100 |
commit | ba85f98c42877287f45644a6d75513239c9490a5 (patch) | |
tree | 4b99cd21520a8c6a56fa4ba4e4fbe4e25d36dfe9 /gas/config/tc-arm.c | |
parent | 5ceb1f4d804b09cb8767ca704c2ba41e50a2bcdb (diff) | |
download | gdb-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.c | 13 |
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; |