import gdb-2000-02-02 snapshot
[external/binutils.git] / gas / config / tc-arm.c
index d842941..86e3600 100644 (file)
@@ -52,6 +52,7 @@
 #define ARM_HALFWORD    0x00000020     /* allow half word loads */
 #define ARM_THUMB       0x00000040     /* allow BX instruction  */
 #define ARM_EXT_V5     0x00000080      /* allow CLZ etc         */
+#define ARM_EXT_V5E     0x00000200     /* "El Segundo"          */
 
 /* Architectures are the sum of the base and extensions */
 #define ARM_ARCH_V4    (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
@@ -138,10 +139,11 @@ CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 symbolS * GOT_symbol;          /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 #endif
 
-CONST int md_reloc_size = 8;           /* Size of relocation record */
-
-static int thumb_mode = 0;      /* non-zero if assembling thumb instructions */
+CONST int md_reloc_size = 8;   /* Size of relocation record */
 
+static int thumb_mode = 0;      /* 0: assemble for ARM, 1: assemble for Thumb,
+                                  2: assemble for Thumb even though target cpu
+                                  does not support thumb instructions */
 typedef struct arm_fix
 {
   int thumb_mode;
@@ -439,6 +441,7 @@ static void do_mrs          PARAMS ((char *, unsigned long));
 static void do_mull            PARAMS ((char *, unsigned long));
 /* ARM THUMB */                                                      
 static void do_bx               PARAMS ((char *, unsigned long));
+
                                                              
 /* Coprocessor Instructions */                               
 static void do_cdp             PARAMS ((char *, unsigned long));
@@ -504,11 +507,16 @@ static bfd_reloc_code_real_type   arm_parse_reloc PARAMS ((void));
 
 #define LONGEST_INST 5
 
+
 struct asm_opcode 
 {
   CONST char *           template;     /* Basic string to match */
   unsigned long          value;                /* Basic instruction code */
-  CONST char *           comp_suffix;  /* Compulsory suffix that must follow conds */
+
+  /* Compulsory suffix that must follow conds. If "", then the
+     instruction is not conditional and must have no suffix. */
+  CONST char *           comp_suffix;  
+
   CONST struct asm_flg * flags;                /* Bits to toggle if flag 'n' set */
   unsigned long          variants;     /* Which CPU variants this exists for */
   /* Function to call to parse args */
@@ -849,20 +857,22 @@ struct reg_entry
 #define REG_LR  14
 #define REG_SP  13
 
-/* These are the standard names;  Users can add aliases with .req */
+/* These are the standard names.  Users can add aliases with .req */
 static CONST struct reg_entry reg_table[] =
 {
-  /* Processor Register Numbers */
+  /* Processor Register Numbers */
   {"r0", 0},    {"r1", 1},      {"r2", 2},      {"r3", 3},
   {"r4", 4},    {"r5", 5},      {"r6", 6},      {"r7", 7},
   {"r8", 8},    {"r9", 9},      {"r10", 10},    {"r11", 11},
   {"r12", 12},  {"r13", REG_SP},{"r14", REG_LR},{"r15", REG_PC},
-  /* APCS conventions */
+  /* APCS conventions */
   {"a1", 0},   {"a2", 1},    {"a3", 2},     {"a4", 3},
   {"v1", 4},   {"v2", 5},    {"v3", 6},     {"v4", 7},     {"v5", 8},
   {"v6", 9},   {"sb", 9},    {"v7", 10},    {"sl", 10},
   {"fp", 11},  {"ip", 12},   {"sp", REG_SP},{"lr", REG_LR},{"pc", REG_PC},
-  /* FP Registers */
+  /* ATPCS additions to APCS conventions.  */
+  {"wr", 7},    {"v8", 11},
+  /* FP Registers.  */
   {"f0", 16},   {"f1", 17},   {"f2", 18},   {"f3", 19},
   {"f4", 20},   {"f5", 21},   {"f6", 22},   {"f7", 23},
   {"c0", 32},   {"c1", 33},   {"c2", 34},   {"c3", 35},
@@ -873,11 +883,20 @@ static CONST struct reg_entry reg_table[] =
   {"cr4", 36},  {"cr5", 37},  {"cr6", 38},  {"cr7", 39},
   {"cr8", 40},  {"cr9", 41},  {"cr10", 42}, {"cr11", 43},
   {"cr12", 44}, {"cr13", 45}, {"cr14", 46}, {"cr15", 47},
+  /* ATPCS additions to float register names.  */
+  {"s0",16},   {"s1",17},      {"s2",18},      {"s3",19},
+  {"s4",20},   {"s5",21},      {"s6",22},      {"s7",23},
+  {"d0",16},   {"d1",17},      {"d2",18},      {"d3",19},
+  {"d4",20},   {"d5",21},      {"d6",22},      {"d7",23},
+  /* FIXME: At some point we need to add VFP register names.  */
+  /* Array terminator.  */
   {NULL, 0}
 };
 
-#define BAD_ARGS       _("Bad arguments to instruction");
-#define BAD_PC                 _("r15 not allowed here");
+#define BAD_ARGS       _("Bad arguments to instruction")
+#define BAD_PC                 _("r15 not allowed here")
+#define BAD_FLAGS      _("Instruction should not have flags")
+#define BAD_COND       _("Instruction is not conditional")
 
 static struct hash_control * arm_ops_hsh = NULL;
 static struct hash_control * arm_tops_hsh = NULL;
@@ -1251,7 +1270,7 @@ s_force_thumb (ignore)
      
   if (! thumb_mode)
     {
-      thumb_mode = 1;
+      thumb_mode = 2;
       
       record_alignment (now_seg, 1);
     }
@@ -1360,7 +1379,7 @@ s_thumb_set (equiv)
   
   THUMB_SET_FUNC (symbolP, 1);
   ARM_SET_THUMB (symbolP, 1);
-#if defined OBJ_COFF || defined OBJ_ELF
+#if defined OBJ_ELF || defined OBJ_COFF
   ARM_SET_INTERWORK (symbolP, support_interwork);
 #endif
 }
@@ -1373,7 +1392,11 @@ arm_s_text (ignore)
   if (now_seg != text_section)
     s_ltorg (0);
   
+#ifdef OBJ_ELF
+  obj_elf_text (ignore);
+#else
   s_text (ignore);
+#endif
 }
 
 static void
@@ -1388,7 +1411,11 @@ arm_s_data (ignore)
   else if (now_seg != data_section)
     s_ltorg (0);
   
+#ifdef OBJ_ELF
+  obj_elf_data (ignore);
+#else
   s_data (ignore);
+#endif
 }
 
 #ifdef OBJ_ELF
@@ -3320,13 +3347,15 @@ do_bx (str, flags)
   skip_whitespace (str);
 
   if ((reg = reg_required_here (&str, 0)) == FAIL)
-    return;
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
   if (reg == REG_PC)
-    as_tsktsk (_("Use of r15 in bx has undefined behaviour"));
+    inst.error = BAD_PC;
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -3487,6 +3516,10 @@ do_co_reg (str, flags)
          return;
        }
     }
+  if (flags)
+    {
+      inst.error = BAD_COND;
+    }
 
   end_of_line (str);
   return;
@@ -4502,15 +4535,12 @@ do_t_arit (str)
 
   skip_whitespace (str);
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-    return;
-
-  if (skip_past_comma (&str) == FAIL
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL
       || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
     {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
+       inst.error = BAD_ARGS;
+       return;
     }
 
   if (skip_past_comma (&str) != FAIL)
@@ -5326,7 +5356,8 @@ md_apply_fix3 (fixP, val, seg)
          && S_GET_SEGMENT (fixP->fx_addsy) != seg)
        {
          if (target_oabi
-             && fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
+             && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+               ))
            value = 0;
          else
            value += md_pcrel_from (fixP);
@@ -5524,6 +5555,7 @@ md_apply_fix3 (fixP, val, seg)
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
+
     case BFD_RELOC_THUMB_PCREL_BRANCH9: /* conditional branch */
       newval = md_chars_to_number (buf, THUMB_SIZE);
       {
@@ -6053,6 +6085,13 @@ md_assemble (str)
       
       if (opcode)
        {
+         /* Check that this instruction is supported for this CPU.  */
+         if (thumb_mode == 1 && (opcode->variants & cpu_variant) == 0)
+            {
+               as_bad (_("selected processor does not support this opcode"));
+               return;
+            }
+
          inst.instruction = opcode->value;
          inst.size = opcode->size;
          (*opcode->parms)(p);
@@ -6063,6 +6102,7 @@ md_assemble (str)
   else
     {
       CONST struct asm_opcode * opcode;
+      unsigned long cond_code;
 
       inst.size = INSN_SIZE;
       /* p now points to the end of the opcode, probably white space, but we
@@ -6089,11 +6129,18 @@ md_assemble (str)
              inst.instruction = opcode->value;
              if (q == p)               /* Just a simple opcode.  */
                {
-                 if (opcode->comp_suffix != 0)
-                   as_bad (_("Opcode `%s' must have suffix from <%s>\n"), str,
-                           opcode->comp_suffix);
+                 if (opcode->comp_suffix)
+                   {
+                      if (*opcode->comp_suffix != '\0')
+                        as_bad (_("Opcode `%s' must have suffix from list: <%s>"),
+                            str, opcode->comp_suffix);
+                      else
+                        /* Not a conditional instruction. */
+                        (*opcode->parms)(q, 0);
+                   }
                  else
                    {
+                     /* A conditional instruction with default condition. */
                      inst.instruction |= COND_ALWAYS;
                      (*opcode->parms)(q, 0);
                    }
@@ -6101,7 +6148,7 @@ md_assemble (str)
                  return;
                }
 
-             /* Now check for a conditional.  */
+             /* Not just a simple opcode.  Check if extra is a conditional. */
              r = q;
              if (p - r >= 2)
                {
@@ -6117,18 +6164,33 @@ md_assemble (str)
                        as_tsktsk (
 _("Warning: Use of the 'nv' conditional is deprecated\n"));
 
-                     inst.instruction |= cond->value;
+                     cond_code = cond->value;
                      r += 2;
                    }
                  else
-                   inst.instruction |= COND_ALWAYS;
+                   cond_code = COND_ALWAYS;
+               }
+             else
+               cond_code = COND_ALWAYS;
+
+             /* Apply the conditional, or complain it's not allowed. */
+             if (opcode->comp_suffix && *opcode->comp_suffix == '\0')
+               {
+                  /* Instruction isn't conditional */
+                  if (cond_code != COND_ALWAYS)
+                    {
+                      as_bad (_("Opcode `%s' is unconditional\n"), str);
+                      return;
+                    }
                }
              else
-               inst.instruction |= COND_ALWAYS;
+               /* Instruction is conditional: set the condition into it. */
+               inst.instruction |= cond_code;       
+
 
              /* If there is a compulsory suffix, it should come here, before
                 any optional flags.  */
-             if (opcode->comp_suffix)
+             if (opcode->comp_suffix && *opcode->comp_suffix != '\0')
                {
                  CONST char *s = opcode->comp_suffix;
 
@@ -6228,7 +6290,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
              if (regnum != FAIL)
                insert_reg_alias (str, regnum);
              else
-               as_warn (_("register '%s' does not exist"), q);
+               as_warn (_("register '%s' does not exist\n"), q);
            }
          else if (regnum != FAIL)
            {
@@ -6265,7 +6327,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
  *            -m[arm]8[10]            Arm 8 processors
  *            -m[arm]9[20][tdmi]      Arm 9 processors
  *            -mstrongarm[110[0]]     StrongARM processors
- *            -m[arm]v[2345]         Arm architecures
+ *            -m[arm]v[2345]         Arm architectures
  *            -mall                   All (except the ARM1)
  *    FP variants:
  *            -mfpa10, -mfpa11        FPA10 and 11 co-processor instructions
@@ -6354,7 +6416,8 @@ md_parse_option (c, arg)
             }
           else if (streq (str, "thumb-interwork"))
             {
-              cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCH_V4;
+             if ((cpu_variant & ARM_THUMB) == 0)
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4T;
 #if defined OBJ_COFF || defined OBJ_ELF
               support_interwork = true;
 #endif
@@ -6476,6 +6539,7 @@ md_parse_option (c, arg)
                case 70:
                case 700:
                case 710:
+               case 720:
                case 7100:
                case 7500:
                  break;
@@ -6532,6 +6596,7 @@ md_parse_option (c, arg)
              else
                goto bad;
              break;
+
              
            case 's':
              if (streq (str, "strongarm")
@@ -6576,13 +6641,13 @@ md_parse_option (c, arg)
                    default:  as_bad (_("Invalid architecture variant -m%s"), arg); break;
                    }
                  break;
-                 
+
                case '5':
                  cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V5;
-                 
                  switch (*++str)
                    {
                    case 't': cpu_variant |= ARM_THUMB; break;
+                   case 'e': cpu_variant |= ARM_EXT_V5E; break;
                    case 0:   break;
                    default:  as_bad (_("Invalid architecture variant -m%s"), arg); break;
                    }
@@ -6623,7 +6688,7 @@ md_show_usage (fp)
 _("\
  ARM Specific Assembler Options:\n\
   -m[arm][<processor name>] select processor variant\n\
-  -m[arm]v[2|2a|3|3m|4|4t|5]select architecture variant\n\
+  -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] select architecture variant\n\
   -mthumb                   only allow Thumb instructions\n\
   -mthumb-interwork         mark the assembled code as supporting interworking\n\
   -mall                     allow any instruction\n\
@@ -6832,12 +6897,14 @@ arm_adjust_symtab ()
     {
       if (ARM_IS_THUMB (sym))
         {
+         elf_sym = elf_symbol (symbol_get_bfdsym (sym));
+         bind = ELF_ST_BIND (elf_sym);
+         
+         /* If it's a .thumb_func, declare it as so, else tag label as .code 16.  */
          if (THUMB_IS_FUNC (sym))
-           {
-             elf_sym = elf_symbol (symbol_get_bfdsym (sym));
-             bind = ELF_ST_BIND (elf_sym);
-             elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
-            }
+           elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
+         else
+           elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_16BIT);
          }
      }
 #endif