mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-24 12:23:31 +08:00
[binutils, ARM, 13/16] Add support for CLRM
Given the similarity between LDM/STM and CLRM register lists, most of the changes in this patch aim at sharing code between those two sets of instruction. Sharing is achieved both in parsing and encoding of those instructions. In terms of parsing, parse_reg_list () is extended to take a type that describe what type of instruction is being parsed. The reg_list_els used for parse_vfp_reg_list () is reused for the type and that function is added an assert for the new REGLIST_CLRM and REGLIST_RN enumerators. parse_reg_list () is then taught to accept APSR and reject SP and PC when parsing for a CLRM instruction. At last, caller of parse_reg_list () is updated accordingly and logic is added for the new OP_CLRMLST operand. Encoding-wise, encode_thumb2_ldmstm () is reused to encode the variable bits of CLRM and is thus renamed encode_thumb2_multi (). A new do_io parameter is added to distinguish between LDM/STM and CLRM which guard all the LDM/STM specific code of the function. Finally objdump is told how to disassemble CLRM, again reusing the logic to print the LDM/STM register list (format specifier 'm'). Tests are also added in the form of negative tests to check parsing and encoding/disassembling tests. ChangeLog entries are as follows: *** gas/ChangeLog *** 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. *** opcodes/ChangeLog *** 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.
This commit is contained in:
@ -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>
|
2019-04-15 Sudakshina Das <sudi.das@arm.com>
|
||||||
Andre Vieira <andre.simoesdiasvieira@arm.com>
|
Andre Vieira <andre.simoesdiasvieira@arm.com>
|
||||||
|
|
||||||
|
@ -1688,14 +1688,27 @@ parse_scalar (char **ccp, int elsize, struct neon_type_el *type)
|
|||||||
return reg * 16 + atype.index;
|
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. */
|
/* Parse an ARM register list. Returns the bitmask, or FAIL. */
|
||||||
|
|
||||||
static long
|
static long
|
||||||
parse_reg_list (char ** strp)
|
parse_reg_list (char ** strp, enum reg_list_els etype)
|
||||||
{
|
{
|
||||||
char * str = * strp;
|
char *str = *strp;
|
||||||
long range = 0;
|
long range = 0;
|
||||||
int another_range;
|
int another_range;
|
||||||
|
|
||||||
|
gas_assert (etype == REGLIST_RN || etype == REGLIST_CLRM);
|
||||||
|
|
||||||
/* We come back here if we get ranges concatenated by '+' or '|'. */
|
/* We come back here if we get ranges concatenated by '+' or '|'. */
|
||||||
do
|
do
|
||||||
@ -1713,11 +1726,35 @@ parse_reg_list (char ** strp)
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
int reg;
|
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]));
|
if (reg == REG_SP || reg == REG_PC)
|
||||||
return FAIL;
|
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)
|
if (in_range)
|
||||||
@ -1761,7 +1798,7 @@ parse_reg_list (char ** strp)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (etype == REGLIST_RN)
|
||||||
{
|
{
|
||||||
expressionS exp;
|
expressionS exp;
|
||||||
|
|
||||||
@ -1816,15 +1853,6 @@ parse_reg_list (char ** strp)
|
|||||||
return range;
|
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.
|
/* Parse a VFP register list. If the string is invalid return FAIL.
|
||||||
Otherwise return the number of registers, and set PBASE to the first
|
Otherwise return the number of registers, and set PBASE to the first
|
||||||
register. Parses registers of type ETYPE.
|
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:
|
case REGLIST_NEON_D:
|
||||||
regtype = REG_TYPE_NDQ;
|
regtype = REG_TYPE_NDQ;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
gas_assert (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (etype != REGLIST_VFP_S)
|
if (etype != REGLIST_VFP_S)
|
||||||
@ -3988,7 +4019,7 @@ s_arm_unwind_save_core (void)
|
|||||||
long range;
|
long range;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
range = parse_reg_list (&input_line_pointer);
|
range = parse_reg_list (&input_line_pointer, REGLIST_RN);
|
||||||
if (range == FAIL)
|
if (range == FAIL)
|
||||||
{
|
{
|
||||||
as_bad (_("expected register list"));
|
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_RRnpcsp_I32, /* ARM register (no BadReg) or literal 1 .. 32 */
|
||||||
|
|
||||||
OP_REGLST, /* ARM register list */
|
OP_REGLST, /* ARM register list */
|
||||||
|
OP_CLRMLST, /* CLRM register list */
|
||||||
OP_VRSLST, /* VFP single-precision register list */
|
OP_VRSLST, /* VFP single-precision register list */
|
||||||
OP_VRDLST, /* VFP double-precision register list */
|
OP_VRDLST, /* VFP double-precision register list */
|
||||||
OP_VRSDLST, /* VFP single or double-precision register list (& quad) */
|
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. */
|
/* Register lists. */
|
||||||
case OP_REGLST:
|
case OP_REGLST:
|
||||||
val = parse_reg_list (&str);
|
val = parse_reg_list (&str, REGLIST_RN);
|
||||||
if (*str == '^')
|
if (*str == '^')
|
||||||
{
|
{
|
||||||
inst.operands[i].writeback = 1;
|
inst.operands[i].writeback = 1;
|
||||||
@ -7181,6 +7213,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_CLRMLST:
|
||||||
|
val = parse_reg_list (&str, REGLIST_CLRM);
|
||||||
|
break;
|
||||||
|
|
||||||
case OP_VRSLST:
|
case OP_VRSLST:
|
||||||
val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
|
val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
|
||||||
break;
|
break;
|
||||||
@ -7304,6 +7340,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
|
|||||||
case OP_COND:
|
case OP_COND:
|
||||||
case OP_oBARRIER_I15:
|
case OP_oBARRIER_I15:
|
||||||
case OP_REGLST:
|
case OP_REGLST:
|
||||||
|
case OP_CLRMLST:
|
||||||
case OP_VRSLST:
|
case OP_VRSLST:
|
||||||
case OP_VRDLST:
|
case OP_VRDLST:
|
||||||
case OP_VRSDLST:
|
case OP_VRSDLST:
|
||||||
@ -11489,16 +11526,19 @@ do_t_it (void)
|
|||||||
|
|
||||||
/* Helper function used for both push/pop and ldm/stm. */
|
/* Helper function used for both push/pop and ldm/stm. */
|
||||||
static void
|
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))
|
if (mask & (1 << 13))
|
||||||
inst.error = _("SP not allowed in register list");
|
inst.error = _("SP not allowed in register list");
|
||||||
|
|
||||||
if ((mask & (1 << base)) != 0
|
if (do_io && (mask & (1 << base)) != 0
|
||||||
&& writeback)
|
&& writeback)
|
||||||
inst.error = _("having the base register in the register list when "
|
inst.error = _("having the base register in the register list when "
|
||||||
"using write back is UNPREDICTABLE");
|
"using write back is UNPREDICTABLE");
|
||||||
@ -11513,13 +11553,13 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
|
|||||||
set_it_insn_type_last ();
|
set_it_insn_type_last ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (store)
|
||||||
{
|
{
|
||||||
if (mask & (1 << 15))
|
if (mask & (1 << 15))
|
||||||
inst.error = _("PC not allowed in register list");
|
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. */
|
/* Single register transfers implemented as str/ldr. */
|
||||||
if (writeback)
|
if (writeback)
|
||||||
@ -11548,7 +11588,8 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
|
|||||||
inst.instruction |= WRITE_BACK;
|
inst.instruction |= WRITE_BACK;
|
||||||
|
|
||||||
inst.instruction |= mask;
|
inst.instruction |= mask;
|
||||||
inst.instruction |= base << 16;
|
if (do_io)
|
||||||
|
inst.instruction |= base << 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -11643,8 +11684,9 @@ do_t_ldmstm (void)
|
|||||||
if (inst.instruction < 0xffff)
|
if (inst.instruction < 0xffff)
|
||||||
inst.instruction = THUMB_OP32 (inst.instruction);
|
inst.instruction = THUMB_OP32 (inst.instruction);
|
||||||
|
|
||||||
encode_thumb2_ldmstm (inst.operands[0].reg, inst.operands[1].imm,
|
encode_thumb2_multi (TRUE /* do_io */, inst.operands[0].reg,
|
||||||
inst.operands[0].writeback);
|
inst.operands[1].imm,
|
||||||
|
inst.operands[0].writeback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -12751,7 +12793,7 @@ do_t_push_pop (void)
|
|||||||
else if (unified_syntax)
|
else if (unified_syntax)
|
||||||
{
|
{
|
||||||
inst.instruction = THUMB_OP32 (inst.instruction);
|
inst.instruction = THUMB_OP32 (inst.instruction);
|
||||||
encode_thumb2_ldmstm (13, mask, TRUE);
|
encode_thumb2_multi (TRUE /* do_io */, 13, mask, TRUE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -12760,6 +12802,18 @@ do_t_push_pop (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_t_rbit (void)
|
do_t_rbit (void)
|
||||||
{
|
{
|
||||||
@ -21834,6 +21888,8 @@ static const struct asm_opcode insns[] =
|
|||||||
toU("dls", _dls, 2, (LR, RRnpcsp), t_loloop),
|
toU("dls", _dls, 2, (LR, RRnpcsp), t_loloop),
|
||||||
toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
|
toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
|
||||||
toU("le", _le, 2, (oLR, EXP), t_loloop),
|
toU("le", _le, 2, (oLR, EXP), t_loloop),
|
||||||
|
|
||||||
|
ToC("clrm", e89f0000, 1, (CLRMLST), t_clrm)
|
||||||
};
|
};
|
||||||
#undef ARM_VARIANT
|
#undef ARM_VARIANT
|
||||||
#undef THUMB_VARIANT
|
#undef THUMB_VARIANT
|
||||||
|
4
gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.d
Normal file
4
gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.d
Normal file
@ -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
|
4
gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l
Normal file
4
gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l
Normal file
@ -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}'
|
8
gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s
Normal file
8
gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.thumb
|
||||||
|
.syntax unified
|
||||||
|
|
||||||
|
T:
|
||||||
|
|
||||||
|
clrm {} @ Rejects empty list
|
||||||
|
clrm {sp} @ Rejects SP in list
|
||||||
|
clrm {pc} @ Reject PC in list
|
14
gas/testsuite/gas/arm/archv8m_1m-cmse-main.d
Normal file
14
gas/testsuite/gas/arm/archv8m_1m-cmse-main.d
Normal file
@ -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}
|
||||||
|
#...
|
9
gas/testsuite/gas/arm/archv8m_1m-cmse-main.s
Normal file
9
gas/testsuite/gas/arm/archv8m_1m-cmse-main.s
Normal file
@ -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
|
@ -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>
|
2019-04-15 Sudakshina Das <sudi.das@arm.com>
|
||||||
|
|
||||||
* arm-dis.c (print_insn_thumb32): Updated to accept new %P
|
* arm-dis.c (print_insn_thumb32): Updated to accept new %P
|
||||||
|
@ -2710,6 +2710,7 @@ static const struct opcode16 thumb_opcodes[] =
|
|||||||
%a print the address of a plain load/store
|
%a print the address of a plain load/store
|
||||||
%w print the width and signedness of a core load/store
|
%w print the width and signedness of a core load/store
|
||||||
%m print register mask for ldm/stm
|
%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
|
%E print the lsb and width fields of a bfc/bfi instruction
|
||||||
%F print the lsb and width fields of a sbfx/ubfx 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. */
|
makes heavy use of special-case bit patterns. */
|
||||||
static const struct opcode32 thumb32_opcodes[] =
|
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),
|
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
|
||||||
0xf040c001, 0xfff0f001, "wls\tlr, %16-19S, %Q"},
|
0xf040c001, 0xfff0f001, "wls\tlr, %16-19S, %Q"},
|
||||||
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
|
{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),
|
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
|
||||||
0xf000e001, 0xf840f001, "bfcsel\t%G, %Z, %18-21c"},
|
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. */
|
/* ARMv8-M and ARMv8-M Security Extensions instructions. */
|
||||||
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M), 0xe97fe97f, 0xffffffff, "sg"},
|
{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++)
|
for (insn = thumb32_opcodes; insn->assembler; insn++)
|
||||||
if ((given & insn->mask) == insn->value)
|
if ((given & insn->mask) == insn->value)
|
||||||
{
|
{
|
||||||
|
bfd_boolean is_clrm = FALSE;
|
||||||
bfd_boolean is_unpredictable = FALSE;
|
bfd_boolean is_unpredictable = FALSE;
|
||||||
signed long value_in_comment = 0;
|
signed long value_in_comment = 0;
|
||||||
const char *c = insn->assembler;
|
const char *c = insn->assembler;
|
||||||
@ -5851,6 +5856,9 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
is_clrm = TRUE;
|
||||||
|
/* Fall through. */
|
||||||
case 'm':
|
case 'm':
|
||||||
{
|
{
|
||||||
int started = 0;
|
int started = 0;
|
||||||
@ -5863,7 +5871,12 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
|
|||||||
if (started)
|
if (started)
|
||||||
func (stream, ", ");
|
func (stream, ", ");
|
||||||
started = 1;
|
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, "}");
|
func (stream, "}");
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user