aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog26
-rw-r--r--gas/config/tc-arm.c114
-rw-r--r--gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.d4
-rw-r--r--gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l4
-rw-r--r--gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s8
-rw-r--r--gas/testsuite/gas/arm/archv8m_1m-cmse-main.d14
-rw-r--r--gas/testsuite/gas/arm/archv8m_1m-cmse-main.s9
-rw-r--r--opcodes/ChangeLog6
-rw-r--r--opcodes/arm-dis.c17
9 files changed, 171 insertions, 31 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index ecb3702..a84bca5 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,29 @@
+2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * config/tc-arm.c (enum reg_list_els): Define earlier and add
+ REGLIST_RN and REGLIST_CLRM enumerators.
+ (parse_reg_list): Add etype parameter to distinguish between regular
+ core register list and CLRM register list. Add logic to
+ recognize CLRM register list.
+ (parse_vfp_reg_list): Assert type is not for core register list.
+ (s_arm_unwind_save_core): Update call to parse_reg_list to new
+ prototype.
+ (enum operand_parse_code): Declare OP_CLRMLST enumerator.
+ (parse_operands): Update call to parse_reg_list to new prototype. Add
+ logic for OP_CLRMLST.
+ (encode_thumb2_ldmstm): Rename into ...
+ (encode_thumb2_multi): This. Add do_io parameter. Add logic to
+ encode CLRM and guard LDM/STM only code by do_io.
+ (do_t_ldmstm): Adapt to use encode_thumb2_multi.
+ (do_t_push_pop): Likewise.
+ (do_t_clrm): New function.
+ (insns): Define CLRM.
+ * testsuite/gas/arm/archv8m_1m-cmse-main-bad.d: New file.
+ * testsuite/gas/arm/archv8m_1m-cmse-main-bad.l: Likewise.
+ * testsuite/gas/arm/archv8m_1m-cmse-main-bad.s: Likewise.
+ * testsuite/gas/arm/archv8m_1m-cmse-main.d: Likewise.
+ * testsuite/gas/arm/archv8m_1m-cmse-main.s: Likewise.
+
2019-04-15 Sudakshina Das <sudi.das@arm.com>
Andre Vieira <andre.simoesdiasvieira@arm.com>
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 828dfc1..e5fe65b 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -1688,14 +1688,27 @@ parse_scalar (char **ccp, int elsize, struct neon_type_el *type)
return reg * 16 + atype.index;
}
+/* Types of registers in a list. */
+
+enum reg_list_els
+{
+ REGLIST_RN,
+ REGLIST_CLRM,
+ REGLIST_VFP_S,
+ REGLIST_VFP_D,
+ REGLIST_NEON_D
+};
+
/* Parse an ARM register list. Returns the bitmask, or FAIL. */
static long
-parse_reg_list (char ** strp)
+parse_reg_list (char ** strp, enum reg_list_els etype)
{
- char * str = * strp;
- long range = 0;
- int another_range;
+ char *str = *strp;
+ long range = 0;
+ int another_range;
+
+ gas_assert (etype == REGLIST_RN || etype == REGLIST_CLRM);
/* We come back here if we get ranges concatenated by '+' or '|'. */
do
@@ -1713,11 +1726,35 @@ parse_reg_list (char ** strp)
do
{
int reg;
+ const char apsr_str[] = "apsr";
+ int apsr_str_len = strlen (apsr_str);
- if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL)
+ reg = arm_reg_parse (&str, REGLIST_RN);
+ if (etype == REGLIST_CLRM)
{
- first_error (_(reg_expected_msgs[REG_TYPE_RN]));
- return FAIL;
+ if (reg == REG_SP || reg == REG_PC)
+ reg = FAIL;
+ else if (reg == FAIL
+ && !strncasecmp (str, apsr_str, apsr_str_len)
+ && !ISALPHA (*(str + apsr_str_len)))
+ {
+ reg = 15;
+ str += apsr_str_len;
+ }
+
+ if (reg == FAIL)
+ {
+ first_error (_("r0-r12, lr or APSR expected"));
+ return FAIL;
+ }
+ }
+ else /* etype == REGLIST_RN. */
+ {
+ if (reg == FAIL)
+ {
+ first_error (_(reg_expected_msgs[REGLIST_RN]));
+ return FAIL;
+ }
}
if (in_range)
@@ -1761,7 +1798,7 @@ parse_reg_list (char ** strp)
return FAIL;
}
}
- else
+ else if (etype == REGLIST_RN)
{
expressionS exp;
@@ -1816,15 +1853,6 @@ parse_reg_list (char ** strp)
return range;
}
-/* Types of registers in a list. */
-
-enum reg_list_els
-{
- REGLIST_VFP_S,
- REGLIST_VFP_D,
- REGLIST_NEON_D
-};
-
/* Parse a VFP register list. If the string is invalid return FAIL.
Otherwise return the number of registers, and set PBASE to the first
register. Parses registers of type ETYPE.
@@ -1873,6 +1901,9 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
case REGLIST_NEON_D:
regtype = REG_TYPE_NDQ;
break;
+
+ default:
+ gas_assert (0);
}
if (etype != REGLIST_VFP_S)
@@ -3988,7 +4019,7 @@ s_arm_unwind_save_core (void)
long range;
int n;
- range = parse_reg_list (&input_line_pointer);
+ range = parse_reg_list (&input_line_pointer, REGLIST_RN);
if (range == FAIL)
{
as_bad (_("expected register list"));
@@ -6548,6 +6579,7 @@ enum operand_parse_code
OP_RRnpcsp_I32, /* ARM register (no BadReg) or literal 1 .. 32 */
OP_REGLST, /* ARM register list */
+ OP_CLRMLST, /* CLRM register list */
OP_VRSLST, /* VFP single-precision register list */
OP_VRDLST, /* VFP double-precision register list */
OP_VRSDLST, /* VFP single or double-precision register list (& quad) */
@@ -7173,7 +7205,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
/* Register lists. */
case OP_REGLST:
- val = parse_reg_list (&str);
+ val = parse_reg_list (&str, REGLIST_RN);
if (*str == '^')
{
inst.operands[i].writeback = 1;
@@ -7181,6 +7213,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
}
break;
+ case OP_CLRMLST:
+ val = parse_reg_list (&str, REGLIST_CLRM);
+ break;
+
case OP_VRSLST:
val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
break;
@@ -7304,6 +7340,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
case OP_COND:
case OP_oBARRIER_I15:
case OP_REGLST:
+ case OP_CLRMLST:
case OP_VRSLST:
case OP_VRDLST:
case OP_VRSDLST:
@@ -11489,16 +11526,19 @@ do_t_it (void)
/* Helper function used for both push/pop and ldm/stm. */
static void
-encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
+encode_thumb2_multi (bfd_boolean do_io, int base, unsigned mask,
+ bfd_boolean writeback)
{
- bfd_boolean load;
+ bfd_boolean load, store;
- load = (inst.instruction & (1 << 20)) != 0;
+ gas_assert (base != -1 || !do_io);
+ load = do_io && ((inst.instruction & (1 << 20)) != 0);
+ store = do_io && !load;
if (mask & (1 << 13))
inst.error = _("SP not allowed in register list");
- if ((mask & (1 << base)) != 0
+ if (do_io && (mask & (1 << base)) != 0
&& writeback)
inst.error = _("having the base register in the register list when "
"using write back is UNPREDICTABLE");
@@ -11513,13 +11553,13 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
set_it_insn_type_last ();
}
}
- else
+ else if (store)
{
if (mask & (1 << 15))
inst.error = _("PC not allowed in register list");
}
- if ((mask & (mask - 1)) == 0)
+ if (do_io && ((mask & (mask - 1)) == 0))
{
/* Single register transfers implemented as str/ldr. */
if (writeback)
@@ -11548,7 +11588,8 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
inst.instruction |= WRITE_BACK;
inst.instruction |= mask;
- inst.instruction |= base << 16;
+ if (do_io)
+ inst.instruction |= base << 16;
}
static void
@@ -11643,8 +11684,9 @@ do_t_ldmstm (void)
if (inst.instruction < 0xffff)
inst.instruction = THUMB_OP32 (inst.instruction);
- encode_thumb2_ldmstm (inst.operands[0].reg, inst.operands[1].imm,
- inst.operands[0].writeback);
+ encode_thumb2_multi (TRUE /* do_io */, inst.operands[0].reg,
+ inst.operands[1].imm,
+ inst.operands[0].writeback);
}
}
else
@@ -12751,8 +12793,20 @@ do_t_push_pop (void)
else if (unified_syntax)
{
inst.instruction = THUMB_OP32 (inst.instruction);
- encode_thumb2_ldmstm (13, mask, TRUE);
+ encode_thumb2_multi (TRUE /* do_io */, 13, mask, TRUE);
+ }
+ else
+ {
+ inst.error = _("invalid register list to push/pop instruction");
+ return;
}
+}
+
+static void
+do_t_clrm (void)
+{
+ if (unified_syntax)
+ encode_thumb2_multi (FALSE /* do_io */, -1, inst.operands[0].imm, FALSE);
else
{
inst.error = _("invalid register list to push/pop instruction");
@@ -21834,6 +21888,8 @@ static const struct asm_opcode insns[] =
toU("dls", _dls, 2, (LR, RRnpcsp), t_loloop),
toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
toU("le", _le, 2, (oLR, EXP), t_loloop),
+
+ ToC("clrm", e89f0000, 1, (CLRMLST), t_clrm)
};
#undef ARM_VARIANT
#undef THUMB_VARIANT
diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.d b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.d
new file mode 100644
index 0000000..a5c7558
--- /dev/null
+++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.d
@@ -0,0 +1,4 @@
+#name: Invalid Armv8.1-M Mainline Security Extensions instructions
+#source: archv8m_1m-cmse-main-bad.s
+#as: -march=armv8.1-m.main
+#error_output: archv8m_1m-cmse-main-bad.l
diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l
new file mode 100644
index 0000000..ed440bf
--- /dev/null
+++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l
@@ -0,0 +1,4 @@
+[^:]*: Assembler messages:
+[^:]*:6: Error: r0-r12, lr or APSR expected -- `clrm {}'
+[^:]*:7: Error: r0-r12, lr or APSR expected -- `clrm {sp}'
+[^:]*:8: Error: r0-r12, lr or APSR expected -- `clrm {pc}'
diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s
new file mode 100644
index 0000000..c991a55
--- /dev/null
+++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s
@@ -0,0 +1,8 @@
+.thumb
+.syntax unified
+
+T:
+
+clrm {} @ Rejects empty list
+clrm {sp} @ Rejects SP in list
+clrm {pc} @ Reject PC in list
diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d
new file mode 100644
index 0000000..b082ff7
--- /dev/null
+++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d
@@ -0,0 +1,14 @@
+#name: Armv8.1-M Mainline Security Extensions instructions
+#source: archv8m_1m-cmse-main.s
+#as: -march=armv8.1-m.main -mimplicit-it=always
+#objdump: -dr --prefix-addresses --show-raw-insn -marmv8.1-m.main
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0+.* <[^>]*> e89f 0005 clrm {r0, r2}
+0+.* <[^>]*> e89f 8000 clrm {APSR}
+0+.* <[^>]*> e89f 8008 clrm {r3, APSR}
+0+.* <[^>]*> bf08 it eq
+0+.* <[^>]*> e89f 0010 clrmeq {r4}
+#...
diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s
new file mode 100644
index 0000000..084d83b
--- /dev/null
+++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s
@@ -0,0 +1,9 @@
+.thumb
+.syntax unified
+
+T:
+
+clrm {r0, r2} @ Accepts list without APSR
+clrm {APSR} @ Accepts APSR alone
+clrm {r3, APSR} @ Accepts core register and APSR together
+clrmeq {r4} @ Accepts conditional execution
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 7f86025..a01e494 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,9 @@
+2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * arm-dis.c (thumb_opcodes): Document %n control code. Add entry for
+ CLRM.
+ (print_insn_thumb32): Add logic to print %n CLRM register list.
+
2019-04-15 Sudakshina Das <sudi.das@arm.com>
* arm-dis.c (print_insn_thumb32): Updated to accept new %P
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index 4a0f76a..e70641c 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -2710,6 +2710,7 @@ static const struct opcode16 thumb_opcodes[] =
%a print the address of a plain load/store
%w print the width and signedness of a core load/store
%m print register mask for ldm/stm
+ %n print register mask for clrm
%E print the lsb and width fields of a bfc/bfi instruction
%F print the lsb and width fields of a sbfx/ubfx instruction
@@ -2751,7 +2752,8 @@ static const struct opcode16 thumb_opcodes[] =
makes heavy use of special-case bit patterns. */
static const struct opcode32 thumb32_opcodes[] =
{
- /* Armv8.1-M Mainline instructions. */
+ /* Armv8.1-M Mainline and Armv8.1-M Mainline Security Extensions
+ instructions. */
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
0xf040c001, 0xfff0f001, "wls\tlr, %16-19S, %Q"},
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
@@ -2772,6 +2774,8 @@ static const struct opcode32 thumb32_opcodes[] =
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
0xf000e001, 0xf840f001, "bfcsel\t%G, %Z, %18-21c"},
+ {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
+ 0xe89f0000, 0xffff2000, "clrm%c\t%n"},
/* ARMv8-M and ARMv8-M Security Extensions instructions. */
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M), 0xe97fe97f, 0xffffffff, "sg"},
@@ -5556,6 +5560,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
for (insn = thumb32_opcodes; insn->assembler; insn++)
if ((given & insn->mask) == insn->value)
{
+ bfd_boolean is_clrm = FALSE;
bfd_boolean is_unpredictable = FALSE;
signed long value_in_comment = 0;
const char *c = insn->assembler;
@@ -5851,6 +5856,9 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
}
break;
+ case 'n':
+ is_clrm = TRUE;
+ /* Fall through. */
case 'm':
{
int started = 0;
@@ -5863,7 +5871,12 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
if (started)
func (stream, ", ");
started = 1;
- func (stream, "%s", arm_regnames[reg]);
+ if (is_clrm && reg == 13)
+ func (stream, "(invalid: %s)", arm_regnames[reg]);
+ else if (is_clrm && reg == 15)
+ func (stream, "%s", "APSR");
+ else
+ func (stream, "%s", arm_regnames[reg]);
}
func (stream, "}");
}