* config/tc-arm.c (do_t_strexbh): New.
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index bf329d6831df058ca60cc99e9b001a563170cc7b..77606a3bb6282bdf9f8140076919bd3a1b9ddb11 100644 (file)
@@ -724,6 +724,7 @@ struct asm_opcode
        _("cannot use register index with PC-relative addressing")
 #define BAD_PC_WRITEBACK \
        _("cannot use writeback with PC-relative addressing")
+#define BAD_RANGE     _("branch out of range")
 
 static struct hash_control * arm_ops_hsh;
 static struct hash_control * arm_cond_hsh;
@@ -758,6 +759,9 @@ typedef struct literal_pool
   symbolS *             symbol;
   segT                  section;
   subsegT               sub_section;
+#ifdef OBJ_ELF
+  struct dwarf2_line_info locs [MAX_LITERAL_POOL_SIZE];
+#endif
   struct literal_pool *  next;
 } literal_pool;
 
@@ -2589,7 +2593,24 @@ mapping_state (enum mstate state)
     /* The mapping symbol has already been emitted.
        There is nothing else to do.  */
     return;
-  else if (TRANSITION (MAP_UNDEFINED, MAP_DATA))
+
+  if (state == MAP_ARM || state == MAP_THUMB)
+    /*  PR gas/12931
+       All ARM instructions require 4-byte alignment.
+       (Almost) all Thumb instructions require 2-byte alignment.
+
+       When emitting instructions into any section, mark the section
+       appropriately.
+
+       Some Thumb instructions are alignment-sensitive modulo 4 bytes,
+       but themselves require 2-byte alignment; this applies to some
+       PC- relative forms.  However, these cases will invovle implicit
+       literal pool generation or an explicit .align >=2, both of
+       which will cause the section to me marked with sufficient
+       alignment.  Thus, we don't handle those cases here.  */
+    record_alignment (now_seg, state == MAP_ARM ? 2 : 1);
+
+  if (TRANSITION (MAP_UNDEFINED, MAP_DATA))
     /* This case will be evaluated later in the next else.  */
     return;
   else if (TRANSITION (MAP_UNDEFINED, MAP_ARM)
@@ -3056,6 +3077,14 @@ add_to_lit_pool (void)
        }
 
       pool->literals[entry] = inst.reloc.exp;
+#ifdef OBJ_ELF
+      /* PR ld/12974: Record the location of the first source line to reference
+        this entry in the literal pool.  If it turns out during linking that the
+        symbol does not exist we will be able to give an accurate line number for
+        the (first use of the) missing reference.  */
+      if (debug_type == DEBUG_DWARF2)
+       dwarf2_where (pool->locs + entry);
+#endif
       pool->next_free_entry += 1;
     }
 
@@ -3153,8 +3182,14 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED)
 #endif
 
   for (entry = 0; entry < pool->next_free_entry; entry ++)
-    /* First output the expression in the instruction to the pool.  */
-    emit_expr (&(pool->literals[entry]), 4); /* .word  */
+    {
+#ifdef OBJ_ELF
+      if (debug_type == DEBUG_DWARF2)
+       dwarf2_gen_line_info (frag_now_fix (), pool->locs + entry);
+#endif
+      /* First output the expression in the instruction to the pool.  */
+      emit_expr (&(pool->literals[entry]), 4); /* .word  */
+    }
 
   /* Mark the pool as empty.  */
   pool->next_free_entry = 0;
@@ -6118,6 +6153,7 @@ enum operand_parse_code
   OP_oI7b,      /* immediate, prefix optional, 0 .. 7 */
   OP_oI31b,     /*                             0 .. 31 */
   OP_oI32b,      /*                             1 .. 32 */
+  OP_oI32z,      /*                             0 .. 32 */
   OP_oIffffb,   /*                             0 .. 65535 */
   OP_oI255c,    /*       curly-brace enclosed, 0 .. 255 */
 
@@ -6447,6 +6483,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_oI31b:
        case OP_I31b:    po_imm_or_fail (  0,     31, TRUE);    break;
         case OP_oI32b:   po_imm_or_fail (  1,     32, TRUE);    break;
+        case OP_oI32z:   po_imm_or_fail (  0,     32, TRUE);    break;
        case OP_oIffffb: po_imm_or_fail (  0, 0xffff, TRUE);    break;
 
          /* Immediate variants */
@@ -8463,6 +8500,21 @@ do_strex (void)
   inst.reloc.type = BFD_RELOC_UNUSED;
 }
 
+static void
+do_t_strexbh (void)
+{
+  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
+             || inst.operands[2].postind || inst.operands[2].writeback
+             || inst.operands[2].immisreg || inst.operands[2].shifted
+             || inst.operands[2].negative,
+             BAD_ADDR_MODE);
+
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
+
+  do_rm_rd_rn ();
+}
+
 static void
 do_strexd (void)
 {
@@ -8736,7 +8788,23 @@ do_vfp_dp_const (void)
 static void
 vfp_conv (int srcsize)
 {
-  unsigned immbits = srcsize - inst.operands[1].imm;
+  int immbits = srcsize - inst.operands[1].imm;
+
+  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)) 
+    {
+      /* If srcsize is 32, inst.operands[1].imm must be in the range 1-32.
+         i.e. immbits must be in range 0 - 31.  */
+      inst.error = _("immediate value out of range, expected range [1, 32]");
+      return;
+    }
+
   inst.instruction |= (immbits & 1) << 5;
   inst.instruction |= (immbits >> 1);
 }
@@ -9438,6 +9506,9 @@ do_t_add_sub (void)
        }
       else
        {
+         unsigned int value = inst.reloc.exp.X_add_number;
+         unsigned int shift = inst.operands[2].shift_kind;
+
          Rn = inst.operands[2].reg;
          /* See if we can do this with a 16-bit instruction.  */
          if (!inst.operands[2].shifted && inst.size_req != 4)
@@ -9488,6 +9559,10 @@ do_t_add_sub (void)
          inst.instruction = THUMB_OP32 (inst.instruction);
          inst.instruction |= Rd << 8;
          inst.instruction |= Rs << 16;
+         constraint (Rd == REG_SP && Rs == REG_SP && value > 3,
+                     _("shift value over 3 not allowed in thumb mode"));
+         constraint (Rd == REG_SP && Rs == REG_SP && shift != SHIFT_LSL,
+                     _("only LSL shift allowed in thumb mode"));
          encode_thumb32_shifted_operand (2);
        }
     }
@@ -17456,9 +17531,9 @@ static const struct asm_opcode insns[] =
  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),
+     strex, t_strexbh),
  TCE("strexh", 1e00f90, e8c00f50, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
-     strex, rm_rd_rn), 
+     strex, t_strexbh),
  TUF("clrex",  57ff01f, f3bf8f2f, 0, (),                             noargs, noargs),
 
 #undef  ARM_VARIANT
@@ -18177,7 +18252,7 @@ static const struct asm_opcode insns[] =
  NCE(vldr,      d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
  NCE(vstr,      d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
 
- nCEF(vcvt,     _vcvt,   3, (RNSDQ, RNSDQ, oI32b), neon_cvt),
+ nCEF(vcvt,     _vcvt,   3, (RNSDQ, RNSDQ, oI32z), neon_cvt),
  nCEF(vcvtr,    _vcvt,   2, (RNSDQ, RNSDQ), neon_cvtr),
  nCEF(vcvtb,   _vcvt,   2, (RVS, RVS), neon_cvtb),
  nCEF(vcvtt,   _vcvt,   2, (RVS, RVS), neon_cvtt),
@@ -20909,8 +20984,7 @@ md_apply_fix (fixS *    fixP,
                      _("misaligned branch destination"));
       if ((value & (offsetT)0xfe000000) != (offsetT)0
          && (value & (offsetT)0xfe000000) != (offsetT)0xfe000000)
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+       as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
       if (fixP->fx_done || !seg->use_rela_p)
        {
@@ -20946,8 +21020,7 @@ md_apply_fix (fixS *    fixP,
       else
        {
          if (value & ~0x7e)
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("branch out of range"));
+           as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
           if (fixP->fx_done || !seg->use_rela_p)
            {
@@ -20960,8 +21033,7 @@ md_apply_fix (fixS *    fixP,
 
     case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
       if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+       as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
       if (fixP->fx_done || !seg->use_rela_p)
        {
@@ -20973,8 +21045,7 @@ md_apply_fix (fixS *    fixP,
 
     case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch.  */
       if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+       as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
       if (fixP->fx_done || !seg->use_rela_p)
        {
@@ -20994,7 +21065,7 @@ md_apply_fix (fixS *    fixP,
          /* Force a relocation for a branch 20 bits wide.  */
          fixP->fx_done = 0;
        }
-      if ((value & ~0x1fffff) && ((value & ~0x1fffff) != ~0x1fffff))
+      if ((value & ~0x1fffff) && ((value & ~0x0fffff) != ~0x0fffff))
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("conditional branch out of range"));
 
@@ -21019,7 +21090,6 @@ md_apply_fix (fixS *    fixP,
       break;
 
     case BFD_RELOC_THUMB_PCREL_BLX:
-
       /* If there is a blx from a thumb state function to
         another thumb function flip this to a bl and warn
         about it.  */
@@ -21044,7 +21114,6 @@ md_apply_fix (fixS *    fixP,
       goto thumb_bl_common;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
-
       /* A bl from Thumb state ISA to an internal ARM state function
         is converted to a blx.  */
       if (fixP->fx_addsy
@@ -21075,21 +21144,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,
-                           _("branch out of range"));
-           }
-         else if ((value & ~0x1ffffff)
-                  && ((value & ~0x1ffffff) != ~0x1ffffff))
-             {
-               as_bad_where (fixP->fx_file, fixP->fx_line,
-                           _("Thumb2 branch out of range"));
-             }
-       }
+        {
+          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);
@@ -21097,9 +21160,8 @@ md_apply_fix (fixS *    fixP,
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH25:
-      if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+      if ((value & ~0x0ffffff) && ((value & ~0x0ffffff) != ~0x0ffffff))
+       as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
       if (fixP->fx_done || !seg->use_rela_p)
          encode_thumb2_b_bl_offset (buf, value);
This page took 0.03515 seconds and 4 git commands to generate.