bfd:
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index 2add8011d1d30258b846fa810b17a650c9b11d4e..8dd342bdeca29d89b1517691321a9c8052d2f25b 100644 (file)
@@ -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
+   2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
@@ -97,13 +97,12 @@ enum arm_float_abi
 
 /* Types of processor to assemble for. */
 #ifndef CPU_DEFAULT
-#if defined __XSCALE__
-#define CPU_DEFAULT    ARM_ARCH_XSCALE
-#else
-#if defined __thumb__
-#define CPU_DEFAULT    ARM_ARCH_V5T
-#endif
-#endif
+/* 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 
+   changing gas' default behaviour depending upon the build host.
+
+   If you have a target that requires a default CPU option then the you
+   should define CPU_DEFAULT here.  */
 #endif
 
 #ifndef FPU_DEFAULT
@@ -185,8 +184,8 @@ static const arm_feature_set arm_ext_v5exp = ARM_FEATURE (ARM_EXT_V5ExP, 0);
 static const arm_feature_set arm_ext_v5j = ARM_FEATURE (ARM_EXT_V5J, 0);
 static const arm_feature_set arm_ext_v6 = ARM_FEATURE (ARM_EXT_V6, 0);
 static const arm_feature_set arm_ext_v6k = ARM_FEATURE (ARM_EXT_V6K, 0);
-static const arm_feature_set arm_ext_v6z = ARM_FEATURE (ARM_EXT_V6Z, 0);
 static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE (ARM_EXT_V6T2, 0);
+static const arm_feature_set arm_ext_v6m = ARM_FEATURE (ARM_EXT_V6M, 0);
 static const arm_feature_set arm_ext_v6_notm = ARM_FEATURE (ARM_EXT_V6_NOTM, 0);
 static const arm_feature_set arm_ext_v6_dsp = ARM_FEATURE (ARM_EXT_V6_DSP, 0);
 static const arm_feature_set arm_ext_barrier = ARM_FEATURE (ARM_EXT_BARRIER, 0);
@@ -197,7 +196,12 @@ 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_m =
-  ARM_FEATURE (ARM_EXT_V6M | ARM_EXT_V7M, 0);
+  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);
+static const arm_feature_set arm_ext_sec = ARM_FEATURE (ARM_EXT_SEC, 0);
+static const arm_feature_set arm_ext_os = ARM_FEATURE (ARM_EXT_OS, 0);
+static const arm_feature_set arm_ext_adiv = ARM_FEATURE (ARM_EXT_ADIV, 0);
+static const arm_feature_set arm_ext_virt = ARM_FEATURE (ARM_EXT_VIRT, 0);
 
 static const arm_feature_set arm_arch_any = ARM_ANY;
 static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1);
@@ -503,6 +507,7 @@ enum arm_reg_type
   REG_TYPE_MMXWC,
   REG_TYPE_MMXWCG,
   REG_TYPE_XSCALE,
+  REG_TYPE_RNB
 };
 
 /* Structure for a hash table entry for a register.
@@ -512,7 +517,7 @@ enum arm_reg_type
 struct reg_entry
 {
   const char *               name;
-  unsigned char              number;
+  unsigned int               number;
   unsigned char              type;
   unsigned char              builtin;
   struct neon_typed_alias *  neon;
@@ -559,7 +564,7 @@ struct asm_opcode
   const char * template_name;
 
   /* Parameters to instruction.         */
-  unsigned char operands[8];
+  unsigned int operands[8];
 
   /* Conditional tag - see opcode_lookup.  */
   unsigned int tag : 4;
@@ -705,6 +710,10 @@ struct asm_opcode
 #define BAD_IT_COND    _("incorrect condition in IT block")
 #define BAD_IT_IT      _("IT falling in the range of a previous IT block")
 #define MISSING_FNSTART        _("missing .fnstart before unwinding directive")
+#define BAD_PC_ADDRESSING \
+       _("cannot use register index with PC-relative addressing")
+#define BAD_PC_WRITEBACK \
+       _("cannot use writeback with PC-relative addressing")
 
 static struct hash_control * arm_ops_hsh;
 static struct hash_control * arm_cond_hsh;
@@ -939,6 +948,8 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode)
       input_line_pointer = save_in;
       return 1;
     }
+#else
+  (void) seg;
 #endif
 
   /* Get rid of any bignums now, so that we don't generate an error for which
@@ -1878,7 +1889,6 @@ parse_neon_el_struct_list (char **str, unsigned *pbase,
   int lane = -1;
   int leading_brace = 0;
   enum arm_reg_type rtype = REG_TYPE_NDQ;
-  int addregs = 1;
   const char *const incr_error = _("register stride must be 1 or 2");
   const char *const type_error = _("mismatched element/structure types in list");
   struct neon_typed_alias firsttype;
@@ -1903,7 +1913,6 @@ parse_neon_el_struct_list (char **str, unsigned *pbase,
           if (rtype == REG_TYPE_NQ)
             {
               reg_incr = 1;
-              addregs = 2;
             }
           firsttype = atype;
         }
@@ -2055,7 +2064,7 @@ parse_reloc (char **str)
 /* Directives: register aliases.  */
 
 static struct reg_entry *
-insert_reg_alias (char *str, int number, int type)
+insert_reg_alias (char *str, unsigned number, int type)
 {
   struct reg_entry *new_reg;
   const char *name;
@@ -2300,7 +2309,16 @@ create_neon_reg_alias (char *newname, char *p)
         }
     }
 
+  /* If TC_CASE_SENSITIVE is defined, then newname already points to
+     the desired alias name, and p points to its end.  If not, then
+     the desired alias name is in the global original_case_string.  */
+#ifdef TC_CASE_SENSITIVE
   namelen = nameend - newname;
+#else
+  newname = original_case_string;
+  namelen = strlen (newname);
+#endif
+
   namebuf = (char *) alloca (namelen + 1);
   strncpy (namebuf, newname, namelen);
   namebuf[namelen] = '\0';
@@ -2490,14 +2508,27 @@ make_mapping_symbol (enum mstate state, valueT value, fragS *frag)
   /* Save the mapping symbols for future reference.  Also check that
      we do not place two mapping symbols at the same offset within a
      frag.  We'll handle overlap between frags in
-     check_mapping_symbols.  */
+     check_mapping_symbols.
+
+     If .fill or other data filling directive generates zero sized data,
+     the mapping symbol for the following code will have the same value
+     as the one generated for the data filling directive.  In this case,
+     we replace the old symbol with the new one at the same address.  */
   if (value == 0)
     {
-      know (frag->tc_frag_data.first_map == NULL);
+      if (frag->tc_frag_data.first_map != NULL)
+       {
+         know (S_GET_VALUE (frag->tc_frag_data.first_map) == 0);
+         symbol_remove (frag->tc_frag_data.first_map, &symbol_rootP, &symbol_lastP);
+       }
       frag->tc_frag_data.first_map = symbolP;
     }
   if (frag->tc_frag_data.last_map != NULL)
-    know (S_GET_VALUE (frag->tc_frag_data.last_map) < S_GET_VALUE (symbolP));
+    {
+      know (S_GET_VALUE (frag->tc_frag_data.last_map) <= S_GET_VALUE (symbolP));
+      if (S_GET_VALUE (frag->tc_frag_data.last_map) == S_GET_VALUE (symbolP))
+       symbol_remove (frag->tc_frag_data.last_map, &symbol_rootP, &symbol_lastP);
+    }
   frag->tc_frag_data.last_map = symbolP;
 }
 
@@ -4245,6 +4276,7 @@ static void s_arm_arch (int);
 static void s_arm_object_arch (int);
 static void s_arm_cpu (int);
 static void s_arm_fpu (int);
+static void s_arm_arch_extension (int);
 
 #ifdef TE_PE
 
@@ -4298,6 +4330,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "arch",       s_arm_arch,    0 },
   { "object_arch", s_arm_object_arch,  0 },
   { "fpu",        s_arm_fpu,     0 },
+  { "arch_extension", s_arm_arch_extension, 0 },
 #ifdef OBJ_ELF
   { "word",            s_arm_elf_cons, 4 },
   { "long",            s_arm_elf_cons, 4 },
@@ -4395,14 +4428,32 @@ parse_big_immediate (char **str, int i)
        }
     }
   else if (exp.X_op == O_big
-           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32
-           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number <= 64)
+          && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32)
     {
       unsigned parts = 32 / LITTLENUM_NUMBER_OF_BITS, j, idx = 0;
+
       /* Bignums have their least significant bits in
          generic_bignum[0]. Make sure we put 32 bits in imm and
          32 bits in reg,  in a (hopefully) portable way.  */
       gas_assert (parts != 0);
+
+      /* Make sure that the number is not too big.
+        PR 11972: Bignums can now be sign-extended to the
+        size of a .octa so check that the out of range bits
+        are all zero or all one.  */
+      if (LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 64)
+       {
+         LITTLENUM_TYPE m = -1;
+
+         if (generic_bignum[parts * 2] != 0
+             && generic_bignum[parts * 2] != m)
+           return FAIL;
+
+         for (j = parts * 2 + 1; j < (unsigned) exp.X_add_number; j++)
+           if (generic_bignum[j] != generic_bignum[j-1])
+             return FAIL;
+       }
+
       inst.operands[i].imm = 0;
       for (j = 0; j < parts; j++, idx++)
         inst.operands[i].imm |= generic_bignum[idx]
@@ -4932,6 +4983,33 @@ parse_shifter_operand_group_reloc (char **str, int i)
   /* Never reached.  */
 }
 
+/* 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)
+{
+  char *p = *str;
+  expressionS exp;
+
+  my_get_expression (&exp, &p, GE_NO_PREFIX);
+
+  if (exp.X_op != O_constant)
+    {
+      inst.error = _("alignment must be constant");
+      return PARSE_OPERAND_FAIL;
+    }
+
+  inst.operands[i].imm = exp.X_add_number << 8;
+  inst.operands[i].immisalign = 1;
+  /* Alignments are not pre-indexes.  */
+  inst.operands[i].preind = 0;
+
+  *str = p;
+  return PARSE_OPERAND_SUCCESS;
+}
+
 /* Parse all forms of an ARM address expression.  Information is written
    to inst.operands[i] and/or inst.reloc.
 
@@ -5015,22 +5093,15 @@ parse_address_main (char **str, int i, int group_relocations,
              return PARSE_OPERAND_FAIL;
        }
       else if (skip_past_char (&p, ':') == SUCCESS)
-        {
-          /* 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.  */
-          expressionS exp;
-          my_get_expression (&exp, &p, GE_NO_PREFIX);
-          if (exp.X_op != O_constant)
-            {
-              inst.error = _("alignment must be constant");
-              return PARSE_OPERAND_FAIL;
-            }
-          inst.operands[i].imm = exp.X_add_number << 8;
-          inst.operands[i].immisalign = 1;
-          /* Alignments are not pre-indexes.  */
-          inst.operands[i].preind = 0;
-        }
+       {
+         /* 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;
+       }
       else
        {
          if (inst.operands[i].negative)
@@ -5094,6 +5165,15 @@ parse_address_main (char **str, int i, int group_relocations,
              return PARSE_OPERAND_FAIL;
        }
     }
+  else if (skip_past_char (&p, ':') == SUCCESS)
+    {
+      /* 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;
+    }
 
   if (skip_past_char (&p, ']') == FAIL)
     {
@@ -5249,7 +5329,9 @@ parse_psr (char **str)
   p = *str;
   if (strncasecmp (p, "SPSR", 4) == 0)
     psr_field = SPSR_BIT;
-  else if (strncasecmp (p, "CPSR", 4) == 0)
+  else if (strncasecmp (p, "CPSR", 4) == 0 
+          || (strncasecmp (p, "APSR", 4) == 0
+              && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m)))
     psr_field = 0;
   else
     {
@@ -5729,6 +5811,11 @@ parse_neon_mov (char **str, int *which_operand)
   return FAIL;
 }
 
+/* Use this macro when the operand constraints are different
+   for ARM and THUMB (e.g. ldrd).  */
+#define MIX_ARM_THUMB_OPERANDS(arm_operand, thumb_operand) \
+       ((arm_operand) | ((thumb_operand) << 16))
+
 /* Matcher codes for parse_operands.  */
 enum operand_parse_code
 {
@@ -5736,7 +5823,10 @@ enum operand_parse_code
 
   OP_RR,       /* ARM register */
   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, 
+                  optional trailing ! */
   OP_RRw,      /* ARM register, not r15, optional trailing ! */
   OP_RCP,      /* Coprocessor number */
   OP_RCN,      /* Coprocessor register */
@@ -5835,6 +5925,7 @@ enum operand_parse_code
 
   OP_oRR,       /* ARM register */
   OP_oRRnpc,    /* ARM register, not the PC */
+  OP_oRRnpcsp,  /* ARM register, neither the PC nor the SP (a.k.a. BadReg) */
   OP_oRRw,      /* ARM register, not r15, optional trailing ! */
   OP_oRND,       /* Optional Neon double precision register */
   OP_oRNQ,       /* Optional Neon quad precision register */
@@ -5844,7 +5935,12 @@ enum operand_parse_code
   OP_oSHar,     /* ASR immediate */
   OP_oSHllar,   /* LSL or ASR immediate */
   OP_oROR,      /* ROR 0/8/16/24 */
-  OP_oBARRIER,  /* Option argument for a barrier instruction.  */
+  OP_oBARRIER_I15, /* Option argument for a barrier instruction.  */
+
+  /* Some pre-defined mixed (ARM/THUMB) operands.  */
+  OP_RR_npcsp          = MIX_ARM_THUMB_OPERANDS (OP_RR, OP_RRnpcsp),
+  OP_RRnpc_npcsp       = MIX_ARM_THUMB_OPERANDS (OP_RRnpc, OP_RRnpcsp),
+  OP_oRRnpc_npcsp      = MIX_ARM_THUMB_OPERANDS (OP_oRRnpc, OP_oRRnpcsp),
 
   OP_FIRST_OPTIONAL = OP_oI7b
 };
@@ -5854,14 +5950,15 @@ enum operand_parse_code
    structure.  Returns SUCCESS or FAIL depending on whether the
    specified grammar matched.  */
 static int
-parse_operands (char *str, const unsigned char *pattern)
+parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 {
-  unsigned const char *upat = pattern;
+  unsigned const int *upat = pattern;
   char *backtrack_pos = 0;
   const char *backtrack_error = 0;
   int i, val, backtrack_index = 0;
   enum arm_reg_type rtype;
   parse_operand_result result;
+  unsigned int op_parse_code;
 
 #define po_char_or_fail(chr)                   \
   do                                           \
@@ -5948,11 +6045,40 @@ parse_operands (char *str, const unsigned char *pattern)
     }                                                  \
   while (0)
 
+#define po_barrier_or_imm(str)                            \
+  do                                                      \
+    {                                                     \
+      val = parse_barrier (&str);                         \
+      if (val == FAIL)                                    \
+       {                                                  \
+         if (ISALPHA (*str))                              \
+             goto failure;                                \
+         else                                             \
+             goto immediate;                              \
+       }                                                  \
+      else                                                \
+       {                                                  \
+         if ((inst.instruction & 0xf0) == 0x60            \
+             && val != 0xf)                               \
+           {                                              \
+              /* ISB can only take SY as an option.  */   \
+              inst.error = _("invalid barrier type");     \
+              goto failure;                               \
+           }                                              \
+       }                                                  \
+    }                                                     \
+  while (0)
+
   skip_whitespace (str);
 
   for (i = 0; upat[i] != OP_stop; i++)
     {
-      if (upat[i] >= OP_FIRST_OPTIONAL)
+      op_parse_code = upat[i];
+      if (op_parse_code >= 1<<16)
+       op_parse_code = thumb ? (op_parse_code >> 16)
+                               : (op_parse_code & ((1<<16)-1));
+
+      if (op_parse_code >= OP_FIRST_OPTIONAL)
        {
          /* Remember where we are in case we need to backtrack.  */
          gas_assert (!backtrack_pos);
@@ -5964,11 +6090,13 @@ parse_operands (char *str, const unsigned char *pattern)
       if (i > 0 && (i > 1 || inst.operands[0].present))
        po_char_or_fail (',');
 
-      switch (upat[i])
+      switch (op_parse_code)
        {
          /* Registers */
        case OP_oRRnpc:
+       case OP_oRRnpcsp:
        case OP_RRnpc:
+       case OP_RRnpcsp:
        case OP_oRR:
        case OP_RR:    po_reg_or_fail (REG_TYPE_RN);      break;
        case OP_RCP:   po_reg_or_fail (REG_TYPE_CP);      break;
@@ -6092,6 +6220,7 @@ parse_operands (char *str, const unsigned char *pattern)
          po_char_or_fail (']');
          break;
 
+       case OP_RRnpctw:
        case OP_RRw:
        case OP_oRRw:
          po_reg_or_fail (REG_TYPE_RN);
@@ -6245,12 +6374,26 @@ parse_operands (char *str, const unsigned char *pattern)
        case OP_oROR:    val = parse_ror (&str);                break;
        case OP_PSR:     val = parse_psr (&str);                break;
        case OP_COND:    val = parse_cond (&str);               break;
-       case OP_oBARRIER:val = parse_barrier (&str);            break;
+       case OP_oBARRIER_I15:
+         po_barrier_or_imm (str); break;
+         immediate:
+         if (parse_immediate (&str, &val, 0, 15, TRUE) == FAIL)
+            goto failure;
+         break;
 
         case OP_RVC_PSR:
-          po_reg_or_goto (REG_TYPE_VFC, try_psr);
+          po_reg_or_goto (REG_TYPE_VFC, try_banked_reg);
           inst.operands[i].isvec = 1;  /* Mark VFP control reg as vector.  */
           break;
+         try_banked_reg:
+         po_reg_or_goto (REG_TYPE_RNB, try_psr);
+         if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_virt))
+           {
+             inst.error = _("Banked registers are not available with this "
+                            "architecture.");
+             goto failure;
+           }
+         break;
           try_psr:
           val = parse_psr (&str);
           break;
@@ -6371,13 +6514,13 @@ parse_operands (char *str, const unsigned char *pattern)
          break;
 
        default:
-         as_fatal (_("unhandled operand code %d"), upat[i]);
+         as_fatal (_("unhandled operand code %d"), op_parse_code);
        }
 
       /* Various value-based sanity checks and shared operations.  We
         do not signal immediate failures for the register constraints;
         this allows a syntax error to take precedence.  */
-      switch (upat[i])
+      switch (op_parse_code)
        {
        case OP_oRRnpc:
        case OP_RRnpc:
@@ -6389,13 +6532,31 @@ parse_operands (char *str, const unsigned char *pattern)
            inst.error = BAD_PC;
          break;
 
+       case OP_oRRnpcsp:
+       case OP_RRnpcsp:
+         if (inst.operands[i].isreg)
+           {
+             if (inst.operands[i].reg == REG_PC)
+               inst.error = BAD_PC;
+             else if (inst.operands[i].reg == REG_SP)
+               inst.error = BAD_SP;
+           }
+         break;
+
+       case OP_RRnpctw:
+         if (inst.operands[i].isreg 
+             && inst.operands[i].reg == REG_PC 
+             && (inst.operands[i].writeback || thumb))
+           inst.error = BAD_PC;
+         break;
+
        case OP_CPSF:
        case OP_ENDI:
        case OP_oROR:
        case OP_PSR:
         case OP_RVC_PSR:
        case OP_COND:
-       case OP_oBARRIER:
+       case OP_oBARRIER_I15:
        case OP_REGLST:
        case OP_VRSLST:
        case OP_VRDLST:
@@ -6460,6 +6621,7 @@ parse_operands (char *str, const unsigned char *pattern)
 #undef po_reg_or_goto
 #undef po_imm_or_fail
 #undef po_scalar_or_fail
+#undef po_barrier_or_imm
 
 /* Shorthand macro for instruction encoding functions issuing errors.  */
 #define constraint(expr, err)                  \
@@ -6674,10 +6836,15 @@ encode_arm_addr_mode_common (int i, bfd_boolean is_t)
 static void
 encode_arm_addr_mode_2 (int i, bfd_boolean is_t)
 {
+  const bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
+
   encode_arm_addr_mode_common (i, is_t);
 
   if (inst.operands[i].immisreg)
     {
+      constraint ((inst.operands[i].imm == REG_PC
+                  || (is_pc && inst.operands[i].writeback)),
+                 BAD_PC_ADDRESSING);
       inst.instruction |= INST_IMMEDIATE;  /* yes, this is backwards */
       inst.instruction |= inst.operands[i].imm;
       if (!inst.operands[i].negative)
@@ -6695,6 +6862,23 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t)
     }
   else /* immediate offset in inst.reloc */
     {
+      if (is_pc && !inst.reloc.pc_rel)
+       {
+         const bfd_boolean is_load = ((inst.instruction & LOAD_BIT) != 0);
+
+         /* If is_t is TRUE, it's called from do_ldstt.  ldrt/strt
+            cannot use PC in addressing.
+            PC cannot be used in writeback addressing, either.  */
+         constraint ((is_t || inst.operands[i].writeback),
+                     BAD_PC_ADDRESSING);
+
+         /* Use of PC in str is deprecated for ARMv7.  */
+         if (warn_on_deprecated
+             && !is_load
+             && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7))
+           as_warn (_("use of PC in this instruction is deprecated"));
+       }
+
       if (inst.reloc.type == BFD_RELOC_UNUSED)
        inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
     }
@@ -6718,12 +6902,18 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t)
 
   if (inst.operands[i].immisreg)
     {
+      constraint ((inst.operands[i].imm == REG_PC
+                  || inst.operands[i].reg == REG_PC),
+                 BAD_PC_ADDRESSING);
       inst.instruction |= inst.operands[i].imm;
       if (!inst.operands[i].negative)
        inst.instruction |= INDEX_UP;
     }
   else /* immediate offset in inst.reloc */
     {
+      constraint ((inst.operands[i].reg == REG_PC && !inst.reloc.pc_rel
+                  && inst.operands[i].writeback),
+                 BAD_PC_WRITEBACK);
       inst.instruction |= HWOFFSET_IMM;
       if (inst.reloc.type == BFD_RELOC_UNUSED)
        inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
@@ -6915,8 +7105,16 @@ do_rd_rm_rn (void)
   unsigned Rn = inst.operands[2].reg;
   /* Enforce restrictions on SWP instruction.  */
   if ((inst.instruction & 0x0fbfffff) == 0x01000090)
-    constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg,
-               _("Rn must not overlap other operands"));
+    {
+      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"));
+
+    }
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg;
   inst.instruction |= Rn << 16;
@@ -6933,6 +7131,11 @@ do_rd_rn_rm (void)
 static void
 do_rm_rd_rn (void)
 {
+  constraint ((inst.operands[2].reg == REG_PC), BAD_PC);
+  constraint (((inst.reloc.exp.X_op != O_constant
+               && inst.reloc.exp.X_op != O_illegal)
+              || inst.reloc.exp.X_add_number != 0),
+             BAD_ADDR_MODE);
   inst.instruction |= inst.operands[0].reg;
   inst.instruction |= inst.operands[1].reg << 12;
   inst.instruction |= inst.operands[2].reg << 16;
@@ -7004,7 +7207,8 @@ do_barrier (void)
   if (inst.operands[0].present)
     {
       constraint ((inst.instruction & 0xf0) != 0x40
-                 && inst.operands[0].imm != 0xf,
+                 && inst.operands[0].imm > 0xf
+                 && inst.operands[0].imm < 0x0,
                  _("bad barrier type"));
       inst.instruction |= inst.operands[0].imm;
     }
@@ -7081,9 +7285,7 @@ encode_branch (int default_reloc)
       inst.reloc.type  = BFD_RELOC_ARM_PLT32;
     }
   else
-    {
-      inst.reloc.type = (bfd_reloc_code_real_type) default_reloc;
-    }
+    inst.reloc.type = (bfd_reloc_code_real_type) default_reloc;
   inst.reloc.pc_rel = 1;
 }
 
@@ -7299,6 +7501,25 @@ do_dbg (void)
   inst.instruction |= inst.operands[0].imm;
 }
 
+static void
+do_div (void)
+{
+  unsigned Rd, Rn, Rm;
+
+  Rd = inst.operands[0].reg;
+  Rn = (inst.operands[1].present
+       ? inst.operands[1].reg : Rd);
+  Rm = inst.operands[2].reg;
+
+  constraint ((Rd == REG_PC), BAD_PC);
+  constraint ((Rn == REG_PC), BAD_PC);
+  constraint ((Rm == REG_PC), BAD_PC);
+
+  inst.instruction |= Rd << 16;
+  inst.instruction |= Rn << 0;
+  inst.instruction |= Rm << 8;
+}
+
 static void
 do_it (void)
 {
@@ -7423,6 +7644,8 @@ do_ldrex (void)
              || inst.reloc.exp.X_add_number != 0,
              _("offset must be zero in ARM encoding"));
 
+  constraint ((inst.operands[1].reg == REG_PC), BAD_PC);
+
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg << 16;
   inst.reloc.type = BFD_RELOC_UNUSED;
@@ -7637,16 +7860,30 @@ do_vmsr (void)
 static void
 do_mrs (void)
 {
+  unsigned br;
+
   if (do_vfp_nsyn_mrs () == SUCCESS)
     return;
 
-  /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
-  constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
-             != (PSR_c|PSR_f),
-             _("'CPSR' or 'SPSR' expected"));
   constraint (inst.operands[0].reg == REG_PC, BAD_PC);
   inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= (inst.operands[1].imm & SPSR_BIT);
+
+  if (inst.operands[1].isreg)
+    {
+      br = inst.operands[1].reg;
+      if (((br & 0x200) == 0) && ((br & 0xf0000) != 0xf000))
+       as_bad (_("bad register for mrs"));
+    }
+  else
+    {
+      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
+      constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
+                 != (PSR_c|PSR_f),
+                 _("'CPSR' or 'SPSR' expected"));
+      br = (15<<16) | (inst.operands[1].imm & SPSR_BIT);
+    }
+
+  inst.instruction |= br;
 }
 
 /* Two possible forms:
@@ -7764,8 +8001,9 @@ do_pkhtb (void)
 }
 
 /* ARMv5TE: Preload-Cache
+   MP Extensions: Preload for write
 
-    PLD <addr_mode>
+    PLD(W) <addr_mode>
 
   Syntactically, like LDR with B=1, W=0, L=1.  */
 
@@ -7906,6 +8144,13 @@ do_smc (void)
   inst.reloc.pc_rel = 0;
 }
 
+static void
+do_hvc (void)
+{
+  inst.reloc.type = BFD_RELOC_ARM_HVC;
+  inst.reloc.pc_rel = 0;
+}
+
 static void
 do_swi (void)
 {
@@ -8672,12 +8917,13 @@ encode_thumb32_shifted_operand (int i)
    Thumb32 format load or store instruction.  Reject forms that cannot
    be used with such instructions.  If is_t is true, reject forms that
    cannot be used with a T instruction; if is_d is true, reject forms
-   that cannot be used with a D instruction.  */
+   that cannot be used with a D instruction.  If it is a store insn,
+   reject PC in Rn.  */
 
 static void
 encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
 {
-  bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
+  const bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
 
   constraint (!inst.operands[i].isreg,
              _("Instruction does not support =N addresses"));
@@ -8685,7 +8931,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   inst.instruction |= inst.operands[i].reg << 16;
   if (inst.operands[i].immisreg)
     {
-      constraint (is_pc, _("cannot use register index with PC-relative addressing"));
+      constraint (is_pc, BAD_PC_ADDRESSING);
       constraint (is_t || is_d, _("cannot use register index with this instruction"));
       constraint (inst.operands[i].negative,
                  _("Thumb does not support negative register indexing"));
@@ -8710,10 +8956,11 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
     }
   else if (inst.operands[i].preind)
     {
-      constraint (is_pc && inst.operands[i].writeback,
-                 _("cannot use writeback with PC-relative addressing"));
+      constraint (is_pc && inst.operands[i].writeback, BAD_PC_WRITEBACK);
       constraint (is_t && inst.operands[i].writeback,
                  _("cannot use writeback with this instruction"));
+      constraint (is_pc && ((inst.instruction & THUMB2_LOAD_BIT) == 0)
+                 && !inst.reloc.pc_rel, BAD_PC_ADDRESSING);
 
       if (is_d)
        {
@@ -9307,7 +9554,8 @@ do_t_barrier (void)
   if (inst.operands[0].present)
     {
       constraint ((inst.instruction & 0xf0) != 0x40
-                 && inst.operands[0].imm != 0xf,
+                 && inst.operands[0].imm > 0xf
+                 && inst.operands[0].imm < 0x0,
                  _("bad barrier type"));
       inst.instruction |= inst.operands[0].imm;
     }
@@ -9416,6 +9664,7 @@ do_t_branch (void)
 {
   int opcode;
   int cond;
+  int reloc;
 
   cond = inst.cond;
   set_it_insn_type (IF_INSIDE_IT_LAST_INSN);
@@ -9438,29 +9687,29 @@ do_t_branch (void)
     {
       inst.instruction = THUMB_OP32(opcode);
       if (cond == COND_ALWAYS)
-       inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH25;
+       reloc = BFD_RELOC_THUMB_PCREL_BRANCH25;
       else
        {
          gas_assert (cond != 0xF);
          inst.instruction |= cond << 22;
-         inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH20;
+         reloc = BFD_RELOC_THUMB_PCREL_BRANCH20;
        }
     }
   else
     {
       inst.instruction = THUMB_OP16(opcode);
       if (cond == COND_ALWAYS)
-       inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
+       reloc = BFD_RELOC_THUMB_PCREL_BRANCH12;
       else
        {
          inst.instruction |= cond << 8;
-         inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
+         reloc = BFD_RELOC_THUMB_PCREL_BRANCH9;
        }
       /* Allow section relaxation.  */
       if (unified_syntax && inst.size_req != 2)
        inst.relax = opcode;
     }
-
+  inst.reloc.type = reloc;
   inst.reloc.pc_rel = 1;
 }
 
@@ -9675,6 +9924,12 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
 
   if (mask & (1 << 13))
     inst.error =  _("SP not allowed in register list");
+
+  if ((mask & (1 << base)) != 0
+      && writeback)
+    inst.error = _("having the base register in the register list when "
+                  "using write back is UNPREDICTABLE");
+
   if (load)
     {
       if (mask & (1 << 15))
@@ -9684,19 +9939,11 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
           else
             set_it_insn_type_last ();
         }
-
-      if ((mask & (1 << base)) != 0
-         && writeback)
-       as_warn (_("base register should not be in register list "
-                  "when written back"));
     }
   else
     {
       if (mask & (1 << 15))
        inst.error = _("PC not allowed in register list");
-
-      if (mask & (1 << base))
-       as_warn (_("value stored for r%d is UNPREDICTABLE"), base);
     }
 
   if ((mask & (mask - 1)) == 0)
@@ -9753,30 +10000,68 @@ do_t_ldmstm (void)
        {
          mask = 1 << inst.operands[0].reg;
 
-         if (inst.operands[0].reg <= 7
-             && (inst.instruction == T_MNEM_stmia
-                 ? inst.operands[0].writeback
-                 : (inst.operands[0].writeback
-                    == !(inst.operands[1].imm & mask))))
+         if (inst.operands[0].reg <= 7)
            {
              if (inst.instruction == T_MNEM_stmia
-                 && (inst.operands[1].imm & mask)
-                 && (inst.operands[1].imm & (mask - 1)))
-               as_warn (_("value stored for r%d is UNPREDICTABLE"),
-                        inst.operands[0].reg);
+                 ? inst.operands[0].writeback
+                 : (inst.operands[0].writeback
+                    == !(inst.operands[1].imm & mask)))
+               {
+                 if (inst.instruction == T_MNEM_stmia
+                     && (inst.operands[1].imm & mask)
+                     && (inst.operands[1].imm & (mask - 1)))
+                   as_warn (_("value stored for r%d is UNKNOWN"),
+                            inst.operands[0].reg);
 
-             inst.instruction = THUMB_OP16 (inst.instruction);
-             inst.instruction |= inst.operands[0].reg << 8;
-             inst.instruction |= inst.operands[1].imm;
-             narrow = TRUE;
+                 inst.instruction = THUMB_OP16 (inst.instruction);
+                 inst.instruction |= inst.operands[0].reg << 8;
+                 inst.instruction |= inst.operands[1].imm;
+                 narrow = TRUE;
+               }
+             else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
+               {
+                 /* This means 1 register in reg list one of 3 situations:
+                    1. Instruction is stmia, but without writeback.
+                    2. lmdia without writeback, but with Rn not in
+                       reglist.
+                    3. ldmia with writeback, but with Rn in reglist.
+                    Case 3 is UNPREDICTABLE behaviour, so we handle
+                    case 1 and 2 which can be converted into a 16-bit
+                    str or ldr. The SP cases are handled below.  */
+                 unsigned long opcode;
+                 /* First, record an error for Case 3.  */
+                 if (inst.operands[1].imm & mask
+                     && inst.operands[0].writeback)
+                   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 
+                                                            : T_MNEM_ldr);
+                 inst.instruction = THUMB_OP16 (opcode);
+                 inst.instruction |= inst.operands[0].reg << 3;
+                 inst.instruction |= (ffs (inst.operands[1].imm)-1);
+                 narrow = TRUE;
+               }
            }
-         else if (inst.operands[0] .reg == REG_SP
-                  && inst.operands[0].writeback)
+         else if (inst.operands[0] .reg == REG_SP)
            {
-             inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
-                                            ? T_MNEM_push : T_MNEM_pop);
-             inst.instruction |= inst.operands[1].imm;
-             narrow = TRUE;
+             if (inst.operands[0].writeback)
+               {
+                 inst.instruction = 
+                       THUMB_OP16 (inst.instruction == T_MNEM_stmia
+                                   ? T_MNEM_push : T_MNEM_pop);
+                 inst.instruction |= inst.operands[1].imm;
+                 narrow = TRUE;
+               }
+             else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
+               {
+                 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);
+                 narrow = TRUE;
+               }
            }
        }
 
@@ -9802,7 +10087,7 @@ do_t_ldmstm (void)
            as_warn (_("this instruction will write back the base register"));
          if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
              && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
-           as_warn (_("value stored for r%d is UNPREDICTABLE"),
+           as_warn (_("value stored for r%d is UNKNOWN"),
                     inst.operands[0].reg);
        }
       else
@@ -9830,6 +10115,8 @@ do_t_ldrex (void)
              || inst.operands[1].negative,
              BAD_ADDR_MODE);
 
+  constraint ((inst.operands[1].reg == REG_PC), BAD_PC);
+
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg << 16;
   inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
@@ -9889,6 +10176,8 @@ do_t_ldst (void)
              /* [Rn, Rik] */
              if (Rn <= 7 && inst.operands[1].imm <= 7)
                goto op16;
+             else if (opcode != T_MNEM_ldr && opcode != T_MNEM_str)
+               reject_bad_reg (inst.operands[1].imm);
            }
          else if ((Rn <= 7 && opcode != T_MNEM_ldrsh
                    && opcode != T_MNEM_ldrsb)
@@ -9928,6 +10217,12 @@ do_t_ldst (void)
            }
        }
       /* Definitely a 32-bit variant.  */
+
+      /* Do some validations regarding addressing modes.  */
+      if (inst.operands[1].immisreg && opcode != T_MNEM_ldr
+         && opcode != T_MNEM_str)
+       reject_bad_reg (inst.operands[1].imm);
+
       inst.instruction = THUMB_OP32 (opcode);
       inst.instruction |= inst.operands[0].reg << 12;
       encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE);
@@ -10141,9 +10436,24 @@ do_t_mov_cmp (void)
                  reject_bad_reg (Rn);
                  reject_bad_reg (Rm);
                }
-             else if ((Rn == REG_SP || Rn == REG_PC)
-                      && (Rm == REG_SP || Rm == REG_PC))
-               reject_bad_reg (Rm);
+             else if (narrow)
+               {
+                 /* This is mov.n.  */
+                 if ((Rn == REG_SP || Rn == REG_PC)
+                     && (Rm == REG_SP || Rm == REG_PC))
+                   {
+                     as_warn (_("Use of r%u as a source register is "
+                                "deprecated when r%u is the destination "
+                                "register."), Rm, Rn);
+                   }
+               }
+             else
+               {
+                 /* This is mov.w.  */
+                 constraint (Rn == REG_PC, BAD_PC);
+                 constraint (Rm == REG_PC, BAD_PC);
+                 constraint (Rn == REG_SP && Rm == REG_SP, BAD_SP);
+               }
            }
          else
            reject_bad_reg (Rn);
@@ -10276,8 +10586,8 @@ do_t_mov_cmp (void)
 
          case T_MNEM_movs:
            /* We know we have low registers at this point.
-              Generate ADD Rd, Rs, #0.  */
-           inst.instruction = T_OPCODE_ADD_I3;
+              Generate LSLS Rd, Rs, #0.  */
+           inst.instruction = T_OPCODE_LSL_I;
            inst.instruction |= Rn;
            inst.instruction |= Rm << 3;
            break;
@@ -10455,34 +10765,48 @@ static void
 do_t_mrs (void)
 {
   unsigned Rd;
-  int flags;
 
   if (do_vfp_nsyn_mrs () == SUCCESS)
     return;
 
-  flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
-  if (flags == 0)
+  Rd = inst.operands[0].reg;
+  reject_bad_reg (Rd);
+  inst.instruction |= Rd << 8;
+
+  if (inst.operands[1].isreg)
     {
-      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_m),
-                 _("selected processor does not support "
-                   "requested special purpose register"));
+      unsigned br = inst.operands[1].reg;
+      if (((br & 0x200) == 0) && ((br & 0xf000) != 0xf000))
+       as_bad (_("bad register for mrs"));
+
+      inst.instruction |= br & (0xf << 16);
+      inst.instruction |= (br & 0x300) >> 4;
+      inst.instruction |= (br & SPSR_BIT) >> 2;
     }
   else
     {
-      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
-                 _("selected processor does not support "
-                   "requested special purpose register"));
-      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
-      constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
-                 _("'CPSR' or 'SPSR' expected"));
-    }
+      int flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
 
-  Rd = inst.operands[0].reg;
-  reject_bad_reg (Rd);
+      if (flags == 0)
+       {
+         constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_m),
+                     _("selected processor does not support "
+                       "requested special purpose register"));
+       }
+      else
+       {
+         constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
+                     _("selected processor does not support "
+                       "requested special purpose register"));
+         /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
+         constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
+                     _("'CPSR' or 'SPSR' expected"));
+       }
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= (flags & SPSR_BIT) >> 2;
-  inst.instruction |= inst.operands[1].imm & 0xff;
+      inst.instruction |= (flags & SPSR_BIT) >> 2;
+      inst.instruction |= inst.operands[1].imm & 0xff;
+      inst.instruction |= 0xf0000;
+    }
 }
 
 static void
@@ -10496,7 +10820,12 @@ do_t_msr (void)
 
   constraint (!inst.operands[1].isreg,
              _("Thumb encoding does not support an immediate here"));
-  flags = inst.operands[0].imm;
+
+  if (inst.operands[0].isreg)
+    flags = (int)(inst.operands[0].reg);
+  else
+    flags = inst.operands[0].imm;
+
   if (flags & ~0xff)
     {
       constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
@@ -10515,7 +10844,8 @@ do_t_msr (void)
   reject_bad_reg (Rn);
 
   inst.instruction |= (flags & SPSR_BIT) >> 2;
-  inst.instruction |= (flags & ~SPSR_BIT) >> 8;
+  inst.instruction |= (flags & 0xf0000) >> 8;
+  inst.instruction |= (flags & 0x300) >> 4;
   inst.instruction |= (flags & 0xff);
   inst.instruction |= Rn << 16;
 }
@@ -11100,6 +11430,8 @@ static void
 do_t_smc (void)
 {
   unsigned int value = inst.reloc.exp.X_add_number;
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7a),
+             _("SMC is not permitted on this architecture"));
   constraint (inst.reloc.exp.X_op != O_constant,
              _("expression too complex"));
   inst.reloc.type = BFD_RELOC_UNUSED;
@@ -11108,6 +11440,16 @@ do_t_smc (void)
   inst.instruction |= (value & 0x000f) << 16;
 }
 
+static void
+do_t_hvc (void)
+{
+  unsigned int value = inst.reloc.exp.X_add_number;
+
+  inst.reloc.type = BFD_RELOC_UNUSED;
+  inst.instruction |= (value & 0x0fff);
+  inst.instruction |= (value & 0xf000) << 4;
+}
+
 static void
 do_t_ssat_usat (int bias)
 {
@@ -11177,6 +11519,8 @@ do_t_strex (void)
              || inst.operands[2].negative,
              BAD_ADDR_MODE);
 
+  constraint (inst.operands[2].reg == REG_PC, BAD_PC);
+
   inst.instruction |= inst.operands[0].reg << 8;
   inst.instruction |= inst.operands[1].reg << 12;
   inst.instruction |= inst.operands[2].reg << 16;
@@ -11191,8 +11535,7 @@ do_t_strexd (void)
 
   constraint (inst.operands[0].reg == inst.operands[1].reg
              || inst.operands[0].reg == inst.operands[2].reg
-             || inst.operands[0].reg == inst.operands[3].reg
-             || inst.operands[1].reg == inst.operands[2].reg,
+             || inst.operands[0].reg == inst.operands[3].reg,
              BAD_OVERLAP);
 
   inst.instruction |= inst.operands[0].reg;
@@ -11259,6 +11602,15 @@ do_t_sxth (void)
 static void
 do_t_swi (void)
 {
+  /* We have to do the following check manually as ARM_EXT_OS only applies
+     to ARM_EXT_V6M.  */
+  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6m))
+    {
+      if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_os))
+       as_bad (_("SVC is not permitted on this architecture"));
+      ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, arm_ext_os);
+    }
+
   inst.reloc.type = BFD_RELOC_ARM_SWI;
 }
 
@@ -11706,6 +12058,8 @@ neon_select_shape (enum neon_shape shape, ...)
             case SE_L:
               break;
             }
+         if (!matches)
+           break;
         }
       if (matches)
         break;
@@ -14530,6 +14884,18 @@ do_neon_ldr_str (void)
 {
   int is_ldr = (inst.instruction & (1 << 20)) != 0;
 
+  /* Use of PC in vstr in ARM mode is deprecated in ARMv7.
+     And is UNPREDICTABLE in thumb mode.  */
+  if (!is_ldr 
+      && inst.operands[1].reg == REG_PC
+      && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7))
+    {
+      if (!thumb_mode && warn_on_deprecated)
+       as_warn (_("Use of PC here is deprecated"));
+      else
+       inst.error = _("Use of PC here is UNPREDICTABLE");
+    }
+
   if (inst.operands[0].issingle)
     {
       if (is_ldr)
@@ -14578,12 +14944,13 @@ do_neon_ld_st_interleave (void)
       {
       case 64: alignbits = 1; break;
       case 128:
-        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
+        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2
+           && NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4)
           goto bad_alignment;
         alignbits = 2;
         break;
       case 256:
-        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
+        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4)
           goto bad_alignment;
         alignbits = 3;
         break;
@@ -15620,7 +15987,7 @@ md_assemble (char *str)
          || (thumb_mode == 1
              && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
        {
-         as_bad (_("selected processor does not support `%s'"), str);
+         as_bad (_("selected processor does not support Thumb mode `%s'"), str);
          return;
        }
       if (inst.cond != COND_ALWAYS && !unified_syntax
@@ -15645,7 +16012,7 @@ md_assemble (char *str)
                inst.size_req = 2;
              else if (inst.size_req == 4)
                {
-                 as_bad (_("selected processor does not support `%s'"), str);
+                 as_bad (_("selected processor does not support Thumb-2 mode `%s'"), str);
                  return;
                }
            }
@@ -15653,7 +16020,7 @@ md_assemble (char *str)
 
       inst.instruction = opcode->tvalue;
 
-      if (!parse_operands (p, opcode->operands))
+      if (!parse_operands (p, opcode->operands, /*thumb=*/TRUE))
         {
           /* Prepare the it_insn_type for those encodings that don't set
              it.  */
@@ -15711,7 +16078,7 @@ md_assemble (char *str)
          && !(opcode->avariant &&
               ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant)))
        {
-         as_bad (_("selected processor does not support `%s'"), str);
+         as_bad (_("selected processor does not support ARM mode `%s'"), str);
          return;
        }
       if (inst.size_req)
@@ -15726,7 +16093,7 @@ md_assemble (char *str)
       else
        inst.instruction |= inst.cond << 28;
       inst.size = INSN_SIZE;
-      if (!parse_operands (p, opcode->operands))
+      if (!parse_operands (p, opcode->operands, /*thumb=*/FALSE))
         {
           it_fsm_pre_encode ();
           opcode->aencode ();
@@ -15891,6 +16258,13 @@ arm_canonicalize_symbol_name (char * name)
   REGNUM2(p, 4,t), REGNUM2(p, 5,t), REGNUM2(p, 6,t), REGNUM2(p, 7,t), \
   REGNUM2(p, 8,t), REGNUM2(p, 9,t), REGNUM2(p,10,t), REGNUM2(p,11,t), \
   REGNUM2(p,12,t), REGNUM2(p,13,t), REGNUM2(p,14,t), REGNUM2(p,15,t)
+#define SPLRBANK(base,bank,t) \
+  REGDEF(lr_##bank, 768|((base+0)<<16), t), \
+  REGDEF(sp_##bank, 768|((base+1)<<16), t), \
+  REGDEF(spsr_##bank, 768|(base<<16)|SPSR_BIT, t), \
+  REGDEF(LR_##bank, 768|((base+0)<<16), t), \
+  REGDEF(SP_##bank, 768|((base+1)<<16), t), \
+  REGDEF(SPSR_##bank, 768|(base<<16)|SPSR_BIT, t)
 
 static const struct reg_entry reg_names[] =
 {
@@ -15921,6 +16295,34 @@ static const struct reg_entry reg_names[] =
   REGSET(c,  CN), REGSET(C, CN),
   REGSET(cr, CN), REGSET(CR, CN),
 
+  /* ARM banked registers.  */
+  REGDEF(R8_usr,512|(0<<16),RNB), REGDEF(r8_usr,512|(0<<16),RNB),
+  REGDEF(R9_usr,512|(1<<16),RNB), REGDEF(r9_usr,512|(1<<16),RNB),
+  REGDEF(R10_usr,512|(2<<16),RNB), REGDEF(r10_usr,512|(2<<16),RNB),
+  REGDEF(R11_usr,512|(3<<16),RNB), REGDEF(r11_usr,512|(3<<16),RNB),
+  REGDEF(R12_usr,512|(4<<16),RNB), REGDEF(r12_usr,512|(4<<16),RNB),
+  REGDEF(SP_usr,512|(5<<16),RNB), REGDEF(sp_usr,512|(5<<16),RNB),
+  REGDEF(LR_usr,512|(6<<16),RNB), REGDEF(lr_usr,512|(6<<16),RNB),
+
+  REGDEF(R8_fiq,512|(8<<16),RNB), REGDEF(r8_fiq,512|(8<<16),RNB),
+  REGDEF(R9_fiq,512|(9<<16),RNB), REGDEF(r9_fiq,512|(9<<16),RNB),
+  REGDEF(R10_fiq,512|(10<<16),RNB), REGDEF(r10_fiq,512|(10<<16),RNB),
+  REGDEF(R11_fiq,512|(11<<16),RNB), REGDEF(r11_fiq,512|(11<<16),RNB),
+  REGDEF(R12_fiq,512|(12<<16),RNB), REGDEF(r12_fiq,512|(12<<16),RNB),
+  REGDEF(SP_fiq,512|(13<<16),RNB), REGDEF(SP_fiq,512|(13<<16),RNB),
+  REGDEF(LR_fiq,512|(14<<16),RNB), REGDEF(lr_fiq,512|(14<<16),RNB),
+  REGDEF(SPSR_fiq,512|(14<<16)|SPSR_BIT,RNB), REGDEF(spsr_fiq,512|(14<<16)|SPSR_BIT,RNB),
+
+  SPLRBANK(0,IRQ,RNB), SPLRBANK(0,irq,RNB),
+  SPLRBANK(2,SVC,RNB), SPLRBANK(2,svc,RNB),
+  SPLRBANK(4,ABT,RNB), SPLRBANK(4,abt,RNB),
+  SPLRBANK(6,UND,RNB), SPLRBANK(6,und,RNB),
+  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),
+
   /* FPA registers.  */
   REGNUM(f,0,FN), REGNUM(f,1,FN), REGNUM(f,2,FN), REGNUM(f,3,FN),
   REGNUM(f,4,FN), REGNUM(f,5,FN), REGNUM(f,6,FN), REGNUM(f,7, FN),
@@ -15997,6 +16399,8 @@ static const struct asm_psr psrs[] =
   {"c",           PSR_c},
   {"x",           PSR_x},
   {"s",           PSR_s},
+  {"g",           PSR_s},
+
   /* Combinations of flags.  */
   {"fs",   PSR_f | PSR_s},
   {"fx",   PSR_f | PSR_x},
@@ -16058,6 +16462,10 @@ static const struct asm_psr psrs[] =
   {"csxf", PSR_c | PSR_s | PSR_x | PSR_f},
   {"cxfs", PSR_c | PSR_x | PSR_f | PSR_s},
   {"cxsf", PSR_c | PSR_x | PSR_s | PSR_f},
+
+  /* APSR flags */
+  {"nzcvq", PSR_f},
+  {"nzcvqg", PSR_s | PSR_f}
 };
 
 /* Table of V7M psr names.  */
@@ -16105,7 +16513,8 @@ static struct reloc_entry reloc_names[] =
   { "tlsldm",  BFD_RELOC_ARM_TLS_LDM32}, { "TLSLDM",  BFD_RELOC_ARM_TLS_LDM32},
   { "tlsldo",  BFD_RELOC_ARM_TLS_LDO32}, { "TLSLDO",  BFD_RELOC_ARM_TLS_LDO32},
   { "gottpoff",BFD_RELOC_ARM_TLS_IE32},  { "GOTTPOFF",BFD_RELOC_ARM_TLS_IE32},
-  { "tpoff",   BFD_RELOC_ARM_TLS_LE32},  { "TPOFF",   BFD_RELOC_ARM_TLS_LE32}
+  { "tpoff",   BFD_RELOC_ARM_TLS_LE32},  { "TPOFF",   BFD_RELOC_ARM_TLS_LE32},
+  { "got_prel", BFD_RELOC_ARM_GOT_PREL}, { "GOT_PREL", BFD_RELOC_ARM_GOT_PREL}
 };
 #endif
 
@@ -16131,10 +16540,18 @@ static const struct asm_cond conds[] =
 
 static struct asm_barrier_opt barrier_opt_names[] =
 {
-  { "sy",   0xf },
-  { "un",   0x7 },
-  { "st",   0xe },
-  { "unst", 0x6 }
+  { "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 }
 };
 
 /* Table of ARM-format instructions.   */
@@ -16150,6 +16567,18 @@ static struct asm_barrier_opt barrier_opt_names[] =
 #define OPS5(a,b,c,d,e)          { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e, }
 #define OPS6(a,b,c,d,e,f) { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e,OP_##f, }
 
+/* These macros are similar to the OPSn, but do not prepend the OP_ prefix.
+   This is useful when mixing operands for ARM and THUMB, i.e. using the
+   MIX_ARM_THUMB_OPERANDS macro.
+   In order to use these macros, prefix the number of operands with _
+   e.g. _3.  */
+#define OPS_1(a)          { a, }
+#define OPS_2(a,b)        { a,b, }
+#define OPS_3(a,b,c)      { a,b,c, }
+#define OPS_4(a,b,c,d)    { a,b,c,d, }
+#define OPS_5(a,b,c,d,e)   { a,b,c,d,e, }
+#define OPS_6(a,b,c,d,e,f) { a,b,c,d,e,f, }
+
 /* These macros abstract out the exact format of the mnemonic table and
    save some repeated characters.  */
 
@@ -16327,9 +16756,6 @@ static struct asm_barrier_opt barrier_opt_names[] =
 
 #define do_0 0
 
-/* Thumb-only, unconditional.  */
-#define UT(mnem,  op, nops, ops, te) TUE (mnem,  0, op, nops, ops, 0, te)
-
 static const struct asm_opcode insns[] =
 {
 #define ARM_VARIANT &arm_ext_v1 /* Core ARM Instructions.  */
@@ -16370,9 +16796,11 @@ static const struct asm_opcode insns[] =
  tC3("mvns",   1f00000, _mvns,    2, (RR, SH),      mov,  t_mvn_tst),
 
  tCE("ldr",    4100000, _ldr,     2, (RR, ADDRGLDR),ldst, t_ldst),
- tC3("ldrb",   4500000, _ldrb,    2, (RR, ADDRGLDR),ldst, t_ldst),
- tCE("str",    4000000, _str,     2, (RR, ADDRGLDR),ldst, t_ldst),
- tC3("strb",   4400000, _strb,    2, (RR, ADDRGLDR),ldst, t_ldst),
+ tC3("ldrb",   4500000, _ldrb,    2, (RRnpc_npcsp, ADDRGLDR),ldst, t_ldst),
+ tCE("str",    4000000, _str,     _2, (MIX_ARM_THUMB_OPERANDS (OP_RR,
+                                                               OP_RRnpc),
+                                       OP_ADDRGLDR),ldst, t_ldst),
+ tC3("strb",   4400000, _strb,    2, (RRnpc_npcsp, ADDRGLDR),ldst, t_ldst),
 
  tCE("stm",    8800000, _stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
  tC3("stmia",  8800000, _stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
@@ -16422,10 +16850,10 @@ static const struct asm_opcode insns[] =
  TC3w("teqs",  1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
   CL("teqp",   130f000,           2, (RR, SH),      cmp),
 
- TC3("ldrt",   4300000, f8500e00, 2, (RR, ADDR),    ldstt, t_ldstt),
- TC3("ldrbt",  4700000, f8100e00, 2, (RR, ADDR),    ldstt, t_ldstt),
- TC3("strt",   4200000, f8400e00, 2, (RR, ADDR),    ldstt, t_ldstt),
- TC3("strbt",  4600000, f8000e00, 2, (RR, ADDR),    ldstt, t_ldstt),
+ TC3("ldrt",   4300000, f8500e00, 2, (RRnpc_npcsp, ADDR),ldstt, t_ldstt),
+ TC3("ldrbt",  4700000, f8100e00, 2, (RRnpc_npcsp, ADDR),ldstt, t_ldstt),
+ TC3("strt",   4200000, f8400e00, 2, (RR_npcsp, ADDR),   ldstt, t_ldstt),
+ TC3("strbt",  4600000, f8000e00, 2, (RRnpc_npcsp, ADDR),ldstt, t_ldstt),
 
  TC3("stmdb",  9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
  TC3("stmfd",     9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
@@ -16467,7 +16895,7 @@ static const struct asm_opcode insns[] =
  TCE("stc",    c000000, ec000000, 3, (RCP, RCN, ADDRGLDC),             lstc,   lstc),
  TC3("stcl",   c400000, ec400000, 3, (RCP, RCN, ADDRGLDC),             lstc,   lstc),
  TCE("mcr",    e000010, ee000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
- TCE("mrc",    e100010, ee100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
+ TCE("mrc",    e100010, ee100010, 6, (RCP, I7b, APSR_RR, RCN, RCN, oI7b),   co_reg, co_reg),
 
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v2s /* ARM 3 - swp instructions.  */
@@ -16480,7 +16908,7 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_msr
 
- TCE("mrs",    10f0000, f3ef8000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
+ TCE("mrs",    1000000, f3e08000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
  TCE("msr",    120f000, f3808000, 2, (RVC_PSR, RR_EXi), msr, t_msr),
 
 #undef  ARM_VARIANT
@@ -16502,12 +16930,12 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v4t
 
- tC3("ldrh",   01000b0, _ldrh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
- tC3("strh",   00000b0, _strh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
- tC3("ldrsh",  01000f0, _ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
- tC3("ldrsb",  01000d0, _ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
- tCM("ld","sh",        01000f0, _ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
- tCM("ld","sb",        01000d0, _ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
+ tC3("ldrh",   01000b0, _ldrh,     2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tC3("strh",   00000b0, _strh,     2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tC3("ldrsh",  01000f0, _ldrsh,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tC3("ldrsb",  01000d0, _ldrsb,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tCM("ld","sh",        01000f0, _ldrsh,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tCM("ld","sb",        01000d0, _ldrsb,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
 
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v4t_5
@@ -16576,8 +17004,10 @@ static const struct asm_opcode insns[] =
 #define THUMB_VARIANT &arm_ext_v6t2
 
  TUF("pld",    450f000, f810f000, 1, (ADDR),                pld,  t_pld),
- TC3("ldrd",   00000d0, e8500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
- TC3("strd",   00000f0, e8400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
+ TC3("ldrd",   00000d0, e8500000, 3, (RRnpc_npcsp, oRRnpc_npcsp, ADDRGLDRS),
+     ldrd, t_ldstd),
+ TC3("strd",   00000f0, e8400000, 3, (RRnpc_npcsp, oRRnpc_npcsp,
+                                      ADDRGLDRS), ldrd, t_ldstd),
 
  TCE("mcrr",   c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
  TCE("mrrc",   c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
@@ -16606,8 +17036,9 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6t2
 
- TCE("ldrex",  1900f9f, e8500f00, 2, (RRnpc, ADDR),              ldrex, t_ldrex),
- TCE("strex",  1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR),        strex,  t_strex),
+ TCE("ldrex",  1900f9f, e8500f00, 2, (RRnpc_npcsp, ADDR),        ldrex, t_ldrex),
+ TCE("strex",  1800f90, e8400000, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
+                                     strex,  t_strex),
  TUF("mcrr2",  c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
  TUF("mrrc2",  c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
 
@@ -16741,26 +17172,42 @@ static const struct asm_opcode insns[] =
 
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6_notm
-
- TCE("ldrexd", 1b00f9f, e8d0007f, 3, (RRnpc, oRRnpc, RRnpcb),        ldrexd, t_ldrexd),
- TCE("strexd", 1a00f90, e8c00070, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb), strexd, t_strexd),
+ TCE("ldrexd", 1b00f9f, e8d0007f, 3, (RRnpc_npcsp, oRRnpc_npcsp, RRnpcb),
+                                     ldrexd, t_ldrexd),
+ TCE("strexd", 1a00f90, e8c00070, 4, (RRnpc_npcsp, RRnpc_npcsp, oRRnpc_npcsp,
+                                      RRnpcb), strexd, t_strexd),
 
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6t2
-
- TCE("ldrexb", 1d00f9f, e8d00f4f, 2, (RRnpc, RRnpcb),                rd_rn,  rd_rn),
- TCE("ldrexh", 1f00f9f, e8d00f5f, 2, (RRnpc, RRnpcb),                rd_rn,  rd_rn),
- TCE("strexb", 1c00f90, e8c00f40, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
- TCE("strexh", 1e00f90, e8c00f50, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
+ TCE("ldrexb", 1d00f9f, e8d00f4f, 2, (RRnpc_npcsp,RRnpcb),
+     rd_rn,  rd_rn),
+ TCE("ldrexh", 1f00f9f, e8d00f5f, 2, (RRnpc_npcsp, RRnpcb),
+     rd_rn,  rd_rn),
+ TCE("strexb", 1c00f90, e8c00f40, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
+     strex, rm_rd_rn),
+ TCE("strexh", 1e00f90, e8c00f50, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
+     strex, rm_rd_rn), 
  TUF("clrex",  57ff01f, f3bf8f2f, 0, (),                             noargs, noargs),
 
 #undef  ARM_VARIANT
-#define ARM_VARIANT  & arm_ext_v6z
+#define ARM_VARIANT    & arm_ext_sec
+#undef THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_sec
 
  TCE("smc",    1600070, f7f08000, 1, (EXPi), smc, t_smc),
 
+#undef ARM_VARIANT
+#define        ARM_VARIANT    & arm_ext_virt
+#undef THUMB_VARIANT
+#define        THUMB_VARIANT    & arm_ext_virt
+
+ TCE("hvc",    1400070, f7e08000, 1, (EXPi), hvc, t_hvc),
+ TCE("eret",   160006e, f3de8f00, 0, (), noargs, noargs),
+
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v6t2
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2
 
  TCE("bfc",    7c0001f, f36f0000, 3, (RRnpc, I31, I32),           bfc, t_bfc),
  TCE("bfi",    7c00010, f3600000, 4, (RRnpc, RRnpc_I0, I31, I32), bfi, t_bfi),
@@ -16772,13 +17219,16 @@ static const struct asm_opcode insns[] =
  TCE("movt",   3400000, f2c00000, 2, (RRnpc, HALF),                mov16, t_mov16),
  TCE("rbit",   6ff0f30, fa90f0a0, 2, (RR, RR),                     rd_rm, t_rbit),
 
- TC3("ldrht",  03000b0, f8300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
- TC3("ldrsht", 03000f0, f9300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
- TC3("ldrsbt", 03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
- TC3("strht",  02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
+ TC3("ldrht",  03000b0, f8300e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
+ TC3("ldrsht", 03000f0, f9300e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
+ TC3("ldrsbt", 03000d0, f9100e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
+ TC3("strht",  02000b0, f8200e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
 
-  UT("cbnz",      b900,    2, (RR, EXP), t_cbz),
-  UT("cbz",       b100,    2, (RR, EXP), t_cbz),
+ /* Thumb-only instructions.  */
+#undef ARM_VARIANT
+#define ARM_VARIANT NULL
+  TUE("cbnz",     0,           b900,     2, (RR, EXP), 0, t_cbz),
+  TUE("cbz",      0,           b100,     2, (RR, EXP), 0, t_cbz),
 
  /* ARM does not really have an IT instruction, so always allow it.
     The opcode is copied from Thumb in order to allow warnings in
@@ -16816,12 +17266,14 @@ static const struct asm_opcode insns[] =
  TCE("tbb",       0, e8d0f000, 1, (TB), 0, t_tb),
  TCE("tbh",       0, e8d0f010, 1, (TB), 0, t_tb),
 
- /* Thumb-2 hardware division instructions (R and M profiles only).  */
+ /* Hardware division instructions.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT    & arm_ext_adiv
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_div
 
- TCE("sdiv",   0, fb90f0f0, 3, (RR, oRR, RR), 0, t_div),
- TCE("udiv",   0, fbb0f0f0, 3, (RR, oRR, RR), 0, t_div),
+ TCE("sdiv",   710f010, fb90f0f0, 3, (RR, oRR, RR), div, t_div),
+ TCE("udiv",   730f010, fbb0f0f0, 3, (RR, oRR, RR), div, t_div),
 
  /* ARM V6M/V7 instructions.  */
 #undef  ARM_VARIANT
@@ -16829,9 +17281,9 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_barrier
 
- TUF("dmb",    57ff050, f3bf8f50, 1, (oBARRIER), barrier,  t_barrier),
- TUF("dsb",    57ff040, f3bf8f40, 1, (oBARRIER), barrier,  t_barrier),
- TUF("isb",    57ff060, f3bf8f60, 1, (oBARRIER), barrier,  t_barrier),
+ TUF("dmb",    57ff050, f3bf8f50, 1, (oBARRIER_I15), barrier,  t_barrier),
+ TUF("dsb",    57ff040, f3bf8f40, 1, (oBARRIER_I15), barrier,  t_barrier),
+ TUF("isb",    57ff060, f3bf8f60, 1, (oBARRIER_I15), barrier,  t_barrier),
 
  /* ARM V7 instructions.  */
 #undef  ARM_VARIANT
@@ -16842,6 +17294,13 @@ static const struct asm_opcode insns[] =
  TUF("pli",    450f000, f910f000, 1, (ADDR),     pli,      t_pld),
  TCE("dbg",    320f0f0, f3af80f0, 1, (I15),      dbg,      t_dbg),
 
+#undef ARM_VARIANT
+#define ARM_VARIANT    & arm_ext_mp
+#undef THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_mp
+
+ TUF("pldw",   410f000, f830f000, 1, (ADDR),   pld,    t_pld),
+
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
 
@@ -17307,22 +17766,22 @@ static const struct asm_opcode insns[] =
   /* Memory operations.         */
  cCE("flds",   d100a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
  cCE("fsts",   d000a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
- cCE("fldmias",        c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
- cCE("fldmfds",        c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
- cCE("fldmdbs",        d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
- cCE("fldmeas",        d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
- cCE("fldmiax",        c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
- cCE("fldmfdx",        c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
- cCE("fldmdbx",        d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
- cCE("fldmeax",        d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
- cCE("fstmias",        c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
- cCE("fstmeas",        c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
- cCE("fstmdbs",        d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
- cCE("fstmfds",        d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
- cCE("fstmiax",        c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
- cCE("fstmeax",        c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
- cCE("fstmdbx",        d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
- cCE("fstmfdx",        d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
+ cCE("fldmias",        c900a00, 2, (RRnpctw, VRSLST),    vfp_sp_ldstmia),
+ cCE("fldmfds",        c900a00, 2, (RRnpctw, VRSLST),    vfp_sp_ldstmia),
+ cCE("fldmdbs",        d300a00, 2, (RRnpctw, VRSLST),    vfp_sp_ldstmdb),
+ cCE("fldmeas",        d300a00, 2, (RRnpctw, VRSLST),    vfp_sp_ldstmdb),
+ cCE("fldmiax",        c900b00, 2, (RRnpctw, VRDLST),    vfp_xp_ldstmia),
+ cCE("fldmfdx",        c900b00, 2, (RRnpctw, VRDLST),    vfp_xp_ldstmia),
+ cCE("fldmdbx",        d300b00, 2, (RRnpctw, VRDLST),    vfp_xp_ldstmdb),
+ cCE("fldmeax",        d300b00, 2, (RRnpctw, VRDLST),    vfp_xp_ldstmdb),
+ cCE("fstmias",        c800a00, 2, (RRnpctw, VRSLST),    vfp_sp_ldstmia),
+ cCE("fstmeas",        c800a00, 2, (RRnpctw, VRSLST),    vfp_sp_ldstmia),
+ cCE("fstmdbs",        d200a00, 2, (RRnpctw, VRSLST),    vfp_sp_ldstmdb),
+ cCE("fstmfds",        d200a00, 2, (RRnpctw, VRSLST),    vfp_sp_ldstmdb),
+ cCE("fstmiax",        c800b00, 2, (RRnpctw, VRDLST),    vfp_xp_ldstmia),
+ cCE("fstmeax",        c800b00, 2, (RRnpctw, VRDLST),    vfp_xp_ldstmia),
+ cCE("fstmdbx",        d200b00, 2, (RRnpctw, VRDLST),    vfp_xp_ldstmdb),
+ cCE("fstmfdx",        d200b00, 2, (RRnpctw, VRDLST),    vfp_xp_ldstmdb),
 
   /* Monadic operations.  */
  cCE("fabss",  eb00ac0, 2, (RVS, RVS),       vfp_sp_monadic),
@@ -17350,14 +17809,14 @@ static const struct asm_opcode insns[] =
     implementations.  */
  cCE("fldd",   d100b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
  cCE("fstd",   d000b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
- cCE("fldmiad",        c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
- cCE("fldmfdd",        c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
- cCE("fldmdbd",        d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
- cCE("fldmead",        d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
- cCE("fstmiad",        c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
- cCE("fstmead",        c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
- cCE("fstmdbd",        d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
- cCE("fstmfdd",        d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
+ cCE("fldmiad",        c900b00, 2, (RRnpctw, VRDLST),    vfp_dp_ldstmia),
+ cCE("fldmfdd",        c900b00, 2, (RRnpctw, VRDLST),    vfp_dp_ldstmia),
+ cCE("fldmdbd",        d300b00, 2, (RRnpctw, VRDLST),    vfp_dp_ldstmdb),
+ cCE("fldmead",        d300b00, 2, (RRnpctw, VRDLST),    vfp_dp_ldstmdb),
+ cCE("fstmiad",        c800b00, 2, (RRnpctw, VRDLST),    vfp_dp_ldstmia),
+ cCE("fstmead",        c800b00, 2, (RRnpctw, VRDLST),    vfp_dp_ldstmia),
+ cCE("fstmdbd",        d200b00, 2, (RRnpctw, VRDLST),    vfp_dp_ldstmdb),
+ cCE("fstmfdd",        d200b00, 2, (RRnpctw, VRDLST),    vfp_dp_ldstmdb),
 
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & fpu_vfp_ext_v1 /* VFP V1 (Double precision).  */
@@ -17437,12 +17896,12 @@ static const struct asm_opcode insns[] =
  NCEF(vabs,     1b10300, 2, (RNSDQ, RNSDQ), neon_abs_neg),
  NCEF(vneg,     1b10380, 2, (RNSDQ, RNSDQ), neon_abs_neg),
 
- NCE(vldm,      c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vldmia,    c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vldmdb,    d100b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vstm,      c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vstmia,    c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
- NCE(vstmdb,    d000b00, 2, (RRw, VRSDLST), neon_ldm_stm),
+ NCE(vldm,      c900b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vldmia,    c900b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vldmdb,    d100b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vstm,      c800b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vstmia,    c800b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
+ NCE(vstmdb,    d000b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm),
  NCE(vldr,      d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
  NCE(vstr,      d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
 
@@ -18409,7 +18868,8 @@ relax_adr (fragS *fragp, asection *sec, long stretch)
   /* Assume worst case for symbols not known to be in the same section.  */
   if (fragp->fr_symbol == NULL
       || !S_IS_DEFINED (fragp->fr_symbol)
-      || sec != S_GET_SEGMENT (fragp->fr_symbol))
+      || sec != S_GET_SEGMENT (fragp->fr_symbol)
+      || S_IS_WEAK (fragp->fr_symbol))
     return 4;
 
   val = relaxed_symbol_addr (fragp, stretch);
@@ -18452,7 +18912,8 @@ relax_branch (fragS *fragp, asection *sec, int bits, long stretch)
 
   /* Assume worst case for symbols not known to be in the same section.  */
   if (!S_IS_DEFINED (fragp->fr_symbol)
-      || sec != S_GET_SEGMENT (fragp->fr_symbol))
+      || sec != S_GET_SEGMENT (fragp->fr_symbol)
+      || S_IS_WEAK (fragp->fr_symbol))
     return 4;
 
 #ifdef OBJ_ELF
@@ -19663,22 +20124,23 @@ md_apply_fix (fixS *  fixP,
         not have a reloc for it, so tc_gen_reloc will reject it.  */
       fixP->fx_done = 1;
 
-      if (fixP->fx_addsy
-         && ! S_IS_DEFINED (fixP->fx_addsy))
+      if (fixP->fx_addsy)
        {
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("undefined symbol %s used as an immediate value"),
-                       S_GET_NAME (fixP->fx_addsy));
-         break;
-       }
+         const char *msg = 0;
 
-      if (fixP->fx_addsy
-         && S_GET_SEGMENT (fixP->fx_addsy) != seg)
-       {
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("symbol %s is in a different section"),
-                       S_GET_NAME (fixP->fx_addsy));
-         break;
+         if (! S_IS_DEFINED (fixP->fx_addsy))
+           msg = _("undefined symbol %s used as an immediate value");
+         else if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
+           msg = _("symbol %s is in a different section");
+         else if (S_IS_WEAK (fixP->fx_addsy))
+           msg = _("symbol %s is weak and may be overridden later");
+
+         if (msg)
+           {
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                           msg, S_GET_NAME (fixP->fx_addsy));
+             break;
+           }
        }
 
       newimm = encode_arm_immediate (value);
@@ -19704,24 +20166,25 @@ md_apply_fix (fixS *  fixP,
        unsigned int highpart = 0;
        unsigned int newinsn  = 0xe1a00000; /* nop.  */
 
-       if (fixP->fx_addsy
-           && ! S_IS_DEFINED (fixP->fx_addsy))
+       if (fixP->fx_addsy)
          {
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("undefined symbol %s used as an immediate value"),
-                         S_GET_NAME (fixP->fx_addsy));
-           break;
-         }
+           const char *msg = 0;
 
-       if (fixP->fx_addsy
-           && S_GET_SEGMENT (fixP->fx_addsy) != seg)
-         {
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("symbol %s is in a different section"),
-                         S_GET_NAME (fixP->fx_addsy));
-           break;
-         }
+           if (! S_IS_DEFINED (fixP->fx_addsy))
+             msg = _("undefined symbol %s used as an immediate value");
+           else if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
+             msg = _("symbol %s is in a different section");
+           else if (S_IS_WEAK (fixP->fx_addsy))
+             msg = _("symbol %s is weak and may be overridden later");
 
+           if (msg)
+             {
+               as_bad_where (fixP->fx_file, fixP->fx_line,
+                             msg, S_GET_NAME (fixP->fx_addsy));
+               break;
+             }
+         }
+       
        newimm = encode_arm_immediate (value);
        temp = md_chars_to_number (buf, INSN_SIZE);
 
@@ -20001,17 +20464,20 @@ md_apply_fix (fixS *  fixP,
          /* Turn add/sum into addw/subw.  */
          if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
            newval = (newval & 0xfeffffff) | 0x02000000;
-
-         /* 12 bit immediate for addw/subw.  */
-         if (value < 0)
+         /* No flat 12-bit imm encoding for addsw/subsw.  */
+         if ((newval & 0x00100000) == 0)
            {
-             value = -value;
-             newval ^= 0x00a00000;
+             /* 12 bit immediate for addw/subw.  */
+             if (value < 0)
+               {
+                 value = -value;
+                 newval ^= 0x00a00000;
+               }
+             if (value > 0xfff)
+               newimm = (unsigned int) FAIL;
+             else
+               newimm = value;
            }
-         if (value > 0xfff)
-           newimm = (unsigned int) FAIL;
-         else
-           newimm = value;
        }
 
       if (newimm == (unsigned int)FAIL)
@@ -20039,6 +20505,15 @@ md_apply_fix (fixS *   fixP,
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
+    case BFD_RELOC_ARM_HVC:
+      if (((unsigned long) value) > 0xffff)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("invalid hvc expression"));
+      newval = md_chars_to_number (buf, INSN_SIZE);
+      newval |= (value & 0xf) | ((value & 0xfff0) << 4);
+      md_number_to_chars (buf, newval, INSN_SIZE);
+      break;
+
     case BFD_RELOC_ARM_SWI:
       if (fixP->tc_fix_data != 0)
        {
@@ -20370,7 +20845,12 @@ md_apply_fix (fixS *   fixP,
       if (fixP->fx_done || !seg->use_rela_p)
        md_number_to_chars (buf, 0, 4);
       break;
-      
+
+    case BFD_RELOC_ARM_GOT_PREL:
+      if (fixP->fx_done || !seg->use_rela_p)
+        md_number_to_chars (buf, value, 4);
+      break;
+
     case BFD_RELOC_ARM_TARGET2:
       /* TARGET2 is not partial-inplace, so we need to write the
          addend here for REL targets, because it won't be written out
@@ -20955,6 +21435,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
 #ifdef OBJ_ELF
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
+    case BFD_RELOC_ARM_GOT_PREL:
     case BFD_RELOC_ARM_PLT32:
     case BFD_RELOC_ARM_TARGET1:
     case BFD_RELOC_ARM_ROSEGREL32:
@@ -21052,6 +21533,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
          case BFD_RELOC_ARM_SWI:          type = "SWI";          break;
          case BFD_RELOC_ARM_MULTI:        type = "MULTI";        break;
          case BFD_RELOC_ARM_CP_OFF_IMM:   type = "CP_OFF_IMM";   break;
+         case BFD_RELOC_ARM_T32_OFFSET_IMM: type = "T32_OFFSET_IMM"; break;
          case BFD_RELOC_ARM_T32_CP_OFF_IMM: type = "T32_CP_OFF_IMM"; break;
          case BFD_RELOC_ARM_THUMB_ADD:    type = "THUMB_ADD";    break;
          case BFD_RELOC_ARM_THUMB_SHIFT:  type = "THUMB_SHIFT";  break;
@@ -21475,6 +21957,8 @@ arm_adjust_symtab (void)
 
   /* Remove any overlapping mapping symbols generated by alignment frags.  */
   bfd_map_over_sections (stdoutput, check_mapping_symbols, (char *) 0);
+  /* Now do generic ELF adjustments.  */
+  elf_adjust_symtab ();
 #endif
 }
 
@@ -22057,24 +22541,32 @@ static const struct arm_cpu_option_table arm_cpus[] =
   {"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, NULL},
-  {"mpcorenovfp",      ARM_ARCH_V6K,    FPU_NONE,        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,    FPU_NONE,        NULL},
-  {"cortex-a8",                ARM_ARCH_V7A,    ARM_FEATURE (0, FPU_VFP_V3
+  {"cortex-a5",                ARM_ARCH_V7A_MP_SEC, 
+                                        FPU_NONE,        "Cortex-A5"},
+  {"cortex-a8",                ARM_ARCH_V7A_SEC,
+                                        ARM_FEATURE (0, FPU_VFP_V3
                                                         | FPU_NEON_EXT_V1),
-                                                          NULL},
-  {"cortex-a9",                ARM_ARCH_V7A,    ARM_FEATURE (0, FPU_VFP_V3
+                                                          "Cortex-A8"},
+  {"cortex-a9",                ARM_ARCH_V7A_MP_SEC,
+                                        ARM_FEATURE (0, FPU_VFP_V3
                                                         | FPU_NEON_EXT_V1),
-                                                          NULL},
-  {"cortex-r4",                ARM_ARCH_V7R,    FPU_NONE,        NULL},
-  {"cortex-r4f",       ARM_ARCH_V7R,    FPU_ARCH_VFP_V3D16,      NULL},
-  {"cortex-m3",                ARM_ARCH_V7M,    FPU_NONE,        NULL},
-  {"cortex-m1",                ARM_ARCH_V6M,    FPU_NONE,        NULL},
-  {"cortex-m0",                ARM_ARCH_V6M,    FPU_NONE,        NULL},
+                                                          "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-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"},
   /* ??? XSCALE is really an architecture.  */
   {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
   /* ??? iwmmxt is not a processor.  */
@@ -22124,6 +22616,7 @@ static const struct arm_arch_option_table arm_archs[] =
   {"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},
   /* The official spelling of the ARMv7 profile variants is the dashed form.
      Accept the non-dashed form for compatibility with old toolchains.  */
@@ -22140,25 +22633,45 @@ static const struct arm_arch_option_table arm_archs[] =
   {NULL,               ARM_ARCH_NONE,   ARM_ARCH_NONE}
 };
 
-/* ISA extensions in the co-processor space.  */
-struct arm_option_cpu_value_table
+/* ISA extensions in the co-processor and main instruction set space.  */
+struct arm_option_extension_value_table
 {
   char *name;
   const arm_feature_set value;
+  const arm_feature_set allowed_archs;
 };
 
-static const struct arm_option_cpu_value_table arm_extensions[] =
+/* The following table must be in alphabetical order with a NULL last entry.
+   */
+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, 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}
+};
+
+/* ISA floating-point and Advanced SIMD extensions.  */
+struct arm_option_fpu_value_table
 {
-  {"maverick",         ARM_FEATURE (0, ARM_CEXT_MAVERICK)},
-  {"xscale",           ARM_FEATURE (0, ARM_CEXT_XSCALE)},
-  {"iwmmxt",           ARM_FEATURE (0, ARM_CEXT_IWMMXT)},
-  {"iwmmxt2",          ARM_FEATURE (0, ARM_CEXT_IWMMXT2)},
-  {NULL,               ARM_ARCH_NONE}
+  char *name;
+  const arm_feature_set value;
 };
 
 /* This list should, at a minimum, contain all the fpu names
    recognized by GCC.  */
-static const struct arm_option_cpu_value_table arm_fpus[] =
+static const struct arm_option_fpu_value_table arm_fpus[] =
 {
   {"softfpa",          FPU_NONE},
   {"fpe",              FPU_ARCH_FPE},
@@ -22236,15 +22749,23 @@ 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 
+     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 
+     -1 -> 1 -> 0.  */
+  const struct arm_option_extension_value_table * opt = NULL;
+  int adding_value = -1;
+
   /* Copy the feature set, so that we can modify it.  */
   *ext_set = **opt_p;
   *opt_p = ext_set;
 
   while (str != NULL && *str != 0)
     {
-      const struct arm_option_cpu_value_table * opt;
       char * ext;
-      int optlen;
+      size_t optlen;
 
       if (*str != '+')
        {
@@ -22260,24 +22781,86 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
       else
        optlen = strlen (str);
 
+      if (optlen >= 2
+         && strncmp (str, "no", 2) == 0)
+       {
+         if (adding_value != 0)
+           {
+             adding_value = 0;
+             opt = arm_extensions;
+           }
+
+         optlen -= 2;
+         str += 2;
+       }
+      else if (optlen > 0)
+       {
+         if (adding_value == -1)
+           {
+             adding_value = 1;
+             opt = arm_extensions;
+           }
+         else if (adding_value != 1)
+           {
+             as_bad (_("must specify extensions to add before specifying "
+                       "those to remove"));
+             return FALSE;
+           }
+       }
+
       if (optlen == 0)
        {
          as_bad (_("missing architectural extension"));
          return FALSE;
        }
 
-      for (opt = arm_extensions; opt->name != NULL; opt++)
-       if (strncmp (opt->name, str, optlen) == 0)
+      gas_assert (adding_value != -1);
+      gas_assert (opt != NULL);
+
+      /* 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)
          {
-           ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
+           /* Check we can apply the extension to this architecture.  */
+           if (!ARM_CPU_HAS_FEATURE (*ext_set, opt->allowed_archs))
+             {
+               as_bad (_("extension does not apply to the base architecture"));
+               return FALSE;
+             }
+
+           /* Add or remove the extension.  */
+           if (adding_value)
+             ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
+           else
+             ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->value);
+
            break;
          }
 
       if (opt->name == NULL)
        {
-         as_bad (_("unknown architectural extension `%s'"), str);
+         /* Did we fail to find an extension because it wasn't specified in
+            alphabetical order, or because it does not exist?  */
+
+         for (opt = arm_extensions; opt->name != NULL; opt++)
+           if (strncmp (opt->name, str, optlen) == 0)
+             break;
+
+         if (opt->name == NULL)
+           as_bad (_("unknown architectural extension `%s'"), str);
+         else
+           as_bad (_("architectural extensions must be specified in "
+                     "alphabetical order"));
+
          return FALSE;
        }
+      else
+       {
+         /* We should skip the extension we've just matched the next time
+            round.  */
+         opt++;
+       }
 
       str = ext;
     };
@@ -22348,7 +22931,7 @@ arm_parse_arch (char * str)
     }
 
   for (opt = arm_archs; opt->name != NULL; opt++)
-    if (streq (opt->name, str))
+    if (strncmp (opt->name, str, optlen) == 0)
       {
        march_cpu_opt = &opt->value;
        march_fpu_opt = &opt->default_fpu;
@@ -22367,7 +22950,7 @@ arm_parse_arch (char * str)
 static bfd_boolean
 arm_parse_fpu (char * str)
 {
-  const struct arm_option_cpu_value_table * opt;
+  const struct arm_option_fpu_value_table * opt;
 
   for (opt = arm_fpus; opt->name != NULL; opt++)
     if (streq (opt->name, str))
@@ -22595,9 +23178,10 @@ static const cpu_arch_ver_table cpu_arch_ver[] =
     {4, ARM_ARCH_V5TE},
     {5, ARM_ARCH_V5TEJ},
     {6, ARM_ARCH_V6},
-    {7, ARM_ARCH_V6Z},
     {9, ARM_ARCH_V6K},
+    {7, ARM_ARCH_V6Z},
     {11, ARM_ARCH_V6M},
+    {12, ARM_ARCH_V6SM},
     {8, ARM_ARCH_V6T2},
     {10, ARM_ARCH_V7A},
     {10, ARM_ARCH_V7R},
@@ -22629,6 +23213,7 @@ static void
 aeabi_set_public_attributes (void)
 {
   int arch;
+  int virt_sec = 0;
   arm_feature_set flags;
   arm_feature_set tmp;
   const cpu_arch_ver_table *p;
@@ -22724,6 +23309,11 @@ aeabi_set_public_attributes (void)
            || ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1xd))
     aeabi_set_attribute_int (Tag_VFP_arch, 1);
 
+  /* Tag_ABI_HardFP_use.  */
+  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1xd)
+      && !ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1))
+    aeabi_set_attribute_int (Tag_ABI_HardFP_use, 1);
+
   /* Tag_WMMX_arch.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_cext_iwmmxt2))
     aeabi_set_attribute_int (Tag_WMMX_arch, 2);
@@ -22739,6 +23329,26 @@ aeabi_set_public_attributes (void)
   /* Tag_VFP_HP_extension (formerly Tag_NEON_FP16_arch).  */
   if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16))
     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))
+    aeabi_set_attribute_int (Tag_DIV_use, 0);
+  else
+    aeabi_set_attribute_int (Tag_DIV_use, 1);
+
+  /* Tag_MP_extension_use.  */
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_mp))
+    aeabi_set_attribute_int (Tag_MPextension_use, 1);
+
+  /* Tag Virtualization_use.  */
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_sec))
+    virt_sec |= 1;
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_virt))
+    virt_sec |= 2;
+  if (virt_sec != 0)
+    aeabi_set_attribute_int (Tag_Virtualization_use, virt_sec);
 }
 
 /* Add the default contents for the .ARM.attributes section.  */
@@ -22858,12 +23468,64 @@ s_arm_object_arch (int ignored ATTRIBUTE_UNUSED)
   ignore_rest_of_line ();
 }
 
+/* Parse a .arch_extension directive.  */
+
+static void
+s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
+{
+  const struct arm_option_extension_value_table *opt;
+  char saved_char;
+  char *name;
+  int adding_value = 1;
+
+  name = input_line_pointer;
+  while (*input_line_pointer && !ISSPACE (*input_line_pointer))
+    input_line_pointer++;
+  saved_char = *input_line_pointer;
+  *input_line_pointer = 0;
+
+  if (strlen (name) >= 2
+      && strncmp (name, "no", 2) == 0)
+    {
+      adding_value = 0;
+      name += 2;
+    }
+
+  for (opt = arm_extensions; opt->name != NULL; opt++)
+    if (streq (opt->name, name))
+      {
+       if (!ARM_CPU_HAS_FEATURE (*mcpu_cpu_opt, opt->allowed_archs))
+         {
+           as_bad (_("architectural extension `%s' is not allowed for the "
+                     "current base architecture"), name);
+           break;
+         }
+
+       if (adding_value)
+         ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu, opt->value);
+       else
+         ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->value);
+
+       mcpu_cpu_opt = &selected_cpu;
+       ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+       *input_line_pointer = saved_char;
+       demand_empty_rest_of_line ();
+       return;
+      }
+
+  if (opt->name == NULL)
+    as_bad (_("unknown architecture `%s'\n"), name);
+
+  *input_line_pointer = saved_char;
+  ignore_rest_of_line ();
+}
+
 /* Parse a .fpu directive.  */
 
 static void
 s_arm_fpu (int ignored ATTRIBUTE_UNUSED)
 {
-  const struct arm_option_cpu_value_table *opt;
+  const struct arm_option_fpu_value_table *opt;
   char saved_char;
   char *name;
 
@@ -22919,6 +23581,7 @@ arm_convert_symbolic_attribute (const char *name)
       T (Tag_CPU_arch_profile),
       T (Tag_ARM_ISA_use),
       T (Tag_THUMB_ISA_use),
+      T (Tag_FP_arch),
       T (Tag_VFP_arch),
       T (Tag_WMMX_arch),
       T (Tag_Advanced_SIMD_arch),
@@ -22933,7 +23596,9 @@ arm_convert_symbolic_attribute (const char *name)
       T (Tag_ABI_FP_exceptions),
       T (Tag_ABI_FP_user_exceptions),
       T (Tag_ABI_FP_number_model),
+      T (Tag_ABI_align_needed),
       T (Tag_ABI_align8_needed),
+      T (Tag_ABI_align_preserved),
       T (Tag_ABI_align8_preserved),
       T (Tag_ABI_enum_size),
       T (Tag_ABI_HardFP_use),
@@ -22943,14 +23608,17 @@ arm_convert_symbolic_attribute (const char *name)
       T (Tag_ABI_FP_optimization_goals),
       T (Tag_compatibility),
       T (Tag_CPU_unaligned_access),
+      T (Tag_FP_HP_extension),
       T (Tag_VFP_HP_extension),
       T (Tag_ABI_FP_16bit_format),
+      T (Tag_MPextension_use),
+      T (Tag_DIV_use),
       T (Tag_nodefaults),
       T (Tag_also_compatible_with),
       T (Tag_conformance),
       T (Tag_T2EE_use),
       T (Tag_Virtualization_use),
-      T (Tag_MPextension_use)
+      /* We deliberately do not include Tag_MPextension_use_legacy.  */
 #undef T
     };
   unsigned int i;
This page took 0.062442 seconds and 4 git commands to generate.