X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=1c5eb3100dbcfa4932248ea3355724f530edb7f7;hb=b79f7053dd3e33f7b5e61bac1f94be303b14fe77;hp=77606a3bb6282bdf9f8140076919bd3a1b9ddb11;hpb=877807f8c481a4c5780b3d7bba7963c068910434;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 77606a3bb6..1c5eb3100d 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1,6 +1,6 @@ /* tc-arm.c -- Assemble for the ARM Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modified by David Taylor (dtaylor@armltd.co.uk) @@ -32,7 +32,7 @@ #include "safe-ctype.h" #include "subsegs.h" #include "obstack.h" - +#include "libiberty.h" #include "opcode/arm.h" #ifdef OBJ_ELF @@ -98,7 +98,7 @@ enum arm_float_abi /* Types of processor to assemble for. */ #ifndef CPU_DEFAULT /* The code that was here used to select a default CPU depending on compiler - pre-defines which were only present when doing native builds, thus + pre-defines which were only present when doing native builds, thus changing gas' default behaviour depending upon the build host. If you have a target that requires a default CPU option then the you @@ -195,6 +195,7 @@ static const arm_feature_set arm_ext_v7 = ARM_FEATURE (ARM_EXT_V7, 0); static const arm_feature_set arm_ext_v7a = ARM_FEATURE (ARM_EXT_V7A, 0); static const arm_feature_set arm_ext_v7r = ARM_FEATURE (ARM_EXT_V7R, 0); static const arm_feature_set arm_ext_v7m = ARM_FEATURE (ARM_EXT_V7M, 0); +static const arm_feature_set arm_ext_v8 = ARM_FEATURE (ARM_EXT_V8, 0); static const arm_feature_set arm_ext_m = ARM_FEATURE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M, 0); static const arm_feature_set arm_ext_mp = ARM_FEATURE (ARM_EXT_MP, 0); @@ -233,6 +234,12 @@ static const arm_feature_set fpu_vfp_v3_or_neon_ext = static const arm_feature_set fpu_vfp_fp16 = ARM_FEATURE (0, FPU_VFP_EXT_FP16); static const arm_feature_set fpu_neon_ext_fma = ARM_FEATURE (0, FPU_NEON_EXT_FMA); static const arm_feature_set fpu_vfp_ext_fma = ARM_FEATURE (0, FPU_VFP_EXT_FMA); +static const arm_feature_set fpu_vfp_ext_armv8 = + ARM_FEATURE (0, FPU_VFP_EXT_ARMV8); +static const arm_feature_set fpu_neon_ext_armv8 = + ARM_FEATURE (0, FPU_NEON_EXT_ARMV8); +static const arm_feature_set fpu_crypto_ext_armv8 = + ARM_FEATURE (0, FPU_CRYPTO_EXT_ARMV8); static int mfloat_abi_opt = -1; /* Record user cpu selection for object attributes. */ @@ -351,6 +358,9 @@ enum it_instruction_type IT_INSN /* The IT insn has been parsed. */ }; +/* The maximum number of operands we need. */ +#define ARM_IT_MAX_OPERANDS 6 + struct arm_it { const char * error; @@ -402,7 +412,7 @@ struct arm_it unsigned negative : 1; /* Index register was negated. */ unsigned shifted : 1; /* Shift applied to operation. */ unsigned shift_kind : 3; /* Shift operation (enum shift_kind). */ - } operands[6]; + } operands[ARM_IT_MAX_OPERANDS]; }; static struct arm_it inst; @@ -451,8 +461,9 @@ struct asm_psr struct asm_barrier_opt { - const char * template_name; - unsigned long value; + const char * template_name; + unsigned long value; + const arm_feature_set arch; }; /* The bit that distinguishes CPSR and SPSR. */ @@ -560,6 +571,7 @@ const char * const reg_expected_msgs[] = }; /* Some well known registers that we refer to directly elsewhere. */ +#define REG_R12 12 #define REG_SP 13 #define REG_LR 14 #define REG_PC 15 @@ -618,6 +630,14 @@ struct asm_opcode #define T2_OPCODE_MASK 0xfe1fffff #define T2_DATA_OP_SHIFT 21 +#define A_COND_MASK 0xf0000000 +#define A_PUSH_POP_OP_MASK 0x0fff0000 + +/* Opcodes for pushing/poping registers to/from the stack. */ +#define A1_OPCODE_PUSH 0x092d0000 +#define A2_OPCODE_PUSH 0x052d0004 +#define A2_OPCODE_POP 0x049d0004 + /* Codes to distinguish the arithmetic instructions. */ #define OPCODE_AND 0 #define OPCODE_EOR 1 @@ -2054,6 +2074,7 @@ parse_neon_el_struct_list (char **str, unsigned *pbase, arm_reloc_hsh contains no entries, so this function can only succeed if there is no () after the word. Returns -1 on error, BFD_RELOC_UNUSED if there wasn't any suffix. */ + static int parse_reloc (char **str) { @@ -3535,6 +3556,7 @@ s_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED) record_alignment (now_seg, 2); ptr = frag_more (8); + memset (ptr, 0, 8); where = frag_now_fix () - 8; /* Self relative offset of the function start. */ @@ -4884,10 +4906,9 @@ parse_shifter_operand (char **str, int i) return FAIL; } - /* Convert to decoded value. md_apply_fix will put it back. */ - inst.reloc.exp.X_add_number - = (((inst.reloc.exp.X_add_number << (32 - value)) - | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff); + /* Encode as specified. */ + inst.operands[i].imm = inst.reloc.exp.X_add_number | value << 7; + return SUCCESS; } inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; @@ -5059,7 +5080,7 @@ parse_shifter_operand_group_reloc (char **str, int i) /* Parse a Neon alignment expression. Information is written to inst.operands[i]. We assume the initial ':' has been skipped. - + align .imm = align << 8, .immisalign=1, .preind=0 */ static parse_operand_result parse_neon_alignment (char **str, int i) @@ -5172,7 +5193,7 @@ parse_address_main (char **str, int i, int group_relocations, code before we get to see it here. This may be subject to change. */ parse_operand_result result = parse_neon_alignment (&p, i); - + if (result != PARSE_OPERAND_SUCCESS) return result; } @@ -5260,7 +5281,7 @@ parse_address_main (char **str, int i, int group_relocations, /* FIXME: '@' should be used here, but it's filtered out by generic code before we get to see it here. This may be subject to change. */ parse_operand_result result = parse_neon_alignment (&p, i); - + if (result != PARSE_OPERAND_SUCCESS) return result; } @@ -5443,7 +5464,7 @@ parse_psr (char **str, bfd_boolean lhs) { if (m_profile) goto unsupported_psr; - + psr_field = SPSR_BIT; } else if (strncasecmp (p, "CPSR", 4) == 0) @@ -5516,7 +5537,7 @@ check_suffix: unsigned int nzcvq_bits = 0; unsigned int g_bit = 0; char *bit; - + for (bit = start; bit != p; bit++) { switch (TOLOWER (*bit)) @@ -5536,24 +5557,24 @@ check_suffix: case 'v': nzcvq_bits |= (nzcvq_bits & 0x08) ? 0x20 : 0x08; break; - + case 'q': nzcvq_bits |= (nzcvq_bits & 0x10) ? 0x20 : 0x10; break; - + case 'g': g_bit |= (g_bit & 0x1) ? 0x2 : 0x1; break; - + default: inst.error = _("unexpected bit specified after APSR"); return FAIL; } } - + if (nzcvq_bits == 0x1f) psr_field |= PSR_f; - + if (g_bit == 0x1) { if (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)) @@ -5565,7 +5586,7 @@ check_suffix: psr_field |= PSR_s; } - + if ((nzcvq_bits & 0x20) != 0 || (nzcvq_bits != 0x1f && nzcvq_bits != 0) || (g_bit & 0x2) != 0) @@ -5746,6 +5767,25 @@ parse_cond (char **str) return c->value; } +/* If the given feature available in the selected CPU, mark it as used. + Returns TRUE iff feature is available. */ +static bfd_boolean +mark_feature_used (const arm_feature_set *feature) +{ + /* Ensure the option is valid on the current architecture. */ + if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature)) + return FALSE; + + /* Add the appropriate architecture feature for the barrier option used. + */ + if (thumb_mode) + ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, *feature); + else + ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, *feature); + + return TRUE; +} + /* Parse an option for a barrier instruction. Returns the encoding for the option, or FAIL. */ static int @@ -5763,6 +5803,9 @@ parse_barrier (char **str) if (!o) return FAIL; + if (!mark_feature_used (&o->arch)) + return FAIL; + *str = q; return o->value; } @@ -5931,7 +5974,7 @@ parse_neon_mov (char **str, int *which_operand) inst.operands[i].reg = val; inst.operands[i].isreg = 1; - inst.operands[i++].present = 1; + inst.operands[i].present = 1; } } else if (parse_qfloat_immediate (&ptr, &inst.operands[i].imm) == SUCCESS) @@ -6021,7 +6064,7 @@ parse_neon_mov (char **str, int *which_operand) inst.operands[i].isvec = 1; inst.operands[i].issingle = 1; inst.operands[i].vectype = optype; - inst.operands[i++].present = 1; + inst.operands[i].present = 1; } } else @@ -6058,7 +6101,7 @@ enum operand_parse_code OP_RRnpc, /* ARM register, not r15 */ OP_RRnpcsp, /* ARM register, neither r15 nor r13 (a.k.a. 'BadReg') */ OP_RRnpcb, /* ARM register, not r15, in square brackets */ - OP_RRnpctw, /* ARM register, not r15 in Thumb-state or with writeback, + OP_RRnpctw, /* ARM register, not r15 in Thumb-state or with writeback, optional trailing ! */ OP_RRw, /* ARM register, not r15, optional trailing ! */ OP_RCP, /* Coprocessor number */ @@ -6189,7 +6232,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) unsigned const int *upat = pattern; char *backtrack_pos = 0; const char *backtrack_error = 0; - int i, val, backtrack_index = 0; + int i, val = 0, backtrack_index = 0; enum arm_reg_type rtype; parse_operand_result result; unsigned int op_parse_code; @@ -6615,7 +6658,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) goto failure; break; - case OP_wPSR: + case OP_wPSR: case OP_rPSR: po_reg_or_goto (REG_TYPE_RNB, try_psr); if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_virt)) @@ -6775,8 +6818,8 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) break; case OP_RRnpctw: - if (inst.operands[i].isreg - && inst.operands[i].reg == REG_PC + if (inst.operands[i].isreg + && inst.operands[i].reg == REG_PC && (inst.operands[i].writeback || thumb)) inst.error = BAD_PC; break; @@ -7018,14 +7061,22 @@ encode_arm_shifter_operand (int i) encode_arm_shift (i); } else - inst.instruction |= INST_IMMEDIATE; + { + inst.instruction |= INST_IMMEDIATE; + if (inst.reloc.type != BFD_RELOC_ARM_IMMEDIATE) + inst.instruction |= inst.operands[i].imm; + } } /* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3. */ static void encode_arm_addr_mode_common (int i, bfd_boolean is_t) { - gas_assert (inst.operands[i].isreg); + /* PR 14260: + Generate an error if the operand is not a register. */ + constraint (!inst.operands[i].isreg, + _("Instruction does not support =N addresses")); + inst.instruction |= inst.operands[i].reg << 16; if (inst.operands[i].preind) @@ -7345,6 +7396,23 @@ do_rn_rd (void) inst.instruction |= inst.operands[1].reg << 12; } +static bfd_boolean +check_obsolete (const arm_feature_set *feature, const char *msg) +{ + if (ARM_CPU_IS_ANY (cpu_variant)) + { + as_warn ("%s", msg); + return TRUE; + } + else if (ARM_CPU_HAS_FEATURE (cpu_variant, *feature)) + { + as_bad ("%s", msg); + return TRUE; + } + + return FALSE; +} + static void do_rd_rm_rn (void) { @@ -7355,12 +7423,15 @@ do_rd_rm_rn (void) constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg, _("Rn must not overlap other operands")); - /* SWP{b} is deprecated for ARMv6* and ARMv7. */ - if (warn_on_deprecated - && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)) - as_warn (_("swp{b} use is deprecated for this architecture")); - + /* SWP{b} is obsolete for ARMv8-A, and deprecated for ARMv6* and ARMv7. + */ + if (!check_obsolete (&arm_ext_v8, + _("swp{b} use is obsoleted for ARMv8 and later")) + && warn_on_deprecated + && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6)) + as_warn (_("swp{b} use is deprecated for ARMv6 and ARMv7")); } + inst.instruction |= inst.operands[0].reg << 12; inst.instruction |= inst.operands[1].reg; inst.instruction |= Rn << 16; @@ -7662,10 +7733,52 @@ do_cmp (void) No special properties. */ +struct deprecated_coproc_regs_s +{ + unsigned cp; + int opc1; + unsigned crn; + unsigned crm; + int opc2; + arm_feature_set deprecated; + arm_feature_set obsoleted; + const char *dep_msg; + const char *obs_msg; +}; + +#define DEPR_ACCESS_V8 \ + N_("This coprocessor register access is deprecated in ARMv8") + +/* Table of all deprecated coprocessor registers. */ +static struct deprecated_coproc_regs_s deprecated_coproc_regs[] = +{ + {15, 0, 7, 10, 5, /* CP15DMB. */ + ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + DEPR_ACCESS_V8, NULL}, + {15, 0, 7, 10, 4, /* CP15DSB. */ + ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + DEPR_ACCESS_V8, NULL}, + {15, 0, 7, 5, 4, /* CP15ISB. */ + ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + DEPR_ACCESS_V8, NULL}, + {14, 6, 1, 0, 0, /* TEEHBR. */ + ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + DEPR_ACCESS_V8, NULL}, + {14, 6, 0, 0, 0, /* TEECR. */ + ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + DEPR_ACCESS_V8, NULL}, +}; + +#undef DEPR_ACCESS_V8 + +static const size_t deprecated_coproc_reg_count = + sizeof (deprecated_coproc_regs) / sizeof (deprecated_coproc_regs[0]); + static void do_co_reg (void) { unsigned Rd; + size_t i; Rd = inst.operands[2].reg; if (thumb_mode) @@ -7685,6 +7798,23 @@ do_co_reg (void) constraint (Rd == REG_PC, BAD_PC); } + for (i = 0; i < deprecated_coproc_reg_count; ++i) + { + const struct deprecated_coproc_regs_s *r = + deprecated_coproc_regs + i; + + if (inst.operands[0].reg == r->cp + && inst.operands[1].imm == r->opc1 + && inst.operands[3].reg == r->crn + && inst.operands[4].reg == r->crm + && inst.operands[5].imm == r->opc2) + { + if (!check_obsolete (&r->obsoleted, r->obs_msg) + && warn_on_deprecated + && ARM_CPU_HAS_FEATURE (cpu_variant, r->deprecated)) + as_warn ("%s", r->dep_msg); + } + } inst.instruction |= inst.operands[0].reg << 8; inst.instruction |= inst.operands[1].imm << 21; @@ -7786,11 +7916,21 @@ do_it (void) } } +/* If there is only one register in the register list, + then return its register number. Otherwise return -1. */ +static int +only_one_reg_in_list (int range) +{ + int i = ffs (range) - 1; + return (i > 15 || range != (1 << i)) ? -1 : i; +} + static void -do_ldmstm (void) +encode_ldmstm(int from_push_pop_mnem) { int base_reg = inst.operands[0].reg; int range = inst.operands[1].imm; + int one_reg; inst.instruction |= base_reg << 16; inst.instruction |= range; @@ -7823,6 +7963,23 @@ do_ldmstm (void) as_warn (_("if writeback register is in list, it must be the lowest reg in the list")); } } + + /* If PUSH/POP has only one register, then use the A2 encoding. */ + one_reg = only_one_reg_in_list (range); + if (from_push_pop_mnem && one_reg >= 0) + { + int is_push = (inst.instruction & A_PUSH_POP_OP_MASK) == A1_OPCODE_PUSH; + + inst.instruction &= A_COND_MASK; + inst.instruction |= is_push ? A2_OPCODE_PUSH : A2_OPCODE_POP; + inst.instruction |= one_reg << 12; + } +} + +static void +do_ldmstm (void) +{ + encode_ldmstm (/*from_push_pop_mnem=*/FALSE); } /* ARMv5TE load-consecutive (argument parse) @@ -7915,6 +8072,18 @@ do_ldrexd (void) inst.instruction |= inst.operands[2].reg << 16; } +/* In both ARM and thumb state 'ldr pc, #imm' with an immediate + which is not a multiple of four is UNPREDICTABLE. */ +static void +check_ldr_r15_aligned (void) +{ + constraint (!(inst.operands[1].immisreg) + && (inst.operands[0].reg == REG_PC + && inst.operands[1].reg == REG_PC + && (inst.reloc.exp.X_add_number & 0x3)), + _("ldr to register 15 must be 4-byte alligned")); +} + static void do_ldst (void) { @@ -7923,6 +8092,7 @@ do_ldst (void) if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE)) return; encode_arm_addr_mode_2 (1, /*is_t=*/FALSE); + check_ldr_r15_aligned (); } static void @@ -8066,7 +8236,7 @@ static void do_vmrs (void) { unsigned Rt = inst.operands[0].reg; - + if (thumb_mode && inst.operands[0].reg == REG_SP) { inst.error = BAD_SP; @@ -8080,8 +8250,18 @@ do_vmrs (void) return; } - if (inst.operands[1].reg != 1) - first_error (_("operand 1 must be FPSCR")); + switch (inst.operands[1].reg) + { + case 0: /* FPSID */ + case 1: /* FPSCR */ + case 6: /* MVFR1 */ + case 7: /* MVFR0 */ + case 8: /* FPEXC */ + inst.instruction |= (inst.operands[1].reg << 16); + break; + default: + first_error (_("operand 1 must be a VFP extension System Register")); + } inst.instruction |= (Rt << 12); } @@ -8090,7 +8270,7 @@ static void do_vmsr (void) { unsigned Rt = inst.operands[1].reg; - + if (thumb_mode) reject_bad_reg (Rt); else if (Rt == REG_PC) @@ -8099,8 +8279,16 @@ do_vmsr (void) return; } - if (inst.operands[0].reg != 1) - first_error (_("operand 0 must be FPSCR")); + switch (inst.operands[0].reg) + { + case 0: /* FPSID */ + case 1: /* FPSCR */ + case 8: /* FPEXC */ + inst.instruction |= (inst.operands[0].reg << 16); + break; + default: + first_error (_("operand 0 must be FPSID or FPSCR pr FPEXC")); + } inst.instruction |= (Rt << 12); } @@ -8293,7 +8481,7 @@ do_push_pop (void) inst.operands[0].isreg = 1; inst.operands[0].writeback = 1; inst.operands[0].reg = REG_SP; - do_ldmstm (); + encode_ldmstm (/*from_push_pop_mnem=*/TRUE); } /* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the @@ -8363,6 +8551,10 @@ do_usat16 (void) static void do_setend (void) { + if (warn_on_deprecated + && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8)) + as_warn (_("setend use is deprecated for ARMv8")); + if (inst.operands[0].imm) inst.instruction |= 0x200; } @@ -8790,14 +8982,14 @@ vfp_conv (int srcsize) { int immbits = srcsize - inst.operands[1].imm; - if (srcsize == 16 && !(immbits >= 0 && immbits <= srcsize)) - { + if (srcsize == 16 && !(immbits >= 0 && immbits <= srcsize)) + { /* If srcsize is 16, inst.operands[1].imm must be in the range 0-16. i.e. immbits must be in range 0 - 16. */ inst.error = _("immediate value out of range, expected range [0, 16]"); return; } - else if (srcsize == 32 && !(immbits >= 0 && immbits < srcsize)) + else if (srcsize == 32 && !(immbits >= 0 && immbits < srcsize)) { /* If srcsize is 32, inst.operands[1].imm must be in the range 1-32. i.e. immbits must be in range 0 - 31. */ @@ -9357,7 +9549,8 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) X(_yield, bf10, f3af8001), \ X(_wfe, bf20, f3af8002), \ X(_wfi, bf30, f3af8003), \ - X(_sev, bf40, f3af8004), + X(_sev, bf40, f3af8004), \ + X(_sevl, bf50, f3af8005) /* To catch errors in encoding functions, the codes are all offset by 0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined @@ -10024,7 +10217,7 @@ do_t_branch23 (void) { set_it_insn_type_last (); encode_branch (BFD_RELOC_THUMB_PCREL_BRANCH23); - + /* md_apply_fix blows up with 'bl foo(PLT)' where foo is defined in this file. We used to simply ignore the PLT reloc type here -- the branch encoding is now needed to deal with TLSCALL relocs. @@ -10191,6 +10384,7 @@ do_t_it (void) set_it_insn_type (IT_INSN); now_it.mask = (inst.instruction & 0xf) | 0x10; now_it.cc = cond; + now_it.warn_deprecated = FALSE; /* If the condition is a negative condition, invert the mask. */ if ((cond & 0x1) == 0x0) @@ -10198,13 +10392,25 @@ do_t_it (void) unsigned int mask = inst.instruction & 0x000f; if ((mask & 0x7) == 0) - /* no conversion needed */; + { + /* No conversion needed. */ + now_it.block_length = 1; + } else if ((mask & 0x3) == 0) - mask ^= 0x8; + { + mask ^= 0x8; + now_it.block_length = 2; + } else if ((mask & 0x1) == 0) - mask ^= 0xC; + { + mask ^= 0xC; + now_it.block_length = 3; + } else - mask ^= 0xE; + { + mask ^= 0xE; + now_it.block_length = 4; + } inst.instruction &= 0xfff0; inst.instruction |= mask; @@ -10331,11 +10537,11 @@ do_t_ldmstm (void) /* First, record an error for Case 3. */ if (inst.operands[1].imm & mask && inst.operands[0].writeback) - inst.error = + inst.error = _("having the base register in the register list when " "using write back is UNPREDICTABLE"); - - opcode = (inst.instruction == T_MNEM_stmia ? T_MNEM_str + + opcode = (inst.instruction == T_MNEM_stmia ? T_MNEM_str : T_MNEM_ldr); inst.instruction = THUMB_OP16 (opcode); inst.instruction |= inst.operands[0].reg << 3; @@ -10347,7 +10553,7 @@ do_t_ldmstm (void) { if (inst.operands[0].writeback) { - inst.instruction = + inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia ? T_MNEM_push : T_MNEM_pop); inst.instruction |= inst.operands[1].imm; @@ -10355,7 +10561,7 @@ do_t_ldmstm (void) } else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0) { - inst.instruction = + inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia ? T_MNEM_str_sp : T_MNEM_ldr_sp); inst.instruction |= ((ffs (inst.operands[1].imm)-1) << 8); @@ -10533,13 +10739,17 @@ do_t_ldst (void) } /* Do some validations regarding addressing modes. */ - if (inst.operands[1].immisreg && opcode != T_MNEM_ldr - && opcode != T_MNEM_str) + if (inst.operands[1].immisreg) reject_bad_reg (inst.operands[1].imm); + constraint (inst.operands[1].writeback == 1 + && inst.operands[0].reg == inst.operands[1].reg, + BAD_OVERLAP); + inst.instruction = THUMB_OP32 (opcode); inst.instruction |= inst.operands[0].reg << 12; encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE); + check_ldr_r15_aligned (); return; } @@ -10630,7 +10840,16 @@ do_t_ldstd (void) inst.operands[1].reg = inst.operands[0].reg + 1; constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here")); + constraint (inst.operands[0].reg == REG_R12, + _("r12 not allowed here")); } + + if (inst.operands[2].writeback + && (inst.operands[0].reg == inst.operands[2].reg + || inst.operands[1].reg == inst.operands[2].reg)) + as_warn (_("base register written back, and overlaps " + "one of transfer registers")); + inst.instruction |= inst.operands[0].reg << 12; inst.instruction |= inst.operands[1].reg << 8; encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE); @@ -10892,6 +11111,17 @@ do_t_mov_cmp (void) switch (inst.instruction) { case T_MNEM_mov: + /* In v4t or v5t a move of two lowregs produces unpredictable + results. Don't allow this. */ + if (low_regs) + { + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6), + "MOV Rd, Rs with two low registers is not " + "permitted on this architecture"); + ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, + arm_ext_v6); + } + inst.instruction = T_OPCODE_MOV_HR; inst.instruction |= (Rn & 0x8) << 4; inst.instruction |= (Rn & 0x7); @@ -11102,8 +11332,14 @@ do_t_mrs (void) int flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT); if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m)) - constraint (flags != 0, _("selected processor does not support " - "requested special purpose register")); + { + /* PR gas/12698: The constraint is only applied for m_profile. + If the user has specified -march=all, we want to ignore it as + we are building for any CPU type, including non-m variants. */ + bfd_boolean m_profile = selected_cpu.core != arm_arch_any.core; + constraint ((flags != 0) && m_profile, _("selected processor does " + "not support requested special purpose register")); + } else /* mrs only accepts APSR/CPSR/SPSR/CPSR_all/SPSR_all (for non-M profile devices). */ @@ -11137,12 +11373,16 @@ do_t_msr (void) { int bits = inst.operands[0].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT); - constraint ((ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp) - && (bits & ~(PSR_s | PSR_f)) != 0) - || (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp) - && bits != PSR_f), - _("selected processor does not support requested special " - "purpose register")); + /* PR gas/12698: The constraint is only applied for m_profile. + If the user has specified -march=all, we want to ignore it as + we are building for any CPU type, including non-m variants. */ + bfd_boolean m_profile = selected_cpu.core != arm_arch_any.core; + constraint (((ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp) + && (bits & ~(PSR_s | PSR_f)) != 0) + || (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp) + && bits != PSR_f)) && m_profile, + _("selected processor does not support requested special " + "purpose register")); } else constraint ((flags & 0xff) != 0, _("selected processor does not support " @@ -11557,6 +11797,10 @@ do_t_rsb (void) static void do_t_setend (void) { + if (warn_on_deprecated + && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8)) + as_warn (_("setend use is deprecated for ARMv8")); + set_it_insn_type (OUTSIDE_IT_INSN); if (inst.operands[0].imm) inst.instruction |= 0x8; @@ -12383,7 +12627,9 @@ neon_select_shape (enum neon_shape shape, ...) if (!matches) break; } - if (matches) + if (matches && (j >= ARM_IT_MAX_OPERANDS || !inst.operands[j].present)) + /* We've matched all the entries in the shape table, and we don't + have any left over operands which have not been matched. */ break; } @@ -15208,7 +15454,7 @@ do_neon_ldr_str (void) /* Use of PC in vstr in ARM mode is deprecated in ARMv7. And is UNPREDICTABLE in thumb mode. */ - if (!is_ldr + if (!is_ldr && inst.operands[1].reg == REG_PC && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7)) { @@ -15986,6 +16232,8 @@ new_automatic_it_block (int cond) now_it.block_length = 1; mapping_state (MAP_THUMB); now_it.insn = output_it_inst (cond, now_it.mask, NULL); + now_it.warn_deprecated = FALSE; + now_it.insn_cond = TRUE; } /* Close an automatic IT block. @@ -16093,6 +16341,7 @@ static int handle_it_state (void) { now_it.state_handled = 1; + now_it.insn_cond = FALSE; switch (now_it.state) { @@ -16170,6 +16419,7 @@ handle_it_state (void) } else { + now_it.insn_cond = TRUE; now_it_add_mask (inst.cond); } @@ -16181,6 +16431,7 @@ handle_it_state (void) case NEUTRAL_IT_INSN: now_it.block_length++; + now_it.insn_cond = TRUE; if (now_it.block_length > 4) force_automatic_it_block_close (); @@ -16203,6 +16454,7 @@ handle_it_state (void) now_it.mask <<= 1; now_it.mask &= 0x1f; is_last = (now_it.mask == 0x10); + now_it.insn_cond = TRUE; switch (inst.it_insn_type) { @@ -16247,6 +16499,25 @@ handle_it_state (void) return SUCCESS; } +struct depr_insn_mask +{ + unsigned long pattern; + unsigned long mask; + const char* description; +}; + +/* List of 16-bit instruction patterns deprecated in an IT block in + ARMv8. */ +static const struct depr_insn_mask depr_it_insns[] = { + { 0xc000, 0xc000, N_("Short branches, Undefined, SVC, LDM/STM") }, + { 0xb000, 0xb000, N_("Miscellaneous 16-bit instructions") }, + { 0xa000, 0xb800, N_("ADR") }, + { 0x4800, 0xf800, N_("Literal loads") }, + { 0x4478, 0xf478, N_("Hi-register ADD, MOV, CMP, BX, BLX using pc") }, + { 0x4487, 0xfc87, N_("Hi-register ADD, MOV, CMP using pc") }, + { 0, 0, NULL } +}; + static void it_fsm_post_encode (void) { @@ -16255,6 +16526,44 @@ it_fsm_post_encode (void) if (!now_it.state_handled) handle_it_state (); + if (now_it.insn_cond + && !now_it.warn_deprecated + && warn_on_deprecated + && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8)) + { + if (inst.instruction >= 0x10000) + { + as_warn (_("it blocks containing wide Thumb instructions are " + "deprecated in ARMv8")); + now_it.warn_deprecated = TRUE; + } + else + { + const struct depr_insn_mask *p = depr_it_insns; + + while (p->mask != 0) + { + if ((inst.instruction & p->mask) == p->pattern) + { + as_warn (_("it blocks containing 16-bit Thumb intsructions " + "of the following class are deprecated in ARMv8: " + "%s"), p->description); + now_it.warn_deprecated = TRUE; + break; + } + + ++p; + } + } + + if (now_it.block_length > 1) + { + as_warn (_("it blocks of more than one conditional instruction are " + "deprecated in ARMv8")); + now_it.warn_deprecated = TRUE; + } + } + is_last = (now_it.mask == 0x10); if (is_last) { @@ -16665,7 +16974,7 @@ static const struct reg_entry reg_names[] = SPLRBANK(12,MON,RNB), SPLRBANK(12,mon,RNB), REGDEF(elr_hyp,768|(14<<16),RNB), REGDEF(ELR_hyp,768|(14<<16),RNB), REGDEF(sp_hyp,768|(15<<16),RNB), REGDEF(SP_hyp,768|(15<<16),RNB), - REGDEF(spsr_hyp,768|(14<<16)|SPSR_BIT,RNB), + REGDEF(spsr_hyp,768|(14<<16)|SPSR_BIT,RNB), REGDEF(SPSR_hyp,768|(14<<16)|SPSR_BIT,RNB), /* FPA registers. */ @@ -16885,22 +17194,32 @@ static const struct asm_cond conds[] = {"al", 0xe} }; +#define UL_BARRIER(L,U,CODE,FEAT) \ + { L, CODE, ARM_FEATURE (FEAT, 0) }, \ + { U, CODE, ARM_FEATURE (FEAT, 0) } + static struct asm_barrier_opt barrier_opt_names[] = { - { "sy", 0xf }, { "SY", 0xf }, - { "un", 0x7 }, { "UN", 0x7 }, - { "st", 0xe }, { "ST", 0xe }, - { "unst", 0x6 }, { "UNST", 0x6 }, - { "ish", 0xb }, { "ISH", 0xb }, - { "sh", 0xb }, { "SH", 0xb }, - { "ishst", 0xa }, { "ISHST", 0xa }, - { "shst", 0xa }, { "SHST", 0xa }, - { "nsh", 0x7 }, { "NSH", 0x7 }, - { "nshst", 0x6 }, { "NSHST", 0x6 }, - { "osh", 0x3 }, { "OSH", 0x3 }, - { "oshst", 0x2 }, { "OSHST", 0x2 } + UL_BARRIER ("sy", "SY", 0xf, ARM_EXT_BARRIER), + UL_BARRIER ("st", "ST", 0xe, ARM_EXT_BARRIER), + UL_BARRIER ("ld", "LD", 0xd, ARM_EXT_V8), + UL_BARRIER ("ish", "ISH", 0xb, ARM_EXT_BARRIER), + UL_BARRIER ("sh", "SH", 0xb, ARM_EXT_BARRIER), + UL_BARRIER ("ishst", "ISHST", 0xa, ARM_EXT_BARRIER), + UL_BARRIER ("shst", "SHST", 0xa, ARM_EXT_BARRIER), + UL_BARRIER ("ishld", "ISHLD", 0x9, ARM_EXT_V8), + UL_BARRIER ("un", "UN", 0x7, ARM_EXT_BARRIER), + UL_BARRIER ("nsh", "NSH", 0x7, ARM_EXT_BARRIER), + UL_BARRIER ("unst", "UNST", 0x6, ARM_EXT_BARRIER), + UL_BARRIER ("nshst", "NSHST", 0x6, ARM_EXT_BARRIER), + UL_BARRIER ("nshld", "NSHLD", 0x5, ARM_EXT_V8), + UL_BARRIER ("osh", "OSH", 0x3, ARM_EXT_BARRIER), + UL_BARRIER ("oshst", "OSHST", 0x2, ARM_EXT_BARRIER), + UL_BARRIER ("oshld", "OSHLD", 0x1, ARM_EXT_V8) }; +#undef UL_BARRIER + /* Table of ARM-format instructions. */ /* Macros for gluing together operand strings. N.B. In all cases @@ -17648,8 +17967,24 @@ static const struct asm_opcode insns[] = TUF("pldw", 410f000, f830f000, 1, (ADDR), pld, t_pld), + /* AArchv8 instructions. */ +#undef ARM_VARIANT +#define ARM_VARIANT & arm_ext_v8 +#undef THUMB_VARIANT +#define THUMB_VARIANT & arm_ext_v8 + + tCE("sevl", 320f005, _sevl, 0, (), noargs, t_hint), + +#undef ARM_VARIANT +#define ARM_VARIANT NULL + TUF("dcps1", 0, f78f8001, 0, (), noargs, noargs), + TUF("dcps2", 0, f78f8002, 0, (), noargs, noargs), + TUF("dcps3", 0, f78f8003, 0, (), noargs, noargs), + #undef ARM_VARIANT #define ARM_VARIANT & fpu_fpa_ext_v1 /* Core FPA instruction set (V1). */ +#undef THUMB_VARIANT +#define THUMB_VARIANT NULL cCE("wfs", e200110, 1, (RR), rd), cCE("rfs", e300110, 1, (RR), rd), @@ -18099,8 +18434,8 @@ static const struct asm_opcode insns[] = cCE("fmrs", e100a10, 2, (RR, RVS), vfp_reg_from_sp), cCE("fmsr", e000a10, 2, (RVS, RR), vfp_sp_from_reg), cCE("fmstat", ef1fa10, 0, (), noargs), - cCE("vmrs", ef10a10, 2, (APSR_RR, RVC), vmrs), - cCE("vmsr", ee10a10, 2, (RVC, RR), vmsr), + cCE("vmrs", ef00a10, 2, (APSR_RR, RVC), vmrs), + cCE("vmsr", ee00a10, 2, (RVC, RR), vmsr), cCE("fsitos", eb80ac0, 2, (RVS, RVS), vfp_sp_monadic), cCE("fuitos", eb80a40, 2, (RVS, RVS), vfp_sp_monadic), cCE("ftosis", ebd0a40, 2, (RVS, RVS), vfp_sp_monadic), @@ -18950,6 +19285,26 @@ md_chars_to_number (char * buf, int n) /* MD interface: Sections. */ +/* Calculate the maximum variable size (i.e., excluding fr_fix) + that an rs_machine_dependent frag may reach. */ + +unsigned int +arm_frag_max_var (fragS *fragp) +{ + /* We only use rs_machine_dependent for variable-size Thumb instructions, + which are either THUMB_SIZE (2) or INSN_SIZE (4). + + Note that we generate relaxable instructions even for cases that don't + really need it, like an immediate that's a trivial constant. So we're + overestimating the instruction size for some of those cases. Rather + than putting more intelligence here, it would probably be better to + avoid generating a relaxation frag in the first place when it can be + determined up front that a short instruction will suffice. */ + + gas_assert (fragp->fr_type == rs_machine_dependent); + return INSN_SIZE; +} + /* Estimate the size of a frag before relaxing. Assume everything fits in 2 bytes. */ @@ -19521,7 +19876,7 @@ arm_frag_align_code (int n, int max) { char err_msg[128]; - sprintf (err_msg, + sprintf (err_msg, _("alignments greater than %d bytes not supported in .text sections."), MAX_MEM_FOR_RS_ALIGN_CODE + 1); as_fatal ("%s", err_msg); @@ -19879,8 +20234,12 @@ create_unwind_entry (int have_data) size = unwind.opcode_count - 2; } else - /* An extra byte is required for the opcode count. */ - size = unwind.opcode_count + 1; + { + gas_assert (unwind.personality_index == -1); + + /* An extra byte is required for the opcode count. */ + size = unwind.opcode_count + 1; + } size = (size + 3) >> 2; if (size > 0xff) @@ -19892,6 +20251,8 @@ create_unwind_entry (int have_data) /* Allocate the table entry. */ ptr = frag_more ((size << 2) + 4); + /* PR 13449: Zero the table entries in case some of them are not used. */ + memset (ptr, 0, (size << 2) + 4); where = frag_now_fix () - ((size << 2) + 4); switch (unwind.personality_index) @@ -19906,7 +20267,7 @@ create_unwind_entry (int have_data) ptr += 4; /* Set the first byte to the number of additional words. */ - data = size - 1; + data = size > 0 ? size - 1 : 0; n = 3; break; @@ -20420,7 +20781,7 @@ encode_thumb2_b_bl_offset (char * buf, offsetT value) I1 = (value >> 23) & 0x01; I2 = (value >> 22) & 0x01; hi = (value >> 12) & 0x3ff; - lo = (value >> 1) & 0x7ff; + lo = (value >> 1) & 0x7ff; newval = md_chars_to_number (buf, THUMB_SIZE); newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE); newval |= (S << 10) | hi; @@ -20496,13 +20857,22 @@ md_apply_fix (fixS * fixP, } } - newimm = encode_arm_immediate (value); temp = md_chars_to_number (buf, INSN_SIZE); - /* If the instruction will fail, see if we can fix things up by - changing the opcode. */ - if (newimm == (unsigned int) FAIL - && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL) + /* If the offset is negative, we should use encoding A2 for ADR. */ + if ((temp & 0xfff0000) == 0x28f0000 && value < 0) + newimm = negate_data_op (&temp, value); + else + { + newimm = encode_arm_immediate (value); + + /* If the instruction will fail, see if we can fix things up by + changing the opcode. */ + if (newimm == (unsigned int) FAIL) + newimm = negate_data_op (&temp, value); + } + + if (newimm == (unsigned int) FAIL) { as_bad_where (fixP->fx_file, fixP->fx_line, _("invalid constant (%lx) after fixup"), @@ -20537,7 +20907,7 @@ md_apply_fix (fixS * fixP, break; } } - + newimm = encode_arm_immediate (value); temp = md_chars_to_number (buf, INSN_SIZE); @@ -21132,8 +21502,8 @@ md_apply_fix (fixS * fixP, thumb_bl_common: #ifdef OBJ_ELF - if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4 && - fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX) + if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4 + && fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX) fixP->fx_r_type = BFD_RELOC_THUMB_PCREL_BRANCH23; #endif @@ -21144,15 +21514,15 @@ md_apply_fix (fixS * fixP, 1 of the base address. */ value = (value + 1) & ~ 1; - if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff)) - { - if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2))) - as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE); - else if ((value & ~0x1ffffff) - && ((value & ~0x1ffffff) != ~0x1ffffff)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Thumb2 branch out of range")); - } + if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff)) + { + if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2))) + as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE); + else if ((value & ~0x1ffffff) + && ((value & ~0x1ffffff) != ~0x1ffffff)) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("Thumb2 branch out of range")); + } if (fixP->fx_done || !seg->use_rela_p) encode_thumb2_b_bl_offset (buf, value); @@ -22157,6 +22527,10 @@ elf32_arm_target_format (void) return (target_big_endian ? "elf32-bigarm-vxworks" : "elf32-littlearm-vxworks"); +#elif defined (TE_NACL) + return (target_big_endian + ? "elf32-bigarm-nacl" + : "elf32-littlearm-nacl"); #else if (target_big_endian) return "elf32-bigarm"; @@ -22400,8 +22774,16 @@ md_begin (void) hash_insert (arm_barrier_opt_hsh, barrier_opt_names[i].template_name, (void *) (barrier_opt_names + i)); #ifdef OBJ_ELF - for (i = 0; i < sizeof (reloc_names) / sizeof (struct reloc_entry); i++) - hash_insert (arm_reloc_hsh, reloc_names[i].name, (void *) (reloc_names + i)); + for (i = 0; i < ARRAY_SIZE (reloc_names); i++) + { + struct reloc_entry * entry = reloc_names + i; + + if (arm_is_eabi() && entry->reloc == BFD_RELOC_ARM_PLT32) + /* This makes encode_branch() use the EABI versions of this relocation. */ + entry->reloc = BFD_RELOC_UNUSED; + + hash_insert (arm_reloc_hsh, entry->name, (void *) entry); + } #endif set_constant_flonums (); @@ -22834,6 +23216,7 @@ const struct arm_legacy_option_table arm_legacy_opts[] = struct arm_cpu_option_table { char *name; + size_t name_len; const arm_feature_set value; /* For some CPUs we assume an FPU unless the user explicitly sets -mfpu=... */ @@ -22845,208 +23228,234 @@ struct arm_cpu_option_table /* This list should, at a minimum, contain all the cpu names recognized by GCC. */ +#define ARM_CPU_OPT(N, V, DF, CN) { N, sizeof (N) - 1, V, DF, CN } static const struct arm_cpu_option_table arm_cpus[] = { - {"all", ARM_ANY, FPU_ARCH_FPA, NULL}, - {"arm1", ARM_ARCH_V1, FPU_ARCH_FPA, NULL}, - {"arm2", ARM_ARCH_V2, FPU_ARCH_FPA, NULL}, - {"arm250", ARM_ARCH_V2S, FPU_ARCH_FPA, NULL}, - {"arm3", ARM_ARCH_V2S, FPU_ARCH_FPA, NULL}, - {"arm6", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm60", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm600", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm610", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm620", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm7", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL}, - {"arm7d", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL}, - {"arm7di", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL}, - {"arm70", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm700", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm700i", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm710", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm720", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm710c", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm7100", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm7500", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, - {"arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm7tdmi-s", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm8", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, - {"arm810", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, - {"strongarm", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, - {"strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, - {"strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, - {"strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, - {"strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, - {"arm9", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm920", ARM_ARCH_V4T, FPU_ARCH_FPA, "ARM920T"}, - {"arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, - {"fa526", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, - {"fa626", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, + ARM_CPU_OPT ("all", ARM_ANY, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm1", ARM_ARCH_V1, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm2", ARM_ARCH_V2, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm250", ARM_ARCH_V2S, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm3", ARM_ARCH_V2S, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm6", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm60", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm600", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm610", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm620", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7d", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7di", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm70", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm700", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm700i", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm710", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm720", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm710c", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7100", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7500", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm7tdmi-s", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm8", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm810", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("strongarm", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm9", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm920", ARM_ARCH_V4T, FPU_ARCH_FPA, "ARM920T"), + ARM_CPU_OPT ("arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("fa526", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), + ARM_CPU_OPT ("fa626", ARM_ARCH_V4, FPU_ARCH_FPA, NULL), /* For V5 or later processors we default to using VFP; but the user should really set the FPU type explicitly. */ - {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL}, - {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, "ARM926EJ-S"}, - {"arm926ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, "ARM926EJ-S"}, - {"arm926ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, NULL}, - {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL}, - {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM946E-S"}, - {"arm946e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL}, - {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM966E-S"}, - {"arm966e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"arm968e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL}, - {"arm10tdmi", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL}, - {"arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM1020E"}, - {"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL}, - {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"arm1022e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"arm1026ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, "ARM1026EJ-S"}, - {"arm1026ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, NULL}, - {"fa606te", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"fa616te", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"fa626te", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"fmp626", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"fa726te", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, - {"arm1136js", ARM_ARCH_V6, FPU_NONE, "ARM1136J-S"}, - {"arm1136j-s", ARM_ARCH_V6, FPU_NONE, NULL}, - {"arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2, "ARM1136JF-S"}, - {"arm1136jf-s", ARM_ARCH_V6, FPU_ARCH_VFP_V2, NULL}, - {"mpcore", ARM_ARCH_V6K, FPU_ARCH_VFP_V2, "MPCore"}, - {"mpcorenovfp", ARM_ARCH_V6K, FPU_NONE, "MPCore"}, - {"arm1156t2-s", ARM_ARCH_V6T2, FPU_NONE, NULL}, - {"arm1156t2f-s", ARM_ARCH_V6T2, FPU_ARCH_VFP_V2, NULL}, - {"arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE, NULL}, - {"arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2, NULL}, - {"cortex-a5", ARM_ARCH_V7A_MP_SEC, - FPU_NONE, "Cortex-A5"}, - {"cortex-a8", ARM_ARCH_V7A_SEC, - ARM_FEATURE (0, FPU_VFP_V3 + ARM_CPU_OPT ("arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, "ARM926EJ-S"), + ARM_CPU_OPT ("arm926ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, "ARM926EJ-S"), + ARM_CPU_OPT ("arm926ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM946E-S"), + ARM_CPU_OPT ("arm946e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM966E-S"), + ARM_CPU_OPT ("arm966e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm968e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL), + ARM_CPU_OPT ("arm10tdmi", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL), + ARM_CPU_OPT ("arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM1020E"), + ARM_CPU_OPT ("arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL), + ARM_CPU_OPT ("arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm1022e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm1026ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, + "ARM1026EJ-S"), + ARM_CPU_OPT ("arm1026ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("fa606te", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("fa616te", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("fa626te", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("fmp626", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("fa726te", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm1136js", ARM_ARCH_V6, FPU_NONE, "ARM1136J-S"), + ARM_CPU_OPT ("arm1136j-s", ARM_ARCH_V6, FPU_NONE, NULL), + ARM_CPU_OPT ("arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2, + "ARM1136JF-S"), + ARM_CPU_OPT ("arm1136jf-s", ARM_ARCH_V6, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("mpcore", ARM_ARCH_V6K, FPU_ARCH_VFP_V2, "MPCore"), + ARM_CPU_OPT ("mpcorenovfp", ARM_ARCH_V6K, FPU_NONE, "MPCore"), + ARM_CPU_OPT ("arm1156t2-s", ARM_ARCH_V6T2, FPU_NONE, NULL), + ARM_CPU_OPT ("arm1156t2f-s", ARM_ARCH_V6T2, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE, NULL), + ARM_CPU_OPT ("arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("cortex-a5", ARM_ARCH_V7A_MP_SEC, + FPU_NONE, "Cortex-A5"), + ARM_CPU_OPT ("cortex-a7", ARM_ARCH_V7A_IDIV_MP_SEC_VIRT, + FPU_ARCH_NEON_VFP_V4, + "Cortex-A7"), + ARM_CPU_OPT ("cortex-a8", ARM_ARCH_V7A_SEC, + ARM_FEATURE (0, FPU_VFP_V3 | FPU_NEON_EXT_V1), - "Cortex-A8"}, - {"cortex-a9", ARM_ARCH_V7A_MP_SEC, - ARM_FEATURE (0, FPU_VFP_V3 + "Cortex-A8"), + ARM_CPU_OPT ("cortex-a9", ARM_ARCH_V7A_MP_SEC, + ARM_FEATURE (0, FPU_VFP_V3 | FPU_NEON_EXT_V1), - "Cortex-A9"}, - {"cortex-a15", ARM_ARCH_V7A_IDIV_MP_SEC_VIRT, - FPU_ARCH_NEON_VFP_V4, - "Cortex-A15"}, - {"cortex-r4", ARM_ARCH_V7R, FPU_NONE, "Cortex-R4"}, - {"cortex-r4f", ARM_ARCH_V7R, FPU_ARCH_VFP_V3D16, - "Cortex-R4F"}, - {"cortex-r5", ARM_ARCH_V7R_IDIV, - FPU_NONE, "Cortex-R5"}, - {"cortex-m4", ARM_ARCH_V7EM, FPU_NONE, "Cortex-M4"}, - {"cortex-m3", ARM_ARCH_V7M, FPU_NONE, "Cortex-M3"}, - {"cortex-m1", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M1"}, - {"cortex-m0", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M0"}, + "Cortex-A9"), + ARM_CPU_OPT ("cortex-a15", ARM_ARCH_V7A_IDIV_MP_SEC_VIRT, + FPU_ARCH_NEON_VFP_V4, + "Cortex-A15"), + ARM_CPU_OPT ("cortex-r4", ARM_ARCH_V7R, FPU_NONE, "Cortex-R4"), + ARM_CPU_OPT ("cortex-r4f", ARM_ARCH_V7R, FPU_ARCH_VFP_V3D16, + "Cortex-R4F"), + ARM_CPU_OPT ("cortex-r5", ARM_ARCH_V7R_IDIV, + FPU_NONE, "Cortex-R5"), + ARM_CPU_OPT ("cortex-m4", ARM_ARCH_V7EM, FPU_NONE, "Cortex-M4"), + ARM_CPU_OPT ("cortex-m3", ARM_ARCH_V7M, FPU_NONE, "Cortex-M3"), + ARM_CPU_OPT ("cortex-m1", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M1"), + ARM_CPU_OPT ("cortex-m0", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M0"), + ARM_CPU_OPT ("cortex-m0plus", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M0+"), /* ??? XSCALE is really an architecture. */ - {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL}, + ARM_CPU_OPT ("xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL), /* ??? iwmmxt is not a processor. */ - {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL}, - {"iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL}, - {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL}, + ARM_CPU_OPT ("iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL), + ARM_CPU_OPT ("i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL), /* Maverick */ - {"ep9312", ARM_FEATURE (ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"}, - {NULL, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL} + ARM_CPU_OPT ("ep9312", ARM_FEATURE (ARM_AEXT_V4T, ARM_CEXT_MAVERICK), + FPU_ARCH_MAVERICK, + "ARM920T"), + { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL } }; +#undef ARM_CPU_OPT struct arm_arch_option_table { char *name; + size_t name_len; const arm_feature_set value; const arm_feature_set default_fpu; }; /* This list should, at a minimum, contain all the architecture names recognized by GCC. */ +#define ARM_ARCH_OPT(N, V, DF) { N, sizeof (N) - 1, V, DF } static const struct arm_arch_option_table arm_archs[] = { - {"all", ARM_ANY, FPU_ARCH_FPA}, - {"armv1", ARM_ARCH_V1, FPU_ARCH_FPA}, - {"armv2", ARM_ARCH_V2, FPU_ARCH_FPA}, - {"armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA}, - {"armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA}, - {"armv3", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA}, - {"armv4", ARM_ARCH_V4, FPU_ARCH_FPA}, - {"armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA}, - {"armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA}, - {"armv5", ARM_ARCH_V5, FPU_ARCH_VFP}, - {"armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP}, - {"armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP}, - {"armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP}, - {"armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP}, - {"armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP}, - {"armv6", ARM_ARCH_V6, FPU_ARCH_VFP}, - {"armv6j", ARM_ARCH_V6, FPU_ARCH_VFP}, - {"armv6k", ARM_ARCH_V6K, FPU_ARCH_VFP}, - {"armv6z", ARM_ARCH_V6Z, FPU_ARCH_VFP}, - {"armv6zk", ARM_ARCH_V6ZK, FPU_ARCH_VFP}, - {"armv6t2", ARM_ARCH_V6T2, FPU_ARCH_VFP}, - {"armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP}, - {"armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP}, - {"armv6zkt2", ARM_ARCH_V6ZKT2, FPU_ARCH_VFP}, - {"armv6-m", ARM_ARCH_V6M, FPU_ARCH_VFP}, - {"armv6s-m", ARM_ARCH_V6SM, FPU_ARCH_VFP}, - {"armv7", ARM_ARCH_V7, FPU_ARCH_VFP}, + ARM_ARCH_OPT ("all", ARM_ANY, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv1", ARM_ARCH_V1, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv2", ARM_ARCH_V2, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv3", ARM_ARCH_V3, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv4", ARM_ARCH_V4, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA), + ARM_ARCH_OPT ("armv5", ARM_ARCH_V5, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6", ARM_ARCH_V6, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6j", ARM_ARCH_V6, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6k", ARM_ARCH_V6K, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6z", ARM_ARCH_V6Z, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6zk", ARM_ARCH_V6ZK, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6t2", ARM_ARCH_V6T2, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6zkt2", ARM_ARCH_V6ZKT2, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6-m", ARM_ARCH_V6M, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv6s-m", ARM_ARCH_V6SM, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv7", ARM_ARCH_V7, FPU_ARCH_VFP), /* The official spelling of the ARMv7 profile variants is the dashed form. Accept the non-dashed form for compatibility with old toolchains. */ - {"armv7a", ARM_ARCH_V7A, FPU_ARCH_VFP}, - {"armv7r", ARM_ARCH_V7R, FPU_ARCH_VFP}, - {"armv7m", ARM_ARCH_V7M, FPU_ARCH_VFP}, - {"armv7-a", ARM_ARCH_V7A, FPU_ARCH_VFP}, - {"armv7-r", ARM_ARCH_V7R, FPU_ARCH_VFP}, - {"armv7-m", ARM_ARCH_V7M, FPU_ARCH_VFP}, - {"armv7e-m", ARM_ARCH_V7EM, FPU_ARCH_VFP}, - {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP}, - {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP}, - {"iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP}, - {NULL, ARM_ARCH_NONE, ARM_ARCH_NONE} + ARM_ARCH_OPT ("armv7a", ARM_ARCH_V7A, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv7r", ARM_ARCH_V7R, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv7m", ARM_ARCH_V7M, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv7-a", ARM_ARCH_V7A, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv7-r", ARM_ARCH_V7R, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv7-m", ARM_ARCH_V7M, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv7e-m", ARM_ARCH_V7EM, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv8-a", ARM_ARCH_V8A, FPU_ARCH_VFP), + ARM_ARCH_OPT ("xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP), + ARM_ARCH_OPT ("iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP), + ARM_ARCH_OPT ("iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP), + { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE } }; +#undef ARM_ARCH_OPT /* ISA extensions in the co-processor and main instruction set space. */ struct arm_option_extension_value_table { char *name; + size_t name_len; const arm_feature_set value; const arm_feature_set allowed_archs; }; /* The following table must be in alphabetical order with a NULL last entry. */ +#define ARM_EXT_OPT(N, V, AA) { N, sizeof (N) - 1, V, AA } static const struct arm_option_extension_value_table arm_extensions[] = { - {"idiv", ARM_FEATURE (ARM_EXT_ADIV | ARM_EXT_DIV, 0), - ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)}, - {"iwmmxt", ARM_FEATURE (0, ARM_CEXT_IWMMXT), ARM_ANY}, - {"iwmmxt2", ARM_FEATURE (0, ARM_CEXT_IWMMXT2), ARM_ANY}, - {"maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK), ARM_ANY}, - {"mp", ARM_FEATURE (ARM_EXT_MP, 0), - ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)}, - {"os", ARM_FEATURE (ARM_EXT_OS, 0), - ARM_FEATURE (ARM_EXT_V6M, 0)}, - {"sec", ARM_FEATURE (ARM_EXT_SEC, 0), - ARM_FEATURE (ARM_EXT_V6K | ARM_EXT_V7A, 0)}, - {"virt", ARM_FEATURE (ARM_EXT_VIRT | ARM_EXT_ADIV | ARM_EXT_DIV, 0), - ARM_FEATURE (ARM_EXT_V7A, 0)}, - {"xscale", ARM_FEATURE (0, ARM_CEXT_XSCALE), ARM_ANY}, - {NULL, ARM_ARCH_NONE, ARM_ARCH_NONE} + ARM_EXT_OPT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8, + ARM_FEATURE (ARM_EXT_V8, 0)), + ARM_EXT_OPT ("fp", FPU_ARCH_VFP_ARMV8, + ARM_FEATURE (ARM_EXT_V8, 0)), + ARM_EXT_OPT ("idiv", ARM_FEATURE (ARM_EXT_ADIV | ARM_EXT_DIV, 0), + ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)), + ARM_EXT_OPT ("iwmmxt",ARM_FEATURE (0, ARM_CEXT_IWMMXT), ARM_ANY), + ARM_EXT_OPT ("iwmmxt2", + ARM_FEATURE (0, ARM_CEXT_IWMMXT2), ARM_ANY), + ARM_EXT_OPT ("maverick", + ARM_FEATURE (0, ARM_CEXT_MAVERICK), ARM_ANY), + ARM_EXT_OPT ("mp", ARM_FEATURE (ARM_EXT_MP, 0), + ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)), + ARM_EXT_OPT ("simd", FPU_ARCH_NEON_VFP_ARMV8, + ARM_FEATURE (ARM_EXT_V8, 0)), + ARM_EXT_OPT ("os", ARM_FEATURE (ARM_EXT_OS, 0), + ARM_FEATURE (ARM_EXT_V6M, 0)), + ARM_EXT_OPT ("sec", ARM_FEATURE (ARM_EXT_SEC, 0), + ARM_FEATURE (ARM_EXT_V6K | ARM_EXT_V7A, 0)), + ARM_EXT_OPT ("virt", ARM_FEATURE (ARM_EXT_VIRT | ARM_EXT_ADIV + | ARM_EXT_DIV, 0), + ARM_FEATURE (ARM_EXT_V7A, 0)), + ARM_EXT_OPT ("xscale",ARM_FEATURE (0, ARM_CEXT_XSCALE), ARM_ANY), + { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE } }; +#undef ARM_EXT_OPT /* ISA floating-point and Advanced SIMD extensions. */ struct arm_option_fpu_value_table @@ -23093,6 +23502,10 @@ static const struct arm_option_fpu_value_table arm_fpus[] = {"vfpv4-d16", FPU_ARCH_VFP_V4D16}, {"fpv4-sp-d16", FPU_ARCH_VFP_V4_SP_D16}, {"neon-vfpv4", FPU_ARCH_NEON_VFP_V4}, + {"fp-armv8", FPU_ARCH_VFP_ARMV8}, + {"neon-fp-armv8", FPU_ARCH_NEON_VFP_ARMV8}, + {"crypto-neon-fp-armv8", + FPU_ARCH_CRYPTO_NEON_VFP_ARMV8}, {NULL, ARM_ARCH_NONE} }; @@ -23130,16 +23543,16 @@ struct arm_long_option_table }; static bfd_boolean -arm_parse_extension (char * str, const arm_feature_set **opt_p) +arm_parse_extension (char *str, const arm_feature_set **opt_p) { arm_feature_set *ext_set = (arm_feature_set *) xmalloc (sizeof (arm_feature_set)); /* We insist on extensions being specified in alphabetical order, and with - extensions being added before being removed. We achieve this by having - the global ARM_EXTENSIONS table in alphabetical order, and using the + extensions being added before being removed. We achieve this by having + the global ARM_EXTENSIONS table in alphabetical order, and using the ADDING_VALUE variable to indicate whether we are adding an extension (1) - or removing it (0) and only allowing it to change in the order + or removing it (0) and only allowing it to change in the order -1 -> 1 -> 0. */ const struct arm_option_extension_value_table * opt = NULL; int adding_value = -1; @@ -23150,8 +23563,8 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) while (str != NULL && *str != 0) { - char * ext; - size_t optlen; + char *ext; + size_t len; if (*str != '+') { @@ -23163,12 +23576,11 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) ext = strchr (str, '+'); if (ext != NULL) - optlen = ext - str; + len = ext - str; else - optlen = strlen (str); + len = strlen (str); - if (optlen >= 2 - && strncmp (str, "no", 2) == 0) + if (len >= 2 && strncmp (str, "no", 2) == 0) { if (adding_value != 0) { @@ -23176,10 +23588,10 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) opt = arm_extensions; } - optlen -= 2; + len -= 2; str += 2; } - else if (optlen > 0) + else if (len > 0) { if (adding_value == -1) { @@ -23194,7 +23606,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) } } - if (optlen == 0) + if (len == 0) { as_bad (_("missing architectural extension")); return FALSE; @@ -23205,8 +23617,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) /* Scan over the options table trying to find an exact match. */ for (; opt->name != NULL; opt++) - if (strncmp (opt->name, str, optlen) == 0 - && strlen (opt->name) == optlen) + if (opt->name_len == len && strncmp (opt->name, str, len) == 0) { /* Check we can apply the extension to this architecture. */ if (!ARM_CPU_HAS_FEATURE (*ext_set, opt->allowed_archs)) @@ -23230,7 +23641,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) alphabetical order, or because it does not exist? */ for (opt = arm_extensions; opt->name != NULL; opt++) - if (strncmp (opt->name, str, optlen) == 0) + if (opt->name_len == len && strncmp (opt->name, str, len) == 0) break; if (opt->name == NULL) @@ -23255,25 +23666,25 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) } static bfd_boolean -arm_parse_cpu (char * str) +arm_parse_cpu (char *str) { - const struct arm_cpu_option_table * opt; - char * ext = strchr (str, '+'); - int optlen; + const struct arm_cpu_option_table *opt; + char *ext = strchr (str, '+'); + size_t len; if (ext != NULL) - optlen = ext - str; + len = ext - str; else - optlen = strlen (str); + len = strlen (str); - if (optlen == 0) + if (len == 0) { as_bad (_("missing cpu name `%s'"), str); return FALSE; } for (opt = arm_cpus; opt->name != NULL; opt++) - if (strncmp (opt->name, str, optlen) == 0) + if (opt->name_len == len && strncmp (opt->name, str, len) == 0) { mcpu_cpu_opt = &opt->value; mcpu_fpu_opt = &opt->default_fpu; @@ -23281,9 +23692,9 @@ arm_parse_cpu (char * str) strcpy (selected_cpu_name, opt->canonical_name); else { - int i; + size_t i; - for (i = 0; i < optlen; i++) + for (i = 0; i < len; i++) selected_cpu_name[i] = TOUPPER (opt->name[i]); selected_cpu_name[i] = 0; } @@ -23299,25 +23710,25 @@ arm_parse_cpu (char * str) } static bfd_boolean -arm_parse_arch (char * str) +arm_parse_arch (char *str) { const struct arm_arch_option_table *opt; char *ext = strchr (str, '+'); - int optlen; + size_t len; if (ext != NULL) - optlen = ext - str; + len = ext - str; else - optlen = strlen (str); + len = strlen (str); - if (optlen == 0) + if (len == 0) { as_bad (_("missing architecture name `%s'"), str); return FALSE; } for (opt = arm_archs; opt->name != NULL; opt++) - if (strncmp (opt->name, str, optlen) == 0) + if (opt->name_len == len && strncmp (opt->name, str, len) == 0) { march_cpu_opt = &opt->value; march_fpu_opt = &opt->default_fpu; @@ -23569,9 +23980,10 @@ static const cpu_arch_ver_table cpu_arch_ver[] = {11, ARM_ARCH_V6M}, {12, ARM_ARCH_V6SM}, {8, ARM_ARCH_V6T2}, - {10, ARM_ARCH_V7A}, + {10, ARM_ARCH_V7A_IDIV_MP_SEC_VIRT}, {10, ARM_ARCH_V7R}, {10, ARM_ARCH_V7M}, + {14, ARM_ARCH_V8A}, {0, ARM_ARCH_NONE} }; @@ -23599,7 +24011,9 @@ static void aeabi_set_public_attributes (void) { int arch; + char profile; int virt_sec = 0; + int fp16_optional = 0; arm_feature_set flags; arm_feature_set tmp; const cpu_arch_ver_table *p; @@ -23609,7 +24023,14 @@ aeabi_set_public_attributes (void) ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used); ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt); ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu); - /*Allow the user to override the reported architecture. */ + + if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_any)) + ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v1); + + if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_any)) + ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v4t); + + /* Allow the user to override the reported architecture. */ if (object_arch) { ARM_CLEAR_FEATURE (flags, flags, arm_arch_any); @@ -23669,11 +24090,16 @@ aeabi_set_public_attributes (void) /* Tag_CPU_arch_profile. */ if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)) - aeabi_set_attribute_int (Tag_CPU_arch_profile, 'A'); + profile = 'A'; else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r)) - aeabi_set_attribute_int (Tag_CPU_arch_profile, 'R'); + profile = 'R'; else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_m)) - aeabi_set_attribute_int (Tag_CPU_arch_profile, 'M'); + profile = 'M'; + else + profile = '\0'; + + if (profile != '\0') + aeabi_set_attribute_int (Tag_CPU_arch_profile, profile); /* Tag_ARM_ISA_use. */ if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v1) @@ -23687,14 +24113,22 @@ aeabi_set_public_attributes (void) ARM_CPU_HAS_FEATURE (flags, arm_arch_t2) ? 2 : 1); /* Tag_VFP_arch. */ - if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_fma)) + if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_armv8)) + aeabi_set_attribute_int (Tag_VFP_arch, 7); + else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_fma)) aeabi_set_attribute_int (Tag_VFP_arch, ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32) ? 5 : 6); else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32)) - aeabi_set_attribute_int (Tag_VFP_arch, 3); + { + fp16_optional = 1; + aeabi_set_attribute_int (Tag_VFP_arch, 3); + } else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v3xd)) - aeabi_set_attribute_int (Tag_VFP_arch, 4); + { + aeabi_set_attribute_int (Tag_VFP_arch, 4); + fp16_optional = 1; + } else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v2)) aeabi_set_attribute_int (Tag_VFP_arch, 2); else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1) @@ -23713,22 +24147,43 @@ aeabi_set_public_attributes (void) aeabi_set_attribute_int (Tag_WMMX_arch, 1); /* Tag_Advanced_SIMD_arch (formerly Tag_NEON_arch). */ - if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v1)) - aeabi_set_attribute_int - (Tag_Advanced_SIMD_arch, (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_fma) - ? 2 : 1)); - + if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_armv8)) + aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 3); + else if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v1)) + { + if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_fma)) + { + aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 2); + } + else + { + aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 1); + fp16_optional = 1; + } + } + /* Tag_VFP_HP_extension (formerly Tag_NEON_FP16_arch). */ - if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16)) + if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16) && fp16_optional) aeabi_set_attribute_int (Tag_VFP_HP_extension, 1); - /* Tag_DIV_use. */ - if (ARM_CPU_HAS_FEATURE (flags, arm_ext_adiv)) - aeabi_set_attribute_int (Tag_DIV_use, 2); - else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_div)) + /* Tag_DIV_use. + + We set Tag_DIV_use to two when integer divide instructions have been used + in ARM state, or when Thumb integer divide instructions have been used, + but we have no architecture profile set, nor have we any ARM instructions. + + For ARMv8 we set the tag to 0 as integer divide is implied by the base + architecture. + + For new architectures we will have to check these tests. */ + gas_assert (arch <= TAG_CPU_ARCH_V8); + if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)) aeabi_set_attribute_int (Tag_DIV_use, 0); - else - aeabi_set_attribute_int (Tag_DIV_use, 1); + else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_adiv) + || (profile == '\0' + && ARM_CPU_HAS_FEATURE (flags, arm_ext_div) + && !ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_any))) + aeabi_set_attribute_int (Tag_DIV_use, 2); /* Tag_MP_extension_use. */ if (ARM_CPU_HAS_FEATURE (flags, arm_ext_mp)) @@ -23783,6 +24238,7 @@ s_arm_cpu (int ignored ATTRIBUTE_UNUSED) int i; for (i = 0; opt->name[i]; i++) selected_cpu_name[i] = TOUPPER (opt->name[i]); + selected_cpu_name[i] = 0; } ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);