import gdb-2000-02-02 snapshot
[external/binutils.git] / gas / config / tc-arm.c
index f0ce280..86e3600 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-arm.c -- Assemble for the ARM
-   Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
 
 #include "symbols.h"
 #include "listing.h"
 
-/* ??? This is currently unused.  */
-#ifdef __STDC__
-#define internalError() \
-  as_fatal ("ARM Internal Error, line %d, %s", __LINE__, __FILE__)
-#else
-#define internalError() as_fatal ("ARM Internal Error")
+#ifdef OBJ_ELF
+#include "elf/arm.h"
 #endif
 
 /* Types of processor to assemble for.  */
 #define ARM_250                ARM_3
 #define ARM_6          0x00000008
 #define ARM_7          ARM_6           /* same core instruction set */
+#define ARM_8          ARM_6           /* same core instruction set */
+#define ARM_9          ARM_6           /* same core instruction set */
 #define ARM_CPU_MASK   0x0000000f
 
 /* The following bitmasks control CPU extensions (ARM7 onwards): */
 #define ARM_LONGMUL    0x00000010      /* allow long multiplies */
 #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"          */
 
-#define ARM_ARCHv4     (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
+/* Architectures are the sum of the base and extensions */
+#define ARM_ARCH_V4    (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
+#define ARM_ARCH_V4T   (ARM_ARCH_V4 | ARM_THUMB)
+#define ARM_ARCH_V5    (ARM_ARCH_V4 | ARM_EXT_V5)
+#define ARM_ARCH_V5T   (ARM_ARCH_V5 | ARM_THUMB)
 
 /* Some useful combinations:  */
 #define ARM_ANY                0x00ffffff
-#define ARM_2UP                0x00fffffe
+#define ARM_2UP                (ARM_ANY - ARM_1)
 #define ARM_ALL                ARM_2UP         /* Not arm1 only */
 #define ARM_3UP                0x00fffffc
 #define ARM_6UP                0x00fffff8      /* Includes ARM7 */
@@ -75,7 +79,7 @@
      
 #ifndef CPU_DEFAULT
 #if defined __thumb__
-#define CPU_DEFAULT (ARM_ARCHv4 | ARM_THUMB)
+#define CPU_DEFAULT (ARM_ARCH_V4 | ARM_THUMB)
 #else
 #define CPU_DEFAULT ARM_ALL
 #endif
 #define FPU_DEFAULT FPU_ALL
 #endif
 
+#define streq(a, b)           (strcmp (a, b) == 0)
+#define skip_whitespace(str)  while (* (str) == ' ') ++ (str)
+
 static unsigned long   cpu_variant = CPU_DEFAULT | FPU_DEFAULT;
+static int target_oabi = 0;
 
-#ifdef OBJ_COFF
-/* Flags stored in private area of BFD COFF structure */
+#if defined OBJ_COFF || defined OBJ_ELF
+/* Flags stored in private area of BFD structure */
 static boolean         uses_apcs_26 = false;
 static boolean         support_interwork = false;
 static boolean         uses_apcs_float = false;
@@ -108,7 +116,11 @@ CONST char comment_chars[] = "@";
 /* Also note that comments like this one will always work. */
 CONST char line_comment_chars[] = "#";
 
+#ifdef TE_LINUX
+CONST char line_separator_chars[] = ";";
+#else
 CONST char line_separator_chars[] = "";
+#endif
 
 /* Chars that can be used to separate mant from exp in floating point nums */
 CONST char EXP_CHARS[] = "eE";
@@ -119,10 +131,19 @@ CONST char EXP_CHARS[] = "eE";
 
 CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 
-CONST int md_reloc_size = 8;           /* Size of relocation record */
+/* Prefix characters that indicate the start of an immediate
+   value.  */
+#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')
+
+#ifdef OBJ_ELF
+symbolS * GOT_symbol;          /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
+#endif
 
-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;
@@ -130,15 +151,15 @@ typedef struct arm_fix
 
 struct arm_it
 {
-  CONST char *error;
+  CONST char *  error;
   unsigned long instruction;
-  int suffix;
-  int size;
+  int           suffix;
+  int           size;
   struct
     {
       bfd_reloc_code_real_type type;
-      expressionS exp;
-      int pc_rel;
+      expressionS              exp;
+      int                      pc_rel;
     } reloc;
 };
 
@@ -146,7 +167,7 @@ struct arm_it inst;
 
 struct asm_shift
 {
-  CONST char *template;
+  CONST char *  template;
   unsigned long value;
 };
 
@@ -171,7 +192,7 @@ static CONST struct asm_shift shift[] =
 
 #define NUM_FLOAT_VALS 8
 
-CONST char *fp_const[] = 
+CONST char * fp_const[] = 
 {
   "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
 };
@@ -201,7 +222,7 @@ LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
 
 struct asm_cond
 {
-  CONST char *template;
+  CONST char *  template;
   unsigned long value;
 };
 
@@ -233,7 +254,7 @@ static CONST struct asm_cond conds[] =
    the set_bits: */
 struct asm_flg
 {
-  CONST char *template;                /* Basic flag string */
+  CONST char *  template;      /* Basic flag string */
   unsigned long set_bits;      /* Bits to set */
 };
 
@@ -359,78 +380,94 @@ static CONST struct asm_flg cplong_flag[] =
 
 struct asm_psr
 {
-  CONST char *template;
+  CONST char *  template;
   unsigned long number;
 };
 
-#define PSR_ALL                0x00010000
+#define PSR_FIELD_MASK  0x000f0000
+
+#define PSR_FLAGS      0x00080000
+#define PSR_CONTROL    0x00010000 /* Undocumented instruction, its use is discouraged by ARM */
+#define PSR_ALL                0x00090000
+
+#define CPSR_ALL       0
+#define SPSR_ALL       1
+#define CPSR_FLG       2
+#define SPSR_FLG       3
+#define CPSR_CTL       4
+#define SPSR_CTL       5
 
 static CONST struct asm_psr psrs[] =
 {
   /* Valid <psr>'s */
-  {"cpsr",     0},
-  {"cpsr_all", 0},
-  {"spsr",     1},
-  {"spsr_all", 1},
+  {"cpsr",     CPSR_ALL},
+  {"cpsr_all", CPSR_ALL},
+  {"spsr",     SPSR_ALL},
+  {"spsr_all", SPSR_ALL},
 
   /* Valid <psrf>'s */
-  {"cpsr_flg", 2},
-  {"spsr_flg", 3}
+  {"cpsr_flg", CPSR_FLG},
+  {"spsr_flg", SPSR_FLG},
+  
+  /* Valid <psrc>'s */
+  {"cpsr_c",   CPSR_CTL},
+  {"cpsr_ctl", CPSR_CTL},
+  {"spsr_c",   SPSR_CTL},
+  {"spsr_ctl", SPSR_CTL}
 };
 
 /* Functions called by parser */
 /* ARM instructions */
-static void do_arit            PARAMS ((char *operands, unsigned long flags));
-static void do_cmp             PARAMS ((char *operands, unsigned long flags));
-static void do_mov             PARAMS ((char *operands, unsigned long flags));
-static void do_ldst            PARAMS ((char *operands, unsigned long flags));
-static void do_ldmstm          PARAMS ((char *operands, unsigned long flags));
-static void do_branch          PARAMS ((char *operands, unsigned long flags));
-static void do_swi             PARAMS ((char *operands, unsigned long flags));
-/* Pseudo Op codes */
-static void do_adr             PARAMS ((char *operands, unsigned long flags));
-static void do_nop             PARAMS ((char *operands, unsigned long flags));
-/* ARM 2 */
-static void do_mul             PARAMS ((char *operands, unsigned long flags));
-static void do_mla             PARAMS ((char *operands, unsigned long flags));
-/* ARM 3 */
-static void do_swap            PARAMS ((char *operands, unsigned long flags));
-/* ARM 6 */
-static void do_msr             PARAMS ((char *operands, unsigned long flags));
-static void do_mrs             PARAMS ((char *operands, unsigned long flags));
-/* ARM 7M */
-static void do_mull            PARAMS ((char *operands, unsigned long flags));
-/* ARM THUMB */
-static void do_bx               PARAMS ((char *operands, unsigned long flags));
-
-/* Coprocessor Instructions */
-static void do_cdp             PARAMS ((char *operands, unsigned long flags));
-static void do_lstc            PARAMS ((char *operands, unsigned long flags));
-static void do_co_reg          PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ctrl         PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ldst         PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ldmstm       PARAMS ((char *operands, unsigned long flags));
-static void do_fp_dyadic       PARAMS ((char *operands, unsigned long flags));
-static void do_fp_monadic      PARAMS ((char *operands, unsigned long flags));
-static void do_fp_cmp          PARAMS ((char *operands, unsigned long flags));
-static void do_fp_from_reg     PARAMS ((char *operands, unsigned long flags));
-static void do_fp_to_reg       PARAMS ((char *operands, unsigned long flags));
-
-static void fix_new_arm                PARAMS ((fragS *frag, int where, 
-                                        short int size, expressionS *exp,
-                                        int pc_rel, int reloc));
-static int arm_reg_parse       PARAMS ((char **ccp));
-static int arm_psr_parse       PARAMS ((char **ccp));
-static void symbol_locate      PARAMS ((symbolS *, CONST char *, segT,
-                                        valueT, fragS *));
+static void do_arit            PARAMS ((char *, unsigned long));
+static void do_cmp             PARAMS ((char *, unsigned long));
+static void do_mov             PARAMS ((char *, unsigned long));
+static void do_ldst            PARAMS ((char *, unsigned long));
+static void do_ldmstm          PARAMS ((char *, unsigned long));
+static void do_branch          PARAMS ((char *, unsigned long));
+static void do_swi             PARAMS ((char *, unsigned long));
+/* Pseudo Op codes */                                        
+static void do_adr             PARAMS ((char *, unsigned long));
+static void do_adrl            PARAMS ((char *, unsigned long));
+static void do_nop             PARAMS ((char *, unsigned long));
+/* ARM 2 */                                                  
+static void do_mul             PARAMS ((char *, unsigned long));
+static void do_mla             PARAMS ((char *, unsigned long));
+/* ARM 3 */                                                  
+static void do_swap            PARAMS ((char *, unsigned long));
+/* ARM 6 */                                                  
+static void do_msr             PARAMS ((char *, unsigned long));
+static void do_mrs             PARAMS ((char *, unsigned long));
+/* ARM 7M */                                                 
+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));
+static void do_lstc            PARAMS ((char *, unsigned long));
+static void do_co_reg          PARAMS ((char *, unsigned long));
+static void do_fp_ctrl         PARAMS ((char *, unsigned long));
+static void do_fp_ldst         PARAMS ((char *, unsigned long));
+static void do_fp_ldmstm       PARAMS ((char *, unsigned long));
+static void do_fp_dyadic       PARAMS ((char *, unsigned long));
+static void do_fp_monadic      PARAMS ((char *, unsigned long));
+static void do_fp_cmp          PARAMS ((char *, unsigned long));
+static void do_fp_from_reg     PARAMS ((char *, unsigned long));
+static void do_fp_to_reg       PARAMS ((char *, unsigned long));
+
+static void fix_new_arm                PARAMS ((fragS *, int, short, expressionS *, int, int));
+static int arm_reg_parse       PARAMS ((char **));
+static int arm_psr_parse       PARAMS ((char **));
+static void symbol_locate      PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *));
 static int add_to_lit_pool     PARAMS ((void));
-static unsigned validate_immediate     PARAMS ((unsigned));
-static int validate_offset_imm PARAMS ((int, int));
+static unsigned validate_immediate PARAMS ((unsigned));
+static unsigned validate_immediate_twopart PARAMS ((unsigned int, unsigned int *));
+static int validate_offset_imm PARAMS ((unsigned int, int));
 static void opcode_select      PARAMS ((int));
 static void end_of_line                PARAMS ((char *));
 static int reg_required_here   PARAMS ((char **, int));
-static int psr_required_here   PARAMS ((char **, int));
-static int psrf_required_here  PARAMS ((char **, int));
+static int psr_required_here   PARAMS ((char **, int, int));
 static int co_proc_number      PARAMS ((char **));
 static int cp_opc_expr         PARAMS ((char **, int, int));
 static int cp_reg_required_here        PARAMS ((char **, int));
@@ -440,8 +477,7 @@ static int cp_address_required_here PARAMS ((char **));
 static int my_get_float_expression     PARAMS ((char **));
 static int skip_past_comma     PARAMS ((char **));
 static int walk_no_bignums     PARAMS ((symbolS *));
-static int negate_data_op      PARAMS ((unsigned long *,
-                                        unsigned long));
+static int negate_data_op      PARAMS ((unsigned long *, unsigned long));
 static int data_op2            PARAMS ((char **));
 static int fp_op2              PARAMS ((char **));
 static long reg_list           PARAMS ((char **));
@@ -455,7 +491,10 @@ static void thumb_mov_compare      PARAMS ((char *, int));
 static void set_constant_flonums       PARAMS ((void));
 static valueT md_chars_to_number       PARAMS ((char *, int));
 static void insert_reg_alias   PARAMS ((char *, int));
-static void output_inst                PARAMS ((char *));
+static void output_inst                PARAMS ((void));
+#ifdef OBJ_ELF
+static bfd_reloc_code_real_type        arm_parse_reloc PARAMS ((void));
+#endif
 
 /* ARM instructions take 4bytes in the object file, Thumb instructions
    take 2: */
@@ -468,15 +507,20 @@ static void output_inst           PARAMS ((char *));
 
 #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 */
-  CONST struct asm_flg *flags; /* Bits to toggle if flag 'n' set */
-  unsigned long variants;      /* Which CPU variants this exists for */
+  CONST char *           template;     /* Basic string to match */
+  unsigned long          value;                /* Basic instruction code */
+
+  /* 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 */
-  void (*parms) PARAMS ((char *, unsigned long));
+  void (*                parms) PARAMS ((char *, unsigned long));
 };
 
 static CONST struct asm_opcode insns[] = 
@@ -508,6 +552,7 @@ static CONST struct asm_opcode insns[] =
 
 /* Pseudo ops */
   {"adr",   0x028f0000, NULL,   NULL,        ARM_ANY,      do_adr},
+  {"adrl",  0x028f0000, NULL,   NULL,        ARM_ANY,      do_adrl},
   {"nop",   0x01a00000, NULL,   NULL,        ARM_ANY,      do_nop},
 
 /* ARM 2 multiplies */
@@ -519,7 +564,10 @@ static CONST struct asm_opcode insns[] =
 
 /* ARM 6 Coprocessor instructions */
   {"mrs",   0x010f0000, NULL,   NULL,        ARM_6UP,      do_mrs},
-  {"msr",   0x0128f000, NULL,   NULL,        ARM_6UP,      do_msr},
+  {"msr",   0x0120f000, NULL,   NULL,        ARM_6UP,      do_msr},
+/* ScottB: our code uses 0x0128f000 for msr.
+   NickC:  but this is wrong because the bits 16 and 19 are handled
+           by the PSR_xxx defines above.  */
 
 /* ARM 7M long multiplies - need signed/unsigned flags! */
   {"smull", 0x00c00090, NULL,   s_flag,      ARM_LONGMUL,  do_mull},
@@ -595,7 +643,7 @@ static CONST struct asm_opcode insns[] =
 #define PRE_INDEX      0x01000000
 #define INDEX_UP       0x00800000
 #define WRITE_BACK     0x00200000
-#define MULTI_SET_PSR  0x00400000
+#define LDM_TYPE_2_OR_3        0x00400000
 
 #define LITERAL_MASK   0xf000f000
 #define COND_MASK      0xf0000000
@@ -621,30 +669,30 @@ static CONST struct asm_opcode insns[] =
 #define OPCODE_BIC     14
 #define OPCODE_MVN     15
 
-static void do_t_nop           PARAMS ((char *operands));
-static void do_t_arit          PARAMS ((char *operands));
-static void do_t_add           PARAMS ((char *operands));
-static void do_t_asr           PARAMS ((char *operands));
-static void do_t_branch9       PARAMS ((char *operands));
-static void do_t_branch12      PARAMS ((char *operands));
-static void do_t_branch23      PARAMS ((char *operands));
-static void do_t_bx            PARAMS ((char *operands));
-static void do_t_compare       PARAMS ((char *operands));
-static void do_t_ldmstm                PARAMS ((char *operands));
-static void do_t_ldr           PARAMS ((char *operands));
-static void do_t_ldrb          PARAMS ((char *operands));
-static void do_t_ldrh          PARAMS ((char *operands));
-static void do_t_lds           PARAMS ((char *operands));
-static void do_t_lsl           PARAMS ((char *operands));
-static void do_t_lsr           PARAMS ((char *operands));
-static void do_t_mov           PARAMS ((char *operands));
-static void do_t_push_pop      PARAMS ((char *operands));
-static void do_t_str           PARAMS ((char *operands));
-static void do_t_strb          PARAMS ((char *operands));
-static void do_t_strh          PARAMS ((char *operands));
-static void do_t_sub           PARAMS ((char *operands));
-static void do_t_swi           PARAMS ((char *operands));
-static void do_t_adr           PARAMS ((char *operands));
+static void do_t_nop           PARAMS ((char *));
+static void do_t_arit          PARAMS ((char *));
+static void do_t_add           PARAMS ((char *));
+static void do_t_asr           PARAMS ((char *));
+static void do_t_branch9       PARAMS ((char *));
+static void do_t_branch12      PARAMS ((char *));
+static void do_t_branch23      PARAMS ((char *));
+static void do_t_bx            PARAMS ((char *));
+static void do_t_compare       PARAMS ((char *));
+static void do_t_ldmstm                PARAMS ((char *));
+static void do_t_ldr           PARAMS ((char *));
+static void do_t_ldrb          PARAMS ((char *));
+static void do_t_ldrh          PARAMS ((char *));
+static void do_t_lds           PARAMS ((char *));
+static void do_t_lsl           PARAMS ((char *));
+static void do_t_lsr           PARAMS ((char *));
+static void do_t_mov           PARAMS ((char *));
+static void do_t_push_pop      PARAMS ((char *));
+static void do_t_str           PARAMS ((char *));
+static void do_t_strb          PARAMS ((char *));
+static void do_t_strh          PARAMS ((char *));
+static void do_t_sub           PARAMS ((char *));
+static void do_t_swi           PARAMS ((char *));
+static void do_t_adr           PARAMS ((char *));
 
 #define T_OPCODE_MUL 0x4340
 #define T_OPCODE_TST 0x4200
@@ -698,7 +746,7 @@ static void do_t_adr                PARAMS ((char *operands));
 
 #define T_OPCODE_BRANCH 0xe7fe
 
-static int thumb_reg           PARAMS ((char **str, int hi_lo));
+static int thumb_reg           PARAMS ((char ** str, int hi_lo));
 
 #define THUMB_SIZE     2       /* Size of thumb instruction */
 #define THUMB_REG_LO   0x1
@@ -727,78 +775,78 @@ static int thumb_reg              PARAMS ((char **str, int hi_lo));
 
 struct thumb_opcode 
 {
-  CONST char *template;                /* Basic string to match */
+  CONST char *  template;      /* Basic string to match */
   unsigned long value;         /* Basic instruction code */
-  int size;
-  /* Function to call to parse args */
-  void (*parms) PARAMS ((char *));
+  int           size;
+  unsigned long          variants;    /* Which CPU variants this exists for */
+  void (*       parms) PARAMS ((char *));  /* Function to call to parse args */
 };
 
 static CONST struct thumb_opcode tinsns[] =
 {
-  {"adc",      0x4140,         2,      do_t_arit},
-  {"add",      0x0000,         2,      do_t_add},
-  {"and",      0x4000,         2,      do_t_arit},
-  {"asr",      0x0000,         2,      do_t_asr},
-  {"b",                T_OPCODE_BRANCH, 2,     do_t_branch12},
-  {"beq",      0xd0fe,         2,      do_t_branch9},
-  {"bne",      0xd1fe,         2,      do_t_branch9},
-  {"bcs",      0xd2fe,         2,      do_t_branch9},
-  {"bhs",      0xd2fe,         2,      do_t_branch9},
-  {"bcc",      0xd3fe,         2,      do_t_branch9},
-  {"bul",      0xd3fe,         2,      do_t_branch9},
-  {"blo",      0xd3fe,         2,      do_t_branch9},
-  {"bmi",      0xd4fe,         2,      do_t_branch9},
-  {"bpl",      0xd5fe,         2,      do_t_branch9},
-  {"bvs",      0xd6fe,         2,      do_t_branch9},
-  {"bvc",      0xd7fe,         2,      do_t_branch9},
-  {"bhi",      0xd8fe,         2,      do_t_branch9},
-  {"bls",      0xd9fe,         2,      do_t_branch9},
-  {"bge",      0xdafe,         2,      do_t_branch9},
-  {"blt",      0xdbfe,         2,      do_t_branch9},
-  {"bgt",      0xdcfe,         2,      do_t_branch9},
-  {"ble",      0xddfe,         2,      do_t_branch9},
-  {"bic",      0x4380,         2,      do_t_arit},
-  {"bl",       0xf7fffffe,     4,      do_t_branch23},
-  {"bx",       0x4700,         2,      do_t_bx},
-  {"cmn",      T_OPCODE_CMN,   2,      do_t_arit},
-  {"cmp",      0x0000,         2,      do_t_compare},
-  {"eor",      0x4040,         2,      do_t_arit},
-  {"ldmia",    0xc800,         2,      do_t_ldmstm},
-  {"ldr",      0x0000,         2,      do_t_ldr},
-  {"ldrb",     0x0000,         2,      do_t_ldrb},
-  {"ldrh",     0x0000,         2,      do_t_ldrh},
-  {"ldrsb",    0x5600,         2,      do_t_lds},
-  {"ldrsh",    0x5e00,         2,      do_t_lds},
-  {"ldsb",     0x5600,         2,      do_t_lds},
-  {"ldsh",     0x5e00,         2,      do_t_lds},
-  {"lsl",      0x0000,         2,      do_t_lsl},
-  {"lsr",      0x0000,         2,      do_t_lsr},
-  {"mov",      0x0000,         2,      do_t_mov},
-  {"mul",      T_OPCODE_MUL,   2,      do_t_arit},
-  {"mvn",      T_OPCODE_MVN,   2,      do_t_arit},
-  {"neg",      T_OPCODE_NEG,   2,      do_t_arit},
-  {"orr",      0x4300,         2,      do_t_arit},
-  {"pop",      0xbc00,         2,      do_t_push_pop},
-  {"push",     0xb400,         2,      do_t_push_pop},
-  {"ror",      0x41c0,         2,      do_t_arit},
-  {"sbc",      0x4180,         2,      do_t_arit},
-  {"stmia",    0xc000,         2,      do_t_ldmstm},
-  {"str",      0x0000,         2,      do_t_str},
-  {"strb",     0x0000,         2,      do_t_strb},
-  {"strh",     0x0000,         2,      do_t_strh},
-  {"swi",      0xdf00,         2,      do_t_swi},
-  {"sub",      0x0000,         2,      do_t_sub},
-  {"tst",      T_OPCODE_TST,   2,      do_t_arit},
+  {"adc",      0x4140,         2,      ARM_THUMB, do_t_arit},
+  {"add",      0x0000,         2,      ARM_THUMB, do_t_add},
+  {"and",      0x4000,         2,      ARM_THUMB, do_t_arit},
+  {"asr",      0x0000,         2,      ARM_THUMB, do_t_asr},
+  {"b",                T_OPCODE_BRANCH, 2,     ARM_THUMB, do_t_branch12},
+  {"beq",      0xd0fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bne",      0xd1fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bcs",      0xd2fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bhs",      0xd2fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bcc",      0xd3fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bul",      0xd3fe,         2,      ARM_THUMB, do_t_branch9},
+  {"blo",      0xd3fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bmi",      0xd4fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bpl",      0xd5fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bvs",      0xd6fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bvc",      0xd7fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bhi",      0xd8fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bls",      0xd9fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bge",      0xdafe,         2,      ARM_THUMB, do_t_branch9},
+  {"blt",      0xdbfe,         2,      ARM_THUMB, do_t_branch9},
+  {"bgt",      0xdcfe,         2,      ARM_THUMB, do_t_branch9},
+  {"ble",      0xddfe,         2,      ARM_THUMB, do_t_branch9},
+  {"bic",      0x4380,         2,      ARM_THUMB, do_t_arit},
+  {"bl",       0xf7fffffe,     4,      ARM_THUMB, do_t_branch23},
+  {"bx",       0x4700,         2,      ARM_THUMB, do_t_bx},
+  {"cmn",      T_OPCODE_CMN,   2,      ARM_THUMB, do_t_arit},
+  {"cmp",      0x0000,         2,      ARM_THUMB, do_t_compare},
+  {"eor",      0x4040,         2,      ARM_THUMB, do_t_arit},
+  {"ldmia",    0xc800,         2,      ARM_THUMB, do_t_ldmstm},
+  {"ldr",      0x0000,         2,      ARM_THUMB, do_t_ldr},
+  {"ldrb",     0x0000,         2,      ARM_THUMB, do_t_ldrb},
+  {"ldrh",     0x0000,         2,      ARM_THUMB, do_t_ldrh},
+  {"ldrsb",    0x5600,         2,      ARM_THUMB, do_t_lds},
+  {"ldrsh",    0x5e00,         2,      ARM_THUMB, do_t_lds},
+  {"ldsb",     0x5600,         2,      ARM_THUMB, do_t_lds},
+  {"ldsh",     0x5e00,         2,      ARM_THUMB, do_t_lds},
+  {"lsl",      0x0000,         2,      ARM_THUMB, do_t_lsl},
+  {"lsr",      0x0000,         2,      ARM_THUMB, do_t_lsr},
+  {"mov",      0x0000,         2,      ARM_THUMB, do_t_mov},
+  {"mul",      T_OPCODE_MUL,   2,      ARM_THUMB, do_t_arit},
+  {"mvn",      T_OPCODE_MVN,   2,      ARM_THUMB, do_t_arit},
+  {"neg",      T_OPCODE_NEG,   2,      ARM_THUMB, do_t_arit},
+  {"orr",      0x4300,         2,      ARM_THUMB, do_t_arit},
+  {"pop",      0xbc00,         2,      ARM_THUMB, do_t_push_pop},
+  {"push",     0xb400,         2,      ARM_THUMB, do_t_push_pop},
+  {"ror",      0x41c0,         2,      ARM_THUMB, do_t_arit},
+  {"sbc",      0x4180,         2,      ARM_THUMB, do_t_arit},
+  {"stmia",    0xc000,         2,      ARM_THUMB, do_t_ldmstm},
+  {"str",      0x0000,         2,      ARM_THUMB, do_t_str},
+  {"strb",     0x0000,         2,      ARM_THUMB, do_t_strb},
+  {"strh",     0x0000,         2,      ARM_THUMB, do_t_strh},
+  {"swi",      0xdf00,         2,      ARM_THUMB, do_t_swi},
+  {"sub",      0x0000,         2,      ARM_THUMB, do_t_sub},
+  {"tst",      T_OPCODE_TST,   2,      ARM_THUMB, do_t_arit},
   /* Pseudo ops: */
-  {"adr",       0x0000,         2,      do_t_adr},
-  {"nop",       0x46C0,         2,      do_t_nop},      /* mov r8,r8 */
+  {"adr",       0x0000,         2,      ARM_THUMB, do_t_adr},
+  {"nop",       0x46C0,         2,      ARM_THUMB, do_t_nop},      /* mov r8,r8 */
 };
 
 struct reg_entry
 {
-  CONST char *name;
-  int number;
+  CONST char * name;
+  int          number;
 };
 
 #define int_register(reg) ((reg) >= 0 && (reg) <= 15)
@@ -809,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},
@@ -833,18 +883,27 @@ 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}
 };
 
-static CONST char *bad_args = "Bad arguments to instruction";
-static CONST char *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;
-static struct hash_control *arm_cond_hsh = NULL;
-static struct hash_control *arm_shift_hsh = NULL;
-static struct hash_control *arm_reg_hsh = NULL;
-static struct hash_control *arm_psr_hsh = NULL;
+static struct hash_control * arm_ops_hsh = NULL;
+static struct hash_control * arm_tops_hsh = NULL;
+static struct hash_control * arm_cond_hsh = NULL;
+static struct hash_control * arm_shift_hsh = NULL;
+static struct hash_control * arm_reg_hsh = NULL;
+static struct hash_control * arm_psr_hsh = NULL;
 
 /* This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
@@ -863,27 +922,47 @@ 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 void s_thumb_set PARAMS ((int));
+static void arm_s_text PARAMS ((int));
+static void arm_s_data PARAMS ((int));
+#ifdef OBJ_ELF
+static void arm_s_section PARAMS ((int));
+static void s_arm_elf_cons PARAMS ((int));
+#endif
 
 static int my_get_expression PARAMS ((expressionS *, char **));
 
 CONST pseudo_typeS md_pseudo_table[] =
 {
-  {"req", s_req, 0},   /* Never called becasue '.req' does not start line */
-  {"bss", s_bss, 0},
-  {"align", s_align, 0},
-  {"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},
-  {"word", cons, 4},
-  {"extend", float_cons, 'x'},
-  {"ldouble", float_cons, 'x'},
-  {"packed", float_cons, 'p'},
-  {0, 0, 0}
+  { "req",         s_req,         0 }, /* Never called becasue '.req' does not start line */
+  { "bss",         s_bss,         0 },
+  { "align",       s_align,       0 },
+  { "arm",         s_arm,         0 },
+  { "thumb",       s_thumb,       0 },
+  { "code",        s_code,        0 },
+  { "force_thumb", s_force_thumb, 0 },
+  { "thumb_func",  s_thumb_func,  0 },
+  { "thumb_set",   s_thumb_set,   0 },
+  { "even",        s_even,        0 },
+  { "ltorg",       s_ltorg,       0 },
+  { "pool",        s_ltorg,       0 },
+  /* Allow for the effect of section changes.  */
+  { "text",        arm_s_text,    0 },
+  { "data",        arm_s_data,    0 },
+#ifdef OBJ_ELF  
+  { "section",     arm_s_section, 0 },
+  { "section.s",   arm_s_section, 0 },
+  { "sect",        arm_s_section, 0 },
+  { "sect.s",      arm_s_section, 0 },
+  { "word",        s_arm_elf_cons, 4 },
+  { "long",        s_arm_elf_cons, 4 },
+#else
+  { "word",        cons, 4},
+#endif
+  { "extend",      float_cons, 'x' },
+  { "ldouble",     float_cons, 'x' },
+  { "packed",      float_cons, 'p' },
+  { 0, 0, 0 }
 };
 
 /* Stuff needed to resolve the label ambiguity
@@ -906,14 +985,13 @@ static int label_is_thumb_function_name = false;
 typedef struct literalS
 {
   struct expressionS  exp;
-  struct arm_it      *inst;
+  struct arm_it *     inst;
 } literalT;
 
-literalT literals[MAX_LITERAL_POOL_SIZE];
-int next_literal_pool_place = 0; /* Next free entry in the pool */
-int lit_pool_num = 1; /* Next literal pool number */
-symbolS *current_poolP = NULL;
-symbolS *symbol_make_empty PARAMS ((void)); 
+literalT  literals[MAX_LITERAL_POOL_SIZE];
+int       next_literal_pool_place = 0; /* Next free entry in the pool */
+int       lit_pool_num = 1; /* Next literal pool number */
+symbolS * current_poolP = NULL;
 
 static int
 add_to_lit_pool ()
@@ -921,7 +999,8 @@ add_to_lit_pool ()
   int lit_count = 0;
 
   if (current_poolP == NULL)
-    current_poolP = symbol_make_empty();
+    current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section,
+                                  (valueT) 0, &zero_address_frag);
 
   /* Check if this literal value is already in the pool: */
   while (lit_count < next_literal_pool_place)
@@ -938,7 +1017,7 @@ add_to_lit_pool ()
     {
       if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE)
         {
-          inst.error = "Literal Pool Overflow";
+          inst.error = _("Literal Pool Overflow");
           return FAIL;
         }
 
@@ -947,24 +1026,24 @@ add_to_lit_pool ()
     }
 
   inst.reloc.exp.X_op = O_symbol;
-  inst.reloc.exp.X_add_number = (lit_count)*4-8;
+  inst.reloc.exp.X_add_number = (lit_count) * 4 - 8;
   inst.reloc.exp.X_add_symbol = current_poolP;
 
   return SUCCESS;
 }
  
 /* Can't use symbol_new here, so have to create a symbol and then at
-   a later date assign it a value. Thats what these functions do */
+   a later date assign it a value. Thats what these functions do */
 static void
 symbol_locate (symbolP, name, segment, valu, frag)
-     symbolS *symbolP; 
-     CONST char *name;         /* It is copied, the caller can modify */
-     segT segment;             /* Segment identifier (SEG_<something>) */
-     valueT valu;              /* Symbol value */
-     fragS *frag;              /* Associated fragment */
+     symbolS *    symbolP; 
+     CONST char * name;                /* It is copied, the caller can modify */
+     segT         segment;     /* Segment identifier (SEG_<something>) */
+     valueT       valu;                /* Symbol value */
+     fragS *      frag;                /* Associated fragment */
 {
   unsigned int name_length;
-  char *preserved_copy_of_name;
+  char * preserved_copy_of_name;
 
   name_length = strlen (name) + 1;      /* +1 for \0 */
   obstack_grow (&notes, name, name_length);
@@ -985,18 +1064,16 @@ symbol_locate (symbolP, name, segment, valu, frag)
   S_SET_VALUE (symbolP, valu);
   symbol_clear_list_pointers(symbolP);
 
-  symbolP->sy_frag = frag;
+  symbol_set_frag (symbolP, frag);
 
-  /*
-   * Link to end of symbol chain.
-   */
+  /* Link to end of symbol chain.  */
   {
     extern int symbol_table_frozen;
     if (symbol_table_frozen)
       abort ();
   }
 
-  symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP);
+  symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
 
   obj_symbol_new_hook (symbolP);
 
@@ -1005,51 +1082,75 @@ symbol_locate (symbolP, name, segment, valu, frag)
 #endif
  
 #ifdef DEBUG_SYMS
-  verify_symbol_chain(symbol_rootP, symbol_lastP);
+  verify_symbol_chain (symbol_rootP, symbol_lastP);
 #endif /* DEBUG_SYMS */
 }
 
-symbolS *
-symbol_make_empty () 
-{
-  symbolS *symbolP; 
-
-  symbolP = (symbolS *) obstack_alloc (&notes, sizeof (symbolS));
-
-  /* symbol must be born in some fixed state.  This seems as good as any. */
-  memset (symbolP, 0, sizeof (symbolS));
-
-  symbolP->bsym = bfd_make_empty_symbol (stdoutput);
-  assert (symbolP->bsym != 0);
-  symbolP->bsym->udata.p = (PTR) symbolP;
+/* Check that an immediate is valid, and if so, convert it to the right format.  */
 
-  return symbolP;
+static unsigned int
+validate_immediate (val)
+     unsigned int val;
+{
+  unsigned int a;
+  unsigned int i;
+  
+#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;
 }
 
-/* Check that an immediate is valid, and if so, convert it to the right format.  */
+/* Check to see if an immediate can be computed as two seperate immediate
+   values, added together.  We already know that this value cannot be
+   computed by just one ARM instruction.  */
 
 static unsigned int
-validate_immediate (val)
+validate_immediate_twopart (val, highpart)
      unsigned int val;
+     unsigned int * highpart;
 {
-    unsigned int a;
-    unsigned int i;
+  unsigned int a;
+  unsigned int i;
+  
+  for (i = 0; i < 32; i += 2)
+    if (((a = rotate_left (val, i)) & 0xff) != 0)
+      {
+       if (a & 0xff00)
+         {
+           if (a & ~ 0xffff)
+             continue;
+           * highpart = (a  >> 8) | ((i + 24) << 7);
+         }
+       else if (a & 0xff0000)
+         {
+           if (a & 0xff000000)
+             continue;
 
-#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;
+           * highpart = (a >> 16) | ((i + 16) << 7);
+         }
+       else
+         {
+           assert (a & 0xff000000);
+
+           * highpart = (a >> 24) | ((i + 8) << 7);
+         }
+
+       return (a & 0xff) | (i << 7);
+      }
+  
+  return FAIL;
 }
 
 static int
 validate_offset_imm (val, hwse)
-     int val;
+     unsigned int val;
      int hwse;
 {
-  if ((hwse && (val < -255 || val > 255))
-      || (val < -4095 || val > 4095))
+  if ((hwse && val > 255) || val > 4095)
      return FAIL;
   return val;
 }
@@ -1059,7 +1160,7 @@ static void
 s_req (a)
      int a;
 {
-  as_bad ("Invalid syntax for .req directive.");
+  as_bad (_("Invalid syntax for .req directive."));
 }
 
 static void
@@ -1078,24 +1179,21 @@ s_even (ignore)
 {
   if (!need_pass_2)            /* Never make frag if expect extra pass. */
     frag_align (1, 0, 0);
+  
   record_alignment (now_seg, 1);
+  
   demand_empty_rest_of_line ();
 }
 
 static void
-s_ltorg (internal)
-     int internal;
+s_ltorg (ignored)
+     int ignored;
 {
   int lit_count = 0;
   char sym_name[20];
 
   if (current_poolP == NULL)
-    {
-      /* Nothing to do */
-      if (!internal)
-       as_tsktsk ("Nothing to put in the pool\n");
-      return;
-    }
+    return;
 
   /* Align pool as you have word accesses */
   /* Only make a frag if we have to ... */
@@ -1104,9 +1202,6 @@ s_ltorg (internal)
 
   record_alignment (now_seg, 2);
 
-  if (internal)
-    as_tsktsk ("Inserting implicit pool at change of section");
-
   sprintf (sym_name, "$$lit_\002%x", lit_pool_num++);
 
   symbol_locate (current_poolP, sym_name, now_seg,
@@ -1114,7 +1209,10 @@ s_ltorg (internal)
   symbol_table_insert (current_poolP);
 
   ARM_SET_THUMB (current_poolP, thumb_mode);
+  
+#if defined OBJ_COFF || defined OBJ_ELF
   ARM_SET_INTERWORK (current_poolP, support_interwork);
+#endif
   
   while (lit_count < next_literal_pool_place)
     /* First output the expression in the instruction to the pool */
@@ -1124,20 +1222,6 @@ s_ltorg (internal)
   current_poolP = NULL;
 }
 
-#if 0 /* not used */
-static void
-arm_align (power, fill)
-     int power;
-     int fill;
-{
-  /* Only make a frag if we HAVE to ... */
-  if (power && !need_pass_2)
-    frag_align (power, fill, 0);
-
-  record_alignment (now_seg, power);
-}
-#endif
-
 static void
 s_align (unused)       /* Same as s_align_ptwo but align 0 => align 2 */
      int unused;
@@ -1148,10 +1232,10 @@ s_align (unused)        /* Same as s_align_ptwo but align 0 => align 2 */
 
   temp = get_absolute_expression ();
   if (temp > max_alignment)
-    as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
+    as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment);
   else if (temp < 0)
     {
-      as_bad ("Alignment negative. 0 assumed.");
+      as_bad (_("Alignment negative. 0 assumed."));
       temp = 0;
     }
 
@@ -1186,7 +1270,7 @@ s_force_thumb (ignore)
      
   if (! thumb_mode)
     {
-      thumb_mode = 1;
+      thumb_mode = 2;
       
       record_alignment (now_seg, 1);
     }
@@ -1203,8 +1287,147 @@ s_thumb_func (ignore)
 
   label_is_thumb_function_name = true;
   
-  demand_empty_rest_of_line();
+  demand_empty_rest_of_line ();
+}
+
+/* Perform a .set directive, but also mark the alias as
+   being a thumb function.  */
+
+static void
+s_thumb_set (equiv)
+     int equiv;
+{
+  /* XXX the following is a duplicate of the code for s_set() in read.c
+     We cannot just call that code as we need to get at the symbol that
+     is created.  */
+  register char *    name;
+  register char      delim;
+  register char *    end_name;
+  register symbolS * symbolP;
+
+  /*
+   * Especial apologies for the random logic:
+   * this just grew, and could be parsed much more simply!
+   * Dean in haste.
+   */
+  name      = input_line_pointer;
+  delim     = get_symbol_end ();
+  end_name  = input_line_pointer;
+  *end_name = delim;
+  
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer != ',')
+    {
+      *end_name = 0;
+      as_bad (_("Expected comma after name \"%s\""), name);
+      *end_name = delim;
+      ignore_rest_of_line ();
+      return;
+    }
+
+  input_line_pointer++;
+  *end_name = 0;
+
+  if (name[0] == '.' && name[1] == '\0')
+    {
+      /* XXX - this should not happen to .thumb_set  */
+      abort ();
+    }
+
+  if ((symbolP = symbol_find (name)) == NULL
+      && (symbolP = md_undefined_symbol (name)) == NULL)
+    {
+#ifndef NO_LISTING
+      /* When doing symbol listings, play games with dummy fragments living
+        outside the normal fragment chain to record the file and line info
+         for this symbol.  */
+      if (listing & LISTING_SYMBOLS)
+       {
+         extern struct list_info_struct * listing_tail;
+         fragS * dummy_frag = (fragS *) xmalloc (sizeof(fragS));
+         memset (dummy_frag, 0, sizeof(fragS));
+         dummy_frag->fr_type = rs_fill;
+         dummy_frag->line = listing_tail;
+         symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
+         dummy_frag->fr_symbol = symbolP;
+       }
+      else
+#endif
+        symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
+                           
+#ifdef OBJ_COFF
+      /* "set" symbols are local unless otherwise specified. */
+      SF_SET_LOCAL (symbolP);
+#endif /* OBJ_COFF */
+    }                          /* make a new symbol */
+
+  symbol_table_insert (symbolP);
+
+  * end_name = delim;
+
+  if (equiv
+      && S_IS_DEFINED (symbolP)
+      && S_GET_SEGMENT (symbolP) != reg_section)
+    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
+
+  pseudo_set (symbolP);
+  
+  demand_empty_rest_of_line ();
+
+  /* XXX Now we come to the Thumb specific bit of code.  */
+  
+  THUMB_SET_FUNC (symbolP, 1);
+  ARM_SET_THUMB (symbolP, 1);
+#if defined OBJ_ELF || defined OBJ_COFF
+  ARM_SET_INTERWORK (symbolP, support_interwork);
+#endif
+}
+
+/* If we change section we must dump the literal pool first.  */
+static void
+arm_s_text (ignore)
+     int ignore;
+{
+  if (now_seg != text_section)
+    s_ltorg (0);
+  
+#ifdef OBJ_ELF
+  obj_elf_text (ignore);
+#else
+  s_text (ignore);
+#endif
+}
+
+static void
+arm_s_data (ignore)
+     int ignore;
+{
+  if (flag_readonly_data_in_text)
+    {
+      if (now_seg != text_section)
+       s_ltorg (0);
+    }
+  else if (now_seg != data_section)
+    s_ltorg (0);
+  
+#ifdef OBJ_ELF
+  obj_elf_data (ignore);
+#else
+  s_data (ignore);
+#endif
+}
+
+#ifdef OBJ_ELF
+static void
+arm_s_section (ignore)
+     int ignore;
+{
+  s_ltorg (0);
+
+  obj_elf_section (ignore);
 }
+#endif
 
 static void
 opcode_select (width)
@@ -1216,7 +1439,7 @@ opcode_select (width)
       if (! thumb_mode)
        {
          if (! (cpu_variant & ARM_THUMB))
-           as_bad ("selected processor does not support THUMB opcodes");
+           as_bad (_("selected processor does not support THUMB opcodes"));
          thumb_mode = 1;
           /* No need to force the alignment, since we will have been
              coming from ARM mode, which is word-aligned. */
@@ -1228,7 +1451,7 @@ opcode_select (width)
       if (thumb_mode)
        {
           if ((cpu_variant & ARM_ANY) == ARM_THUMB)
-           as_bad ("selected processor does not support ARM opcodes");
+           as_bad (_("selected processor does not support ARM opcodes"));
          thumb_mode = 0;
           if (!need_pass_2)
             frag_align (2, 0, 0);
@@ -1237,7 +1460,7 @@ opcode_select (width)
       break;
 
     default:
-      as_bad ("invalid instruction size selected (%d)", width);
+      as_bad (_("invalid instruction size selected (%d)"), width);
     }
 }
 
@@ -1268,28 +1491,27 @@ s_code (unused)
     {
     case 16:
     case 32:
-      opcode_select(temp);
+      opcode_select (temp);
       break;
 
     default:
-      as_bad ("invalid operand to .code directive (%d) (expecting 16 or 32)", temp);
+      as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
     }
 }
 
 static void
 end_of_line (str)
-     char *str;
+     char * str;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
-  if (*str != '\0')
-    inst.error = "Garbage following instruction";
+  if (* str != '\0')
+    inst.error = _("Garbage following instruction");
 }
 
 static int
 skip_past_comma (str)
-     char **str;
+     char ** str;
 {
   char *p = *str, c;
   int comma = 0;
@@ -1308,74 +1530,59 @@ skip_past_comma (str)
   return comma ? SUCCESS : FAIL;
 }
 
-/* A standard register must be given at this point.  Shift is the place to
-   put it in the instruction. */
+/* A standard register must be given at this point.
+   Shift is the place to put it in inst.instruction.
+   Restores input start point on err.
+   Returns the reg#, or FAIL. */
 
 static int
 reg_required_here (str, shift)
-     char **str;
-     int shift;
+     char ** str;
+     int     shift;
 {
-  int reg;
-  char *start = *str;
+  static char buff [128]; /* XXX */
+  int    reg;
+  char * start = *str;
 
   if ((reg = arm_reg_parse (str)) != FAIL && int_register (reg))
     {
-      inst.instruction |= reg << shift;
+      if (shift >= 0)
+       inst.instruction |= reg << shift;
       return reg;
     }
 
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden */
-  inst.error = "Register expected";
-
   /* Restore the start point, we may have got a reg of the wrong class.  */
   *str = start;
-  return FAIL;
-}
-
-static int
-psr_required_here (str, shift)
-     char **str;
-     int shift;
-{
-  int psr;
-  char *start = *str;
-
-  if  ((psr = arm_psr_parse (str)) != FAIL && psr < 2)
-    {
-      if (psr == 1)
-       inst.instruction |= 1 << shift; /* Should be bit 22 */
-      return psr;
-    }
-
+  
   /* In the few cases where we might be able to accept something else
-     this error can be overridden */
-  inst.error = "<psr> expected";
+     this error can be overridden.  */
+  sprintf (buff, _("Register expected, not '%.100s'"), start);
+  inst.error = buff;
 
-  /* Restore the start point.  */
-  *str = start;
   return FAIL;
 }
 
 static int
-psrf_required_here (str, shift)
-     char **str;
-     int shift;
-{
-  int psrf;
-  char *start = *str;
-
-  if  ((psrf = arm_psr_parse (str)) != FAIL && psrf > 1)
+psr_required_here (str, cpsr, spsr)
+     char ** str;
+     int     cpsr;
+     int     spsr;
+{
+  int    psr;
+  char * start = *str;
+  psr = arm_psr_parse (str);
+  
+  if  (psr == cpsr || psr == spsr)
     {
-      if (psrf == 1 || psrf == 3)
-       inst.instruction |= 1 << shift; /* Should be bit 22 */
-      return psrf;
+      if (psr == spsr)
+       inst.instruction |= 1 << 22;
+      
+      return SUCCESS;
     }
 
   /* In the few cases where we might be able to accept something else
-     this error can be overridden */
-  inst.error = "<psrf> expected";
+     this error can be overridden */
+  inst.error = _("<psr(f)> expected");
 
   /* Restore the start point.  */
   *str = start;
@@ -1384,12 +1591,11 @@ psrf_required_here (str, shift)
 
 static int
 co_proc_number (str)
-     char **str;
+     char ** str;
 {
   int processor, pchar;
 
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
 
   /* The data sheet seems to imply that just a number on its own is valid
      here, but the RISC iX assembler seems to accept a prefix 'p'.  We will
@@ -1406,14 +1612,14 @@ co_proc_number (str)
          processor = processor * 10 + *(*str)++ - '0';
          if (processor > 15)
            {
-             inst.error = "Illegal co-processor number";
+             inst.error = _("Illegal co-processor number");
              return FAIL;
            }
        }
     }
   else
     {
-      inst.error = "Bad or missing co-processor number";
+      inst.error = _("Bad or missing co-processor number");
       return FAIL;
     }
 
@@ -1423,14 +1629,13 @@ co_proc_number (str)
 
 static int
 cp_opc_expr (str, where, length)
-     char **str;
+     char ** str;
      int where;
      int length;
 {
   expressionS expr;
 
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
 
   memset (&expr, '\0', sizeof (expr));
 
@@ -1438,13 +1643,13 @@ cp_opc_expr (str, where, length)
     return FAIL;
   if (expr.X_op != O_constant)
     {
-      inst.error = "bad or missing expression";
+      inst.error = _("bad or missing expression");
       return FAIL;
     }
 
   if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number)
     {
-      inst.error = "immediate co-processor expression too large";
+      inst.error = _("immediate co-processor expression too large");
       return FAIL;
     }
 
@@ -1454,11 +1659,11 @@ cp_opc_expr (str, where, length)
 
 static int
 cp_reg_required_here (str, where)
-     char **str;
-     int where;
+     char ** str;
+     int     where;
 {
-  int reg;
-  char *start = *str;
+  int    reg;
+  char * start = *str;
 
   if ((reg = arm_reg_parse (str)) != FAIL && cp_register (reg))
     {
@@ -1468,21 +1673,21 @@ cp_reg_required_here (str, where)
     }
 
   /* In the few cases where we might be able to accept something else
-     this error can be overridden */
-  inst.error = "Co-processor register expected";
+     this error can be overridden */
+  inst.error = _("Co-processor register expected");
 
-  /* Restore the start point */
+  /* Restore the start point */
   *str = start;
   return FAIL;
 }
 
 static int
 fp_reg_required_here (str, where)
-     char **str;
-     int where;
+     char ** str;
+     int     where;
 {
   int reg;
-  char *start = *str;
+  char * start = *str;
 
   if ((reg = arm_reg_parse (str)) != FAIL && fp_register (reg))
     {
@@ -1492,44 +1697,46 @@ fp_reg_required_here (str, where)
     }
 
   /* In the few cases where we might be able to accept something else
-     this error can be overridden */
-  inst.error = "Floating point register expected";
+     this error can be overridden */
+  inst.error = _("Floating point register expected");
 
-  /* Restore the start point */
+  /* Restore the start point */
   *str = start;
   return FAIL;
 }
 
 static int
 cp_address_offset (str)
-     char **str;
+     char ** str;
 {
   int offset;
 
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
 
-  if (**str != '#')
+  if (! is_immediate_prefix (**str))
     {
-      inst.error = "immediate expression expected";
+      inst.error = _("immediate expression expected");
       return FAIL;
     }
 
   (*str)++;
-  if (my_get_expression (&inst.reloc.exp, str))
+  
+  if (my_get_expression (& inst.reloc.exp, str))
     return FAIL;
+  
   if (inst.reloc.exp.X_op == O_constant)
     {
       offset = inst.reloc.exp.X_add_number;
+      
       if (offset & 3)
        {
-         inst.error = "co-processor address must be word aligned";
+         inst.error = _("co-processor address must be word aligned");
          return FAIL;
        }
 
       if (offset > 1023 || offset < -1023)
        {
-         inst.error = "offset too large";
+         inst.error = _("offset too large");
          return FAIL;
        }
 
@@ -1548,43 +1755,40 @@ cp_address_offset (str)
 
 static int
 cp_address_required_here (str)
-     char **str;
+     char ** str;
 {
-  char *p = *str;
-  int pre_inc = 0;
-  int write_back = 0;
+  char * p = * str;
+  int    pre_inc = 0;
+  int    write_back = 0;
 
   if (*p == '[')
     {
       int reg;
 
       p++;
-      while (*p == ' ')
-       p++;
+      skip_whitespace (p);
 
-      if ((reg = reg_required_here (&p, 16)) == FAIL)
-       {
-         inst.error = "Register required";
-         return FAIL;
-       }
+      if ((reg = reg_required_here (& p, 16)) == FAIL)
+       return FAIL;
 
-      while (*p == ' ')
-       p++;
+      skip_whitespace (p);
 
       if (*p == ']')
        {
          p++;
-         if (skip_past_comma (&p) == SUCCESS)
+         
+         if (skip_past_comma (& p) == SUCCESS)
            {
              /* [Rn], #expr */
              write_back = WRITE_BACK;
+             
              if (reg == REG_PC)
                {
-                 inst.error = "pc may not be used in post-increment";
+                 inst.error = _("pc may not be used in post-increment");
                  return FAIL;
                }
 
-             if (cp_address_offset (&p) == FAIL)
+             if (cp_address_offset (& p) == FAIL)
                return FAIL;
            }
          else
@@ -1594,33 +1798,32 @@ cp_address_required_here (str)
        {
          /* '['Rn, #expr']'[!] */
 
-         if (skip_past_comma (&p) == FAIL)
+         if (skip_past_comma (& p) == FAIL)
            {
-             inst.error = "pre-indexed expression expected";
+             inst.error = _("pre-indexed expression expected");
              return FAIL;
            }
 
          pre_inc = PRE_INDEX;
-         if (cp_address_offset (&p) == FAIL)
+         
+         if (cp_address_offset (& p) == FAIL)
            return FAIL;
 
-         while (*p == ' ')
-           p++;
+         skip_whitespace (p);
 
          if (*p++ != ']')
            {
-             inst.error = "missing ]";
+             inst.error = _("missing ]");
              return FAIL;
            }
 
-         while (*p == ' ')
-           p++;
+         skip_whitespace (p);
 
          if (*p == '!')
            {
              if (reg == REG_PC)
                {
-                 inst.error = "pc may not be used with write-back";
+                 inst.error = _("pc may not be used with write-back");
                  return FAIL;
                }
 
@@ -1648,11 +1851,11 @@ cp_address_required_here (str)
 
 static void
 do_nop (str, flags)
-     char *str;
+     char * str;
      unsigned long flags;
 {
-  /* Do nothing really */
-  inst.instruction |= flags; /* This is pointless */
+  /* Do nothing really */
+  inst.instruction |= flags; /* This is pointless */
   end_of_line (str);
   return;
 }
@@ -1662,20 +1865,19 @@ do_mrs (str, flags)
      char *str;
      unsigned long flags;
 {
-  /* Only one syntax */
-  while (*str == ' ')
-    str++;
+  /* Only one syntax.  */
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
-      || psr_required_here (&str, 22) == FAIL)
+      || psr_required_here (& str, CPSR_ALL, SPSR_ALL) == FAIL)
     {
-      inst.error = "<psr> expected";
+      inst.error = _("<psr> expected");
       return;
     }
 
@@ -1684,45 +1886,59 @@ do_mrs (str, flags)
   return;
 }
 
+/* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression".  */
 static void
 do_msr (str, flags)
-     char *str;
+     char * str;
      unsigned long flags;
 {
-  int psr, psrf, reg;
-  /* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression" */
+  int reg;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
-  if ((psr = psr_required_here (&str, 22)) != FAIL)
+  if (psr_required_here (&str, CPSR_ALL, SPSR_ALL) == SUCCESS)
     {
       inst.instruction |= PSR_ALL;
+
       /* Sytax should be "<psr>, Rm" */
       if (skip_past_comma (&str) == FAIL
          || (reg = reg_required_here (&str, 0)) == FAIL)
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
     }
-  else if ((psrf = psrf_required_here (&str, 22)) != FAIL)
-    /* Syntax could be "<psrf>, rm", "<psrf>, #expression" */
+  else
     {
+      if (psr_required_here (& str, CPSR_FLG, SPSR_FLG) == SUCCESS)
+       inst.instruction |= PSR_FLAGS;
+      else if (psr_required_here (& str, CPSR_CTL, SPSR_CTL) == SUCCESS)
+       inst.instruction |= PSR_CONTROL;
+      else
+       {
+         inst.error = BAD_ARGS;
+         return;
+       }
+      
       if (skip_past_comma (&str) == FAIL)
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
-      if ((reg = reg_required_here (&str, 0)) != FAIL)
+      
+      /* Syntax could be "<psrf>, rm", "<psrf>, #expression" */
+      
+      if ((reg = reg_required_here (& str, 0)) != FAIL)
        ;
-      /* Immediate expression */
-      else if (*(str++) == '#')
+      /* Immediate expression */
+      else if (is_immediate_prefix (* str))
        {
+         str ++;
          inst.error = NULL;
-         if (my_get_expression (&inst.reloc.exp, &str))
+         
+         if (my_get_expression (& inst.reloc.exp, & str))
            {
-             inst.error = "Register or shift expression expected";
+             inst.error = _("Register or shift expression expected");
              return;
            }
 
@@ -1736,7 +1952,7 @@ do_msr (str, flags)
              unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
              if (value == FAIL)
                {
-                 inst.error = "Invalid constant";
+                 inst.error = _("Invalid constant");
                  return;
                }
 
@@ -1747,16 +1963,11 @@ do_msr (str, flags)
        }
       else
        {
-         inst.error = "Error: the other";
+         inst.error = _("Error: unrecognised syntax for second argument to msr instruction");
          return;
        }
     }
-  else
-    {
-      inst.error = bad_args;
-      return;
-    }
-     
+
   inst.error = NULL; 
   inst.instruction |= flags;
   end_of_line (str);
@@ -1771,49 +1982,48 @@ do_msr (str, flags)
 */   
 static void
 do_mull (str, flags)
-     char *str;
+     char * str;
      unsigned long flags;
 {
   int rdlo, rdhi, rm, rs;
 
-  /* only one format "rdlo, rdhi, rm, rs" */
-  while (*str == ' ')
-    str++;
+  /* Only one format "rdlo, rdhi, rm, rs" */
+  skip_whitespace (str);
 
   if ((rdlo = reg_required_here (&str, 12)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || (rdhi = reg_required_here (&str, 16)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 0)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   /* rdhi, rdlo and rm must all be different */
   if (rdlo == rdhi || rdlo == rm || rdhi == rm)
-    as_tsktsk ("rdhi, rdlo and rm must all be different");
+    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
 
   if (skip_past_comma (&str) == FAIL
       || (rs = reg_required_here (&str, 8)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
    
@@ -1824,53 +2034,52 @@ do_mull (str, flags)
 
 static void
 do_mul (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   int rd, rm;
   
-  /* only one format "rd, rm, rs" */
-  while (*str == ' ')
-    str++;
+  /* Only one format "rd, rm, rs" */
+  skip_whitespace (str);
 
   if ((rd = reg_required_here (&str, 16)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rd == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 0)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rm == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
   if (rm == rd)
-    as_tsktsk ("rd and rm should be different in mul");
+    as_tsktsk (_("rd and rm should be different in mul"));
 
   if (skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 8)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rm == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
@@ -1881,55 +2090,54 @@ do_mul (str, flags)
 
 static void
 do_mla (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   int rd, rm;
 
-  /* only one format "rd, rm, rs, rn" */
-  while (*str == ' ')
-    str++;
+  /* Only one format "rd, rm, rs, rn" */
+  skip_whitespace (str);
 
   if ((rd = reg_required_here (&str, 16)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rd == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 0)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rm == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
   if (rm == rd)
-    as_tsktsk ("rd and rm should be different in mla");
+    as_tsktsk (_("rd and rm should be different in mla"));
 
   if (skip_past_comma (&str) == FAIL
       || (rd = reg_required_here (&str, 8)) == FAIL
       || skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 12)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rd == REG_PC || rm == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
@@ -1942,12 +2150,13 @@ do_mla (str, flags)
    not in the table.  */
 static int
 my_get_float_expression (str)
-     char **str;
+     char ** str;
 {
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  char *save_in;
-  expressionS exp;
-  int i, j;
+  char *         save_in;
+  expressionS    exp;
+  int            i;
+  int            j;
 
   memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
   /* Look for a raw floating point number */
@@ -2008,16 +2217,16 @@ my_get_float_expression (str)
 /* Return true if anything in the expression is a bignum */
 static int
 walk_no_bignums (sp)
-     symbolS *sp;
+     symbolS * sp;
 {
-  if (sp->sy_value.X_op == O_big)
+  if (symbol_get_value_expression (sp)->X_op == O_big)
     return 1;
 
-  if (sp->sy_value.X_add_symbol)
+  if (symbol_get_value_expression (sp)->X_add_symbol)
     {
-      return (walk_no_bignums (sp->sy_value.X_add_symbol)
-             || (sp->sy_value.X_op_symbol
-                 && walk_no_bignums (sp->sy_value.X_op_symbol)));
+      return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
+             || (symbol_get_value_expression (sp)->X_op_symbol
+                 && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
     }
 
   return 0;
@@ -2025,11 +2234,11 @@ walk_no_bignums (sp)
 
 static int
 my_get_expression (ep, str)
-     expressionS *ep;
-     char **str;
+     expressionS * ep;
+     char ** str;
 {
-  char *save_in;
-  segT seg;
+  char * save_in;
+  segT   seg;
   
   save_in = input_line_pointer;
   input_line_pointer = *str;
@@ -2042,7 +2251,7 @@ my_get_expression (ep, str)
       && seg != bss_section
       && seg != undefined_section)
     {
-      inst.error = "bad_segment";
+      inst.error = _("bad_segment");
       *str = input_line_pointer;
       input_line_pointer = save_in;
       return 1;
@@ -2058,7 +2267,7 @@ my_get_expression (ep, str)
              || (ep->X_op_symbol
                  && walk_no_bignums (ep->X_op_symbol)))))
     {
-      inst.error = "Invalid constant";
+      inst.error = _("Invalid constant");
       *str = input_line_pointer;
       input_line_pointer = save_in;
       return 1;
@@ -2074,22 +2283,21 @@ my_get_expression (ep, str)
 
 static int
 decode_shift (str, unrestrict)
-     char **str;
-     int unrestrict;
+     char ** str;
+     int     unrestrict;
 {
-  struct asm_shift *shft;
-  char *p;
-  char c;
+  struct asm_shift * shft;
+  char * p;
+  char   c;
     
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
     
   for (p = *str; isalpha (*p); p++)
     ;
 
   if (p == *str)
     {
-      inst.error = "Shift expression expected";
+      inst.error = _("Shift expression expected");
       return FAIL;
     }
 
@@ -2099,24 +2307,23 @@ decode_shift (str, unrestrict)
   *p = c;
   if (shft)
     {
-      if (!strcmp (*str, "rrx")
-          || !strcmp (*str, "RRX"))
+      if (!strncmp (*str, "rrx", 3)
+          || !strncmp (*str, "RRX", 3))
        {
          *str = p;
          inst.instruction |= shft->value;
          return SUCCESS;
        }
 
-      while (*p == ' ')
-       p++;
-
+      skip_whitespace (p);
+      
       if (unrestrict && reg_required_here (&p, 8) != FAIL)
        {
          inst.instruction |= shft->value | SHIFT_BY_REG;
          *str = p;
          return SUCCESS;
        }
-      else if (*p == '#')
+      else if (is_immediate_prefix (* p))
        {
          inst.error = NULL;
          p++;
@@ -2131,7 +2338,7 @@ decode_shift (str, unrestrict)
              /* Reject operations greater than 32, or lsl #32 */
              if (num > 32 || (num == 32 && shft->value == 0))
                {
-                 inst.error = "Invalid immediate shift";
+                 inst.error = _("Invalid immediate shift");
                  return FAIL;
                }
 
@@ -2160,14 +2367,14 @@ decode_shift (str, unrestrict)
        }
       else
        {
-         inst.error = unrestrict ? "shift requires register or #expression"
-           : "shift requires #expression";
+         inst.error = unrestrict ? _("shift requires register or #expression")
+           : _("shift requires #expression");
          *str = p;
          return FAIL;
        }
     }
 
-  inst.error = "Shift expression expected";
+  inst.error = _("Shift expression expected");
   return FAIL;
 }
 
@@ -2183,8 +2390,8 @@ decode_shift (str, unrestrict)
 */
 static int
 negate_data_op (instruction, value)
-     unsigned long *instruction;
-     unsigned long value;
+     unsigned long * instruction;
+     unsigned long   value;
 {
   int op, new_inst;
   unsigned long negated, inverted;
@@ -2262,29 +2469,29 @@ negate_data_op (instruction, value)
 
 static int
 data_op2 (str)
-     char **str;
+     char ** str;
 {
   int value;
   expressionS expr;
 
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
     
   if (reg_required_here (str, 0) != FAIL)
     {
       if (skip_past_comma (str) == SUCCESS)
-       {
-         /* Shift operation on register */
-         return decode_shift (str, NO_SHIFT_RESTRICT);
-       }
+       /* Shift operation on register.  */
+       return decode_shift (str, NO_SHIFT_RESTRICT);
+
       return SUCCESS;
     }
   else
     {
       /* Immediate expression */
-      if (*((*str)++) == '#')
+      if (is_immediate_prefix (**str))
        {
+         (*str)++;
          inst.error = NULL;
+         
          if (my_get_expression (&inst.reloc.exp, str))
            return FAIL;
 
@@ -2303,7 +2510,7 @@ data_op2 (str)
 
                  if (expr.X_op != O_constant)
                    {
-                     inst.error = "Constant expression expected";
+                     inst.error = _("Constant expression expected");
                      return FAIL;
                    }
  
@@ -2312,7 +2519,7 @@ data_op2 (str)
                      || (expr.X_add_number & 1) != 0
                      || ((unsigned) inst.reloc.exp.X_add_number) > 255)
                    {
-                     inst.error = "Invalid constant";
+                     inst.error = _("Invalid constant");
                      return FAIL;
                    }
                  inst.instruction |= INST_IMMEDIATE;
@@ -2332,7 +2539,7 @@ data_op2 (str)
                                               inst.reloc.exp.X_add_number))
                      == FAIL)
                    {
-                     inst.error = "Invalid constant";
+                     inst.error = _("Invalid constant");
                      return FAIL;
                    }
                }
@@ -2344,17 +2551,17 @@ data_op2 (str)
          return SUCCESS;
        }
 
-      inst.error = "Register or shift expression expected";
+      (*str)++;
+      inst.error = _("Register or shift expression expected");
       return FAIL;
     }
 }
 
 static int
 fp_op2 (str)
-     char **str;
+     char ** str;
 {
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
 
   if (fp_reg_required_here (str, 0) != FAIL)
     return SUCCESS;
@@ -2366,8 +2573,8 @@ fp_op2 (str)
          int i;
 
          inst.error = NULL;
-         while (**str == ' ')
-           (*str)++;
+
+         skip_whitespace (* str);
 
          /* First try and match exact strings, this is to guarantee that
             some formats will work even for cross assembly */
@@ -2398,21 +2605,20 @@ fp_op2 (str)
              return SUCCESS;
            }
 
-         inst.error = "Invalid floating point immediate expression";
+         inst.error = _("Invalid floating point immediate expression");
          return FAIL;
        }
-      inst.error = "Floating point register or immediate expression expected";
+      inst.error = _("Floating point register or immediate expression expected");
       return FAIL;
     }
 }
 
 static void
 do_arit (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL
       || skip_past_comma (&str) == FAIL
@@ -2421,7 +2627,7 @@ do_arit (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2432,21 +2638,20 @@ do_arit (str, flags)
 
 static void
 do_adr (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   /* This is a pseudo-op of the form "adr rd, label" to be converted
      into a relative address of the form "add rd, pc, #label-.-8" */
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL
       || skip_past_comma (&str) == FAIL
       || my_get_expression (&inst.reloc.exp, &str))
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
   /* Frag hacking will turn this into a sub instruction if the offset turns
@@ -2460,17 +2665,50 @@ do_adr (str, flags)
 }
 
 static void
+do_adrl (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  /* This is a pseudo-op of the form "adrl rd, label" to be converted
+     into a relative address of the form:
+       add rd, pc, #low(label-.-8)"
+       add rd, rd, #high(label-.-8)"   */
+
+  skip_whitespace (str);
+
+  if (reg_required_here (& str, 12) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || my_get_expression (& inst.reloc.exp, & str))
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+  
+  end_of_line (str);
+  
+  /* Frag hacking will turn this into a sub instruction if the offset turns
+     out to be negative.  */
+  inst.reloc.type              = BFD_RELOC_ARM_ADRL_IMMEDIATE;
+  inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+  inst.reloc.pc_rel            = 1;
+  inst.instruction            |= flags;
+  inst.size                    = INSN_SIZE * 2;
+  
+  return;
+}
+
+static void
 do_cmp (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 16) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2478,7 +2716,7 @@ do_cmp (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2492,16 +2730,15 @@ do_cmp (str, flags)
 
 static void
 do_mov (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2509,7 +2746,7 @@ do_mov (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2520,16 +2757,17 @@ do_mov (str, flags)
 
 static int
 ldst_extend (str, hwse)
-     char **str;
-     int hwse;
+     char ** str;
+     int     hwse;
 {
   int add = INDEX_UP;
 
   switch (**str)
     {
     case '#':
+    case '$':
       (*str)++;
-      if (my_get_expression (&inst.reloc.exp, str))
+      if (my_get_expression (& inst.reloc.exp, str))
        return FAIL;
 
       if (inst.reloc.exp.X_op == O_constant)
@@ -2539,7 +2777,7 @@ ldst_extend (str, hwse)
           if ((hwse && (value < -255 || value > 255))
                || (value < -4095 || value > 4095))
            {
-             inst.error = "address offset too large";
+             inst.error = _("address offset too large");
              return FAIL;
            }
 
@@ -2552,7 +2790,7 @@ ldst_extend (str, hwse)
           /* Halfword and signextension instructions have the
              immediate value split across bits 11..8 and bits 3..0 */
           if (hwse)
-            inst.instruction |= add | HWOFFSET_IMM | (value >> 4) << 8 | value & 0xF;
+            inst.instruction |= add | HWOFFSET_IMM | ((value >> 4) << 8) | (value & 0xF);
           else
             inst.instruction |= add | value;
        }
@@ -2575,10 +2813,7 @@ ldst_extend (str, hwse)
       (*str)++;        /* and fall through */
     default:
       if (reg_required_here (str, 0) == FAIL)
-       {
-         inst.error = "Register expected";
-         return FAIL;
-       }
+       return FAIL;
 
       if (hwse)
         inst.instruction |= add;
@@ -2595,7 +2830,7 @@ ldst_extend (str, hwse)
 
 static void
 do_ldst (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   int halfword = 0;
@@ -2606,14 +2841,15 @@ do_ldst (str, flags)
   /* This is not ideal, but it is the simplest way of dealing with the
      ARM7T halfword instructions (since they use a different
      encoding, but the same mnemonic): */
-  if (halfword = ((flags & 0x80000000) != 0))
+  halfword = (flags & 0x80000000) != 0;
+  if (halfword)
     {
       /* This is actually a load/store of a halfword, or a
          signed-extension load */
       if ((cpu_variant & ARM_HALFWORD) == 0)
         {
           inst.error
-           = "Processor does not support halfwords or signed bytes";
+           = _("Processor does not support halfwords or signed bytes");
           return;
         }
 
@@ -2623,19 +2859,18 @@ do_ldst (str, flags)
       flags = 0;
     }
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
     
-  if ((conflict_reg = reg_required_here (&str, 12)) == FAIL)
+  if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
-  if (skip_past_comma (&str) == FAIL)
+  if (skip_past_comma (& str) == FAIL)
     {
-      inst.error = "Address expected";
+      inst.error = _("Address expected");
       return;
     }
 
@@ -2644,32 +2879,29 @@ do_ldst (str, flags)
       int reg;
 
       str++;
-      while (*str == ' ')
-       str++;
+
+      skip_whitespace (str);
 
       if ((reg = reg_required_here (&str, 16)) == FAIL)
-       {
-         inst.error = "Register required";
-         return;
-       }
+       return;
 
-      conflict_reg = (((conflict_reg == reg)
-                      && (inst.instruction & LOAD_BIT))
-                     ? 1 : 0);
+      /* Conflicts can occur on stores as well as loads.  */
+      conflict_reg = (conflict_reg == reg);
 
-      while (*str == ' ')
-       str++;
+      skip_whitespace (str);
 
       if (*str == ']')
        {
-         str++;
+         str ++;
+         
          if (skip_past_comma (&str) == SUCCESS)
            {
              /* [Rn],... (post inc) */
              if (ldst_extend (&str, halfword) == FAIL)
                return;
              if (conflict_reg)
-               as_warn ("destination register same as write-back base\n");
+               as_warn (_("%s register same as write-back base"),
+                        (inst.instruction & LOAD_BIT) ? _("destination") : _("source") );
            }
          else
            {
@@ -2677,13 +2909,13 @@ do_ldst (str, flags)
               if (halfword)
                 inst.instruction |= HWOFFSET_IMM;
 
-              while (*str == ' ')
-               str++;
+              skip_whitespace (str);
 
               if (*str == '!')
                {
                  if (conflict_reg)
-                  as_warn ("destination register same as write-back base\n");
+                  as_warn (_("%s register same as write-back base"),
+                           (inst.instruction & LOAD_BIT) ? _("destination") : _("source") );
                  str++;
                  inst.instruction |= WRITE_BACK;
                }
@@ -2698,7 +2930,7 @@ do_ldst (str, flags)
          /* [Rn,...] */
          if (skip_past_comma (&str) == FAIL)
            {
-             inst.error = "pre-indexed expression expected";
+             inst.error = _("pre-indexed expression expected");
              return;
            }
 
@@ -2706,22 +2938,21 @@ do_ldst (str, flags)
          if (ldst_extend (&str, halfword) == FAIL)
            return;
 
-         while (*str == ' ')
-           str++;
+         skip_whitespace (str);
 
          if (*str++ != ']')
            {
-             inst.error = "missing ]";
+             inst.error = _("missing ]");
              return;
            }
 
-         while (*str == ' ')
-           str++;
+         skip_whitespace (str);
 
          if (*str == '!')
            {
              if (conflict_reg)
-               as_tsktsk ("destination register same as write-back base\n");
+               as_warn (_("%s register same as write-back base"),
+                        (inst.instruction & LOAD_BIT) ? _("destination") : _("source") );
              str++;
              inst.instruction |= WRITE_BACK;
            }
@@ -2732,8 +2963,7 @@ do_ldst (str, flags)
       /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */
       str++;
 
-      while (*str == ' ')
-       str++;
+      skip_whitespace (str);
 
       if (my_get_expression (&inst.reloc.exp, &str))
        return;
@@ -2741,7 +2971,7 @@ do_ldst (str, flags)
       if (inst.reloc.exp.X_op != O_constant
          && inst.reloc.exp.X_op != O_symbol)
        {
-         inst.error = "Constant expression expected";
+         inst.error = _("Constant expression expected");
          return;
        }
 
@@ -2761,7 +2991,7 @@ do_ldst (str, flags)
          if (add_to_lit_pool () == FAIL)
            {
              if (!inst.error)
-               inst.error = "literal pool insertion failed"
+               inst.error = _("literal pool insertion failed")
              return;
            }
 
@@ -2797,7 +3027,7 @@ do_ldst (str, flags)
     }
     
   if (pre_inc && (flags & TRANS_BIT))
-    inst.error = "Pre-increment instruction with translate";
+    inst.error = _("Pre-increment instruction with translate");
 
   inst.instruction |= flags | (pre_inc ? PRE_INDEX : 0);
   end_of_line (str);
@@ -2806,11 +3036,11 @@ do_ldst (str, flags)
 
 static long
 reg_list (strp)
-     char **strp;
+     char ** strp;
 {
-  char *str = *strp;
-  long range = 0;
-  int another_range;
+  char * str = *strp;
+  long   range = 0;
+  int    another_range;
 
   /* We come back here if we get ranges concatenated by '+' or '|' */
   do
@@ -2827,22 +3057,18 @@ reg_list (strp)
            {
              int reg;
            
-             while (*str == ' ')
-               str++;
-
-             if ((reg = arm_reg_parse (&str)) == FAIL || !int_register (reg))
-               {
-                 inst.error = "Register expected";
-                 return FAIL;
-               }
+             skip_whitespace (str);
 
+             if ((reg = reg_required_here (& str, -1)) == FAIL)
+               return FAIL;
+             
              if (in_range)
                {
                  int i;
              
                  if (reg <= cur_reg)
                    {
-                     inst.error = "Bad range in register list";
+                     inst.error = _("Bad range in register list");
                      return FAIL;
                    }
 
@@ -2850,7 +3076,7 @@ reg_list (strp)
                    {
                      if (range & (1 << i))
                        as_tsktsk 
-                         ("Warning: Duplicated register (r%d) in register list",
+                         (_("Warning: Duplicated register (r%d) in register list"),
                           i);
                      else
                        range |= 1 << i;
@@ -2859,22 +3085,21 @@ reg_list (strp)
                }
 
              if (range & (1 << reg))
-               as_tsktsk ("Warning: Duplicated register (r%d) in register list",
+               as_tsktsk (_("Warning: Duplicated register (r%d) in register list"),
                           reg);
              else if (reg <= cur_reg)
-               as_tsktsk ("Warning: Register range not in ascending order");
+               as_tsktsk (_("Warning: Register range not in ascending order"));
 
              range |= 1 << reg;
              cur_reg = reg;
            } while (skip_past_comma (&str) != FAIL
                     || (in_range = 1, *str++ == '-'));
          str--;
-         while (*str == ' ')
-           str++;
+         skip_whitespace (str);
 
          if (*str++ != '}')
            {
-             inst.error = "Missing `}'";
+             inst.error = _("Missing `}'");
              return FAIL;
            }
        }
@@ -2890,7 +3115,7 @@ reg_list (strp)
              if (expr.X_add_number 
                  != (expr.X_add_number & 0x0000ffff))
                {
-                 inst.error = "invalid register mask";
+                 inst.error = _("invalid register mask");
                  return FAIL;
                }
 
@@ -2901,7 +3126,7 @@ reg_list (strp)
                  regno &= -regno;
                  regno = (1 << regno) - 1;
                  as_tsktsk 
-                   ("Warning: Duplicated register (r%d) in register list",
+                   (_("Warning: Duplicated register (r%d) in register list"),
                     regno);
                }
 
@@ -2911,7 +3136,7 @@ reg_list (strp)
            {
              if (inst.reloc.type != 0)
                {
-                 inst.error = "expression too complex";
+                 inst.error = _("expression too complex");
                  return FAIL;
                }
 
@@ -2921,8 +3146,7 @@ reg_list (strp)
            }
        }
 
-      while (*str == ' ')
-       str++;
+      skip_whitespace (str);
 
       if (*str == '|' || *str == '+')
        {
@@ -2937,30 +3161,25 @@ reg_list (strp)
 
 static void
 do_ldmstm (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   int base_reg;
   long range;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((base_reg = reg_required_here (&str, 16)) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = bad_args;
-      return;
-    }
+    return;
 
   if (base_reg == REG_PC)
     {
-      inst.error = "r15 not allowed as base register";
+      inst.error = _("r15 not allowed as base register");
       return;
     }
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
+
   if (*str == '!')
     {
       flags |= WRITE_BACK;
@@ -2971,14 +3190,14 @@ do_ldmstm (str, flags)
       || (range = reg_list (&str)) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
   if (*str == '^')
     {
       str++;
-      flags |= MULTI_SET_PSR;
+      flags |= LDM_TYPE_2_OR_3;
     }
 
   inst.instruction |= flags | range;
@@ -2988,41 +3207,42 @@ do_ldmstm (str, flags)
 
 static void
 do_swi (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
+  skip_whitespace (str);
+  
   /* Allow optional leading '#'.  */
-  while (*str == ' ')
-    str++;
-  if (*str == '#')
+  if (is_immediate_prefix (*str))
     str++;
 
-  if (my_get_expression (&inst.reloc.exp, &str))
+  if (my_get_expression (& inst.reloc.exp, & str))
     return;
 
   inst.reloc.type = BFD_RELOC_ARM_SWI;
   inst.reloc.pc_rel = 0;
   inst.instruction |= flags;
+  
   end_of_line (str);
+  
   return;
 }
 
 static void
 do_swap (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   int reg;
   
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((reg = reg_required_here (&str, 12)) == FAIL)
     return;
 
   if (reg == REG_PC)
     {
-      inst.error = "r15 not allowed in swap";
+      inst.error = _("r15 not allowed in swap");
       return;
     }
 
@@ -3030,41 +3250,39 @@ do_swap (str, flags)
       || (reg = reg_required_here (&str, 0)) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
   if (reg == REG_PC)
     {
-      inst.error = "r15 not allowed in swap";
+      inst.error = _("r15 not allowed in swap");
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || *str++ != '[')
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((reg = reg_required_here (&str, 16)) == FAIL)
     return;
 
   if (reg == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (*str++ != ']')
     {
-      inst.error = "missing ]";
+      inst.error = _("missing ]");
       return;
     }
 
@@ -3075,51 +3293,84 @@ do_swap (str, flags)
 
 static void
 do_branch (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   if (my_get_expression (&inst.reloc.exp, &str))
     return;
-  inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
+  
+#ifdef OBJ_ELF
+  {
+    char * save_in;
+  
+    /* ScottB: February 5, 1998 */
+    /* Check to see of PLT32 reloc required for the instruction.  */
+    
+    /* arm_parse_reloc() works on input_line_pointer.
+       We actually want to parse the operands to the branch instruction
+       passed in 'str'.  Save the input pointer and restore it later.  */
+    save_in = input_line_pointer;
+    input_line_pointer = str;
+    if (inst.reloc.exp.X_op == O_symbol
+       && *str == '('
+       && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
+      {
+       inst.reloc.type   = BFD_RELOC_ARM_PLT32;
+       inst.reloc.pc_rel = 0;
+       /* Modify str to point to after parsed operands, otherwise
+          end_of_line() will complain about the (PLT) left in str.  */
+       str = input_line_pointer;
+      }
+    else
+      {
+       inst.reloc.type   = BFD_RELOC_ARM_PCREL_BRANCH;
+       inst.reloc.pc_rel = 1;
+      }
+    input_line_pointer = save_in;
+  }
+#else
+  inst.reloc.type   = BFD_RELOC_ARM_PCREL_BRANCH;
   inst.reloc.pc_rel = 1;
+#endif /* OBJ_ELF */
+  
   end_of_line (str);
   return;
 }
 
 static void
 do_bx (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   int reg;
 
-  while (*str == ' ')
-    str++;
+  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
 do_cdp (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   /* Co-processor data operation.
      Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>}  */
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (co_proc_number (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3127,7 +3378,7 @@ do_cdp (str, flags)
       || cp_opc_expr (&str, 20,4) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3135,7 +3386,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3143,7 +3394,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 16) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3151,7 +3402,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 0) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3160,7 +3411,7 @@ do_cdp (str, flags)
       if (cp_opc_expr (&str, 5, 3) == FAIL)
        {
          if (!inst.error)
-           inst.error = bad_args;
+           inst.error = BAD_ARGS;
          return;
        }
     }
@@ -3171,19 +3422,18 @@ do_cdp (str, flags)
 
 static void
 do_lstc (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   /* Co-processor register load/store.
      Format: <LDC|STC{cond}[L] CP#,CRd,<address>  */
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (co_proc_number (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3191,7 +3441,7 @@ do_lstc (str, flags)
       || cp_reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3199,7 +3449,7 @@ do_lstc (str, flags)
       || cp_address_required_here (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3210,19 +3460,18 @@ do_lstc (str, flags)
 
 static void
 do_co_reg (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   /* Co-processor register transfer.
      Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>}  */
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (co_proc_number (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3230,7 +3479,7 @@ do_co_reg (str, flags)
       || cp_opc_expr (&str, 21, 3) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3238,7 +3487,7 @@ do_co_reg (str, flags)
       || reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3246,7 +3495,7 @@ do_co_reg (str, flags)
       || cp_reg_required_here (&str, 16) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3254,7 +3503,7 @@ do_co_reg (str, flags)
       || cp_reg_required_here (&str, 0) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3263,10 +3512,14 @@ do_co_reg (str, flags)
       if (cp_opc_expr (&str, 5, 3) == FAIL)
        {
          if (!inst.error)
-           inst.error = bad_args;
+           inst.error = BAD_ARGS;
          return;
        }
     }
+  if (flags)
+    {
+      inst.error = BAD_COND;
+    }
 
   end_of_line (str);
   return;
@@ -3274,19 +3527,18 @@ do_co_reg (str, flags)
 
 static void
 do_fp_ctrl (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   /* FP control registers.
      Format: <WFS|RFS|WFC|RFC>{cond} Rn  */
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3296,11 +3548,10 @@ do_fp_ctrl (str, flags)
 
 static void
 do_fp_ldst (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   switch (inst.suffix)
     {
@@ -3322,7 +3573,7 @@ do_fp_ldst (str, flags)
   if (fp_reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3330,7 +3581,7 @@ do_fp_ldst (str, flags)
       || cp_address_required_here (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3339,18 +3590,17 @@ do_fp_ldst (str, flags)
 
 static void
 do_fp_ldmstm (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
   int num_regs;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (fp_reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3359,13 +3609,13 @@ do_fp_ldmstm (str, flags)
       || my_get_expression (&inst.reloc.exp, &str))
     {
       if (! inst.error)
-       inst.error = "constant expression expected";
+       inst.error = _("constant expression expected");
       return;
     }
 
   if (inst.reloc.exp.X_op != O_constant)
     {
-      inst.error = "Constant value required for number of registers";
+      inst.error = _("Constant value required for number of registers");
       return;
     }
 
@@ -3373,7 +3623,7 @@ do_fp_ldmstm (str, flags)
 
   if (num_regs < 1 || num_regs > 4)
     {
-      inst.error = "number of registers must be in the range [1:4]";
+      inst.error = _("number of registers must be in the range [1:4]");
       return;
     }
 
@@ -3408,26 +3658,21 @@ do_fp_ldmstm (str, flags)
          || *str != '[')
        {
          if (! inst.error)
-           inst.error = bad_args;
+           inst.error = BAD_ARGS;
          return;
        }
 
       str++;
-      while (*str == ' ')
-       str++;
+      skip_whitespace (str);
 
       if ((reg = reg_required_here (&str, 16)) == FAIL)
-       {
-         inst.error = "Register required";
-         return;
-       }
+       return;
 
-      while (*str == ' ')
-       str++;
+      skip_whitespace (str);
 
       if (*str != ']')
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
 
@@ -3438,7 +3683,7 @@ do_fp_ldmstm (str, flags)
          str++;
          if (reg == REG_PC)
            {
-             inst.error = "R15 not allowed as base register with write-back";
+             inst.error = _("R15 not allowed as base register with write-back");
              return;
            }
        }
@@ -3475,7 +3720,7 @@ do_fp_ldmstm (str, flags)
           || cp_address_required_here (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3484,11 +3729,10 @@ do_fp_ldmstm (str, flags)
 
 static void
 do_fp_dyadic (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   switch (inst.suffix)
     {
@@ -3507,7 +3751,7 @@ do_fp_dyadic (str, flags)
   if (fp_reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3515,7 +3759,7 @@ do_fp_dyadic (str, flags)
       || fp_reg_required_here (&str, 16) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3523,7 +3767,7 @@ do_fp_dyadic (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3534,11 +3778,10 @@ do_fp_dyadic (str, flags)
 
 static void
 do_fp_monadic (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   switch (inst.suffix)
     {
@@ -3557,7 +3800,7 @@ do_fp_monadic (str, flags)
   if (fp_reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3565,7 +3808,7 @@ do_fp_monadic (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3576,16 +3819,15 @@ do_fp_monadic (str, flags)
 
 static void
 do_fp_cmp (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (fp_reg_required_here (&str, 16) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3593,7 +3835,7 @@ do_fp_cmp (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3604,11 +3846,10 @@ do_fp_cmp (str, flags)
 
 static void
 do_fp_from_reg (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   switch (inst.suffix)
     {
@@ -3627,7 +3868,7 @@ do_fp_from_reg (str, flags)
   if (fp_reg_required_here (&str, 16) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3635,7 +3876,7 @@ do_fp_from_reg (str, flags)
       || reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3646,24 +3887,19 @@ do_fp_from_reg (str, flags)
 
 static void
 do_fp_to_reg (str, flags)
-     char *str;
+     char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL)
-    {
-      if (! inst.error)
-       inst.error = bad_args;
-      return;
-    }
+    return;
 
   if (skip_past_comma (&str) == FAIL
       || fp_reg_required_here (&str, 0) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3681,23 +3917,20 @@ do_fp_to_reg (str, flags)
    has been parsed.  */
 static int
 thumb_reg (strp, hi_lo)
-     char **strp;
-     int hi_lo;
+     char ** strp;
+     int     hi_lo;
 {
   int reg;
 
-  if ((reg = arm_reg_parse (strp)) == FAIL || ! int_register (reg))
-    {
-      inst.error = "Register expected";
-      return FAIL;
-    }
+  if ((reg = reg_required_here (strp, -1)) == FAIL)
+    return FAIL;
 
   switch (hi_lo)
     {
     case THUMB_REG_LO:
       if (reg > 7)
        {
-         inst.error = "lo register required";
+         inst.error = _("lo register required");
          return FAIL;
        }
       break;
@@ -3705,7 +3938,7 @@ thumb_reg (strp, hi_lo)
     case THUMB_REG_HI:
       if (reg < 8)
        {
-         inst.error = "hi register required";
+         inst.error = _("hi register required");
          return FAIL;
        }
       break;
@@ -3721,23 +3954,22 @@ thumb_reg (strp, hi_lo)
    was SUB.  */
 static void
 thumb_add_sub (str, subtract)
-     char *str;
-     int subtract;
+     char * str;
+     int    subtract;
 {
   int Rd, Rs, Rn = FAIL;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
-  if (*str == '#')
+  if (is_immediate_prefix (*str))
     {
       Rs = Rd;
       str++;
@@ -3756,7 +3988,7 @@ thumb_add_sub (str, subtract)
          Rn = Rs;
          Rs = Rd;
        }
-      else if (*str == '#')
+      else if (is_immediate_prefix (*str))
        {
          str++;
          if (my_get_expression (&inst.reloc.exp, &str))
@@ -3775,14 +4007,14 @@ thumb_add_sub (str, subtract)
        {
          if (Rs != Rd)
            {
-             inst.error = "dest and source1 must be the same register";
+             inst.error = _("dest and source1 must be the same register");
              return;
            }
 
          /* Can't do this for SUB */
          if (subtract)
            {
-             inst.error = "subtract valid only on lo regs";
+             inst.error = _("subtract valid only on lo regs");
              return;
            }
 
@@ -3806,7 +4038,7 @@ thumb_add_sub (str, subtract)
       if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
          || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
        {
-         inst.error = "invalid Hi register with immediate";
+         inst.error = _("invalid Hi register with immediate");
          return;
        }
 
@@ -3833,7 +4065,7 @@ thumb_add_sub (str, subtract)
              /* Quick check, in case offset is MIN_INT */
              if (offset < 0)
                {
-                 inst.error = "immediate value out of range";
+                 inst.error = _("immediate value out of range");
                  return;
                }
            }
@@ -3844,7 +4076,7 @@ thumb_add_sub (str, subtract)
            {
              if (offset & ~0x1fc)
                {
-                 inst.error = "invalid immediate value for stack adjust";
+                 inst.error = _("invalid immediate value for stack adjust");
                  return;
                }
              inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
@@ -3855,7 +4087,7 @@ thumb_add_sub (str, subtract)
              if (subtract
                  || (offset & ~0x3fc))
                {
-                 inst.error = "invalid immediate for address calculation";
+                 inst.error = _("invalid immediate for address calculation");
                  return;
                }
              inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
@@ -3866,7 +4098,7 @@ thumb_add_sub (str, subtract)
            {
              if (offset & ~0xff)
                {
-                 inst.error = "immediate value out of range";
+                 inst.error = _("immediate value out of range");
                  return;
                }
              inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
@@ -3876,7 +4108,7 @@ thumb_add_sub (str, subtract)
            {
              if (offset & ~0x7)
                {
-                 inst.error = "immediate value out of range";
+                 inst.error = _("immediate value out of range");
                  return;
                }
              inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
@@ -3889,23 +4121,22 @@ thumb_add_sub (str, subtract)
 
 static void
 thumb_shift (str, shift)
-     char *str;
-     int shift;
+     char * str;
+     int    shift;
 {
   int Rd, Rs, Rn = FAIL;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
-  if (*str == '#')
+  if (is_immediate_prefix (*str))
     {
       /* Two operand immediate format, set Rs to Rd.  */
       Rs = Rd;
@@ -3925,7 +4156,7 @@ thumb_shift (str, shift)
          Rn = Rs;
          Rs = Rd;
        }
-      else if (*str == '#')
+      else if (is_immediate_prefix (*str))
        {
          str++;
          if (my_get_expression (&inst.reloc.exp, &str))
@@ -3942,7 +4173,7 @@ thumb_shift (str, shift)
     {
       if (Rs != Rd)
        {
-         inst.error = "source1 and dest must be same register";
+         inst.error = _("source1 and dest must be same register");
          return;
        }
 
@@ -3977,7 +4208,7 @@ thumb_shift (str, shift)
 
          if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
            {
-             inst.error = "Invalid immediate for shift";
+             inst.error = _("Invalid immediate for shift");
              return;
            }
 
@@ -3999,23 +4230,22 @@ thumb_shift (str, shift)
 
 static void
 thumb_mov_compare (str, move)
-     char *str;
-     int move;
+     char * str;
+     int    move;
 {
   int Rd, Rs = FAIL;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
-  if (*str == '#')
+  if (is_immediate_prefix (*str))
     {
       str++;
       if (my_get_expression (&inst.reloc.exp, &str))
@@ -4056,7 +4286,7 @@ thumb_mov_compare (str, move)
     {
       if (Rd > 7)
        {
-         inst.error = "only lo regs allowed with immediate";
+         inst.error = _("only lo regs allowed with immediate");
          return;
        }
 
@@ -4075,7 +4305,7 @@ thumb_mov_compare (str, move)
 
          if (value > 255)
            {
-             inst.error = "invalid immediate";
+             inst.error = _("invalid immediate");
              return;
            }
 
@@ -4088,20 +4318,19 @@ thumb_mov_compare (str, move)
 
 static void
 thumb_load_store (str, load_store, size)
-     char *str;
-     int load_store;
-     int size;
+     char * str;
+     int    load_store;
+     int    size;
 {
   int Rd, Rb, Ro = FAIL;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4113,7 +4342,7 @@ thumb_load_store (str, load_store, size)
 
       if (skip_past_comma (&str) != FAIL)
        {
-         if (*str == '#')
+         if (is_immediate_prefix (*str))
            {
              str++;
              if (my_get_expression (&inst.reloc.exp, &str))
@@ -4130,7 +4359,7 @@ thumb_load_store (str, load_store, size)
 
       if (*str != ']')
        {
-         inst.error = "expected ']'";
+         inst.error = _("expected ']'");
          return;
        }
       str++;
@@ -4140,8 +4369,7 @@ thumb_load_store (str, load_store, size)
       /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */
       str++;
 
-      while (*str == ' ')
-       str++;
+      skip_whitespace (str);
 
       if (my_get_expression (& inst.reloc.exp, & str))
        return;
@@ -4197,17 +4425,17 @@ thumb_load_store (str, load_store, size)
     {
       if (size != THUMB_WORD)
        {
-         inst.error = "byte or halfword not valid for base register";
+         inst.error = _("byte or halfword not valid for base register");
          return;
        }
       else if (Rb == REG_PC && load_store != THUMB_LOAD)
        {
-         inst.error = "R15 based store not allowed";
+         inst.error = _("R15 based store not allowed");
          return;
        }
       else if (Ro != FAIL)
        {
-         inst.error = "Invalid base register for register offset";
+         inst.error = _("Invalid base register for register offset");
          return;
        }
 
@@ -4225,7 +4453,7 @@ thumb_load_store (str, load_store, size)
 
          if (offset & ~0x3fc)
            {
-             inst.error = "invalid offset";
+             inst.error = _("invalid offset");
              return;
            }
 
@@ -4236,7 +4464,7 @@ thumb_load_store (str, load_store, size)
     }
   else if (Rb > 7)
     {
-      inst.error = "invalid base register in load/store";
+      inst.error = _("invalid base register in load/store");
       return;
     }
   else if (Ro == FAIL)
@@ -4260,7 +4488,7 @@ thumb_load_store (str, load_store, size)
          
          if (offset & ~(0x1f << size))
            {
-             inst.error = "Invalid offset";
+             inst.error = _("Invalid offset");
              return;
            }
          inst.instruction |= (offset >> size) << 6;
@@ -4289,7 +4517,7 @@ thumb_load_store (str, load_store, size)
 
 static void
 do_t_nop (str)
-     char *str;
+     char * str;
 {
   /* Do nothing */
   end_of_line (str);
@@ -4301,22 +4529,18 @@ do_t_nop (str)
    BIC and MVN.  */
 static void
 do_t_arit (str)
-     char *str;
+     char * str;
 {
   int Rd, Rs, Rn;
 
-  while (*str == ' ')
-    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)
@@ -4329,7 +4553,7 @@ do_t_arit (str)
          || inst.instruction == T_OPCODE_NEG
          || inst.instruction == T_OPCODE_MVN)
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
 
@@ -4338,7 +4562,7 @@ do_t_arit (str)
 
       if (Rs != Rd)
        {
-         inst.error = "dest and source1 one must be the same register";
+         inst.error = _("dest and source1 one must be the same register");
          return;
        }
       Rs = Rn;
@@ -4346,7 +4570,7 @@ do_t_arit (str)
 
   if (inst.instruction == T_OPCODE_MUL
       && Rs == Rd)
-    as_tsktsk ("Rs and Rd must be different in MUL");
+    as_tsktsk (_("Rs and Rd must be different in MUL"));
 
   inst.instruction |= Rd | (Rs << 3);
   end_of_line (str);
@@ -4354,21 +4578,21 @@ do_t_arit (str)
 
 static void
 do_t_add (str)
-     char *str;
+     char * str;
 {
   thumb_add_sub (str, 0);
 }
 
 static void
 do_t_asr (str)
-     char *str;
+     char * str;
 {
   thumb_shift (str, THUMB_ASR);
 }
 
 static void
 do_t_branch9 (str)
-     char *str;
+     char * str;
 {
   if (my_get_expression (&inst.reloc.exp, &str))
     return;
@@ -4379,7 +4603,7 @@ do_t_branch9 (str)
 
 static void
 do_t_branch12 (str)
-     char *str;
+     char * str;
 {
   if (my_get_expression (&inst.reloc.exp, &str))
     return;
@@ -4388,25 +4612,74 @@ do_t_branch12 (str)
   end_of_line (str);
 }
 
+/* Find the real, Thumb encoded start of a Thumb function.  */
+
+static symbolS *
+find_real_start (symbolP)
+     symbolS * symbolP;
+{
+  char *       real_start;
+  const char * name = S_GET_NAME (symbolP);
+  symbolS *    new_target;
+
+  /* This definiton must agree with the one in gcc/config/arm/thumb.c */
+#define STUB_NAME ".real_start_of"
+
+  if (name == NULL)
+    abort();
+
+  /* Names that start with '.' are local labels, not function entry points.
+     The compiler may generate BL instructions to these labels because it
+     needs to perform a branch to a far away location.  */
+  if (name[0] == '.')
+    return symbolP;
+  
+  real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1);
+  sprintf (real_start, "%s%s", STUB_NAME, name);
+
+  new_target = symbol_find (real_start);
+  
+  if (new_target == NULL)
+    {
+      as_warn ("Failed to find real start of function: %s\n", name);
+      new_target = symbolP;
+    }
+
+  free (real_start);
+
+  return new_target;
+}
+
+
 static void
 do_t_branch23 (str)
-     char *str;
+     char * str;
 {
-  if (my_get_expression (&inst.reloc.exp, &str))
+  if (my_get_expression (& inst.reloc.exp, & str))
     return;
-  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
+  
+  inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
   inst.reloc.pc_rel = 1;
   end_of_line (str);
+
+  /* If the destination of the branch is a defined symbol which does not have
+     the THUMB_FUNC attribute, then we must be calling a function which has
+     the (interfacearm) attribute.  We look for the Thumb entry point to that
+     function and change the branch to refer to that function instead.  */
+  if (   inst.reloc.exp.X_op == O_symbol
+      && inst.reloc.exp.X_add_symbol != NULL
+      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
+      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
+    inst.reloc.exp.X_add_symbol = find_real_start (inst.reloc.exp.X_add_symbol);
 }
 
 static void
 do_t_bx (str)
-     char *str;
+     char * str;
 {
   int reg;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
     return;
@@ -4423,26 +4696,25 @@ do_t_bx (str)
 
 static void
 do_t_compare (str)
-     char *str;
+     char * str;
 {
   thumb_mov_compare (str, THUMB_COMPARE);
 }
 
 static void
 do_t_ldmstm (str)
-     char *str;
+     char * str;
 {
   int Rb;
   long range;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
     return;
 
   if (*str != '!')
-    as_warn ("Inserted missing '!': load/store multiple always writes back base register");
+    as_warn (_("Inserted missing '!': load/store multiple always writes back base register"));
   else
     str++;
 
@@ -4450,7 +4722,7 @@ do_t_ldmstm (str)
       || (range = reg_list (&str)) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4458,13 +4730,13 @@ do_t_ldmstm (str)
     {
       /* This really doesn't seem worth it. */
       inst.reloc.type = BFD_RELOC_NONE;
-      inst.error = "Expression too complex";
+      inst.error = _("Expression too complex");
       return;
     }
 
   if (range & ~0xff)
     {
-      inst.error = "only lo-regs valid in load/store multiple";
+      inst.error = _("only lo-regs valid in load/store multiple");
       return;
     }
 
@@ -4474,33 +4746,32 @@ do_t_ldmstm (str)
 
 static void
 do_t_ldr (str)
-     char *str;
+     char * str;
 {
   thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
 }
 
 static void
 do_t_ldrb (str)
-     char *str;
+     char * str;
 {
   thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
 }
 
 static void
 do_t_ldrh (str)
-     char *str;
+     char * str;
 {
   thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
 }
 
 static void
 do_t_lds (str)
-     char *str;
+     char * str;
 {
   int Rd, Rb, Ro;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
       || skip_past_comma (&str) == FAIL
@@ -4511,7 +4782,7 @@ do_t_lds (str)
       || *str++ != ']')
     {
       if (! inst.error)
-       inst.error = "Syntax: ldrs[b] Rd, [Rb, Ro]";
+       inst.error = _("Syntax: ldrs[b] Rd, [Rb, Ro]");
       return;
     }
 
@@ -4521,38 +4792,37 @@ do_t_lds (str)
 
 static void
 do_t_lsl (str)
-     char *str;
+     char * str;
 {
   thumb_shift (str, THUMB_LSL);
 }
 
 static void
 do_t_lsr (str)
-     char *str;
+     char * str;
 {
   thumb_shift (str, THUMB_LSR);
 }
 
 static void
 do_t_mov (str)
-     char *str;
+     char * str;
 {
   thumb_mov_compare (str, THUMB_MOVE);
 }
 
 static void
 do_t_push_pop (str)
-     char *str;
+     char * str;
 {
   long range;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((range = reg_list (&str)) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4560,7 +4830,7 @@ do_t_push_pop (str)
     {
       /* This really doesn't seem worth it. */
       inst.reloc.type = BFD_RELOC_NONE;
-      inst.error = "Expression too complex";
+      inst.error = _("Expression too complex");
       return;
     }
 
@@ -4576,7 +4846,7 @@ do_t_push_pop (str)
        }
       else
        {
-         inst.error = "invalid register list to push/pop instruction";
+         inst.error = _("invalid register list to push/pop instruction");
          return;
        }
     }
@@ -4587,38 +4857,37 @@ do_t_push_pop (str)
 
 static void
 do_t_str (str)
-     char *str;
+     char * str;
 {
   thumb_load_store (str, THUMB_STORE, THUMB_WORD);
 }
 
 static void
 do_t_strb (str)
-     char *str;
+     char * str;
 {
   thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
 }
 
 static void
 do_t_strh (str)
-     char *str;
+     char * str;
 {
   thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
 }
 
 static void
 do_t_sub (str)
-     char *str;
+     char * str;
 {
   thumb_add_sub (str, 1);
 }
 
 static void
 do_t_swi (str)
-     char *str;
+     char * str;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (my_get_expression (&inst.reloc.exp, &str))
     return;
@@ -4630,19 +4899,18 @@ do_t_swi (str)
 
 static void
 do_t_adr (str)
-     char *str;
+     char * str;
 {
   /* This is a pseudo-op of the form "adr rd, label" to be converted
      into a relative address of the form "add rd, pc, #label-.-4" */
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   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))
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4657,10 +4925,10 @@ static void
 insert_reg (entry)
      int entry;
 {
-  int len = strlen (reg_table[entry].name) + 2;
-  char *buf = (char *) xmalloc (len);
-  char *buf2 = (char *) xmalloc (len);
-  int i = 0;
+  int    len = strlen (reg_table[entry].name) + 2;
+  char * buf = (char *) xmalloc (len);
+  char * buf2 = (char *) xmalloc (len);
+  int    i = 0;
 
 #ifdef REGISTER_PREFIX
   buf[i++] = REGISTER_PREFIX;
@@ -4708,13 +4976,13 @@ md_begin ()
 {
   int i;
   
-  if ((arm_ops_hsh = hash_new ()) == NULL
+  if (   (arm_ops_hsh = hash_new ()) == NULL
       || (arm_tops_hsh = hash_new ()) == NULL
       || (arm_cond_hsh = hash_new ()) == NULL
       || (arm_shift_hsh = hash_new ()) == NULL
       || (arm_reg_hsh = hash_new ()) == NULL
       || (arm_psr_hsh = hash_new ()) == NULL)
-    as_fatal ("Virtual memory exhausted");
+    as_fatal (_("Virtual memory exhausted"));
     
   for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
     hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i));
@@ -4732,7 +5000,7 @@ md_begin ()
 
   set_constant_flonums ();
 
-#ifdef OBJ_COFF
+#if defined OBJ_COFF || defined OBJ_ELF
   {
     unsigned int flags = 0;
     
@@ -4741,7 +5009,8 @@ md_begin ()
     if (support_interwork) flags |= F_INTERWORK;
     if (uses_apcs_float)   flags |= F_APCS_FLOAT;
     if (pic_code)          flags |= F_PIC;
-    
+    if ((cpu_variant & FPU_ALL) == FPU_NONE) flags |= F_SOFT_FLOAT;
+
     bfd_set_private_flags (stdoutput, flags);
   }
 #endif
@@ -4770,12 +5039,16 @@ md_begin ()
        break;
       }
 
-    /* Catch special cases */
+    /* Catch special cases */
     if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
       {
-       if (cpu_variant & ARM_THUMB)
+       if (cpu_variant & (ARM_EXT_V5 & ARM_THUMB))
+         mach = bfd_mach_arm_5T;
+       else if (cpu_variant & ARM_EXT_V5)
+         mach = bfd_mach_arm_5;
+       else if (cpu_variant & ARM_THUMB)
          mach = bfd_mach_arm_4T;
-       else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4)
+       else if ((cpu_variant & ARM_ARCH_V4) == ARM_ARCH_V4)
          mach = bfd_mach_arm_4;
        else if (cpu_variant & ARM_LONGMUL)
          mach = bfd_mach_arm_3M;
@@ -4790,13 +5063,12 @@ md_begin ()
    This knows about the endian-ness of the target machine and does
    THE RIGHT THING, whatever it is.  Possible values for n are 1 (byte)
    2 (short) and 4 (long)  Floating numbers are put out as a series of
-   LITTLENUMS (shorts, here at least)
-   */
+   LITTLENUMS (shorts, here at least).  */
 void
 md_number_to_chars (buf, val, n)
-     char *buf;
+     char * buf;
      valueT val;
-     int n;
+     int    n;
 {
   if (target_big_endian)
     number_to_chars_bigendian (buf, val, n);
@@ -4806,11 +5078,11 @@ md_number_to_chars (buf, val, n)
 
 static valueT 
 md_chars_to_number (buf, n)
-     char *buf;
+     char * buf;
      int n;
 {
   valueT result = 0;
-  unsigned char *where = (unsigned char *) buf;
+  unsigned char * where = (unsigned char *) buf;
 
   if (target_big_endian)
     {
@@ -4848,9 +5120,9 @@ md_chars_to_number (buf, n)
 
 char *
 md_atof (type, litP, sizeP)
-     char type;
-     char *litP;
-     int *sizeP;
+     char   type;
+     char * litP;
+     int *  sizeP;
 {
   int prec;
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
@@ -4885,7 +5157,7 @@ md_atof (type, litP, sizeP)
 
     default:
       *sizeP = 0;
-      return "Bad call to MD_ATOF()";
+      return _("Bad call to MD_ATOF()");
     }
 
   t = atof_ieee (input_line_pointer, type, words);
@@ -4916,44 +5188,66 @@ md_atof (type, litP, sizeP)
   return 0;
 }
 
-/* We have already put the pipeline compensation in the instruction */
-
+/* The knowledge of the PC's pipeline offset is built into the insns themselves.  */ 
 long
 md_pcrel_from (fixP)
-     fixS *fixP;
+     fixS * fixP;
 {
-  if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
+  if (   fixP->fx_addsy
+      && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
       && fixP->fx_subsy == NULL)
-    return 0;  /* HACK */
-
+    return 0;
+  
   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 */
+        for the calculation */
       return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
     }
-  
+
   return fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
 /* Round up a section size to the appropriate boundary. */
 valueT
 md_section_align (segment, size)
-     segT segment;
+     segT   segment;
      valueT size;
 {
+#ifdef OBJ_ELF
+  return size;
+#else
   /* Round all sects to multiple of 4 */
   return (size + 3) & ~3;
+#endif
 }
 
-/* We have no need to default values of symbols.  */
+/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.  Otherwise 
+   we have no need to default values of symbols.  */
 
 /* ARGSUSED */
 symbolS *
 md_undefined_symbol (name)
-     char *name;
+     char * name;
 {
+#ifdef OBJ_ELF
+  if (name[0] == '_' && name[1] == 'G'
+      && streq (name, GLOBAL_OFFSET_TABLE_NAME))
+    {
+      if (!GOT_symbol)
+       {
+         if (symbol_find (name))
+           as_bad ("GOT already in the symbol table");
+         
+         GOT_symbol = symbol_new (name, undefined_section,
+                                  (valueT)0, & zero_address_frag);
+       }
+      
+      return GOT_symbol;
+    }
+#endif
+  
   return 0;
 }
 
@@ -4962,12 +5256,12 @@ md_undefined_symbol (name)
 
 static int
 arm_reg_parse (ccp)
-     register char **ccp;
+     register char ** ccp;
 {
-  char *start = *ccp;
-  char c;
-  char *p;
-  struct reg_entry *reg;
+  char * start = * ccp;
+  char   c;
+  char * p;
+  struct reg_entry * reg;
 
 #ifdef REGISTER_PREFIX
   if (*start != REGISTER_PREFIX)
@@ -5002,11 +5296,12 @@ arm_reg_parse (ccp)
 
 static int
 arm_psr_parse (ccp)
-     register char **ccp;
+     register char ** ccp;
 {
-  char *start = *ccp;
-  char c, *p;
-  CONST struct asm_psr *psr;
+  char * start = * ccp;
+  char   c;
+  char * p;
+  CONST struct asm_psr * psr;
 
   p = start;
   c = *p++;
@@ -5028,22 +5323,23 @@ arm_psr_parse (ccp)
 
 int
 md_apply_fix3 (fixP, val, seg)
-     fixS *fixP;
-     valueT *val;
-     segT seg;
-{
-  offsetT value = *val;
-  offsetT newval;
-  unsigned long temp;
-  int sign;
-  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
-  arm_fix_data *arm_data = (arm_fix_data *) fixP->tc_fix_data;
+     fixS *      fixP;
+     valueT *    val;
+     segT        seg;
+{
+  offsetT        value = * val;
+  offsetT        newval;
+  unsigned int   newimm;
+  unsigned long  temp;
+  int            sign;
+  char *         buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data;
 
   assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
 
   /* Note whether this will delete the relocation.  */
 #if 0 /* patch from REarnshaw to JDavis (disabled for the moment, since it doesn't work fully) */
-  if ((fixP->fx_addsy == 0 || fixP->fx_addsy->sy_value.X_op == O_constant)
+  if ((fixP->fx_addsy == 0 || symbol_constant_p (fixP->fx_addsy))
       && !fixP->fx_pcrel)
 #else
   if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
@@ -5055,47 +5351,98 @@ md_apply_fix3 (fixP, val, seg)
      so we have to undo it's effects here.  */
   if (fixP->fx_pcrel)
     {
-      if (S_IS_DEFINED (fixP->fx_addsy)
+      if (fixP->fx_addsy != NULL
+         && S_IS_DEFINED (fixP->fx_addsy)
          && S_GET_SEGMENT (fixP->fx_addsy) != seg)
        {
-         if (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
+         if (target_oabi
+             && (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 */
+  fixP->fx_addnumber = value;  /* Remember value for emit_reloc */
 
   switch (fixP->fx_r_type)
     {
     case BFD_RELOC_ARM_IMMEDIATE:
-      newval = validate_immediate (value);
+      newimm = validate_immediate (value);
       temp = md_chars_to_number (buf, INSN_SIZE);
 
       /* If the instruction will fail, see if we can fix things up by
         changing the opcode.  */
-      if (newval == FAIL
-         && (newval = negate_data_op (&temp, value)) == FAIL)
+      if (newimm == (unsigned int) FAIL
+         && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
        {
          as_bad_where (fixP->fx_file, fixP->fx_line,
-                       "invalid constant after fixup\n");
+                       _("invalid constant (%lx) after fixup"),
+                       (unsigned long) value);
          break;
        }
 
-      newval |= (temp & 0xfffff000);
-      md_number_to_chars (buf, newval, INSN_SIZE);
+      newimm |= (temp & 0xfffff000);
+      md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
+      break;
+
+    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
+      {
+       unsigned int highpart = 0;
+       unsigned int newinsn  = 0xe1a00000; /* nop */
+       newimm = validate_immediate (value);
+       temp = md_chars_to_number (buf, INSN_SIZE);
+
+       /* If the instruction will fail, see if we can fix things up by
+          changing the opcode.  */
+       if (newimm == (unsigned int) FAIL
+           && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
+         {
+           /* No ?  OK - try using two ADD instructions to generate the value.  */
+           newimm = validate_immediate_twopart (value, & highpart);
+
+           /* Yes - then make sure that the second instruction is also an add.  */
+           if (newimm != (unsigned int) FAIL)
+             newinsn = temp;
+           /* Still No ?  Try using a negated value.  */
+           else if (validate_immediate_twopart (- value, & highpart) != (unsigned int) FAIL)
+               temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
+           /* Otherwise - give up.  */
+           else
+             {
+               as_bad_where (fixP->fx_file, fixP->fx_line,
+                             _("Unable to compute ADRL instructions for PC offset of 0x%x"), value);
+               break;
+             }
+
+           /* Replace the first operand in the 2nd instruction (which is the PC)
+              with the destination register.  We have already added in the PC in the
+              first instruction and we do not want to do it again.  */
+           newinsn &= ~ 0xf0000;
+           newinsn |= ((newinsn & 0x0f000) << 4);
+         }
+
+       newimm |= (temp & 0xfffff000);
+       md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
+
+       highpart |= (newinsn & 0xfffff000);
+       md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
+      }
       break;
 
-     case BFD_RELOC_ARM_OFFSET_IMM:
+    case BFD_RELOC_ARM_OFFSET_IMM:
       sign = value >= 0;
-      if ((value = validate_offset_imm (value, 0)) == FAIL)
+      
+      if (value < 0)
+       value = - value;
+      
+      if (validate_offset_imm (value, 0) == FAIL)
         {
-          as_bad ("bad immediate value for offset (%d)", val);
+         as_bad_where (fixP->fx_file, fixP->fx_line, 
+                        _("bad immediate value for offset (%ld)"), (long) value);
           break;
         }
-      if (value < 0)
-       value = -value;
 
       newval = md_chars_to_number (buf, INSN_SIZE);
       newval &= 0xff7ff000;
@@ -5106,34 +5453,37 @@ md_apply_fix3 (fixP, val, seg)
      case BFD_RELOC_ARM_OFFSET_IMM8:
      case BFD_RELOC_ARM_HWLITERAL:
       sign = value >= 0;
-      if ((value = validate_offset_imm (value, 1)) == FAIL)
+      
+      if (value < 0)
+       value = - value;
+
+      if (validate_offset_imm (value, 1) == FAIL)
         {
           if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
            as_bad_where (fixP->fx_file, fixP->fx_line, 
-                       "invalid literal constant: pool needs to be closer\n");
+                       _("invalid literal constant: pool needs to be closer"));
           else
-            as_bad ("bad immediate value for offset (%d)", value);
+            as_bad (_("bad immediate value for half-word offset (%ld)"),
+                   (long) value);
           break;
         }
 
-      if (value < 0)
-       value = -value;
-
       newval = md_chars_to_number (buf, INSN_SIZE);
       newval &= 0xff7ff0f0;
-      newval |= ((value >> 4) << 8) | value & 0xf | (sign ? INDEX_UP : 0);
+      newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_LITERAL:
       sign = value >= 0;
+      
       if (value < 0)
-       value = -value;
+       value = - value;
 
-      if ((value = validate_offset_imm (value, 0)) == FAIL)
+      if (validate_offset_imm (value, 0) == FAIL)
        {
          as_bad_where (fixP->fx_file, fixP->fx_line, 
-                       "invalid literal constant: pool needs to be closer\n");
+                       _("invalid literal constant: pool needs to be closer"));
          break;
        }
 
@@ -5150,7 +5500,7 @@ md_apply_fix3 (fixP, val, seg)
              && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
        {
          as_bad_where (fixP->fx_file, fixP->fx_line,
-                       "shift expression is too large");
+                       _("shift expression is too large"));
          break;
        }
 
@@ -5168,7 +5518,7 @@ md_apply_fix3 (fixP, val, seg)
        {
          if (((unsigned long) value) > 0xff)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "Invalid swi expression");
+                         _("Invalid swi expression"));
          newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00;
          newval |= value;
          md_number_to_chars (buf, newval, THUMB_SIZE);
@@ -5177,7 +5527,7 @@ md_apply_fix3 (fixP, val, seg)
        {
          if (((unsigned long) value) > 0x00ffffff)
            as_bad_where (fixP->fx_file, fixP->fx_line, 
-                         "Invalid swi expression");
+                         _("Invalid swi expression"));
          newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000;
          newval |= value;
          md_number_to_chars (buf, newval , INSN_SIZE);
@@ -5187,19 +5537,25 @@ md_apply_fix3 (fixP, val, seg)
     case BFD_RELOC_ARM_MULTI:
       if (((unsigned long) value) > 0xffff)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     "Invalid expression in load/store multiple");
+                     _("Invalid expression in load/store multiple"));
       newval = value | md_chars_to_number (buf, INSN_SIZE);
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_PCREL_BRANCH:
-      value = (value >> 2) & 0x00ffffff;
       newval = md_chars_to_number (buf, INSN_SIZE);
-      value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
+
+#ifdef OBJ_ELF
+      if (! target_oabi)
+        value = fixP->fx_offset;
+#endif
+      value  = (value >> 2) & 0x00ffffff;
+      value  = (value + (newval & 0x00ffffff)) & 0x00ffffff;
       newval = value | (newval & 0xff000000);
       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);
       {
@@ -5208,9 +5564,9 @@ md_apply_fix3 (fixP, val, seg)
          diff |= ~0xff;
 
         value += diff;
-        if ((value & 0x100) && ((value & ~0xff) != ~0xff))
+        if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
          as_bad_where (fixP->fx_file, fixP->fx_line,
-                       "Branch out of range");
+                       _("Branch out of range"));
         newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
       }
       md_number_to_chars (buf, newval, THUMB_SIZE);
@@ -5224,57 +5580,98 @@ md_apply_fix3 (fixP, val, seg)
          diff |= ~0x7ff;
 
         value += diff;
-        if ((value & 0x800) && ((value & ~0x7ff) != ~0x7ff))
+        if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
          as_bad_where (fixP->fx_file, fixP->fx_line,
-                       "Branch out of range");
+                       _("Branch out of range"));
         newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
       }
       md_number_to_chars (buf, newval, THUMB_SIZE);
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
-      newval = md_chars_to_number (buf, THUMB_SIZE);
       {
         offsetT newval2;
         addressT diff;
 
-        newval2 = md_chars_to_number (buf + 2, THUMB_SIZE);
+       newval  = md_chars_to_number (buf, THUMB_SIZE);
+        newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
         diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
         if (diff & 0x400000)
-         diff |= ~0x3fffff;
+         diff |= ~0x3fffff;
+#ifdef OBJ_ELF
+       value = fixP->fx_offset;
+#endif
         value += diff;
-        if ((value & 0x400000) && ((value & ~0x3fffff) != ~0x3fffff))
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       "Branch with link out of range");
+        if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("Branch with link out of range"));
 
-        newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
+        newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
         newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
         md_number_to_chars (buf, newval, THUMB_SIZE);
-        md_number_to_chars (buf + 2, newval2, THUMB_SIZE);
+        md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
       }
       break;
 
     case BFD_RELOC_8:
       if (fixP->fx_done || fixP->fx_pcrel)
        md_number_to_chars (buf, value, 1);
+#ifdef OBJ_ELF
+      else if (!target_oabi)
+        {
+          value = fixP->fx_offset;
+          md_number_to_chars (buf, value, 1);
+        }
+#endif
       break;
 
     case BFD_RELOC_16:
       if (fixP->fx_done || fixP->fx_pcrel)
        md_number_to_chars (buf, value, 2);
+#ifdef OBJ_ELF
+      else if (!target_oabi)
+        {
+          value = fixP->fx_offset;
+          md_number_to_chars (buf, value, 2);
+        }
+#endif
       break;
 
+#ifdef OBJ_ELF
+    case BFD_RELOC_ARM_GOT32:
+    case BFD_RELOC_ARM_GOTOFF:
+       md_number_to_chars (buf, 0, 4);
+       break;
+#endif
+
     case BFD_RELOC_RVA:
     case BFD_RELOC_32:
       if (fixP->fx_done || fixP->fx_pcrel)
        md_number_to_chars (buf, value, 4);
+#ifdef OBJ_ELF
+      else if (!target_oabi)
+        {
+          value = fixP->fx_offset;
+          md_number_to_chars (buf, value, 4);
+        }
+#endif
       break;
 
+#ifdef OBJ_ELF
+    case BFD_RELOC_ARM_PLT32:
+      /* It appears the instruction is fully prepared at this point. */
+      break;
+#endif
+
+    case BFD_RELOC_ARM_GOTPC:
+      md_number_to_chars (buf, value, 4);
+      break;
+      
     case BFD_RELOC_ARM_CP_OFF_IMM:
       sign = value >= 0;
       if (value < -1023 || value > 1023 || (value & 3))
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     "Illegal value for co-processor offset");
+                     _("Illegal value for co-processor offset"));
       if (value < 0)
        value = -value;
       newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
@@ -5297,12 +5694,12 @@ md_apply_fix3 (fixP, val, seg)
 
          if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "Invalid offset, target not word aligned (0x%08X)",
+                         _("Invalid offset, target not word aligned (0x%08X)"),
                           (unsigned int)(fixP->fx_frag->fr_address + fixP->fx_where + value));
 
          if ((value + 2) & ~0x3fe)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "Invalid offset");
+                         _("Invalid offset, value too big (0x%08X)"), value);
 
           /* Round up, since pc will be rounded down.  */
          newval |= (value + 2) >> 2;
@@ -5311,34 +5708,35 @@ md_apply_fix3 (fixP, val, seg)
        case 9: /* SP load/store */
          if (value & ~0x3fc)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "Invalid offset");
+                         _("Invalid offset, value too big (0x%08X)"), value);
          newval |= value >> 2;
          break;
 
        case 6: /* Word load/store */
          if (value & ~0x7c)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "Invalid offset");
+                         _("Invalid offset, value too big (0x%08X)"), value);
          newval |= value << 4; /* 6 - 2 */
          break;
 
        case 7: /* Byte load/store */
          if (value & ~0x1f)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "Invalid offset");
+                         _("Invalid offset, value too big (0x%08X)"), value);
          newval |= value << 6;
          break;
 
        case 8: /* Halfword load/store */
          if (value & ~0x3e)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "Invalid offset");
+                         _("Invalid offset, value too big (0x%08X)"), value);
          newval |= value << 5; /* 6 - 1 */
          break;
 
        default:
          as_bad_where (fixP->fx_file, fixP->fx_line,
-                       "Unable to process relocation for thumb opcode: %x", newval);
+                       "Unable to process relocation for thumb opcode: %lx",
+                       (unsigned long) newval);
          break;
        }
       md_number_to_chars (buf, newval, THUMB_SIZE);
@@ -5368,7 +5766,7 @@ md_apply_fix3 (fixP, val, seg)
           {
             if (value & ~0x1fc)
               as_bad_where (fixP->fx_file, fixP->fx_line,
-                            "Invalid immediate for stack address calculation");
+                            _("Invalid immediate for stack address calculation"));
             newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
             newval |= value >> 2;
           }
@@ -5377,7 +5775,8 @@ md_apply_fix3 (fixP, val, seg)
             if (subtract ||
                 value & ~0x3fc)
               as_bad_where (fixP->fx_file, fixP->fx_line,
-                            "Invalid immediate for address calculation (value = 0x%08X)", value);
+                            _("Invalid immediate for address calculation (value = 0x%08lX)"),
+                           (unsigned long) value);
             newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
             newval |= rd << 8;
             newval |= value >> 2;
@@ -5386,7 +5785,7 @@ md_apply_fix3 (fixP, val, seg)
           {
             if (value & ~0xff)
               as_bad_where (fixP->fx_file, fixP->fx_line,
-                            "Invalid 8bit immediate");
+                            _("Invalid 8bit immediate"));
             newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
             newval |= (rd << 8) | value;
           }
@@ -5394,7 +5793,7 @@ md_apply_fix3 (fixP, val, seg)
           {
             if (value & ~0x7)
               as_bad_where (fixP->fx_file, fixP->fx_line,
-                            "Invalid 3bit immediate");
+                            _("Invalid 3bit immediate"));
             newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
             newval |= rd | (rs << 3) | (value << 6);
           }
@@ -5410,7 +5809,8 @@ md_apply_fix3 (fixP, val, seg)
         case 0x05: /* 8bit immediate CMP */
           if (value < 0 || value > 255)
             as_bad_where (fixP->fx_file, fixP->fx_line,
-                          "Invalid immediate: %d is too large", value);
+                          _("Invalid immediate: %ld is too large"),
+                         (long) value);
           newval |= value;
           break;
 
@@ -5424,16 +5824,21 @@ md_apply_fix3 (fixP, val, seg)
       /* 5bit shift value (0..31) */
       if (value < 0 || value > 31)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     "Illegal Thumb shift value: %d", value);
+                     _("Illegal Thumb shift value: %ld"), (long) value);
       newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f;
       newval |= value << 6;
       md_number_to_chars (buf, newval , THUMB_SIZE);
       break;
 
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+      return 1;
+
     case BFD_RELOC_NONE:
     default:
       as_bad_where (fixP->fx_file, fixP->fx_line,
-                   "Bad relocation fixup type (%d)\n", fixP->fx_r_type);
+                   _("Bad relocation fixup type (%d)"), fixP->fx_r_type);
     }
 
   return 1;
@@ -5443,22 +5848,27 @@ md_apply_fix3 (fixP, val, seg)
    format.  */
 arelent *
 tc_gen_reloc (section, fixp)
-     asection *section;
-     fixS *fixp;
+     asection * section;
+     fixS * fixp;
 {
-  arelent *reloc;
+  arelent * reloc;
   bfd_reloc_code_real_type code;
 
   reloc = (arelent *) xmalloc (sizeof (arelent));
 
-  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
   /* @@ Why fx_addnumber sometimes and fx_offset other times?  */
+#ifndef OBJ_ELF
   if (fixp->fx_pcrel == 0)
     reloc->addend = fixp->fx_offset;
   else
     reloc->addend = fixp->fx_offset = reloc->address;
+#else  /* OBJ_ELF */
+  reloc->addend = fixp->fx_offset;
+#endif
 
   switch (fixp->fx_r_type)
     {
@@ -5488,15 +5898,43 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_THUMB_PCREL_BRANCH9:
     case BFD_RELOC_THUMB_PCREL_BRANCH12:
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
+    case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_VTABLE_INHERIT:
       code = fixp->fx_r_type;
       break;
 
     case BFD_RELOC_ARM_LITERAL:
     case BFD_RELOC_ARM_HWLITERAL:
       /* If this is called then the a literal has been referenced across
-        a section boundry - possibly due to an implicit dump */
+        a section boundary - possibly due to an implicit dump */
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+                   _("Literal referenced across section boundary (Implicit dump?)"));
+      return NULL;
+
+#ifdef OBJ_ELF
+    case BFD_RELOC_ARM_GOT32:
+    case BFD_RELOC_ARM_GOTOFF:
+    case BFD_RELOC_ARM_PLT32:
+       code = fixp->fx_r_type;
+    break;
+#endif
+
+    case BFD_RELOC_ARM_IMMEDIATE:
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Literal referenced across section boundry (Implicit dump?)");
+                   _("Internal_relocation (type %d) not fixed up (IMMEDIATE)"),
+                   fixp->fx_r_type);
+      return NULL;
+
+    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+                   _("ADRL used for a symbol not defined in the same file"),
+                   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;
 
     default:
@@ -5515,66 +5953,56 @@ tc_gen_reloc (section, fixp)
          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;
+         default:                         type = _("<unknown>"); break;
          }
        as_bad_where (fixp->fx_file, fixp->fx_line,
-                     "Can not represent %s relocation in this object file format (%d)",
+                     _("Can not represent %s relocation in this object file format (%d)"),
                      type, fixp->fx_pcrel);
        return NULL;
       }
     }
 
+#ifdef OBJ_ELF
+ if (code == BFD_RELOC_32_PCREL
+     && GOT_symbol
+     && fixp->fx_addsy == GOT_symbol)
+   {
+     code = BFD_RELOC_ARM_GOTPC;
+     reloc->addend = fixp->fx_offset = reloc->address;
+   }
+#endif
+   
   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
 
   if (reloc->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Can not represent %s relocation in this object file format",
+                   _("Can not represent %s relocation in this object file format"),
                    bfd_get_reloc_code_name (code));
       return NULL;
     }
 
-  return reloc;
-}
-
-CONST int md_short_jump_size = 4;
-CONST int md_long_jump_size = 4;
+   /* HACK: Since arm ELF uses Rel instead of Rela, encode the
+      vtable entry to be used in the relocation's section offset.  */
+   if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+     reloc->address = fixp->fx_offset;
 
-/* These should never be called on the arm */
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  as_fatal ("md_create_long_jump\n");
-}
-
-void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  as_fatal ("md_create_short_jump\n");
+  return reloc;
 }
 
 int
 md_estimate_size_before_relax (fragP, segtype)
-     fragS *fragP;
-     segT segtype;
+     fragS * fragP;
+     segT    segtype;
 {
-  as_fatal ("md_estimate_size_before_relax\n");
-  return (1);
+  as_fatal (_("md_estimate_size_before_relax\n"));
+  return 1;
 }
 
 static void
-output_inst (str)
-     char *str;
+output_inst PARAMS ((void))
 {
-  char *to = NULL;
+  char * to = NULL;
     
   if (inst.error)
     {
@@ -5583,18 +6011,25 @@ output_inst (str)
     }
 
   to = frag_more (inst.size);
+  
   if (thumb_mode && (inst.size > THUMB_SIZE))
     {
       assert (inst.size == (2 * THUMB_SIZE));
       md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE);
-      md_number_to_chars (to + 2, inst.instruction, THUMB_SIZE);
+      md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE);
+    }
+  else if (inst.size > INSN_SIZE)
+    {
+      assert (inst.size == (2 * INSN_SIZE));
+      md_number_to_chars (to, inst.instruction, INSN_SIZE);
+      md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
     }
   else
     md_number_to_chars (to, inst.instruction, inst.size);
 
   if (inst.reloc.type != BFD_RELOC_NONE)
     fix_new_arm (frag_now, to - frag_now->fr_literal,
-                inst.size, &inst.reloc.exp, inst.reloc.pc_rel,
+                inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
                 inst.reloc.type);
 
   return;
@@ -5602,20 +6037,22 @@ output_inst (str)
 
 void
 md_assemble (str)
-     char *str;
+     char * str;
 {
-  char c;
-  char *p, *q, *start;
+  char   c;
+  char * p;
+  char * q;
+  char * start;
 
-  /* Align the instruction */
-  /* this may not be the right thing to do but ... */
+  /* Align the instruction.
+     This may not be the right thing to do but ... */
   /* arm_align (2, 0); */
   listing_prev_line (); /* Defined in listing.h */
 
-  /* Align the previous label if needed */
+  /* Align the previous label if needed */
   if (last_label_seen != NULL)
     {
-      last_label_seen->sy_frag = frag_now;
+      symbol_set_frag (last_label_seen, frag_now);
       S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
       S_SET_SEGMENT (last_label_seen, now_seg);
     }
@@ -5623,47 +6060,55 @@ md_assemble (str)
   memset (&inst, '\0', sizeof (inst));
   inst.reloc.type = BFD_RELOC_NONE;
 
-  if (*str == ' ')
-    str++;                     /* Skip leading white space */
-    
-  /* scan up to the end of the op-code, which must end in white space or
-     end of string */
+  skip_whitespace (str);
+  
+  /* Scan up to the end of the op-code, which must end in white space or
+     end of string.  */
   for (start = p = str; *p != '\0'; p++)
     if (*p == ' ')
       break;
     
   if (p == str)
     {
-      as_bad ("No operator -- statement `%s'\n", str);
+      as_bad (_("No operator -- statement `%s'\n"), str);
       return;
     }
 
   if (thumb_mode)
     {
-      CONST struct thumb_opcode *opcode;
+      CONST struct thumb_opcode * opcode;
 
       c = *p;
       *p = '\0';
       opcode = (CONST struct thumb_opcode *) hash_find (arm_tops_hsh, str);
       *p = c;
+      
       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);
-         output_inst (start);
+         output_inst ();
          return;
        }
     }
   else
     {
-      CONST struct asm_opcode *opcode;
+      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
         have to break the opcode up in case it contains condionals and flags;
         keep trying with progressively smaller basic instructions until one
-        matches, or we run out of opcode. */
+        matches, or we run out of opcode.  */
       q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p;
       for (; q != str; q--)
        {
@@ -5671,31 +6116,39 @@ md_assemble (str)
          *q = '\0';
          opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
          *q = c;
+         
          if (opcode && opcode->template)
            {
              unsigned long flag_bits = 0;
-             char *r;
+             char * r;
 
-             /* Check that this instruction is supported for this CPU */
+             /* Check that this instruction is supported for this CPU */
              if ((opcode->variants & cpu_variant) == 0)
                goto try_shorter;
 
              inst.instruction = opcode->value;
-             if (q == p)               /* Just a simple opcode */
+             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);
                    }
-                 output_inst (start);
+                 output_inst ();
                  return;
                }
 
-             /* Now check for a conditional */
+             /* Not just a simple opcode.  Check if extra is a conditional. */
              r = q;
              if (p - r >= 2)
                {
@@ -5709,20 +6162,35 @@ md_assemble (str)
                    {
                      if (cond->value == 0xf0000000)
                        as_tsktsk (
-"Warning: Use of the 'nv' conditional is deprecated\n");
+_("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
-               inst.instruction |= COND_ALWAYS;
+               cond_code = COND_ALWAYS;
 
-             /* if there is a compulsory suffix, it should come here, before
-                any optional flags. */
-             if (opcode->comp_suffix)
+             /* 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
+               /* 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 && *opcode->comp_suffix != '\0')
                {
                  CONST char *s = opcode->comp_suffix;
 
@@ -5736,7 +6204,7 @@ md_assemble (str)
 
                  if (*s == '\0')
                    {
-                     as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
+                     as_bad (_("Opcode `%s' must have suffix from <%s>\n"), str,
                              opcode->comp_suffix);
                      return;
                    }
@@ -5760,7 +6228,7 @@ md_assemble (str)
 
                      for (flagno = 0; flag[flagno].template; flagno++)
                        {
-                         if (! strcmp (r, flag[flagno].template))
+                         if (streq (r, flag[flagno].template))
                            {
                              flag_bits |= flag[flagno].set_bits;
                              break;
@@ -5776,7 +6244,7 @@ md_assemble (str)
                }
 
              (*opcode->parms) (p, flag_bits);
-             output_inst (start);
+             output_inst ();
              return;
            }
 
@@ -5786,11 +6254,9 @@ md_assemble (str)
     }
 
   /* It wasn't an instruction, but it might be a register alias of the form
-     alias .req reg
-     */
+     alias .req reg */
   q = p;
-  while (*q == ' ')
-    q++;
+  skip_whitespace (q);
 
   c = *p;
   *p = '\0';
@@ -5802,8 +6268,7 @@ md_assemble (str)
       char * r;
       
       q += 4;
-      while (*q == ' ')
-       q++;
+      skip_whitespace (q);
 
       for (r = q; *r != '\0'; r++)
        if (*r == ' ')
@@ -5823,34 +6288,30 @@ md_assemble (str)
          if (reg == FAIL)
            {
              if (regnum != FAIL)
-               {
-                 insert_reg_alias (str, regnum);
-               }
+               insert_reg_alias (str, regnum);
              else
-               {
-                 as_warn ("register '%s' does not exist\n", q);
-               }
+               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 );
+               as_warn (_("ignoring redefinition of register alias '%s'"), copy_of_str );
              
-             /* Do not warn abpout redefinitions to the same alias.  */
+             /* Do not warn about redefinitions to the same alias.  */
            }
          else
-           as_warn ("ignoring redefinition of register alias '%s' to non-existant register '%s'",
+           as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"),
                     copy_of_str, q);
        }
       else
-       as_warn ("ignoring incomplete .req pseuso op");
+       as_warn (_("ignoring incomplete .req pseuso op"));
       
       *p = c;
       return;
     }
 
   *p = c;
-  as_bad ("bad instruction `%s'", start);
+  as_bad (_("bad instruction `%s'"), start);
 }
 
 /*
@@ -5861,8 +6322,12 @@ md_assemble (str)
  *            -m[arm]1                Currently not supported.
  *            -m[arm]2, -m[arm]250    Arm 2 and Arm 250 processor
  *            -m[arm]3                Arm 3 processor
- *            -m[arm]6,               Arm 6 processors
- *            -m[arm]7[t][[d]m]       Arm 7 processors
+ *            -m[arm]6[xx],           Arm 6 processors
+ *            -m[arm]7[xx][t][[d]m]   Arm 7 processors
+ *            -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 architectures
  *            -mall                   All (except the ARM1)
  *    FP variants:
  *            -mfpa10, -mfpa11        FPA10 and 11 co-processor instructions
@@ -5877,9 +6342,10 @@ md_assemble (str)
  *           -mapcs-float            Pass floats in float regs
  *           -mapcs-reentrant        Position independent code
  *            -mthumb-interwork       Code supports Arm/Thumb interworking
+ *            -moabi                  Old ELF ABI
  */
 
-CONST char *md_shortopts = "m:";
+CONST char * md_shortopts = "m:k";
 struct option md_longopts[] =
 {
 #ifdef ARM_BI_ENDIAN
@@ -5887,6 +6353,10 @@ struct option md_longopts[] =
   {"EB", no_argument, NULL, OPTION_EB},
 #define OPTION_EL (OPTION_MD_BASE + 1)
   {"EL", no_argument, NULL, OPTION_EL},
+#ifdef OBJ_ELF
+#define OPTION_OABI (OPTION_MD_BASE +2)
+  {"oabi", no_argument, NULL, OPTION_OABI},
+#endif
 #endif
   {NULL, no_argument, NULL, 0}
 };
@@ -5894,10 +6364,10 @@ size_t md_longopts_size = sizeof (md_longopts);
 
 int
 md_parse_option (c, arg)
-     int c;
-     char *arg;
+     int    c;
+     char * arg;
 {
-  char *str = arg;
+  char * str = arg;
 
   switch (c)
     {
@@ -5914,33 +6384,41 @@ md_parse_option (c, arg)
       switch (*str)
        {
        case 'f':
-         if (! strcmp (str, "fpa10"))
+         if (streq (str, "fpa10"))
            cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA10;
-         else if (! strcmp (str, "fpa11"))
+         else if (streq (str, "fpa11"))
            cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA11;
-         else if (! strcmp (str, "fpe-old"))
+         else if (streq (str, "fpe-old"))
            cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_CORE;
          else
            goto bad;
          break;
 
        case 'n':
-         if (! strcmp (str, "no-fpu"))
+         if (streq (str, "no-fpu"))
            cpu_variant &= ~FPU_ALL;
          break;
 
+#ifdef OBJ_ELF
+        case 'o':
+          if (streq (str, "oabi"))
+            target_oabi = true;
+          break;
+#endif
+         
         case 't':
           /* Limit assembler to generating only Thumb instructions: */
-          if (! strcmp (str, "thumb"))
+          if (streq (str, "thumb"))
             {
               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB;
               cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE;
               thumb_mode = 1;
             }
-          else if (! strcmp (str, "thumb-interwork"))
+          else if (streq (str, "thumb-interwork"))
             {
-              cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCHv4;
-#ifdef OBJ_COFF
+             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
             }
@@ -5949,12 +6427,12 @@ md_parse_option (c, arg)
           break;
 
        default:
-         if (! strcmp (str, "all"))
+         if (streq (str, "all"))
            {
              cpu_variant = ARM_ALL | FPU_ALL;
              return 1;
            }
-#ifdef OBJ_COFF
+#if defined OBJ_COFF || defined OBJ_ELF
          if (! strncmp (str, "apcs-", 5))
            {
              /* GCC passes on all command line options starting "-mapcs-..."
@@ -5962,23 +6440,23 @@ md_parse_option (c, arg)
 
              str += 5;
              
-             if (! strcmp (str, "32"))
+             if (streq (str, "32"))
                {
                  uses_apcs_26 = false;
                  return 1;
                }
-             else if (! strcmp (str, "26"))
+             else if (streq (str, "26"))
                {
                  uses_apcs_26 = true;
                  return 1;
                }
-             else if (! strcmp (str, "frame"))
+             else if (streq (str, "frame"))
                {
                  /* Stack frames are being generated - does not affect
                     linkage of code.  */
                  return 1;
                }
-             else if (! strcmp (str, "stack-check"))
+             else if (streq (str, "stack-check"))
                {
                  /* Stack checking is being performed - does not affect
                     linkage, but does require that the functions
@@ -5987,7 +6465,7 @@ md_parse_option (c, arg)
 
                  return 1;
                }
-             else if (! strcmp (str, "float"))
+             else if (streq (str, "float"))
                {
                  /* Floating point arguments are being passed in the floating
                     point registers.  This does affect linking, since this
@@ -5997,7 +6475,7 @@ md_parse_option (c, arg)
                  uses_apcs_float = true;
                  return 1;
                }
-             else if (! strcmp (str, "reentrant"))
+             else if (streq (str, "reentrant"))
                {
                  /* Reentrant code has been generated.  This does affect
                     linking, since there is no point in linking reentrant/
@@ -6006,7 +6484,7 @@ md_parse_option (c, arg)
                  return 1;
                }
              
-             as_bad ("Unrecognised APCS switch -m%s", arg);
+             as_bad (_("Unrecognised APCS switch -m%s"), arg);
              return 0;
            }
 #endif
@@ -6017,58 +6495,64 @@ md_parse_option (c, arg)
          switch (*str)
            {
            case '1':
-             if (! strcmp (str, "1"))
+             if (streq (str, "1"))
                cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_1;
              else
                goto bad;
              break;
 
            case '2':
-             if (! strcmp (str, "2"))
+             if (streq (str, "2"))
                cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2;
-             else if (! strcmp (str, "250"))
+             else if (streq (str, "250"))
                cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_250;
              else
                goto bad;
              break;
 
            case '3':
-             if (! strcmp (str, "3"))
+             if (streq (str, "3"))
                cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3;
              else
                goto bad;
              break;
 
-           case 's':
-             if (! strcmp (str, "strongarm") || ! strcmp (str, "strongarm110"))
-               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL;
-             else
-               goto bad;
-             break;
-               
-           case '8':
-             if (! strcmp (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;
-             else
-               goto bad;
+             switch (strtol (str, NULL, 10))
+               {
+               case 6:
+               case 60:
+               case 600:
+               case 610:
+               case 620:
+                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6;
+                 break;
+               default:
+                 goto bad;
+               }
              break;
 
            case '7':
-              str++; /* eat the '7' */
+             switch (strtol (str, & str, 10))  /* Eat the processor name */
+               {
+               case 7:
+               case 70:
+               case 700:
+               case 710:
+               case 720:
+               case 7100:
+               case 7500:
+                 break;
+               default:
+                 goto bad;
+               }
               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7;
               for (; *str; str++)
                 {
                 switch (* str)
                   {
                   case 't':
-                    cpu_variant |= (ARM_THUMB | ARM_ARCHv4);
+                    cpu_variant |= (ARM_THUMB | ARM_ARCH_V4);
                     break;
 
                   case 'm':
@@ -6081,9 +6565,9 @@ md_parse_option (c, arg)
                    else
                      goto bad;
                    
-                 case 'c': /* Unknown */
-                  case 'd': /* debug */
-                  case 'i': /* embedded ice */
+                 case 'c': /* Left over from 710c processor name.  */
+                  case 'd': /* Debug */
+                  case 'i': /* Embedded ICE */
                     /* Included for completeness in ARM processor naming. */
                     break;
 
@@ -6093,6 +6577,36 @@ md_parse_option (c, arg)
                 }
              break;
 
+           case '8':
+             if (streq (str, "8") || streq (str, "810"))
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
+             else
+               goto bad;
+             break;
+             
+           case '9':
+             if (streq (str, "9"))
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+             else if (streq (str, "920"))
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL;
+             else if (streq (str, "920t"))
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+             else if (streq (str, "9tdmi"))
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+             else
+               goto bad;
+             break;
+
+             
+           case 's':
+             if (streq (str, "strongarm")
+                 || streq (str, "strongarm110")
+                 || streq (str, "strongarm1100"))
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
+             else
+               goto bad;
+             break;
+               
            case 'v':
              /* Select variant based on architecture rather than processor */
              switch (*++str)
@@ -6102,7 +6616,7 @@ md_parse_option (c, arg)
                    {
                    case 'a': cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3; break;
                    case 0:   cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2; break;
-                   default:  as_bad ("Invalid architecture variant -m%s", arg); break;
+                   default:  as_bad (_("Invalid architecture variant -m%s"), arg); break;
                    }
                  break;
                  
@@ -6113,35 +6627,52 @@ md_parse_option (c, arg)
                    {
                    case 'm': cpu_variant |= ARM_LONGMUL; break;
                    case 0:   break;
-                   default:  as_bad ("Invalid architecture variant -m%s", arg); break;
+                   default:  as_bad (_("Invalid architecture variant -m%s"), arg); break;
                    }
                  break;
                  
                case '4':
-                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCHv4;
+                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4;
                  
                  switch (*++str)
                    {
                    case 't': cpu_variant |= ARM_THUMB; break;
                    case 0:   break;
-                   default:  as_bad ("Invalid architecture variant -m%s", arg); break;
+                   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;
                    }
                  break;
                  
                default:
-                 as_bad ("Invalid architecture variant -m%s", arg);
+                 as_bad (_("Invalid architecture variant -m%s"), arg);
                  break;
                }
              break;
              
            default:
            bad:
-             as_bad ("Invalid processor variant -m%s", arg);
+             as_bad (_("Invalid processor variant -m%s"), arg);
              return 0;
            }
        }
       break;
 
+#if defined OBJ_ELF || defined OBJ_COFF
+    case 'k':
+      pic_code = 1;
+      break;
+#endif
+      
     default:
       return 0;
     }
@@ -6151,29 +6682,43 @@ md_parse_option (c, arg)
 
 void
 md_show_usage (fp)
-     FILE *fp;
+     FILE * fp;
 {
   fprintf (fp,
-"-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\
--mno-fpu\t\tdon't allow any floating-point instructions.\n");
-#ifdef OBJ_COFF
+_("\
+ ARM Specific Assembler Options:\n\
+  -m[arm][<processor name>] select processor 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\
+  -mfpa10, -mfpa11          select floating point architecture\n\
+  -mfpe-old                 don't allow floating-point multiple instructions\n\
+  -mno-fpu                  don't allow any floating-point instructions.\n"));
+  fprintf (fp,
+_("\
+  -k                        generate PIC code.\n"));
+#if defined OBJ_COFF || defined OBJ_ELF
+  fprintf (fp,
+_("\
+  -mapcs-32, -mapcs-26      specify which ARM Procedure Calling Standard to use\n"));
   fprintf (fp,
-"-mapcs-32, -mapcs-26\tspecify which ARM Procedure Calling Standard is in use\n");
+_("\
+  -mapcs-float              floating point args are passed in FP regs\n"));
   fprintf (fp,
-"-mapcs-float\t\tfloating point args are passed in floating point regs\n");
+_("\
+  -mapcs-reentrant          the code is position independent/reentrant\n"));
+  #endif
+#ifdef OBJ_ELF
   fprintf (fp,
-"-mapcs-reentrant\tposition independent/reentrant code has been generated\n");
+_("\
+  -moabi                    support the old ELF ABI\n"));
 #endif
 #ifdef ARM_BI_ENDIAN
   fprintf (fp,
-"-EB\t\t\tassemble code for a big endian cpu\n\
--EL\t\t\tassemble code for a little endian cpu\n");
+_("\
+  -EB                       assemble code for a big endian cpu\n\
+  -EL                       assemble code for a little endian cpu\n"));
 #endif
 }
 
@@ -6186,15 +6731,15 @@ md_show_usage (fp)
 
 static void
 fix_new_arm (frag, where, size, exp, pc_rel, reloc)
-     fragS *frag;
-     int where;
-     short int size;
-     expressionS *exp;
-     int pc_rel;
-     int reloc;
+     fragS *       frag;
+     int           where;
+     short int     size;
+     expressionS * exp;
+     int           pc_rel;
+     int           reloc;
 {
-  fixS *new_fix;
-  arm_fix_data *arm_data;
+  fixS *         new_fix;
+  arm_fix_data * arm_data;
 
   switch (exp->X_op)
     {
@@ -6212,25 +6757,58 @@ fix_new_arm (frag, where, size, exp, pc_rel, reloc)
     }
 
   /* Mark whether the fix is to a THUMB instruction, or an ARM instruction */
-  arm_data = (arm_fix_data *) obstack_alloc (&notes, sizeof (arm_fix_data));
+  arm_data = (arm_fix_data *) obstack_alloc (& notes, sizeof (arm_fix_data));
   new_fix->tc_fix_data = (PTR) arm_data;
   arm_data->thumb_mode = thumb_mode;
 
   return;
 }
 
-/* A good place to do this, although this was probably not intended
- * for this kind of use.  We need to dump the literal pool before
- * references are made to a null symbol pointer.  */
+
+/* This fix_new is called by cons via TC_CONS_FIX_NEW.  */
 void
-arm_after_pass_hook ()
-{
-  if (current_poolP != NULL)
+cons_fix_new_arm (frag, where, size, exp)
+     fragS *       frag;
+     int           where;
+     int           size;
+     expressionS * exp;
+{
+  bfd_reloc_code_real_type type;
+  int pcrel = 0;
+  
+  /* Pick a reloc ...
+   *
+   * @@ Should look at CPU word size.
+   */
+  switch (size) 
     {
-      subseg_set (text_section, 0); /* Put it at the end of text section */
-      s_ltorg (0);
-      listing_prev_line ();
+    case 2:
+      type = BFD_RELOC_16;
+      break;
+    case 4:
+    default:
+      type = BFD_RELOC_32;
+      break;
+    case 8:
+      type = BFD_RELOC_64;
+      break;
     }
+  
+  fix_new_exp (frag, where, (int) size, exp, pcrel, type);
+}
+
+/* A good place to do this, although this was probably not intended
+   for this kind of use.  We need to dump the literal pool before
+   references are made to a null symbol pointer.  */
+void
+arm_cleanup ()
+{
+  if (current_poolP == NULL)
+    return;
+  
+  subseg_set (text_section, 0); /* Put it at the end of text section.  */
+  s_ltorg (0);
+  listing_prev_line ();
 }
 
 void
@@ -6241,12 +6819,16 @@ arm_start_line_hook ()
 
 void
 arm_frob_label (sym)
-     symbolS *sym;
+     symbolS * sym;
 {
   last_label_seen = sym;
+  
   ARM_SET_THUMB (sym, thumb_mode);
+  
+#if defined OBJ_COFF || defined OBJ_ELF
   ARM_SET_INTERWORK (sym, support_interwork);
-
+#endif
+  
   if (label_is_thumb_function_name)
     {
       /* When the address of a Thumb function is taken the bottom
@@ -6267,7 +6849,7 @@ void
 arm_adjust_symtab ()
 {
 #ifdef OBJ_COFF
-  symbolS *sym;
+  symbolS * sym;
 
   for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
     {
@@ -6279,10 +6861,12 @@ arm_adjust_symtab ()
              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));
+               as_bad (_("%s: unexpected function type: %d"),
+                       S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
            }
           else switch (S_GET_STORAGE_CLASS (sym))
             {
@@ -6299,13 +6883,31 @@ arm_adjust_symtab ()
                 break;
             }
         }
-      
+
       if (ARM_IS_INTERWORK (sym))
-       {
-         coffsymbol(sym->bsym)->native->u.syment.n_flags = 0xFF;
-       }
+       coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
     }
 #endif
+#ifdef OBJ_ELF
+  symbolS *         sym;
+  elf_symbol_type * elf_sym;
+  char              bind;
+
+  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
+    {
+      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->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
 }
 
 int
@@ -6318,20 +6920,209 @@ arm_data_in_code ()
       *input_line_pointer = 0;
       return 1;
     }
+  
   return 0;
 }
 
 char *
 arm_canonicalize_symbol_name (name)
-     char *name;
+     char * name;
 {
   int len;
 
   if (thumb_mode && (len = strlen (name)) > 5
-      && ! strcmp (name + len - 5, "/data"))
+      && streq (name + len - 5, "/data"))
+    *(name + len - 5) = 0;
+
+  return name;
+}
+
+boolean
+arm_validate_fix (fixP)
+     fixS * fixP;
+{
+  /* If the destination of the branch is a defined symbol which does not have
+     the THUMB_FUNC attribute, then we must be calling a function which has
+     the (interfacearm) attribute.  We look for the Thumb entry point to that
+     function and change the branch to refer to that function instead.  */
+  if (   fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
+      && fixP->fx_addsy != NULL
+      && S_IS_DEFINED (fixP->fx_addsy)
+      && ! THUMB_IS_FUNC (fixP->fx_addsy))
     {
-      *(name + len - 5) = 0;
+      fixP->fx_addsy = find_real_start (fixP->fx_addsy);
+      return true;
     }
 
-  return name;
+  return false;
+}
+
+#ifdef OBJ_ELF
+/* Relocations against Thumb function names must be left unadjusted,
+   so that the linker can use this information to correctly set the
+   bottom bit of their addresses.  The MIPS version of this function
+   also prevents relocations that are mips-16 specific, but I do not
+   know why it does this.
+
+   FIXME:
+   There is one other problem that ought to be addressed here, but
+   which currently is not:  Taking the address of a label (rather
+   than a function) and then later jumping to that address.  Such
+   addresses also ought to have their bottom bit set (assuming that
+   they reside in Thumb code), but at the moment they will not.  */
+   
+boolean
+arm_fix_adjustable (fixP)
+   fixS * fixP;
+{
+  if (fixP->fx_addsy == NULL)
+    return 1;
+  
+  /* Prevent all adjustments to global symbols. */
+  if (S_IS_EXTERN (fixP->fx_addsy))
+    return 0;
+  
+  if (S_IS_WEAK (fixP->fx_addsy))
+    return 0;
+
+  if (THUMB_IS_FUNC (fixP->fx_addsy)
+      && fixP->fx_subsy == NULL)
+    return 0;
+  
+  /* We need the symbol name for the VTABLE entries */
+  if (   fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 0;
+
+  return 1;
+}
+
+const char *
+elf32_arm_target_format ()
+{
+  if (target_big_endian)
+    if (target_oabi)
+      return "elf32-bigarm-oabi";
+    else
+      return "elf32-bigarm";
+  else
+    if (target_oabi)
+      return "elf32-littlearm-oabi";
+    else
+      return "elf32-littlearm";
+}
+
+void
+armelf_frob_symbol (symp, puntp)
+     symbolS * symp;
+     int * puntp;
+{
+  elf_frob_symbol (symp, puntp);
+} 
+
+int
+arm_force_relocation (fixp)
+     struct fix * fixp;
+{
+  if (   fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+      || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+      || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)    
+    return 1;
+  
+  return 0;
+}
+
+static bfd_reloc_code_real_type
+arm_parse_reloc ()
+{
+  char   id[16];
+  char * ip;
+  int    i;
+  static struct
+  {
+    char * str;
+    int    len;
+    bfd_reloc_code_real_type reloc;
+  }
+  reloc_map[] =
+  {
+#define MAP(str,reloc) { str, sizeof (str)-1, reloc }
+    MAP ("(got)",    BFD_RELOC_ARM_GOT32),
+    MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF),
+    /* ScottB: Jan 30, 1998 */
+    /* Added support for parsing "var(PLT)" branch instructions */
+    /* generated by GCC for PLT relocs */
+    MAP ("(plt)",    BFD_RELOC_ARM_PLT32),
+    { NULL, 0,         BFD_RELOC_UNUSED }
+#undef MAP    
+  };
+
+  for (i = 0, ip = input_line_pointer;
+       i < sizeof (id) && (isalnum (*ip) || ispunct (*ip));
+       i++, ip++)
+    id[i] = tolower (*ip);
+  
+  for (i = 0; reloc_map[i].str; i++)
+    if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0)
+      break;
+  
+  input_line_pointer += reloc_map[i].len;
+  
+  return reloc_map[i].reloc;
+}
+
+static void
+s_arm_elf_cons (nbytes)
+     int nbytes;
+{
+  expressionS exp;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  if (is_it_end_of_statement ())
+    {
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+#ifdef md_cons_align
+  md_cons_align (nbytes);
+#endif
+
+  do
+    {
+      bfd_reloc_code_real_type reloc;
+      
+      expression (& exp);
+
+      if (exp.X_op == O_symbol
+          && * input_line_pointer == '('
+          && (reloc = arm_parse_reloc()) != BFD_RELOC_UNUSED)
+        {
+          reloc_howto_type * howto = bfd_reloc_type_lookup (stdoutput, reloc);
+          int size = bfd_get_reloc_size (howto);
+
+          if (size > nbytes)
+            as_bad ("%s relocations do not fit in %d bytes", howto->name, nbytes);
+          else
+            {
+              register char * p = frag_more ((int) nbytes);
+              int offset = nbytes - size;
+
+              fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
+                          & exp, 0, reloc);
+            }
+        }
+      else
+        emit_expr (& exp, (unsigned int) nbytes);
+    }
+  while (*input_line_pointer++ == ',');
+
+  input_line_pointer--;                /* Put terminator back into stream. */
+  demand_empty_rest_of_line ();
 }
+
+#endif /* OBJ_ELF */