Replace <sys/dir.h> (and <dirent.h>) with "gdb_dirent.h".
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index 27d069fc46f894bea7a14f0b146b904b83523aa1..4c71976c877e1eb0034b94e7bb4fa7483ace18ae 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-arm.c -- Assemble for the ARM
-   Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000 Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
 
@@ -31,7 +31,6 @@
 #include "obstack.h"
 #include "symbols.h"
 #include "listing.h"
-#include "struc-symbol.h"
 
 #ifdef OBJ_ELF
 #include "elf/arm.h"
 #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_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 */
@@ -74,7 +78,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
@@ -84,7 +88,8 @@
 #define FPU_DEFAULT FPU_ALL
 #endif
 
-#define streq(a,b)  (strcmp (a, b) == 0)
+#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;
@@ -98,16 +103,16 @@ static boolean             pic_code = false;
 #endif
 
 /* This array holds the chars that always start a comment.  If the
-   pre-processor is disabled, these aren't very useful */
+   pre-processor is disabled, these aren't very useful */
 CONST char comment_chars[] = "@";
 
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
-   .line and .file directives will appear in the pre-processed output */
+   .line and .file directives will appear in the pre-processed output */
 /* Note that input_file.c hand checks for '#' at the beginning of the
    first line of the input file.  This is because the compiler outputs
-   #NO_APP at the beginning of its output. */
-/* Also note that comments like this one will always work. */
+   #NO_APP at the beginning of its output.  */
+/* Also note that comments like this one will always work.  */
 CONST char line_comment_chars[] = "#";
 
 #ifdef TE_LINUX
@@ -116,7 +121,8 @@ CONST char line_separator_chars[] = ";";
 CONST char line_separator_chars[] = "";
 #endif
 
-/* Chars that can be used to separate mant from exp in floating point nums */
+/* Chars that can be used to separate mant
+   from exp in floating point numbers.  */
 CONST char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant */
@@ -133,10 +139,11 @@ CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 symbolS * GOT_symbol;          /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 #endif
 
-CONST int md_reloc_size = 8;           /* Size of relocation record */
-
-static int thumb_mode = 0;      /* non-zero if assembling thumb instructions */
+CONST int md_reloc_size = 8;   /* Size of relocation record */
 
+static int thumb_mode = 0;      /* 0: assemble for ARM, 1: assemble for Thumb,
+                                  2: assemble for Thumb even though target cpu
+                                  does not support thumb instructions.  */
 typedef struct arm_fix
 {
   int thumb_mode;
@@ -190,7 +197,7 @@ CONST char * fp_const[] =
   "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
 };
 
-/* Number of littlenums required to hold an extended precision number */
+/* Number of littlenums required to hold an extended precision number */
 #define MAX_LITTLENUMS 6
 
 LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
@@ -219,7 +226,7 @@ struct asm_cond
   unsigned long value;
 };
 
-/* This is to save a hash look-up in the common case */
+/* This is to save a hash look-up in the common case */
 #define COND_ALWAYS 0xe0000000
 
 static CONST struct asm_cond conds[] = 
@@ -244,7 +251,7 @@ static CONST struct asm_cond conds[] =
 
 /* Warning: If the top bit of the set_bits is set, then the standard
    instruction bitmask is ignored, and the new bitmask is taken from
-   the set_bits: */
+   the set_bits:  */
 struct asm_flg
 {
   CONST char *  template;      /* Basic flag string */
@@ -374,93 +381,104 @@ static CONST struct asm_flg cplong_flag[] =
 struct asm_psr
 {
   CONST char *  template;
-  unsigned long number;
+  boolean       cpsr;
+  unsigned long field;
 };
 
-#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 SPSR_BIT   (1 << 22)  /* The bit that distnguishes CPSR and SPSR.  */
+#define PSR_SHIFT  16  /* How many bits to shift the PSR_xxx bits up by.  */
 
-#define CPSR_ALL       0
-#define SPSR_ALL       1
-#define CPSR_FLG       2
-#define SPSR_FLG       3
-#define CPSR_CTL       4
-#define SPSR_CTL       5
+#define PSR_c   (1 << 0)
+#define PSR_x   (1 << 1)
+#define PSR_s   (1 << 2)
+#define PSR_f   (1 << 3)
 
 static CONST struct asm_psr psrs[] =
 {
-  /* Valid <psr>'s */
-  {"cpsr",     CPSR_ALL},
-  {"cpsr_all", CPSR_ALL},
-  {"spsr",     SPSR_ALL},
-  {"spsr_all", SPSR_ALL},
-
-  /* Valid <psrf>'s */
-  {"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}
+  {"CPSR",     true,  PSR_c | PSR_f},
+  {"CPSR_all", true,  PSR_c | PSR_f},
+  {"SPSR",     false, PSR_c | PSR_f},
+  {"SPSR_all", false, PSR_c | PSR_f},
+  {"CPSR_flg", true,  PSR_f},
+  {"CPSR_f",    true,  PSR_f},
+  {"SPSR_flg", false, PSR_f},
+  {"SPSR_f",    false, PSR_f}, 
+  {"CPSR_c",   true,  PSR_c},
+  {"CPSR_ctl", true,  PSR_c},
+  {"SPSR_c",   false, PSR_c},
+  {"SPSR_ctl", false, PSR_c},
+  {"CPSR_x",    true,  PSR_x},
+  {"CPSR_s",    true,  PSR_s},
+  {"SPSR_x",    false, PSR_x},
+  {"SPSR_s",    false, PSR_s},
+  /* For backwards compatability with older toolchain we also
+     support lower case versions of some of these flags.  */
+  {"cpsr",     true,  PSR_c | PSR_f},
+  {"cpsr_all", true,  PSR_c | PSR_f},
+  {"spsr",     false, PSR_c | PSR_f},
+  {"spsr_all", false, PSR_c | PSR_f},
+  {"cpsr_flg", true,  PSR_f},
+  {"cpsr_f",    true,  PSR_f},
+  {"spsr_flg", false, PSR_f},
+  {"spsr_f",    false, PSR_f}, 
+  {"cpsr_c",   true,  PSR_c},
+  {"cpsr_ctl", true,  PSR_c},
+  {"spsr_c",   false, PSR_c},
+  {"spsr_ctl", false, PSR_c}
 };
 
-/* Functions called by parser */
+/* 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 CONST struct asm_psr * 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, int));
+static int psr_required_here   PARAMS ((char **));
 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));
@@ -470,8 +488,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 **));
@@ -485,27 +502,30 @@ 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: */
+   take 2:  */
 #define INSN_SIZE       4
 
 /* LONGEST_INST is the longest basic instruction name without conditions or 
- * flags.
- * ARM7M has 4 of length 5
- */
+   flags.  ARM7M has 4 of length 5.  */
 
 #define LONGEST_INST 5
 
+
 struct asm_opcode 
 {
   CONST char *           template;     /* Basic string to match */
   unsigned long          value;                /* Basic instruction code */
-  CONST char *           comp_suffix;  /* Compulsory suffix that must follow conds */
+
+  /* Compulsory suffix that must follow conds. If "", then the
+     instruction is not conditional and must have no suffix. */
+  CONST char *           comp_suffix;  
+
   CONST struct asm_flg * flags;                /* Bits to toggle if flag 'n' set */
   unsigned long          variants;     /* Which CPU variants this exists for */
   /* Function to call to parse args */
@@ -536,11 +556,17 @@ static CONST struct asm_opcode insns[] =
   {"stm",   0x08000000, NULL,   stm_flags,   ARM_ANY,      do_ldmstm},
   {"ldm",   0x08100000, NULL,   ldm_flags,   ARM_ANY,      do_ldmstm},
   {"swi",   0x0f000000, NULL,   NULL,        ARM_ANY,      do_swi},
+#ifdef TE_WINCE
+  {"bl",    0x0b000000, NULL,   NULL,        ARM_ANY,      do_branch},
+  {"b",     0x0a000000, NULL,   NULL,        ARM_ANY,      do_branch},
+#else
   {"bl",    0x0bfffffe, NULL,   NULL,        ARM_ANY,      do_branch},
   {"b",     0x0afffffe, NULL,   NULL,        ARM_ANY,      do_branch},
-
+#endif
+  
 /* 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 */
@@ -554,8 +580,8 @@ static CONST struct asm_opcode insns[] =
   {"mrs",   0x010f0000, NULL,   NULL,        ARM_6UP,      do_mrs},
   {"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.  */
+   NickC:  but this is wrong because the bits 16 through 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},
@@ -614,7 +640,7 @@ static CONST struct asm_opcode insns[] =
   {"flt",   0x0e000110, "sde",  round_flags, FPU_ALL,      do_fp_from_reg},
   {"fix",   0x0e100110, NULL,   fix_flags,   FPU_ALL,      do_fp_to_reg},
 
-/* Generic copressor instructions */
+/* Generic copressor instructions */
   {"cdp",   0x0e000000, NULL,  NULL,         ARM_2UP,      do_cdp},
   {"ldc",   0x0c100000, NULL,  cplong_flag,  ARM_2UP,      do_lstc},
   {"stc",   0x0c000000, NULL,  cplong_flag,  ARM_2UP,      do_lstc},
@@ -622,8 +648,7 @@ static CONST struct asm_opcode insns[] =
   {"mrc",   0x0e100010, NULL,  NULL,         ARM_2UP,      do_co_reg},
 };
 
-/* defines for various bits that we will want to toggle */
-
+/* Defines for various bits that we will want to toggle.  */
 #define INST_IMMEDIATE 0x02000000
 #define OFFSET_REG     0x02000000
 #define HWOFFSET_IMM    0x00400000
@@ -631,15 +656,14 @@ 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
 #define OPCODE_MASK    0xfe1fffff
 #define DATA_OP_SHIFT  21
 
-/* Codes to distinguish the arithmetic instructions */
-
+/* Codes to distinguish the arithmetic instructions.  */
 #define OPCODE_AND     0
 #define OPCODE_EOR     1
 #define OPCODE_SUB     2
@@ -657,30 +681,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
@@ -736,7 +760,7 @@ static void do_t_adr                PARAMS ((char *operands));
 
 static int thumb_reg           PARAMS ((char ** str, int hi_lo));
 
-#define THUMB_SIZE     2       /* Size of thumb instruction */
+#define THUMB_SIZE     2       /* Size of thumb instruction */
 #define THUMB_REG_LO   0x1
 #define THUMB_REG_HI   0x2
 #define THUMB_REG_ANY  0x3
@@ -756,7 +780,7 @@ static int thumb_reg                PARAMS ((char ** str, int hi_lo));
 
 #define THUMB_PP_PC_LR 0x0100
 
-/* These three are used for immediate shifts, do not alter */
+/* These three are used for immediate shifts, do not alter */
 #define THUMB_WORD 2
 #define THUMB_HALFWORD 1
 #define THUMB_BYTE 0
@@ -766,68 +790,70 @@ struct thumb_opcode
   CONST char *  template;      /* Basic string to match */
   unsigned long value;         /* Basic instruction code */
   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},
+  {"bal",      0xdefe,         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
@@ -844,20 +870,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},
@@ -868,11 +896,20 @@ static CONST struct reg_entry reg_table[] =
   {"cr4", 36},  {"cr5", 37},  {"cr6", 38},  {"cr7", 39},
   {"cr8", 40},  {"cr9", 41},  {"cr10", 42}, {"cr11", 43},
   {"cr12", 44}, {"cr13", 45}, {"cr14", 46}, {"cr15", 47},
+  /* ATPCS additions to float register names.  */
+  {"s0",16},   {"s1",17},      {"s2",18},      {"s3",19},
+  {"s4",20},   {"s5",21},      {"s6",22},      {"s7",23},
+  {"d0",16},   {"d1",17},      {"d2",18},      {"d3",19},
+  {"d4",20},   {"d5",21},      {"d6",22},      {"d7",23},
+  /* FIXME: At some point we need to add VFP register names.  */
+  /* Array terminator.  */
   {NULL, 0}
 };
 
-#define bad_args _("Bad arguments to instruction");
-#define bad_pc _("r15 not allowed here");
+#define BAD_ARGS       _("Bad arguments to instruction")
+#define BAD_PC                 _("r15 not allowed here")
+#define BAD_FLAGS      _("Instruction should not have flags")
+#define BAD_COND       _("Instruction is not conditional")
 
 static struct hash_control * arm_ops_hsh = NULL;
 static struct hash_control * arm_tops_hsh = NULL;
@@ -883,10 +920,9 @@ 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:
-   pseudo-op name without dot
-   function to call to execute this pseudo-op
-   Integer arg to pass to the function
-   */
+     pseudo-op name without dot
+     function to call to execute this pseudo-op
+     Integer arg to pass to the function.  */
 
 static void s_req PARAMS ((int));
 static void s_align PARAMS ((int));
@@ -978,12 +1014,13 @@ add_to_lit_pool ()
     current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section,
                                   (valueT) 0, &zero_address_frag);
 
-  /* Check if this literal value is already in the pool: */
+  /* Check if this literal value is already in the pool:  */
   while (lit_count < next_literal_pool_place)
     {
       if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
           && inst.reloc.exp.X_op == O_constant
-          && literals[lit_count].exp.X_add_number == inst.reloc.exp.X_add_number
+          && literals[lit_count].exp.X_add_number
+            == inst.reloc.exp.X_add_number
           && literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned)
         break;
       lit_count++;
@@ -1062,8 +1099,8 @@ symbol_locate (symbolP, name, segment, valu, frag)
 #endif /* DEBUG_SYMS */
 }
 
-/* Check that an immediate is valid, and if so, convert it to the right format.  */
-
+/* Check that an immediate is valid, and if so,
+   convert it to the right format.  */
 static unsigned int
 validate_immediate (val)
      unsigned int val;
@@ -1080,13 +1117,52 @@ validate_immediate (val)
   return FAIL;
 }
 
+/* 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_twopart (val, highpart)
+     unsigned int val;
+     unsigned int * highpart;
+{
+  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;
+
+           * 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;
 }
@@ -1094,14 +1170,14 @@ validate_offset_imm (val, hwse)
     
 static void
 s_req (a)
-     int a;
+     int a ATTRIBUTE_UNUSED;
 {
   as_bad (_("Invalid syntax for .req directive."));
 }
 
 static void
 s_bss (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   /* We don't support putting frags in the BSS segment, we fake it by
      marking in_bss, then looking at s_skip for clues?.. */
@@ -1111,7 +1187,7 @@ s_bss (ignore)
 
 static void
 s_even (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   if (!need_pass_2)            /* Never make frag if expect extra pass. */
     frag_align (1, 0, 0);
@@ -1123,7 +1199,7 @@ s_even (ignore)
 
 static void
 s_ltorg (ignored)
-     int ignored;
+     int ignored ATTRIBUTE_UNUSED;
 {
   int lit_count = 0;
   char sym_name[20];
@@ -1151,7 +1227,7 @@ s_ltorg (ignored)
 #endif
   
   while (lit_count < next_literal_pool_place)
-    /* First output the expression in the instruction to the pool */
+    /* First output the expression in the instruction to the pool */
     emit_expr (&(literals[lit_count++].exp), 4); /* .word */
 
   next_literal_pool_place = 0;
@@ -1160,7 +1236,7 @@ s_ltorg (ignored)
 
 static void
 s_align (unused)       /* Same as s_align_ptwo but align 0 => align 2 */
-     int unused;
+     int unused ATTRIBUTE_UNUSED;
 {
   register int temp;
   register long temp_fill;
@@ -1196,7 +1272,7 @@ s_align (unused)  /* Same as s_align_ptwo but align 0 => align 2 */
 
 static void
 s_force_thumb (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   /* If we are not already in thumb mode go into it, EVEN if
      the target processor does not support thumb instructions.
@@ -1206,7 +1282,7 @@ s_force_thumb (ignore)
      
   if (! thumb_mode)
     {
-      thumb_mode = 1;
+      thumb_mode = 2;
       
       record_alignment (now_seg, 1);
     }
@@ -1216,7 +1292,7 @@ s_force_thumb (ignore)
 
 static void
 s_thumb_func (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   /* The following label is the name/address of the start of a Thumb function.
      We need to know this for the interworking support.  */
@@ -1311,11 +1387,13 @@ s_thumb_set (equiv)
   
   demand_empty_rest_of_line ();
 
-  /* XXX now we come to the Thumb specific bit of code.  */
+  /* 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.  */
@@ -1326,7 +1404,11 @@ arm_s_text (ignore)
   if (now_seg != text_section)
     s_ltorg (0);
   
+#ifdef OBJ_ELF
+  obj_elf_text (ignore);
+#else
   s_text (ignore);
+#endif
 }
 
 static void
@@ -1341,7 +1423,11 @@ arm_s_data (ignore)
   else if (now_seg != data_section)
     s_ltorg (0);
   
+#ifdef OBJ_ELF
+  obj_elf_data (ignore);
+#else
   s_data (ignore);
+#endif
 }
 
 #ifdef OBJ_ELF
@@ -1392,7 +1478,7 @@ opcode_select (width)
 
 static void
 s_arm (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   opcode_select (32);
   demand_empty_rest_of_line ();
@@ -1400,7 +1486,7 @@ s_arm (ignore)
 
 static void
 s_thumb (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   opcode_select (16);
   demand_empty_rest_of_line ();
@@ -1408,7 +1494,7 @@ s_thumb (ignore)
 
 static void
 s_code (unused)
-     int unused;
+     int unused ATTRIBUTE_UNUSED;
 {
   register int temp;
 
@@ -1429,10 +1515,9 @@ static void
 end_of_line (str)
      char * str;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
-  if (*str != '\0')
+  if (* str != '\0')
     inst.error = _("Garbage following instruction");
 }
 
@@ -1457,9 +1542,10 @@ 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;
@@ -1480,34 +1566,72 @@ reg_required_here (str, shift)
   *str = start;
   
   /* In the few cases where we might be able to accept something else
-     this error can be overridden */
+     this error can be overridden */
   sprintf (buff, _("Register expected, not '%.100s'"), start);
   inst.error = buff;
 
   return FAIL;
 }
 
+static CONST struct asm_psr *
+arm_psr_parse (ccp)
+     register char ** ccp;
+{
+  char * start = * ccp;
+  char   c;
+  char * p;
+  CONST struct asm_psr * psr;
+
+  p = start;
+
+  /* Skip to the end of the next word in the input stream.  */
+  do
+    {
+      c = *p++;
+    }
+  while (isalpha (c) || c == '_');
+
+  /* Terminate the word.  */
+  *--p = 0;
+
+  /* Now locate the word in the psr hash table.  */
+  psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
+
+  /* Restore the input stream.  */
+  *p = c;
+
+  /* If we found a valid match, advance the
+     stream pointer past the end of the word.  */
+  *ccp = p;
+
+  return psr;
+}
+
+/* Parse the input looking for a PSR flag.  */
 static int
-psr_required_here (str, cpsr, spsr)
+psr_required_here (str)
      char ** str;
-     int     cpsr;
-     int     spsr;
 {
-  int    psr;
   char * start = *str;
-  psr = arm_psr_parse (str);
+  CONST struct asm_psr * psr;
   
-  if  (psr == cpsr || psr == spsr)
+  psr = arm_psr_parse (str);
+
+  if (psr)
     {
-      if (psr == spsr)
-       inst.instruction |= 1 << 22;
+      /* If this is the SPSR that is being modified, set the R bit.  */
+      if (! psr->cpsr)
+       inst.instruction |= SPSR_BIT;
+
+      /* Set the psr flags in the MSR instruction.  */
+      inst.instruction |= psr->field << PSR_SHIFT;
       
       return SUCCESS;
     }
 
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden */
-  inst.error = _("<psr(f)> expected");
+  /* In the few cases where we might be able to accept
+     something else this error can be overridden.  */
+  inst.error = _("flag for {c}psr instruction expected");
 
   /* Restore the start point.  */
   *str = start;
@@ -1516,12 +1640,11 @@ psr_required_here (str, cpsr, spsr)
 
 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
@@ -1561,8 +1684,7 @@ cp_opc_expr (str, where, length)
 {
   expressionS expr;
 
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
 
   memset (&expr, '\0', sizeof (expr));
 
@@ -1600,10 +1722,10 @@ cp_reg_required_here (str, where)
     }
 
   /* In the few cases where we might be able to accept something else
-     this error can be overridden */
+     this error can be overridden */
   inst.error = _("Co-processor register expected");
 
-  /* Restore the start point */
+  /* Restore the start point */
   *str = start;
   return FAIL;
 }
@@ -1624,10 +1746,10 @@ fp_reg_required_here (str, where)
     }
 
   /* In the few cases where we might be able to accept something else
-     this error can be overridden */
+     this error can be overridden */
   inst.error = _("Floating point register expected");
 
-  /* Restore the start point */
+  /* Restore the start point */
   *str = start;
   return FAIL;
 }
@@ -1638,8 +1760,7 @@ cp_address_offset (str)
 {
   int offset;
 
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
 
   if (! is_immediate_prefix (**str))
     {
@@ -1694,14 +1815,12 @@ cp_address_required_here (str)
       int reg;
 
       p++;
-      while (*p == ' ')
-       p++;
+      skip_whitespace (p);
 
       if ((reg = reg_required_here (& p, 16)) == FAIL)
        return FAIL;
 
-      while (*p == ' ')
-       p++;
+      skip_whitespace (p);
 
       if (*p == ']')
        {
@@ -1739,8 +1858,7 @@ cp_address_required_here (str)
          if (cp_address_offset (& p) == FAIL)
            return FAIL;
 
-         while (*p == ' ')
-           p++;
+         skip_whitespace (p);
 
          if (*p++ != ']')
            {
@@ -1748,8 +1866,7 @@ cp_address_required_here (str)
              return FAIL;
            }
 
-         while (*p == ' ')
-           p++;
+         skip_whitespace (p);
 
          if (*p == '!')
            {
@@ -1786,8 +1903,8 @@ do_nop (str, flags)
      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;
 }
@@ -1797,115 +1914,119 @@ 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, CPSR_ALL, SPSR_ALL) == FAIL)
+  if (skip_past_comma (&str) == FAIL)
+    {
+      inst.error = _("comma expected after register name");
+      return;
+    }
+
+  skip_whitespace (str);
+
+  if (   strcmp (str, "CPSR") == 0
+      || strcmp (str, "SPSR") == 0
+        /* Lower case versions for backwards compatability.  */
+      || strcmp (str, "cpsr") == 0
+      || strcmp (str, "spsr") == 0)
+    str += 4;
+  /* This is for backwards compatability with older toolchains.  */
+  else if (strcmp (str, "cpsr_all") == 0
+          || strcmp (str, "spsr_all") == 0)
+    str += 7;
+  else
     {
-      inst.error = _("<psr> expected");
+      inst.error = _("{C|S}PSR expected");
       return;
     }
 
+  if (* str == 's' || * str == 'S')
+    inst.instruction |= SPSR_BIT;
+  
   inst.instruction |= flags;
   end_of_line (str);
-  return;
 }
 
-/* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression" */
+/* Two possible forms:
+      "{C|S}PSR_<field>, Rm",
+      "{C|S}PSR_f, #expression".  */
 static void
 do_msr (str, flags)
      char * str;
      unsigned long flags;
 {
-  int reg;
+  skip_whitespace (str);
 
-  while (*str == ' ')
-    str ++;
+  if (psr_required_here (& str) == FAIL)
+    return;
+    
+  if (skip_past_comma (& str) == FAIL)
+    {
+      inst.error = _("comma missing after psr flags");
+      return;
+    }
+
+  skip_whitespace (str);
 
-  if (psr_required_here (&str, CPSR_ALL, SPSR_ALL) == SUCCESS)
+  if (reg_required_here (& str, 0) != FAIL)
     {
-      inst.instruction |= PSR_ALL;
+      inst.error = NULL; 
+      inst.instruction |= flags;
+      end_of_line (str);
+      return;
+    }
 
-      /* Sytax should be "<psr>, Rm" */
-      if (skip_past_comma (&str) == FAIL
-         || (reg = reg_required_here (&str, 0)) == FAIL)
-       {
-         inst.error = bad_args;
-         return;
-       }
+  if (! is_immediate_prefix (* str))
+    {
+      inst.error = _("only a register or immediate value can follow a psr flag");
+      return;
+    }
+
+  str ++;
+  inst.error = NULL;
+  
+  if (my_get_expression (& inst.reloc.exp, & str))
+    {
+      inst.error = _("only a register or immediate value can follow a psr flag");
+      return;
+    }
+  
+  if (inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
+    {
+      inst.error = _("can only set flag field with immediate value");
+      return;
+    }
+  
+  flags |= INST_IMMEDIATE;
+         
+  if (inst.reloc.exp.X_add_symbol)
+    {
+      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+      inst.reloc.pc_rel = 0;
     }
   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;
-       }
+      unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
       
-      if (skip_past_comma (&str) == FAIL)
+      if (value == (unsigned) FAIL)
        {
-         inst.error = bad_args;
+         inst.error = _("Invalid constant");
          return;
        }
       
-      /* Syntax could be "<psrf>, rm", "<psrf>, #expression" */
-      
-      if ((reg = reg_required_here (& str, 0)) != FAIL)
-       ;
-      /* Immediate expression */
-      else if (is_immediate_prefix (* str))
-       {
-         str ++;
-         inst.error = NULL;
-         
-         if (my_get_expression (& inst.reloc.exp, & str))
-           {
-             inst.error = _("Register or shift expression expected");
-             return;
-           }
-
-         if (inst.reloc.exp.X_add_symbol)
-           {
-             inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-             inst.reloc.pc_rel = 0;
-           }
-         else
-           {
-             unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
-             if (value == FAIL)
-               {
-                 inst.error = _("Invalid constant");
-                 return;
-               }
-
-             inst.instruction |= value;
-           }
-
-         flags |= INST_IMMEDIATE;
-       }
-      else
-       {
-         inst.error = _("Error: unrecognised syntax for second argument to msr instruction");
-         return;
-       }
+      inst.instruction |= value;
     }
 
   inst.error = NULL; 
   inst.instruction |= flags;
   end_of_line (str);
-  return;
 }
 
 /* Long Multiply Parser
@@ -1921,27 +2042,26 @@ do_mull (str, 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;
     }
 
@@ -1952,13 +2072,13 @@ do_mull (str, flags)
   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;
     }
    
@@ -1974,32 +2094,31 @@ do_mul (str, 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;
     }
 
@@ -2009,13 +2128,13 @@ do_mul (str, flags)
   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;
     }
 
@@ -2031,32 +2150,31 @@ do_mla (str, 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;
     }
 
@@ -2068,13 +2186,13 @@ do_mla (str, flags)
       || 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;
     }
 
@@ -2227,8 +2345,7 @@ decode_shift (str, unrestrict)
   char * p;
   char   c;
     
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
     
   for (p = *str; isalpha (*p); p++)
     ;
@@ -2253,9 +2370,8 @@ decode_shift (str, unrestrict)
          return SUCCESS;
        }
 
-      while (*p == ' ')
-       p++;
-
+      skip_whitespace (p);
+      
       if (unrestrict && reg_required_here (&p, 8) != FAIL)
        {
          inst.instruction |= shft->value | SHIFT_BY_REG;
@@ -2398,7 +2514,7 @@ negate_data_op (instruction, value)
       return FAIL;
     }
 
-  if (value == FAIL)
+  if (value == (unsigned) FAIL)
     return FAIL;
 
   *instruction &= OPCODE_MASK;
@@ -2413,16 +2529,14 @@ data_op2 (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
@@ -2432,6 +2546,7 @@ data_op2 (str)
        {
          (*str)++;
          inst.error = NULL;
+         
          if (my_get_expression (&inst.reloc.exp, str))
            return FAIL;
 
@@ -2501,8 +2616,7 @@ static int
 fp_op2 (str)
      char ** str;
 {
-  while (**str == ' ')
-    (*str)++;
+  skip_whitespace (* str);
 
   if (fp_reg_required_here (str, 0) != FAIL)
     return SUCCESS;
@@ -2514,8 +2628,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 */
@@ -2559,8 +2673,7 @@ do_arit (str, flags)
      char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL
       || skip_past_comma (&str) == FAIL
@@ -2569,7 +2682,7 @@ do_arit (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2584,26 +2697,59 @@ do_adr (str, flags)
      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++;
+     into a relative address of the form "add rd, pc, #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;
+       inst.error = BAD_ARGS;
       return;
     }
+  
   /* Frag hacking will turn this into a sub instruction if the offset turns
      out to be negative.  */
   inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-  inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+  inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
   inst.reloc.pc_rel = 1;
   inst.instruction |= flags;
+  
   end_of_line (str);
+}
+
+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;
 }
 
@@ -2612,13 +2758,12 @@ do_cmp (str, flags)
      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;
     }
 
@@ -2626,7 +2771,7 @@ do_cmp (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2643,13 +2788,12 @@ do_mov (str, flags)
      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;
     }
 
@@ -2657,7 +2801,7 @@ do_mov (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2701,7 +2845,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;
        }
@@ -2752,7 +2896,8 @@ 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 */
@@ -2769,13 +2914,12 @@ do_ldst (str, flags)
       flags = 0;
     }
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
     
   if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2790,29 +2934,29 @@ do_ldst (str, flags)
       int reg;
 
       str++;
-      while (*str == ' ')
-       str++;
+
+      skip_whitespace (str);
 
       if ((reg = reg_required_here (&str, 16)) == FAIL)
        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
            {
@@ -2820,13 +2964,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;
                }
@@ -2849,8 +2993,7 @@ do_ldst (str, flags)
          if (ldst_extend (&str, halfword) == FAIL)
            return;
 
-         while (*str == ' ')
-           str++;
+         skip_whitespace (str);
 
          if (*str++ != ']')
            {
@@ -2858,13 +3001,13 @@ do_ldst (str, flags)
              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;
            }
@@ -2875,8 +3018,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;
@@ -2933,7 +3075,9 @@ do_ldst (str, flags)
         }
       else
         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+#ifndef TE_WINCE
       inst.reloc.exp.X_add_number -= 8;  /* PC rel adjust */
+#endif
       inst.reloc.pc_rel = 1;
       inst.instruction |= (REG_PC << 16);
       pre_inc = 1;
@@ -2970,8 +3114,7 @@ reg_list (strp)
            {
              int reg;
            
-             while (*str == ' ')
-               str++;
+             skip_whitespace (str);
 
              if ((reg = reg_required_here (& str, -1)) == FAIL)
                return FAIL;
@@ -3009,8 +3152,7 @@ reg_list (strp)
            } while (skip_past_comma (&str) != FAIL
                     || (in_range = 1, *str++ == '-'));
          str--;
-         while (*str == ' ')
-           str++;
+         skip_whitespace (str);
 
          if (*str++ != '}')
            {
@@ -3061,8 +3203,7 @@ reg_list (strp)
            }
        }
 
-      while (*str == ' ')
-       str++;
+      skip_whitespace (str);
 
       if (*str == '|' || *str == '+')
        {
@@ -3083,8 +3224,7 @@ do_ldmstm (str, flags)
   int base_reg;
   long range;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((base_reg = reg_required_here (&str, 16)) == FAIL)
     return;
@@ -3095,8 +3235,8 @@ do_ldmstm (str, flags)
       return;
     }
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
+
   if (*str == '!')
     {
       flags |= WRITE_BACK;
@@ -3107,14 +3247,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;
@@ -3127,8 +3267,7 @@ do_swi (str, flags)
      char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
   
   /* Allow optional leading '#'.  */
   if (is_immediate_prefix (*str))
@@ -3153,8 +3292,7 @@ do_swap (str, flags)
 {
   int reg;
   
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((reg = reg_required_here (&str, 12)) == FAIL)
     return;
@@ -3169,7 +3307,7 @@ do_swap (str, flags)
       || (reg = reg_required_here (&str, 0)) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3182,24 +3320,22 @@ do_swap (str, flags)
   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++ != ']')
     {
@@ -3215,7 +3351,7 @@ do_swap (str, flags)
 static void
 do_branch (str, flags)
      char *        str;
-     unsigned long flags;
+     unsigned long flags ATTRIBUTE_UNUSED;
 {
   if (my_get_expression (&inst.reloc.exp, &str))
     return;
@@ -3261,37 +3397,37 @@ do_branch (str, flags)
 static void
 do_bx (str, flags)
      char *        str;
-     unsigned long flags;
+     unsigned long flags ATTRIBUTE_UNUSED;
 {
   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;
-     unsigned long flags;
+     unsigned long flags ATTRIBUTE_UNUSED;
 {
   /* 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;
     }
 
@@ -3299,7 +3435,7 @@ do_cdp (str, flags)
       || cp_opc_expr (&str, 20,4) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3307,7 +3443,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3315,7 +3451,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 16) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3323,7 +3459,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 0) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3332,7 +3468,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;
        }
     }
@@ -3349,13 +3485,12 @@ do_lstc (str, 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;
     }
 
@@ -3363,7 +3498,7 @@ do_lstc (str, flags)
       || cp_reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3371,7 +3506,7 @@ do_lstc (str, flags)
       || cp_address_required_here (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3388,13 +3523,12 @@ do_co_reg (str, 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;
     }
 
@@ -3402,7 +3536,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;
     }
 
@@ -3410,7 +3544,7 @@ do_co_reg (str, flags)
       || reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3418,7 +3552,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;
     }
 
@@ -3426,7 +3560,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;
     }
 
@@ -3435,10 +3569,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;
@@ -3447,18 +3585,17 @@ do_co_reg (str, flags)
 static void
 do_fp_ctrl (str, flags)
      char *        str;
-     unsigned long flags;
+     unsigned long flags ATTRIBUTE_UNUSED;
 {
   /* 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;
     }
 
@@ -3469,10 +3606,9 @@ do_fp_ctrl (str, flags)
 static void
 do_fp_ldst (str, flags)
      char *        str;
-     unsigned long flags;
+     unsigned long flags ATTRIBUTE_UNUSED;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   switch (inst.suffix)
     {
@@ -3494,7 +3630,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;
     }
 
@@ -3502,7 +3638,7 @@ do_fp_ldst (str, flags)
       || cp_address_required_here (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3516,13 +3652,12 @@ do_fp_ldmstm (str, 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;
     }
 
@@ -3580,23 +3715,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)
        return;
 
-      while (*str == ' ')
-       str++;
+      skip_whitespace (str);
 
       if (*str != ']')
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
 
@@ -3644,7 +3777,7 @@ do_fp_ldmstm (str, flags)
           || cp_address_required_here (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3656,8 +3789,7 @@ do_fp_dyadic (str, flags)
      char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   switch (inst.suffix)
     {
@@ -3676,7 +3808,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;
     }
 
@@ -3684,7 +3816,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;
     }
 
@@ -3692,7 +3824,7 @@ do_fp_dyadic (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3706,8 +3838,7 @@ do_fp_monadic (str, flags)
      char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   switch (inst.suffix)
     {
@@ -3726,7 +3857,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;
     }
 
@@ -3734,7 +3865,7 @@ do_fp_monadic (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3748,13 +3879,12 @@ do_fp_cmp (str, flags)
      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;
     }
 
@@ -3762,7 +3892,7 @@ do_fp_cmp (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3776,8 +3906,7 @@ do_fp_from_reg (str, flags)
      char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   switch (inst.suffix)
     {
@@ -3796,7 +3925,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;
     }
 
@@ -3804,7 +3933,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;
     }
 
@@ -3818,8 +3947,7 @@ do_fp_to_reg (str, flags)
      char *        str;
      unsigned long flags;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL)
     return;
@@ -3828,7 +3956,7 @@ do_fp_to_reg (str, flags)
       || fp_reg_required_here (&str, 0) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3888,14 +4016,13 @@ thumb_add_sub (str, 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;
     }
 
@@ -4046,6 +4173,7 @@ thumb_add_sub (str, subtract)
            }
        }
     }
+  
   end_of_line (str);
 }
 
@@ -4056,14 +4184,13 @@ thumb_shift (str, 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;
     }
 
@@ -4071,7 +4198,7 @@ thumb_shift (str, shift)
     {
       /* Two operand immediate format, set Rs to Rd.  */
       Rs = Rd;
-      str++;
+      str ++;
       if (my_get_expression (&inst.reloc.exp, &str))
        return;
     }
@@ -4156,6 +4283,7 @@ thumb_shift (str, shift)
 
       inst.instruction |= Rd | (Rs << 3);
     }
+  
   end_of_line (str);
 }
 
@@ -4166,14 +4294,13 @@ thumb_mov_compare (str, 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;
     }
 
@@ -4256,14 +4383,13 @@ thumb_load_store (str, load_store, 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;
     }
 
@@ -4302,8 +4428,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;
@@ -4467,18 +4592,14 @@ do_t_arit (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)
@@ -4491,7 +4612,7 @@ do_t_arit (str)
          || inst.instruction == T_OPCODE_NEG
          || inst.instruction == T_OPCODE_MVN)
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
 
@@ -4560,7 +4681,7 @@ find_real_start (symbolP)
   const char * name = S_GET_NAME (symbolP);
   symbolS *    new_target;
 
-  /* This definitonmust agree with the one in gcc/config/arm/thumb.c */
+  /* This definiton must agree with the one in gcc/config/arm/thumb.c */
 #define STUB_NAME ".real_start_of"
 
   if (name == NULL)
@@ -4593,8 +4714,9 @@ static void
 do_t_branch23 (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.pc_rel = 1;
   end_of_line (str);
@@ -4616,8 +4738,7 @@ do_t_bx (str)
 {
   int reg;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
     return;
@@ -4646,8 +4767,7 @@ do_t_ldmstm (str)
   int Rb;
   long range;
 
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
     return;
@@ -4661,7 +4781,7 @@ do_t_ldmstm (str)
       || (range = reg_list (&str)) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4710,8 +4830,7 @@ do_t_lds (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
@@ -4757,13 +4876,12 @@ do_t_push_pop (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;
     }
 
@@ -4828,8 +4946,7 @@ static void
 do_t_swi (str)
      char * str;
 {
-  while (*str == ' ')
-    str++;
+  skip_whitespace (str);
 
   if (my_get_expression (&inst.reloc.exp, &str))
     return;
@@ -4843,24 +4960,28 @@ static void
 do_t_adr (str)
      char * str;
 {
+  int reg;
+
   /* 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++;
+     into a relative address of the form "add rd, pc, #label-.-4".  */
+  skip_whitespace (str);
 
-  if (reg_required_here (&str, 4) == FAIL  /* Store Rd in temporary location inside instruction.  */
+  /* Store Rd in temporary location inside instruction.  */
+  if ((reg = reg_required_here (&str, 4)) == FAIL
+      || (reg > 7)  /* For Thumb reg must be r0..r7.  */
       || skip_past_comma (&str) == FAIL
       || my_get_expression (&inst.reloc.exp, &str))
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
   inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-  inst.reloc.exp.X_add_number -= 4; /* PC relative adjust */
+  inst.reloc.exp.X_add_number -= 4; /* PC relative adjust */
   inst.reloc.pc_rel = 1;
-  inst.instruction |= REG_PC; /* Rd is already placed into the instruction */
+  inst.instruction |= REG_PC; /* Rd is already placed into the instruction.  */
+  
   end_of_line (str);
 }
 
@@ -4917,7 +5038,8 @@ set_constant_flonums ()
 void
 md_begin ()
 {
-  int i;
+  unsigned mach;
+  unsigned int i;
   
   if (   (arm_ops_hsh = hash_new ()) == NULL
       || (arm_tops_hsh = hash_new ()) == NULL
@@ -4947,53 +5069,54 @@ md_begin ()
   {
     unsigned int flags = 0;
     
-    /* Set the flags in the private structure */
+    /* Set the flags in the private structure */
     if (uses_apcs_26)      flags |= F_APCS26;
     if (support_interwork) flags |= F_INTERWORK;
     if (uses_apcs_float)   flags |= F_APCS_FLOAT;
     if (pic_code)          flags |= F_PIC;
+    if ((cpu_variant & FPU_ALL) == FPU_NONE) flags |= F_SOFT_FLOAT;
 
     bfd_set_private_flags (stdoutput, flags);
   }
 #endif
   
-  {
-    unsigned mach;
-    
-    /* Record the CPU type as well */
-    switch (cpu_variant & ARM_CPU_MASK)
-      {
-      case ARM_2:
-       mach = bfd_mach_arm_2;
-       break;
-       
-      case ARM_3: /* also ARM_250 */
-       mach = bfd_mach_arm_2a;
-       break;
-
-      default:
-      case ARM_6 | ARM_3 | ARM_2:      /* Actually no CPU type defined */
+  /* Record the CPU type as well.  */
+  switch (cpu_variant & ARM_CPU_MASK)
+    {
+    case ARM_2:
+      mach = bfd_mach_arm_2;
+      break;
+      
+    case ARM_3:                /* Also ARM_250.  */
+      mach = bfd_mach_arm_2a;
+      break;
+      
+    default:
+    case ARM_6 | ARM_3 | ARM_2:        /* Actually no CPU type defined.  */
+      mach = bfd_mach_arm_4;
+      break;
+      
+    case ARM_7:                /* Also ARM_6.  */
+      mach = bfd_mach_arm_3;
+      break;
+    }
+  
+  /* Catch special cases.  */
+  if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
+    {
+      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_ARCH_V4) == ARM_ARCH_V4)
        mach = bfd_mach_arm_4;
-       break;
-       
-      case ARM_7:                      /* also ARM_6 */
-       mach = bfd_mach_arm_3;
-       break;
-      }
-
-    /* Catch special cases */
-    if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
-      {
-       if (cpu_variant & ARM_THUMB)
-         mach = bfd_mach_arm_4T;
-       else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4)
-         mach = bfd_mach_arm_4;
-       else if (cpu_variant & ARM_LONGMUL)
-         mach = bfd_mach_arm_3M;
-      }
-       
-    bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
-  }
+      else if (cpu_variant & ARM_LONGMUL)
+       mach = bfd_mach_arm_3M;
+    }
+  
+  bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
 }
 
 /* Turn an integer of n bytes (in val) into a stream of bytes appropriate
@@ -5001,8 +5124,7 @@ 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;
@@ -5141,26 +5263,31 @@ md_pcrel_from (fixP)
     {
       /* 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;
     }
 
+#ifdef TE_WINCE
+  /* The pattern was adjusted to accomodate CE's off-by-one fixups,
+     so we un-adjust here to compensate for the accomodation.  */
+  return fixP->fx_where + fixP->fx_frag->fr_address + 8;
+#else
   return fixP->fx_where + fixP->fx_frag->fr_address;
+#endif
 }
 
 /* Round up a section size to the appropriate boundary. */
 valueT
 md_section_align (segment, size)
-     segT   segment;
+     segT   segment ATTRIBUTE_UNUSED;
      valueT size;
 {
 #ifdef OBJ_ELF
-  /* Don't align the dwarf2 debug sections */
-  if (!strncmp (segment->name, ".debug", 5))
-    return size;
-#endif
+  return size;
+#else
   /* Round all sects to multiple of 4 */
   return (size + 3) & ~3;
+#endif
 }
 
 /* Under ELF we need to default _GLOBAL_OFFSET_TABLE.  Otherwise 
@@ -5169,7 +5296,7 @@ md_section_align (segment, size)
 /* ARGSUSED */
 symbolS *
 md_undefined_symbol (name)
-     char * name;
+     char * name ATTRIBUTE_UNUSED;
 {
 #ifdef OBJ_ELF
   if (name[0] == '_' && name[1] == 'G'
@@ -5234,33 +5361,6 @@ arm_reg_parse (ccp)
   return FAIL;
 }
 
-static int
-arm_psr_parse (ccp)
-     register char ** ccp;
-{
-  char * start = * ccp;
-  char   c;
-  char * p;
-  CONST struct asm_psr * psr;
-
-  p = start;
-  c = *p++;
-  while (isalpha (c) || c == '_')
-    c = *p++;
-
-  *--p = 0;  
-  psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
-  *p = c;
-
-  if (psr)
-    {
-      *ccp = p;
-      return psr->number;
-    }
-
-  return FAIL;
-}
-
 int
 md_apply_fix3 (fixP, val, seg)
      fixS *      fixP;
@@ -5279,7 +5379,7 @@ md_apply_fix3 (fixP, val, seg)
 
   /* 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)
@@ -5296,14 +5396,16 @@ md_apply_fix3 (fixP, val, seg)
          && S_GET_SEGMENT (fixP->fx_addsy) != seg)
        {
          if (target_oabi
-             && fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
+             && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+               || fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
+               ))
            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)
     {
@@ -5317,7 +5419,8 @@ md_apply_fix3 (fixP, val, seg)
          && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
        {
          as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("invalid constant (%x) after fixup\n"), value);
+                       _("invalid constant (%lx) after fixup"),
+                       (unsigned long) value);
          break;
        }
 
@@ -5325,15 +5428,62 @@ md_apply_fix3 (fixP, val, seg)
       md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
       break;
 
-     case BFD_RELOC_ARM_OFFSET_IMM:
+    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:
       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;
@@ -5344,34 +5494,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;
        }
 
@@ -5433,16 +5586,82 @@ md_apply_fix3 (fixP, val, seg)
     case BFD_RELOC_ARM_PCREL_BRANCH:
       newval = md_chars_to_number (buf, INSN_SIZE);
 
+      /* Sign-extend a 24-bit number.  */
+#define SEXT24(x)      ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
+
 #ifdef OBJ_ELF
       if (! target_oabi)
-        value = fixP->fx_offset;
+       value = fixP->fx_offset;
 #endif
-      value  = (value >> 2) & 0x00ffffff;
-      value  = (value + (newval & 0x00ffffff)) & 0x00ffffff;
-      newval = value | (newval & 0xff000000);
+
+      /* We are going to store value (shifted right by two) in the
+        instruction, in a 24 bit, signed field.  Thus we need to check
+        that none of the top 8 bits of the shifted value (top 7 bits of
+         the unshifted, unsigned value) are set, or that they are all set.  */
+      if ((value & ~ ((offsetT) 0x1ffffff)) != 0
+         && ((value & ~ ((offsetT) 0x1ffffff)) != ~ ((offsetT) 0x1ffffff)))
+       {
+#ifdef OBJ_ELF
+         /* Normally we would be stuck at this point, since we cannot store
+            the absolute address that is the destination of the branch in the
+            24 bits of the branch instruction.  If however, we happen to know
+            that the destination of the branch is in the same section as the
+            branch instruciton itself, then we can compute the relocation for
+            ourselves and not have to bother the linker with it.
+            
+            FIXME: The tests for OBJ_ELF and ! target_oabi are only here
+            because I have not worked out how to do this for OBJ_COFF or
+            target_oabi.  */
+         if (! target_oabi
+             && fixP->fx_addsy != NULL
+             && S_IS_DEFINED (fixP->fx_addsy)
+             && S_GET_SEGMENT (fixP->fx_addsy) == seg)
+           {
+             /* Get pc relative value to go into the branch.  */
+             value = * val;
+
+             /* Permit a backward branch provided that enough bits are set.
+                Allow a forwards branch, provided that enough bits are clear.  */
+             if ((value & ~ ((offsetT) 0x1ffffff)) == ~ ((offsetT) 0x1ffffff)
+                 || (value & ~ ((offsetT) 0x1ffffff)) == 0)
+               fixP->fx_done = 1;
+           }
+         
+         if (! fixP->fx_done)
+#endif
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("gas can't handle same-section branch dest >= 0x04000000"));
+       }
+
+      value >>= 2;
+      value += SEXT24 (newval);
+      
+      if ((value & ~ ((offsetT) 0xffffff)) != 0
+         && ((value & ~ ((offsetT) 0xffffff)) != ~ ((offsetT) 0xffffff)))
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("out of range branch"));
+      
+      newval = (value & 0x00ffffff) | (newval & 0xff000000);
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
+    case BFD_RELOC_ARM_PCREL_BLX:
+      {
+       offsetT hbit;
+       newval = md_chars_to_number (buf, INSN_SIZE);
+
+#ifdef OBJ_ELF
+       if (! target_oabi)
+           value = fixP->fx_offset;
+#endif
+       hbit   = (value >> 1) & 1;
+       value  = (value >> 2) & 0x00ffffff;
+       value  = (value + (newval & 0x00ffffff)) & 0x00ffffff;
+       newval = value | (newval & 0xfe000000) | (hbit << 24);
+       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);
       {
@@ -5475,6 +5694,7 @@ md_apply_fix3 (fixP, val, seg)
       md_number_to_chars (buf, newval, THUMB_SIZE);
       break;
 
+    case BFD_RELOC_THUMB_PCREL_BLX:
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
       {
         offsetT newval2;
@@ -5485,6 +5705,9 @@ md_apply_fix3 (fixP, val, seg)
         diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
         if (diff & 0x400000)
          diff |= ~0x3fffff;
+#ifdef OBJ_ELF
+       value = fixP->fx_offset;
+#endif
         value += diff;
         if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
          as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -5583,7 +5806,7 @@ md_apply_fix3 (fixP, val, seg)
 
          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;
@@ -5592,34 +5815,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);
@@ -5658,7 +5882,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;
@@ -5691,7 +5916,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;
 
@@ -5705,7 +5931,7 @@ 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);
@@ -5719,7 +5945,7 @@ md_apply_fix3 (fixP, val, seg)
     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;
@@ -5729,7 +5955,7 @@ md_apply_fix3 (fixP, val, seg)
    format.  */
 arelent *
 tc_gen_reloc (section, fixp)
-     asection * section;
+     asection * section ATTRIBUTE_UNUSED;
      fixS * fixp;
 {
   arelent * reloc;
@@ -5775,10 +6001,12 @@ tc_gen_reloc (section, fixp)
        }
 
     case BFD_RELOC_ARM_PCREL_BRANCH:
+    case BFD_RELOC_ARM_PCREL_BLX:
     case BFD_RELOC_RVA:      
     case BFD_RELOC_THUMB_PCREL_BRANCH9:
     case BFD_RELOC_THUMB_PCREL_BRANCH12:
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
+    case BFD_RELOC_THUMB_PCREL_BLX:
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
       code = fixp->fx_r_type;
@@ -5787,17 +6015,11 @@ tc_gen_reloc (section, fixp)
     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 boundry (Implicit dump?)"));
+                   _("Literal referenced across section boundary (Implicit dump?)"));
       return NULL;
 
-    case BFD_RELOC_ARM_GOTPC:
-      assert (fixp->fx_pcrel != 0);
-      code = fixp->fx_r_type;
-      code = BFD_RELOC_32_PCREL;
-      break;
-
 #ifdef OBJ_ELF
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
@@ -5812,6 +6034,12 @@ tc_gen_reloc (section, fixp)
                    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)"),
@@ -5834,7 +6062,7 @@ 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)"),
@@ -5863,21 +6091,25 @@ tc_gen_reloc (section, fixp)
       return NULL;
     }
 
+   /* 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;
+
   return reloc;
 }
 
 int
 md_estimate_size_before_relax (fragP, segtype)
-     fragS * fragP;
-     segT    segtype;
+     fragS * fragP ATTRIBUTE_UNUSED;
+     segT    segtype ATTRIBUTE_UNUSED;
 {
   as_fatal (_("md_estimate_size_before_relax\n"));
   return 1;
 }
 
 static void
-output_inst (str)
-     char * str;
+output_inst PARAMS ((void))
 {
   char * to = NULL;
     
@@ -5888,11 +6120,18 @@ 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);
@@ -5930,9 +6169,8 @@ md_assemble (str)
   memset (&inst, '\0', sizeof (inst));
   inst.reloc.type = BFD_RELOC_NONE;
 
-  if (*str == ' ')
-    str++;                     /* Skip leading white space */
-    
+  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++)
@@ -5947,62 +6185,81 @@ md_assemble (str)
 
   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--)
        {
          c = *q;
          *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)
                {
@@ -6018,18 +6275,33 @@ md_assemble (str)
                        as_tsktsk (
 _("Warning: Use of the 'nv' conditional is deprecated\n"));
 
-                     inst.instruction |= cond->value;
+                     cond_code = cond->value;
                      r += 2;
                    }
                  else
-                   inst.instruction |= COND_ALWAYS;
+                   cond_code = COND_ALWAYS;
                }
              else
-               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;
 
@@ -6083,7 +6355,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
                }
 
              (*opcode->parms) (p, flag_bits);
-             output_inst (start);
+             output_inst ();
              return;
            }
 
@@ -6093,11 +6365,9 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
     }
 
   /* 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';
@@ -6109,8 +6379,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
       char * r;
       
       q += 4;
-      while (*q == ' ')
-       q++;
+      skip_whitespace (q);
 
       for (r = q; *r != '\0'; r++)
        if (*r == ' ')
@@ -6130,20 +6399,17 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
          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'"),
@@ -6170,9 +6436,10 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
  *            -m[arm]3                Arm 3 processor
  *            -m[arm]6[xx],           Arm 6 processors
  *            -m[arm]7[xx][t][[d]m]   Arm 7 processors
- *            -m8[10]                 Arm 8 processors
- *            -m9[20][tdmi]           Arm 9 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[t]]       Arm architectures
  *            -mall                   All (except the ARM1)
  *    FP variants:
  *            -mfpa10, -mfpa11        FPA10 and 11 co-processor instructions
@@ -6261,7 +6528,8 @@ md_parse_option (c, arg)
             }
           else if (streq (str, "thumb-interwork"))
             {
-              cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCHv4;
+             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
@@ -6383,6 +6651,7 @@ md_parse_option (c, arg)
                case 70:
                case 700:
                case 710:
+               case 720:
                case 7100:
                case 7500:
                  break;
@@ -6395,7 +6664,7 @@ md_parse_option (c, arg)
                 switch (* str)
                   {
                   case 't':
-                    cpu_variant |= (ARM_THUMB | ARM_ARCHv4);
+                    cpu_variant |= (ARM_THUMB | ARM_ARCH_V4);
                     break;
 
                   case 'm':
@@ -6422,43 +6691,56 @@ md_parse_option (c, arg)
 
            case '8':
              if (streq (str, "8") || streq (str, "810"))
-               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCHv4 | ARM_LONGMUL;
+               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_ARCHv4 | ARM_LONGMUL | ARM_THUMB;
+               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_ARCHv4 | ARM_LONGMUL;
+               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_ARCHv4 | ARM_LONGMUL | ARM_THUMB;
+               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_ARCHv4 | ARM_LONGMUL | ARM_THUMB;
+               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_ARCHv4 | ARM_LONGMUL;
+               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 */
+             /* Select variant based on architecture rather than processor */
              switch (*++str)
                {
                case '2':
                  switch (*++str)
                    {
-                   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;
+                   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;
                    }
                  break;
                  
@@ -6469,18 +6751,34 @@ 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 0:   break;
+                   default:
+                     as_bad (_("Invalid architecture variant -m%s"), arg);
+                     break;
                    }
                  break;
                  
@@ -6498,9 +6796,11 @@ md_parse_option (c, arg)
        }
       break;
 
+#if defined OBJ_ELF || defined OBJ_COFF
     case 'k':
       pic_code = 1;
       break;
+#endif
       
     default:
       return 0;
@@ -6513,39 +6813,29 @@ void
 md_show_usage (fp)
      FILE * fp;
 {
-  fprintf (fp,
-_("\
+  fprintf (fp, _("\
  ARM Specific Assembler Options:\n\
   -m[arm][<processor name>] select processor variant\n\
-  -m[arm]v[2|2a|3|3m|4|4t select architecture variant\n\
+  -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] select architecture variant\n\
   -mthumb                   only allow Thumb instructions\n\
   -mthumb-interwork         mark the assembled code as supporting interworking\n\
   -mall                     allow any instruction\n\
   -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,
-_("\
+  -mno-fpu                  don't allow any floating-point instructions.\n\
   -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-float              floating point args are passed in FP regs\n"));
-  fprintf (fp,
-_("\
+  fprintf (fp, _("\
+  -mapcs-32, -mapcs-26      specify which ARM Procedure Calling Standard to use\n\
+  -mapcs-float              floating point args are passed in FP regs\n\
   -mapcs-reentrant          the code is position independent/reentrant\n"));
   #endif
 #ifdef OBJ_ELF
-  fprintf (fp,
-_("\
+  fprintf (fp, _("\
   -moabi                    support the old ELF ABI\n"));
 #endif
 #ifdef ARM_BI_ENDIAN
-  fprintf (fp,
-_("\
+  fprintf (fp, _("\
   -EB                       assemble code for a big endian cpu\n\
   -EL                       assemble code for a little endian cpu\n"));
 #endif
@@ -6594,24 +6884,7 @@ fix_new_arm (frag, where, size, exp, pc_rel, reloc)
 }
 
 
-/*
- * This fix_new is called by cons via TC_CONS_FIX_NEW
- *
- * We check the expression to see if it is of the form
- *  __GLOBAL_OFFSET_TABLE + ???
- * If it is then this is a PC relative reference to the GOT.
- * i.e.
- *     ldr     sl, L1
- *     add     sl, pc, sl
- * L2:
- *     ...
- * L1:
- *     .word   __GLOBAL_OFFSET_TABLE + (. - (L2 + 4))
- *
- * In this case use a reloc type BFD_RELOC_ARM_GOTPC instead of the
- * normal BFD_RELOC_{16,32,64}
- */
-
+/* This fix_new is called by cons via TC_CONS_FIX_NEW.  */
 void
 cons_fix_new_arm (frag, where, size, exp)
      fragS *       frag;
@@ -6640,28 +6913,21 @@ cons_fix_new_arm (frag, where, size, exp)
       break;
     }
   
-  /* Look for possible GOTPC reloc */
-  
-  /*
-   * Look for pic assembler and 'undef symbol + expr symbol' expression
-   * and a 32 bit size.
-   */
-  
   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.  */
  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)
-    {
-      subseg_set (text_section, 0); /* Put it at the end of text section */
-      s_ltorg (0);
-      listing_prev_line ();
-    }
+  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
@@ -6738,24 +7004,30 @@ arm_adjust_symtab ()
         }
 
       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_symbol_type * elf_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,
+            otherwise tag label as .code 16.  */
          if (THUMB_IS_FUNC (sym))
-           {
-             elf_sym = elf_symbol (symbol_get_bfdsym (sym));
-             bind = ELF_ST_BIND (elf_sym);
-             elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
-            }
+           elf_sym->internal_elf_sym.st_info =
+             ELF_ST_INFO (bind, STT_ARM_TFUNC);
+         else
+           elf_sym->internal_elf_sym.st_info =
+             ELF_ST_INFO (bind, STT_ARM_16BIT);
          }
      }
 #endif
@@ -6783,9 +7055,7 @@ arm_canonicalize_symbol_name (name)
 
   if (thumb_mode && (len = strlen (name)) > 5
       && streq (name + len - 5, "/data"))
-    {
-      *(name + len - 5) = 0;
-    }
+    *(name + len - 5) = 0;
 
   return name;
 }
@@ -6828,7 +7098,6 @@ boolean
 arm_fix_adjustable (fixP)
    fixS * fixP;
 {
-
   if (fixP->fx_addsy == NULL)
     return 1;
   
@@ -6880,7 +7149,10 @@ arm_force_relocation (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_ARM_PCREL_BRANCH
+      || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
+      || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
+      || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)    
     return 1;
   
   return 0;
@@ -6891,7 +7163,7 @@ arm_parse_reloc ()
 {
   char   id[16];
   char * ip;
-  int    i;
+  unsigned int i;
   static struct
   {
     char * str;
@@ -6907,7 +7179,7 @@ arm_parse_reloc ()
     /* 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
+    { NULL, 0,         BFD_RELOC_UNUSED }
 #undef MAP    
   };
 
@@ -6959,7 +7231,8 @@ s_arm_elf_cons (nbytes)
           int size = bfd_get_reloc_size (howto);
 
           if (size > nbytes)
-            as_bad ("%s relocations do not fit in %d bytes", howto->name, nbytes);
+            as_bad ("%s relocations do not fit in %d bytes",
+                   howto->name, nbytes);
           else
             {
               register char * p = frag_more ((int) nbytes);
@@ -6974,7 +7247,7 @@ s_arm_elf_cons (nbytes)
     }
   while (*input_line_pointer++ == ',');
 
-  input_line_pointer--;                /* Put terminator back into stream. */
+  input_line_pointer--;                /* Put terminator back into stream.  */
   demand_empty_rest_of_line ();
 }
 
This page took 0.074057 seconds and 4 git commands to generate.