Add support for more ARM processor names.
authorNick Clifton <nickc@redhat.com>
Fri, 12 Dec 1997 18:42:40 +0000 (18:42 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 12 Dec 1997 18:42:40 +0000 (18:42 +0000)
gas/ChangeLog
gas/config/tc-arm.c

index bdaa4cd..2508ee1 100644 (file)
@@ -1,3 +1,11 @@
+Fri Dec 12 10:35:01 1997  Nick Clifton  <nickc@cygnus.com>
+
+       * doc/c-arm.texi (ARM Options): Document support for new ARM
+       processor names.
+
+       * config/tc-arm.c (md_parse_option): Add support for new ARM
+       processor names.
+
 Thu Dec 11 17:46:50 1997  Richard Henderson  <rth@cygnus.com>
 
        * config/tc-m68k.c (m68k_ip): Don't overwrite opcode table data.
index 1a4a3f4..9a5a5bf 100644 (file)
 
 /* The following bitmasks control CPU extensions (ARM7 onwards): */
 #define ARM_LONGMUL    0x00000010      /* allow long multiplies */
-#define ARM_ARCH4       0x00000020
-#define ARM_THUMB       ARM_ARCH4
+#define ARM_HALFWORD    0x00000020     /* allow half word loads */
+#define ARM_THUMB       0x00000040     /* allow BX instruction  */
+
+#define ARM_ARCHv4     (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
 
 /* Some useful combinations:  */
 #define ARM_ANY                0x00ffffff
@@ -73,7 +75,7 @@
      
 #ifndef CPU_DEFAULT
 #if defined __thumb__
-#define CPU_DEFAULT (ARM_7 | ARM_THUMB)
+#define CPU_DEFAULT (ARM_ARCHv4 | ARM_THUMB)
 #else
 #define CPU_DEFAULT ARM_ALL
 #endif
@@ -88,6 +90,9 @@ static unsigned long  cpu_variant = CPU_DEFAULT | FPU_DEFAULT;
 #ifdef OBJ_COFF
 /* Flags stored in private area of BFD COFF structure */
 static boolean         uses_apcs_26 = false;
+static boolean         support_interwork = false;
+static boolean         uses_apcs_float = false;
+static boolean         pic_code = false;
 #endif
 
 /* This array holds the chars that always start a comment.  If the
@@ -419,7 +424,7 @@ static int arm_psr_parse    PARAMS ((char **ccp));
 static void symbol_locate      PARAMS ((symbolS *, CONST char *, segT,
                                         valueT, fragS *));
 static int add_to_lit_pool     PARAMS ((void));
-static int validate_immediate  PARAMS ((int));
+static unsigned validate_immediate     PARAMS ((unsigned));
 static int validate_offset_imm PARAMS ((int, int));
 static void opcode_select      PARAMS ((int));
 static void end_of_line                PARAMS ((char *));
@@ -856,6 +861,8 @@ static void s_ltorg PARAMS ((int));
 static void s_arm PARAMS ((int));
 static void s_thumb PARAMS ((int));
 static void s_code PARAMS ((int));
+static void s_force_thumb PARAMS ((int));
+static void s_thumb_func PARAMS ((int));
 
 static int my_get_expression PARAMS ((expressionS *, char **));
 
@@ -867,6 +874,8 @@ CONST pseudo_typeS md_pseudo_table[] =
   {"arm", s_arm, 0},
   {"thumb", s_thumb, 0},
   {"code", s_code, 0},
+  {"force_thumb", s_force_thumb, 0},
+  {"thumb_func", s_thumb_func, 0},
   {"even", s_even, 0},
   {"ltorg", s_ltorg, 0},
   {"pool", s_ltorg, 0},
@@ -887,7 +896,8 @@ CONST pseudo_typeS md_pseudo_table[] =
               <insn>
 */
 
-symbolS *last_label_seen;
+symbolS *  last_label_seen;
+static int label_is_thumb_function_name = false;
 
 /* Literal stuff */
 
@@ -928,7 +938,7 @@ add_to_lit_pool ()
     {
       if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE)
         {
-          inst.error = "Literal Pool Overflow\n";
+          inst.error = "Literal Pool Overflow";
           return FAIL;
         }
 
@@ -1016,35 +1026,21 @@ symbol_make_empty ()
   return symbolP;
 }
 
-/* Check that an immediate is valid, and if so, convert it to the right format
- */
-
-/* OH, for a rotate instruction in C! */
+/* Check that an immediate is valid, and if so, convert it to the right format.  */
 
-static int
+static unsigned int
 validate_immediate (val)
-     int val;
+     unsigned int val;
 {
-  unsigned int a = (unsigned int) val;
-  int i;
-  
-  /* Do the easy (and most common ones) quickly */
-  for (i = 0; i <= 24; i += 2)
-    {
-      if ((a & (0xff << i)) == a)
-       return (int) (((32 - i) & 0x1e) << 7) | ((a >> i) & 0xff);
-    }
+    unsigned int a;
+    unsigned int i;
 
-  /* Now do the harder ones */
-  for (; i < 32; i += 2)
-    {
-      if ((a & ((0xff << i) | (0xff >> (32 - i)))) == a)
-       {
-         a = ((a >> i) & 0xff) | ((a << (32 - i)) & 0xff);
-         return (int) a | (((32 - i) >> 1) << 8);
-       }
-    }
-  return FAIL;
+#define rotate_left(v, n) (v << n | v >> (32 - n))
+    
+    for (i = 0; i < 32; i += 2)
+        if ((a = rotate_left (val, i)) <= 0xff)
+            return a | (i << 7); /* 12-bit pack: [shift-cnt,const] */
+    return FAIL;
 }
 
 static int
@@ -1117,6 +1113,9 @@ s_ltorg (internal)
                 (valueT) frag_now_fix (), frag_now);
   symbol_table_insert (current_poolP);
 
+  ARM_SET_THUMB (current_poolP, thumb_mode);
+  ARM_SET_INTERWORK (current_poolP, support_interwork);
+  
   while (lit_count < next_literal_pool_place)
     /* First output the expression in the instruction to the pool */
     emit_expr (&(literals[lit_count++].exp), 4); /* .word */
@@ -1176,6 +1175,38 @@ s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */
 }
 
 static void
+s_force_thumb (ignore)
+     int ignore;
+{
+  /* If we are not already in thumb mode go into it, EVEN if
+     the target processor does not support thumb instructions.
+     This is used by gcc/config/arm/lib1funcs.asm for example
+     to compile interworking support functions even if the
+     target processor should not support interworking.  */
+     
+  if (! thumb_mode)
+    {
+      thumb_mode = 1;
+      
+      record_alignment (now_seg, 1);
+    }
+  
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_thumb_func (ignore)
+     int ignore;
+{
+  /* The following label is the name/address of the start of a Thumb function.
+     We need to know this for the interworking support.  */
+
+  label_is_thumb_function_name = true;
+  
+  demand_empty_rest_of_line();
+}
+
+static void
 opcode_select (width)
      int width;
 {
@@ -1702,7 +1733,7 @@ do_msr (str, flags)
            }
          else
            {
-             int value = validate_immediate (inst.reloc.exp.X_add_number);
+             unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
              if (value == FAIL)
                {
                  inst.error = "Invalid constant";
@@ -2579,10 +2610,10 @@ do_ldst (str, flags)
     {
       /* This is actually a load/store of a halfword, or a
          signed-extension load */
-      if ((cpu_variant & ARM_ARCH4) == 0)
+      if ((cpu_variant & ARM_HALFWORD) == 0)
         {
           inst.error
-           = "Processor does not support halfwords or signed bytes\n";
+           = "Processor does not support halfwords or signed bytes";
           return;
         }
 
@@ -2730,7 +2761,7 @@ do_ldst (str, flags)
          if (add_to_lit_pool () == FAIL)
            {
              if (!inst.error)
-               inst.error = "literal pool insertion failed\n"; 
+               inst.error = "literal pool insertion failed"; 
              return;
            }
 
@@ -3998,8 +4029,8 @@ thumb_mov_compare (str, move)
       if (Rs < 8 && Rd < 8)
        {
          if (move == THUMB_MOVE)
-           /* A move of two lowregs is, by convention, encoded as
-              ADD Rd, Rs, #0 */
+           /* A move of two lowregs is encoded as ADD Rd, Rs, #0
+              since a MOV instruction produces unpredictable results */
            inst.instruction = T_OPCODE_ADD_I3;
          else
            inst.instruction = T_OPCODE_CMP_LR;
@@ -4106,8 +4137,48 @@ thumb_load_store (str, load_store, size)
     }
   else if (*str == '=')
     {
-      /* TODO: We should allow the "ldr Rd,=expr" pseudo op in thumb mode */
-      abort ();
+      /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */
+      str++;
+
+      while (*str == ' ')
+       str++;
+
+      if (my_get_expression (& inst.reloc.exp, & str))
+       return;
+
+      end_of_line (str);
+      
+      if (   inst.reloc.exp.X_op != O_constant
+         && inst.reloc.exp.X_op != O_symbol)
+       {
+         inst.error = "Constant expression expected";
+         return;
+       }
+
+      if (inst.reloc.exp.X_op == O_constant
+         && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
+       {
+         /* This can be done with a mov instruction */
+
+         inst.instruction  = T_OPCODE_MOV_I8 | (Rd << 8);
+         inst.instruction |= inst.reloc.exp.X_add_number;
+         return; 
+       }
+
+      /* Insert into literal pool */     
+      if (add_to_lit_pool () == FAIL)
+       {
+         if (!inst.error)
+           inst.error = "literal pool insertion failed"; 
+         return;
+       }
+
+      inst.reloc.type   = BFD_RELOC_ARM_THUMB_OFFSET;
+      inst.reloc.pc_rel = 1;
+      inst.instruction  = T_OPCODE_LDR_PC | (Rd << 8);
+      inst.reloc.exp.X_add_number += 4; /* Adjust ARM pipeline offset to Thumb */
+
+      return;
     }
   else
     {
@@ -4566,7 +4637,7 @@ do_t_adr (str)
   while (*str == ' ')
     str++;
 
-  if (reg_required_here (&str, 4) == FAIL
+  if (reg_required_here (&str, 4) == FAIL  /* Store Rd in temporary location inside instruction.  */
       || skip_past_comma (&str) == FAIL
       || my_get_expression (&inst.reloc.exp, &str))
     {
@@ -4636,7 +4707,7 @@ void
 md_begin ()
 {
   int i;
-
+  
   if ((arm_ops_hsh = hash_new ()) == NULL
       || (arm_tops_hsh = hash_new ()) == NULL
       || (arm_cond_hsh = hash_new ()) == NULL
@@ -4662,8 +4733,17 @@ md_begin ()
   set_constant_flonums ();
 
 #ifdef OBJ_COFF
-  /* Set the flags in the private structure */
-  bfd_set_private_flags (stdoutput, uses_apcs_26 ? F_APCS26 : 0);
+  {
+    unsigned int flags = 0;
+    
+    /* Set the flags in the private structure */
+    if (uses_apcs_26)      flags |= F_APCS26;
+    if (support_interwork) flags |= F_INTERWORK;
+    if (uses_apcs_float)   flags |= F_APCS_FLOAT;
+    if (pic_code)          flags |= F_PIC;
+    
+    bfd_set_private_flags (stdoutput, flags);
+  }
 #endif
   
   {
@@ -4695,7 +4775,7 @@ md_begin ()
       {
        if (cpu_variant & ARM_THUMB)
          mach = bfd_mach_arm_4T;
-       else if (cpu_variant & ARM_ARCH4)
+       else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4)
          mach = bfd_mach_arm_4;
        else if (cpu_variant & ARM_LONGMUL)
          mach = bfd_mach_arm_3M;
@@ -4846,6 +4926,14 @@ md_pcrel_from (fixP)
       && fixP->fx_subsy == NULL)
     return 0;  /* HACK */
 
+  if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD))
+    {
+      /* PC relative addressing on the Thumb is slightly odd
+        as the bottom two bits of the PC are forced to zero
+        for the calculation */
+      return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
+    }
+  
   return fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
@@ -4969,7 +5057,12 @@ md_apply_fix3 (fixP, val, seg)
     {
       if (S_IS_DEFINED (fixP->fx_addsy)
          && S_GET_SEGMENT (fixP->fx_addsy) != seg)
-       value += md_pcrel_from (fixP);
+       {
+         if (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
+           value = 0;
+         else
+           value += md_pcrel_from (fixP);
+       }
     }
 
   fixP->fx_addnumber = value;  /* Remember value for emit_reloc */
@@ -5244,7 +5337,9 @@ md_apply_fix3 (fixP, val, seg)
          break;
 
        default:
-         abort ();
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       "Unable to process relocation for thumb opcode: %x", newval);
+         break;
        }
       md_number_to_chars (buf, newval, THUMB_SIZE);
       break;
@@ -5404,61 +5499,41 @@ tc_gen_reloc (section, fixp)
                    "Literal referenced across section boundry (Implicit dump?)");
       return NULL;
 
-    case BFD_RELOC_ARM_IMMEDIATE:
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Internal_relocation (type %d) not fixed up (IMMEDIATE)",
-                   fixp->fx_r_type);
-      return NULL;
-
-    case BFD_RELOC_ARM_OFFSET_IMM:
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Internal_relocation (type %d) not fixed up (OFFSET_IMM)",
-                   fixp->fx_r_type);
-      return NULL;
-
-    case BFD_RELOC_ARM_OFFSET_IMM8:
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Internal_relocation (type %d) not fixed up (OFFSET_IMM8)",
-                   fixp->fx_r_type);
-      return NULL;
-
-    case BFD_RELOC_ARM_SHIFT_IMM:
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Internal_relocation (type %d) not fixed up (SHIFT_IMM)",
-                   fixp->fx_r_type);
-      return NULL;
-
-    case BFD_RELOC_ARM_SWI:
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Internal_relocation (type %d) not fixed up (SWI)",
-                   fixp->fx_r_type);
-      return NULL;
-
-    case BFD_RELOC_ARM_MULTI:
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Internal_relocation (type %d) not fixed up (MULTI)",
-                   fixp->fx_r_type);
-      return NULL;
+    default:
+      {
+       char * type;
+       switch (fixp->fx_r_type)
+         {
+         case BFD_RELOC_ARM_IMMEDIATE:    type = "IMMEDIATE";    break;
+         case BFD_RELOC_ARM_OFFSET_IMM:   type = "OFFSET_IMM";   break;
+         case BFD_RELOC_ARM_OFFSET_IMM8:  type = "OFFSET_IMM8";  break;
+         case BFD_RELOC_ARM_SHIFT_IMM:    type = "SHIFT_IMM";    break;
+         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_THUMB_ADD:    type = "THUMB_ADD";    break;
+         case BFD_RELOC_ARM_THUMB_SHIFT:  type = "THUMB_SHIFT";  break;
+         case BFD_RELOC_ARM_THUMB_IMM:    type = "THUMB_IMM";    break;
+         case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
+         default:                         type = "<unknown>";    break;
+         }
+       as_bad_where (fixp->fx_file, fixp->fx_line,
+                     "Can not represent %s relocation in this object file format (%d)",
+                     type, fixp->fx_pcrel);
+       return NULL;
+      }
+    }
 
-    case BFD_RELOC_ARM_CP_OFF_IMM:
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Internal_relocation (type %d) not fixed up (CP_OFF_IMM)",
-                   fixp->fx_r_type);
-      return NULL;
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
 
-    case BFD_RELOC_ARM_THUMB_OFFSET:
+  if (reloc->howto == NULL)
+    {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Internal_relocation (type %d) not fixed up (THUMB_OFFSET)",
-                   fixp->fx_r_type);
+                   "Can not represent %s relocation in this object file format",
+                   bfd_get_reloc_code_name (code));
       return NULL;
-
-    default:
-      abort ();
     }
 
-  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
-  assert (reloc->howto != 0);
-
   return reloc;
 }
 
@@ -5503,7 +5578,7 @@ output_inst (str)
     
   if (inst.error)
     {
-      as_bad ("%s -- statement `%s'\n", inst.error, str);
+      as_bad (inst.error);
       return;
     }
 
@@ -5722,40 +5797,56 @@ md_assemble (str)
     
   if (*q && !strncmp (q, ".req ", 4))
     {
-      int reg;
-      if ((reg = arm_reg_parse (&str)) == FAIL)
-       {
-         char *r;
+      int    reg;
+      char * copy_of_str = str;
+      char * r;
       
-         q += 4;
-         while (*q == ' ')
-           q++;
+      q += 4;
+      while (*q == ' ')
+       q++;
 
-         for (r = q; *r != '\0'; r++)
-           if (*r == ' ')
-             break;
+      for (r = q; *r != '\0'; r++)
+       if (*r == ' ')
+         break;
+      
+      if (r != q)
+       {
+         int regnum;
+         char d = *r;
 
-         if (r != q)
-           {
-             int regnum;
-             char d = *r;
+         *r = '\0';
+         regnum = arm_reg_parse (& q);
+         *r = d;
 
-             *r = '\0';
-             regnum = arm_reg_parse (&q);
-             *r = d;
+         reg = arm_reg_parse (& str);
+         
+         if (reg == FAIL)
+           {
              if (regnum != FAIL)
                {
                  insert_reg_alias (str, regnum);
-                 *p = c;
-                 return;
+               }
+             else
+               {
+                 as_warn ("register '%s' does not exist\n", q);
                }
            }
+         else if (regnum != FAIL)
+           {
+             if (reg != regnum)
+               as_warn ("ignoring redefinition of register alias '%s'", copy_of_str );
+             
+             /* Do not warn abpout redefinitions to the same alias.  */
+           }
+         else
+           as_warn ("ignoring redefinition of register alias '%s' to non-existant register '%s'",
+                    copy_of_str, q);
        }
       else
-       {
-         *p = c;
-         return;
-       }
+       as_warn ("ignoring incomplete .req pseuso op");
+      
+      *p = c;
+      return;
     }
 
   *p = c;
@@ -5783,6 +5874,9 @@ md_assemble (str)
  *    ARM Procedure Calling Standard:
  *           -mapcs-32               32 bit APCS
  *           -mapcs-26               26 bit APCS
+ *           -mapcs-float            Pass floats in float regs
+ *           -mapcs-reentrant        Position independent code
+ *            -mthumb-interwork       Code supports Arm/Thumb interworking
  */
 
 CONST char *md_shortopts = "m:";
@@ -5843,6 +5937,13 @@ md_parse_option (c, arg)
               cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE;
               thumb_mode = 1;
             }
+          else if (! strcmp (str, "thumb-interwork"))
+            {
+              cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCHv4;
+#ifdef OBJ_COFF
+              support_interwork = true;
+#endif
+            }
           else
            goto bad;
           break;
@@ -5854,16 +5955,60 @@ md_parse_option (c, arg)
              return 1;
            }
 #ifdef OBJ_COFF
-         if (! strcmp (str, "apcs-32"))
-           {
-             uses_apcs_26 = false;
-             return 1;
-           }
-         else if (! strcmp (str, "apcs-26"))
+         if (! strncmp (str, "apcs-", 5))
            {
-             uses_apcs_26 = true;
-             return 1;
-           }
+             /* GCC passes on all command line options starting "-mapcs-..."
+                to us, so we must parse them here.  */
+
+             str += 5;
+             
+             if (! strcmp (str, "32"))
+               {
+                 uses_apcs_26 = false;
+                 return 1;
+               }
+             else if (! strcmp (str, "26"))
+               {
+                 uses_apcs_26 = true;
+                 return 1;
+               }
+             else if (! strcmp (str, "frame"))
+               {
+                 /* Stack frames are being generated - does not affect
+                    linkage of code.  */
+                 return 1;
+               }
+             else if (! strcmp (str, "stack-check"))
+               {
+                 /* Stack checking is being performed - does not affect
+                    linkage, but does require that the functions
+                    __rt_stkovf_split_small and __rt_stkovf_split_big be
+                    present in the final link.  */
+
+                 return 1;
+               }
+             else if (! strcmp (str, "float"))
+               {
+                 /* Floating point arguments are being passed in the floating
+                    point registers.  This does affect linking, since this
+                    version of the APCS is incompatible with the version that
+                    passes floating points in the integer registers.  */
+
+                 uses_apcs_float = true;
+                 return 1;
+               }
+             else if (! strcmp (str, "reentrant"))
+               {
+                 /* Reentrant code has been generated.  This does affect
+                    linking, since there is no point in linking reentrant/
+                    position independent code with absolute position code. */
+                 pic_code = true;
+                 return 1;
+               }
+             
+             as_bad ("Unrecognised APCS switch -m%s", arg);
+             return 0;
+           }
 #endif
          /* Strip off optional "arm" */
          if (! strncmp (str, "arm", 3))
@@ -5894,6 +6039,20 @@ md_parse_option (c, arg)
                goto bad;
              break;
 
+           case 's':
+             if (streq (str, "strongarm") || streq (str, "strongarm110"))
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL;
+             else
+               goto bad;
+             break;
+               
+           case '8':
+             if (streq (str, "8"))
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL;
+             else
+               goto bad;
+             break;
+
            case '6':
              if (! strcmp (str, "6"))
                cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6;
@@ -5906,20 +6065,26 @@ md_parse_option (c, arg)
               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7;
               for (; *str; str++)
                 {
-                switch (*str)
+                switch (* str)
                   {
                   case 't':
-                    cpu_variant |= ARM_THUMB;
+                    cpu_variant |= (ARM_THUMB | ARM_ARCHv4);
                     break;
 
                   case 'm':
                     cpu_variant |= ARM_LONGMUL;
                     break;
 
+                 case 'f': /* fe => fp enabled cpu.  */
+                   if (str[1] == 'e')
+                     ++ str;
+                   else
+                     goto bad;
+                   
+                 case 'c': /* Unknown */
                   case 'd': /* debug */
                   case 'i': /* embedded ice */
-                    /* Included for completeness in ARM processor
-                       naming. */
+                    /* Included for completeness in ARM processor naming. */
                     break;
 
                   default:
@@ -5953,7 +6118,7 @@ md_parse_option (c, arg)
                  break;
                  
                case '4':
-                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7;
+                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCHv4;
                  
                  switch (*++str)
                    {
@@ -5989,9 +6154,10 @@ md_show_usage (fp)
      FILE *fp;
 {
   fprintf (fp,
-"-m[arm][1|2|250|3|6|7[t][d][m][i]] select processor variant\n\
+"-m[arm][<processor name>] select processor variant\n\
 -m[arm]v[2|2a|3|3m|4|4t] select architecture variant\n\
 -mthumb\t\t\tonly allow Thumb instructions\n\
+-mthumb-interwork\tmark the assembled code as supporting interworking\n\
 -mall\t\t\tallow any instruction\n\
 -mfpa10, -mfpa11\tselect floating point architecture\n\
 -mfpe-old\t\tdon't allow floating-point multiple instructions\n\
@@ -5999,6 +6165,10 @@ md_show_usage (fp)
 #ifdef OBJ_COFF
   fprintf (fp,
 "-mapcs-32, -mapcs-26\tspecify which ARM Procedure Calling Standard is in use\n");
+  fprintf (fp,
+"-mapcs-float\t\tfloating point args are passed in floating point regs\n");
+  fprintf (fp,
+"-mapcs-reentrant\tposition independent/reentrant code has been generated\n");
 #endif
 #ifdef ARM_BI_ENDIAN
   fprintf (fp,
@@ -6074,7 +6244,20 @@ arm_frob_label (sym)
      symbolS *sym;
 {
   last_label_seen = sym;
-  ARM_SET_TYPE(sym,thumb_mode);
+  ARM_SET_THUMB (sym, thumb_mode);
+  ARM_SET_INTERWORK (sym, support_interwork);
+
+  if (label_is_thumb_function_name)
+    {
+      /* When the address of a Thumb function is taken the bottom
+        bit of that address should be set.  This will allow
+        interworking between Arm and Thumb functions to work
+        correctly.  */
+
+      THUMB_SET_FUNC (sym, 1);
+      
+      label_is_thumb_function_name = false;
+    }
 }
 
 /* Adjust the symbol table.  This marks Thumb symbols as distinct from
@@ -6088,9 +6271,20 @@ arm_adjust_symtab ()
 
   for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
     {
-      if (ARM_GET_TYPE(sym)) /* Thumb */
+      if (ARM_IS_THUMB (sym))
         {
-          switch (S_GET_STORAGE_CLASS (sym))
+         if (THUMB_IS_FUNC (sym))
+           {
+             /* Mark the symbol as a Thumb function.  */
+             if (   S_GET_STORAGE_CLASS (sym) == C_STAT
+                 || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */
+               S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
+             else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
+               S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
+             else
+               as_bad ("%s: unexpected function type: %d", S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
+           }
+          else switch (S_GET_STORAGE_CLASS (sym))
             {
               case C_EXT:
                 S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
@@ -6105,6 +6299,11 @@ arm_adjust_symtab ()
                 break;
             }
         }
+      
+      if (ARM_IS_INTERWORK (sym))
+       {
+         coffsymbol(sym->bsym)->native->u.syment.n_flags = 0xFF;
+       }
     }
 #endif
 }