gas/
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index a9839cd93425fe168d01297c1b477432968cd279..ae70f69501d937fd348d0355b699dbfb1b4c5d56 100644 (file)
@@ -2589,7 +2589,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)
@@ -5200,8 +5217,24 @@ parse_address_main (char **str, int i, int group_relocations,
                }
             }
           else
-           if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
-             return PARSE_OPERAND_FAIL;
+           {
+             char *q = p;
+             if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+               return PARSE_OPERAND_FAIL;
+             /* If the offset is 0, find out if it's a +0 or -0.  */
+             if (inst.reloc.exp.X_op == O_constant
+                 && inst.reloc.exp.X_add_number == 0)
+               {
+                 skip_whitespace (q);
+                 if (*q == '#')
+                   {
+                     q++;
+                     skip_whitespace (q);
+                   }
+                 if (*q == '-')
+                   inst.operands[i].negative = 1;
+               }
+           }
        }
     }
   else if (skip_past_char (&p, ':') == SUCCESS)
@@ -5275,6 +5308,7 @@ parse_address_main (char **str, int i, int group_relocations,
            }
          else
            {
+             char *q = p;
              if (inst.operands[i].negative)
                {
                  inst.operands[i].negative = 0;
@@ -5282,6 +5316,19 @@ parse_address_main (char **str, int i, int group_relocations,
                }
              if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
                return PARSE_OPERAND_FAIL;
+             /* If the offset is 0, find out if it's a +0 or -0.  */
+             if (inst.reloc.exp.X_op == O_constant
+                 && inst.reloc.exp.X_add_number == 0)
+               {
+                 skip_whitespace (q);
+                 if (*q == '#')
+                   {
+                     q++;
+                     skip_whitespace (q);
+                   }
+                 if (*q == '-')
+                   inst.operands[i].negative = 1;
+               }
            }
        }
     }
@@ -5365,6 +5412,12 @@ parse_psr (char **str, bfd_boolean lhs)
   bfd_boolean is_apsr = FALSE;
   bfd_boolean m_profile = ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m);
 
+  /* PR gas/12698:  If the user has specified -march=all then m_profile will
+     be TRUE, but we want to ignore it in this case as we are building for any
+     CPU type, including non-m variants.  */
+  if (selected_cpu.core == arm_arch_any.core)
+    m_profile = FALSE;
+
   /* CPSR's and SPSR's can now be lowercase.  This is just a convenience
      feature for ease of use and backwards compatibility.  */
   p = *str;
@@ -6082,6 +6135,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 */
 
@@ -6411,6 +6465,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 */
@@ -7038,7 +7093,12 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t)
        }
 
       if (inst.reloc.type == BFD_RELOC_UNUSED)
-       inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+       {
+         /* Prefer + for zero encoded value.  */
+         if (!inst.operands[i].negative)
+           inst.instruction |= INDEX_UP;
+         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+       }
     }
 }
 
@@ -7074,7 +7134,13 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t)
                  BAD_PC_WRITEBACK);
       inst.instruction |= HWOFFSET_IMM;
       if (inst.reloc.type == BFD_RELOC_UNUSED)
-       inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
+       {
+         /* Prefer + for zero encoded value.  */
+         if (!inst.operands[i].negative)
+           inst.instruction |= INDEX_UP;
+
+         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
+       }
     }
 }
 
@@ -7136,6 +7202,10 @@ encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
         inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
     }
 
+  /* Prefer + for zero encoded value.  */
+  if (!inst.operands[i].negative)
+    inst.instruction |= INDEX_UP;
+
   return SUCCESS;
 }
 
@@ -7747,35 +7817,34 @@ static void
 do_ldrd (void)
 {
   constraint (inst.operands[0].reg % 2 != 0,
-             _("first destination register must be even"));
+             _("first transfer register must be even"));
   constraint (inst.operands[1].present
              && inst.operands[1].reg != inst.operands[0].reg + 1,
-             _("can only load two consecutive registers"));
+             _("can only transfer two consecutive registers"));
   constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
   constraint (!inst.operands[2].isreg, _("'[' expected"));
 
   if (!inst.operands[1].present)
     inst.operands[1].reg = inst.operands[0].reg + 1;
 
-  if (inst.instruction & LOAD_BIT)
-    {
-      /* encode_arm_addr_mode_3 will diagnose overlap between the base
-        register and the first register written; we have to diagnose
-        overlap between the base and the second register written here.  */
+  /* encode_arm_addr_mode_3 will diagnose overlap between the base
+     register and the first register written; we have to diagnose
+     overlap between the base and the second register written here.  */
 
-      if (inst.operands[2].reg == inst.operands[1].reg
-         && (inst.operands[2].writeback || inst.operands[2].postind))
-       as_warn (_("base register written back, and overlaps "
-                  "second destination register"));
+  if (inst.operands[2].reg == inst.operands[1].reg
+      && (inst.operands[2].writeback || inst.operands[2].postind))
+    as_warn (_("base register written back, and overlaps "
+              "second transfer register"));
 
+  if (!(inst.instruction & V4_STR_BIT))
+    {
       /* For an index-register load, the index register must not overlap the
-        destination (even if not write-back).  */
-      else if (inst.operands[2].immisreg
-              && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
-                  || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
-       as_warn (_("index register overlaps destination register"));
+       destination (even if not write-back).  */
+      if (inst.operands[2].immisreg
+             && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
+             || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
+       as_warn (_("index register overlaps transfer register"));
     }
-
   inst.instruction |= inst.operands[0].reg << 12;
   encode_arm_addr_mode_3 (2, /*is_t=*/FALSE);
 }
@@ -8293,6 +8362,9 @@ do_shift (void)
     {
       inst.instruction |= inst.operands[2].reg << 8;
       inst.instruction |= SHIFT_BY_REG;
+      /* PR 12854: Error on extraneous shifts.  */
+      constraint (inst.operands[2].shifted,
+                 _("extraneous shift as part of operand to shift insn"));
     }
   else
     inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
@@ -8683,7 +8755,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);
 }
@@ -9845,7 +9933,9 @@ do_t_branch (void)
 
   if (unified_syntax
       && (inst.size_req == 4
-         || (inst.size_req != 2 && inst.operands[0].hasreloc)))
+         || (inst.size_req != 2
+             && (inst.operands[0].hasreloc
+                 || inst.reloc.exp.X_op == O_constant))))
     {
       inst.instruction = THUMB_OP32(opcode);
       if (cond == COND_ALWAYS)
@@ -11483,6 +11573,10 @@ do_t_shift (void)
              inst.instruction |= inst.operands[0].reg << 8;
              inst.instruction |= inst.operands[1].reg << 16;
              inst.instruction |= inst.operands[2].reg;
+
+             /* PR 12854: Error on extraneous shifts.  */
+             constraint (inst.operands[2].shifted,
+                         _("extraneous shift as part of operand to shift insn"));
            }
          else
            {
@@ -11511,6 +11605,10 @@ do_t_shift (void)
 
              inst.instruction |= inst.operands[0].reg;
              inst.instruction |= inst.operands[2].reg << 3;
+
+             /* PR 12854: Error on extraneous shifts.  */
+             constraint (inst.operands[2].shifted,
+                         _("extraneous shift as part of operand to shift insn"));
            }
          else
            {
@@ -11550,6 +11648,10 @@ do_t_shift (void)
 
          inst.instruction |= inst.operands[0].reg;
          inst.instruction |= inst.operands[2].reg << 3;
+
+         /* PR 12854: Error on extraneous shifts.  */
+         constraint (inst.operands[2].shifted,
+                     _("extraneous shift as part of operand to shift insn"));
        }
       else
        {
@@ -15434,6 +15536,29 @@ fix_new_arm (fragS *      frag,
   switch (exp->X_op)
     {
     case O_constant:
+      if (pc_rel)
+       {
+         /* Create an absolute valued symbol, so we have something to
+             refer to in the object file.  Unfortunately for us, gas's
+             generic expression parsing will already have folded out
+             any use of .set foo/.type foo %function that may have
+             been used to set type information of the target location,
+             that's being specified symbolically.  We have to presume
+             the user knows what they are doing.  */
+         char name[16 + 8];
+         symbolS *symbol;
+
+         sprintf (name, "*ABS*0x%lx", (unsigned long)exp->X_add_number);
+
+         symbol = symbol_find_or_make (name);
+         S_SET_SEGMENT (symbol, absolute_section);
+         symbol_set_frag (symbol, &zero_address_frag);
+         S_SET_VALUE (symbol, exp->X_add_number);
+         exp->X_op = O_symbol;
+         exp->X_add_symbol = symbol;
+         exp->X_add_number = 0;
+       }
+      /* FALLTHROUGH */
     case O_symbol:
     case O_add:
     case O_subtract:
@@ -18087,7 +18212,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),
@@ -20422,7 +20547,7 @@ md_apply_fix (fixS *    fixP,
        value = 0;
 
     case BFD_RELOC_ARM_LITERAL:
-      sign = value >= 0;
+      sign = value > 0;
 
       if (value < 0)
        value = - value;
@@ -20440,14 +20565,19 @@ md_apply_fix (fixS *  fixP,
        }
 
       newval = md_chars_to_number (buf, INSN_SIZE);
-      newval &= 0xff7ff000;
-      newval |= value | (sign ? INDEX_UP : 0);
+      if (value == 0)
+       newval &= 0xfffff000;
+      else
+       {
+         newval &= 0xff7ff000;
+         newval |= value | (sign ? INDEX_UP : 0);
+       }
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_OFFSET_IMM8:
     case BFD_RELOC_ARM_HWLITERAL:
-      sign = value >= 0;
+      sign = value > 0;
 
       if (value < 0)
        value = - value;
@@ -20464,8 +20594,13 @@ md_apply_fix (fixS *   fixP,
        }
 
       newval = md_chars_to_number (buf, INSN_SIZE);
-      newval &= 0xff7ff0f0;
-      newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
+      if (value == 0)
+       newval &= 0xfffff0f0;
+      else
+       {
+         newval &= 0xff7ff0f0;
+         newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
+       }
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
@@ -21092,7 +21227,7 @@ md_apply_fix (fixS *    fixP,
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("co-processor offset out of range"));
     cp_off_common:
-      sign = value >= 0;
+      sign = value > 0;
       if (value < 0)
        value = -value;
       if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
@@ -21100,8 +21235,13 @@ md_apply_fix (fixS *   fixP,
        newval = md_chars_to_number (buf, INSN_SIZE);
       else
        newval = get_thumb32_insn (buf);
-      newval &= 0xff7fff00;
-      newval |= (value >> 2) | (sign ? INDEX_UP : 0);
+      if (value == 0)
+       newval &= 0xffffff00;
+      else
+       {
+         newval &= 0xff7fff00;
+         newval |= (value >> 2) | (sign ? INDEX_UP : 0);
+       }
       if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
          || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
        md_number_to_chars (buf, newval, INSN_SIZE);
@@ -21870,14 +22010,25 @@ arm_force_relocation (struct fix * fixp)
     }
 #endif
 
-  /* Resolve these relocations even if the symbol is extern or weak.  */
+  /* Resolve these relocations even if the symbol is extern or weak.
+     Technically this is probably wrong due to symbol preemption.
+     In practice these relocations do not have enough range to be useful
+     at dynamic link time, and some code (e.g. in the Linux kernel)
+     expects these references to be resolved.  */
   if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
       || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM8
       || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE
+      || fixp->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2
+      || fixp->fx_r_type == BFD_RELOC_ARM_THUMB_OFFSET
       || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM
       || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
       || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMM12
-      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12)
+      || fixp->fx_r_type == BFD_RELOC_ARM_T32_OFFSET_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12
+      || fixp->fx_r_type == BFD_RELOC_ARM_T32_CP_OFF_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_T32_CP_OFF_IMM_S2)
     return 0;
 
   /* Always leave these relocations for the linker.  */
@@ -22769,6 +22920,8 @@ static const struct arm_cpu_option_table arm_cpus[] =
   {"cortex-r4",                ARM_ARCH_V7R,    FPU_NONE,        "Cortex-R4"},
   {"cortex-r4f",       ARM_ARCH_V7R,    FPU_ARCH_VFP_V3D16,
                                                          "Cortex-R4F"},
+  {"cortex-r5",                ARM_ARCH_V7R_IDIV,
+                                        FPU_NONE,        "Cortex-R5"},
   {"cortex-m4",                ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M4"},
   {"cortex-m3",                ARM_ARCH_V7M,    FPU_NONE,        "Cortex-M3"},
   {"cortex-m1",                ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M1"},
@@ -22852,7 +23005,7 @@ struct arm_option_extension_value_table
 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)},
+                                  ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)},
   {"iwmmxt",   ARM_FEATURE (0, ARM_CEXT_IWMMXT),       ARM_ANY},
   {"iwmmxt2",  ARM_FEATURE (0, ARM_CEXT_IWMMXT2),      ARM_ANY},
   {"maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK),     ARM_ANY},
This page took 0.039612 seconds and 4 git commands to generate.