Automate generate on man pages
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index fd83a42af70a33c2d0a7f5ba22a10ca15bdd697d..e5f0c136af19898790b2b3bd9c7529282fec3a03 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-arm.c -- Assemble for the ARM
-   Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
    Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
@@ -35,6 +35,7 @@
 
 #ifdef OBJ_ELF
 #include "elf/arm.h"
+#include "dwarf2dbg.h"
 #endif
 
 /* Types of processor to assemble for.  */
 #define ARM_CPU_MASK   0x0000000f
 
 /* The following bitmasks control CPU extensions (ARM7 onwards):   */
-#define ARM_LONGMUL    0x00000010      /* Allow long multiplies.  */
-#define ARM_HALFWORD   0x00000020      /* Allow half word loads.  */
-#define ARM_THUMB      0x00000040      /* Allow BX instruction.   */
+#define ARM_EXT_LONGMUL        0x00000010      /* Allow long multiplies.  */
+#define ARM_EXT_HALFWORD 0x00000020    /* Allow half word loads.  */
+#define ARM_EXT_THUMB  0x00000040      /* Allow BX instruction.   */
 #define ARM_EXT_V5     0x00000080      /* Allow CLZ, etc.         */
+#define ARM_EXT_V5E    0x00000100      /* "El Segundo".           */
+#define ARM_EXT_XSCALE 0x00000200      /* Allow MIA etc.          */
 
 /* 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_V3M     ARM_EXT_LONGMUL
+#define ARM_ARCH_V4     (ARM_ARCH_V3M | ARM_EXT_HALFWORD)
+#define ARM_ARCH_V4T   (ARM_ARCH_V4 | ARM_EXT_THUMB)
 #define ARM_ARCH_V5    (ARM_ARCH_V4 | ARM_EXT_V5)
-#define ARM_ARCH_V5T   (ARM_ARCH_V5 | ARM_THUMB)
+#define ARM_ARCH_V5T   (ARM_ARCH_V5 | ARM_EXT_THUMB)
+#define ARM_ARCH_V5TE  (ARM_ARCH_V5T | ARM_EXT_V5E)
+#define ARM_ARCH_XSCALE (ARM_ARCH_V5TE | ARM_EXT_XSCALE)
 
 /* Some useful combinations:  */
 #define ARM_ANY                0x00ffffff
 #define FPU_MEMMULTI   0x7f000000      /* Not fpu_core.  */
 
 #ifndef CPU_DEFAULT
+#if defined __XSCALE__
+#define CPU_DEFAULT    (ARM_9 | ARM_ARCH_XSCALE)
+#else
 #if defined __thumb__
-#define CPU_DEFAULT (ARM_ARCH_V4 | ARM_THUMB)
+#define CPU_DEFAULT    (ARM_7 | ARM_ARCH_V4T)
 #else
-#define CPU_DEFAULT ARM_ALL
+#define CPU_DEFAULT    ARM_ALL
+#endif
 #endif
 #endif
 
@@ -97,6 +107,7 @@ static int target_oabi = 0;
 #if defined OBJ_COFF || defined OBJ_ELF
 /* Flags stored in private area of BFD structure.  */
 static boolean uses_apcs_26      = false;
+static boolean atpcs             = false;
 static boolean support_interwork = false;
 static boolean uses_apcs_float   = false;
 static boolean pic_code          = false;
@@ -243,9 +254,11 @@ LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
 #define CP_T_UD  0x00800000
 #define CP_T_WB  0x00200000
 
-#define CONDS_BIT       (0x00100000)
-#define LOAD_BIT        (0x00100000)
-#define TRANS_BIT      (0x00200000)
+#define CONDS_BIT        0x00100000
+#define LOAD_BIT         0x00100000
+#define TRANS_BIT       0x00200000
+
+#define DOUBLE_LOAD_FLAG 0x00000001
 
 struct asm_cond
 {
@@ -293,6 +306,7 @@ static CONST struct asm_flg s_flag[] =
 
 static CONST struct asm_flg ldr_flags[] =
 {
+  {"d",  DOUBLE_LOAD_FLAG},
   {"b",  0x00400000},
   {"t",  TRANS_BIT},
   {"bt", 0x00400000 | TRANS_BIT},
@@ -304,6 +318,7 @@ static CONST struct asm_flg ldr_flags[] =
 
 static CONST struct asm_flg str_flags[] =
 {
+  {"d",  DOUBLE_LOAD_FLAG},
   {"b",  0x00400000},
   {"t",  TRANS_BIT},
   {"bt", 0x00400000 | TRANS_BIT},
@@ -329,24 +344,24 @@ static CONST struct asm_flg ldm_flags[] =
   {"ed", 0x01800000},
   {"fd", 0x00800000},
   {"ea", 0x01000000},
-  {"fa", 0x08000000},
+  {"fa", 0x00000000},
   {"ib", 0x01800000},
   {"ia", 0x00800000},
   {"db", 0x01000000},
-  {"da", 0x08000000},
+  {"da", 0x00000000},
   {NULL, 0}
 };
 
 static CONST struct asm_flg stm_flags[] =
 {
-  {"ed", 0x08000000},
+  {"ed", 0x00000000},
   {"fd", 0x01000000},
   {"ea", 0x00800000},
   {"fa", 0x01800000},
   {"ib", 0x01800000},
   {"ia", 0x00800000},
   {"db", 0x01000000},
-  {"da", 0x08000000},
+  {"da", 0x00000000},
   {NULL, 0}
 };
 
@@ -590,6 +605,31 @@ static void do_mull                PARAMS ((char *, unsigned long));
 /* ARM THUMB.  */
 static void do_bx               PARAMS ((char *, unsigned long));
 
+/* ARM_EXT_XScale.  */
+static void do_mia             PARAMS ((char *, unsigned long));
+static void do_mar             PARAMS ((char *, unsigned long));
+static void do_mra             PARAMS ((char *, unsigned long));
+static void do_pld             PARAMS ((char *, unsigned long));
+static void do_ldrd            PARAMS ((char *, unsigned long));
+
+/* ARM_EXT_V5.  */
+static void do_blx             PARAMS ((char *, unsigned long));
+static void do_bkpt            PARAMS ((char *, unsigned long));
+static void do_clz             PARAMS ((char *, unsigned long));
+static void do_lstc2           PARAMS ((char *, unsigned long));
+static void do_cdp2            PARAMS ((char *, unsigned long));
+static void do_co_reg2         PARAMS ((char *, unsigned long));
+
+static void do_t_blx           PARAMS ((char *));
+static void do_t_bkpt          PARAMS ((char *));
+
+/* ARM_EXT_V5E.  */
+static void do_smla            PARAMS ((char *, unsigned long));
+static void do_smlal           PARAMS ((char *, unsigned long));
+static void do_smul            PARAMS ((char *, unsigned long));
+static void do_qadd            PARAMS ((char *, unsigned long));
+static void do_co_reg2c                PARAMS ((char *, unsigned long));
+
 /* Coprocessor Instructions.  */
 static void do_cdp             PARAMS ((char *, unsigned long));
 static void do_lstc            PARAMS ((char *, unsigned long));
@@ -647,10 +687,10 @@ static bfd_reloc_code_real_type   arm_parse_reloc PARAMS ((void));
    take 2:  */
 #define INSN_SIZE       4
 
-/* LONGEST_INST is the longest basic instruction name without conditions or
-   flags.  ARM7M has 4 of length 5.  */
-
-#define LONGEST_INST 5
+/* LONGEST_INST is the longest basic instruction name without
+   conditions or flags.  ARM7M has 4 of length 5.  El Segundo
+   has one basic instruction name of length 7 (SMLALxy).  */
+#define LONGEST_INST 7
 
 struct asm_opcode
 {
@@ -676,6 +716,19 @@ struct asm_opcode
 
 static CONST struct asm_opcode insns[] =
 {
+/* Intel XScale extensions to ARM V5 ISA.  */
+  {"mia",   0x0e200010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miaph", 0x0e280010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miabb", 0x0e2c0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miabt", 0x0e2d0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miatb", 0x0e2e0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miatt", 0x0e2f0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"mar",   0x0c400000, NULL,   NULL,        ARM_EXT_XSCALE, do_mar},
+  {"mra",   0x0c500000, NULL,   NULL,        ARM_EXT_XSCALE, do_mra},
+  {"pld",   0xf450f000, "",     NULL,        ARM_EXT_XSCALE, do_pld},
+  {"ldr",   0x000000d0, NULL,   ldr_flags,   ARM_ANY,        do_ldrd},
+  {"str",   0x000000f0, NULL,   str_flags,   ARM_ANY,        do_ldrd},
+
 /* ARM Instructions.  */
   {"and",   0x00000000, NULL,   s_flag,      ARM_ANY,      do_arit},
   {"eor",   0x00200000, NULL,   s_flag,      ARM_ANY,      do_arit},
@@ -726,13 +779,13 @@ static CONST struct asm_opcode insns[] =
            handled by the PSR_xxx defines above.  */
 
 /* ARM 7M long multiplies - need signed/unsigned flags!  */
-  {"smull", 0x00c00090, NULL,   s_flag,      ARM_LONGMUL,  do_mull},
-  {"umull", 0x00800090, NULL,   s_flag,      ARM_LONGMUL,  do_mull},
-  {"smlal", 0x00e00090, NULL,   s_flag,      ARM_LONGMUL,  do_mull},
-  {"umlal", 0x00a00090, NULL,   s_flag,      ARM_LONGMUL,  do_mull},
+  {"smull", 0x00c00090, NULL,   s_flag,      ARM_EXT_LONGMUL,  do_mull},
+  {"umull", 0x00800090, NULL,   s_flag,      ARM_EXT_LONGMUL,  do_mull},
+  {"smlal", 0x00e00090, NULL,   s_flag,      ARM_EXT_LONGMUL,  do_mull},
+  {"umlal", 0x00a00090, NULL,   s_flag,      ARM_EXT_LONGMUL,  do_mull},
 
 /* ARM THUMB interworking.  */
-  {"bx",    0x012fff10, NULL,   NULL,        ARM_THUMB,    do_bx},
+  {"bx",    0x012fff10, NULL,   NULL,        ARM_EXT_THUMB,    do_bx},
 
 /* Floating point instructions.  */
   {"wfs",   0x0e200110, NULL,   NULL,        FPU_ALL,      do_fp_ctrl},
@@ -788,6 +841,48 @@ static CONST struct asm_opcode insns[] =
   {"stc",   0x0c000000, NULL,  cplong_flag,  ARM_2UP,      do_lstc},
   {"mcr",   0x0e000010, NULL,  NULL,         ARM_2UP,      do_co_reg},
   {"mrc",   0x0e100010, NULL,  NULL,         ARM_2UP,      do_co_reg},
+
+/*  ARM ISA extension 5.  */
+/* Note: blx is actually 2 opcodes, so the .value is set dynamically.
+   And it's sometimes conditional and sometimes not.  */
+  {"blx",            0, NULL,   NULL,        ARM_EXT_V5, do_blx},
+  {"clz",   0x016f0f10, NULL,   NULL,        ARM_EXT_V5, do_clz},
+  {"bkpt",  0xe1200070, "",    NULL,        ARM_EXT_V5, do_bkpt},
+  {"ldc2",  0xfc100000, "",    cplong_flag, ARM_EXT_V5, do_lstc2},
+  {"stc2",  0xfc000000, "",    cplong_flag, ARM_EXT_V5, do_lstc2},
+  {"cdp2",  0xfe000000, "",    NULL,        ARM_EXT_V5, do_cdp2},
+  {"mcr2",  0xfe000010, "",    NULL,        ARM_EXT_V5, do_co_reg2},
+  {"mrc2",  0xfe100010, "",    NULL,        ARM_EXT_V5, do_co_reg2},
+
+/*  ARM ISA extension 5E, El Segundo.  */
+  {"smlabb", 0x01000080, NULL,   NULL,        ARM_EXT_V5E, do_smla},
+  {"smlatb", 0x010000a0, NULL,   NULL,        ARM_EXT_V5E, do_smla},
+  {"smlabt", 0x010000c0, NULL,   NULL,        ARM_EXT_V5E, do_smla},
+  {"smlatt", 0x010000e0, NULL,   NULL,        ARM_EXT_V5E, do_smla},
+
+  {"smlawb", 0x01200080, NULL,   NULL,        ARM_EXT_V5E, do_smla},
+  {"smlawt", 0x012000c0, NULL,   NULL,        ARM_EXT_V5E, do_smla},
+
+  {"smlalbb",0x01400080, NULL,   NULL,        ARM_EXT_V5E, do_smlal},
+  {"smlaltb",0x014000a0, NULL,   NULL,        ARM_EXT_V5E, do_smlal},
+  {"smlalbt",0x014000c0, NULL,   NULL,        ARM_EXT_V5E, do_smlal},
+  {"smlaltt",0x014000e0, NULL,   NULL,        ARM_EXT_V5E, do_smlal},
+
+  {"smulbb", 0x01600080, NULL,   NULL,        ARM_EXT_V5E, do_smul},
+  {"smultb", 0x016000a0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
+  {"smulbt", 0x016000c0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
+  {"smultt", 0x016000e0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
+
+  {"smulwb", 0x012000a0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
+  {"smulwt", 0x012000e0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
+
+  {"qadd",   0x01000050, NULL,   NULL,        ARM_EXT_V5E, do_qadd},
+  {"qdadd",  0x01400050, NULL,   NULL,        ARM_EXT_V5E, do_qadd},
+  {"qsub",   0x01200050, NULL,   NULL,        ARM_EXT_V5E, do_qadd},
+  {"qdsub",  0x01600050, NULL,   NULL,        ARM_EXT_V5E, do_qadd},
+
+  {"mcrr",  0x0c400000, NULL,   NULL,         ARM_EXT_V5E, do_co_reg2c},
+  {"mrrc",  0x0c500000, NULL,   NULL,         ARM_EXT_V5E, do_co_reg2c},
 };
 
 /* Defines for various bits that we will want to toggle.  */
@@ -946,64 +1041,66 @@ struct thumb_opcode
 
 static CONST struct thumb_opcode tinsns[] =
 {
-  {"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},
+  {"adc",      0x4140,         2,      ARM_EXT_THUMB, do_t_arit},
+  {"add",      0x0000,         2,      ARM_EXT_THUMB, do_t_add},
+  {"and",      0x4000,         2,      ARM_EXT_THUMB, do_t_arit},
+  {"asr",      0x0000,         2,      ARM_EXT_THUMB, do_t_asr},
+  {"b",                T_OPCODE_BRANCH, 2,     ARM_EXT_THUMB, do_t_branch12},
+  {"beq",      0xd0fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bne",      0xd1fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bcs",      0xd2fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bhs",      0xd2fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bcc",      0xd3fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bul",      0xd3fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"blo",      0xd3fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bmi",      0xd4fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bpl",      0xd5fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bvs",      0xd6fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bvc",      0xd7fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bhi",      0xd8fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bls",      0xd9fe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bge",      0xdafe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"blt",      0xdbfe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bgt",      0xdcfe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"ble",      0xddfe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bal",      0xdefe,         2,      ARM_EXT_THUMB, do_t_branch9},
+  {"bic",      0x4380,         2,      ARM_EXT_THUMB, do_t_arit},
+  {"bl",       0xf7fffffe,     4,      ARM_EXT_THUMB, do_t_branch23},
+  {"blx",      0,              0,      ARM_EXT_V5, do_t_blx},
+  {"bkpt",     0xbe00,         2,      ARM_EXT_V5, do_t_bkpt},
+  {"bx",       0x4700,         2,      ARM_EXT_THUMB, do_t_bx},
+  {"cmn",      T_OPCODE_CMN,   2,      ARM_EXT_THUMB, do_t_arit},
+  {"cmp",      0x0000,         2,      ARM_EXT_THUMB, do_t_compare},
+  {"eor",      0x4040,         2,      ARM_EXT_THUMB, do_t_arit},
+  {"ldmia",    0xc800,         2,      ARM_EXT_THUMB, do_t_ldmstm},
+  {"ldr",      0x0000,         2,      ARM_EXT_THUMB, do_t_ldr},
+  {"ldrb",     0x0000,         2,      ARM_EXT_THUMB, do_t_ldrb},
+  {"ldrh",     0x0000,         2,      ARM_EXT_THUMB, do_t_ldrh},
+  {"ldrsb",    0x5600,         2,      ARM_EXT_THUMB, do_t_lds},
+  {"ldrsh",    0x5e00,         2,      ARM_EXT_THUMB, do_t_lds},
+  {"ldsb",     0x5600,         2,      ARM_EXT_THUMB, do_t_lds},
+  {"ldsh",     0x5e00,         2,      ARM_EXT_THUMB, do_t_lds},
+  {"lsl",      0x0000,         2,      ARM_EXT_THUMB, do_t_lsl},
+  {"lsr",      0x0000,         2,      ARM_EXT_THUMB, do_t_lsr},
+  {"mov",      0x0000,         2,      ARM_EXT_THUMB, do_t_mov},
+  {"mul",      T_OPCODE_MUL,   2,      ARM_EXT_THUMB, do_t_arit},
+  {"mvn",      T_OPCODE_MVN,   2,      ARM_EXT_THUMB, do_t_arit},
+  {"neg",      T_OPCODE_NEG,   2,      ARM_EXT_THUMB, do_t_arit},
+  {"orr",      0x4300,         2,      ARM_EXT_THUMB, do_t_arit},
+  {"pop",      0xbc00,         2,      ARM_EXT_THUMB, do_t_push_pop},
+  {"push",     0xb400,         2,      ARM_EXT_THUMB, do_t_push_pop},
+  {"ror",      0x41c0,         2,      ARM_EXT_THUMB, do_t_arit},
+  {"sbc",      0x4180,         2,      ARM_EXT_THUMB, do_t_arit},
+  {"stmia",    0xc000,         2,      ARM_EXT_THUMB, do_t_ldmstm},
+  {"str",      0x0000,         2,      ARM_EXT_THUMB, do_t_str},
+  {"strb",     0x0000,         2,      ARM_EXT_THUMB, do_t_strb},
+  {"strh",     0x0000,         2,      ARM_EXT_THUMB, do_t_strh},
+  {"swi",      0xdf00,         2,      ARM_EXT_THUMB, do_t_swi},
+  {"sub",      0x0000,         2,      ARM_EXT_THUMB, do_t_sub},
+  {"tst",      T_OPCODE_TST,   2,      ARM_EXT_THUMB, do_t_arit},
   /* Pseudo ops:  */
-  {"adr",       0x0000,         2,      ARM_THUMB, do_t_adr},
-  {"nop",       0x46C0,         2,      ARM_THUMB, do_t_nop},      /* mov r8,r8  */
+  {"adr",       0x0000,         2,      ARM_EXT_THUMB, do_t_adr},
+  {"nop",       0x46C0,         2,      ARM_EXT_THUMB, do_t_nop},      /* mov r8,r8  */
 };
 
 struct reg_entry
@@ -1060,6 +1157,7 @@ static CONST struct reg_entry reg_table[] =
 #define BAD_PC                 _("r15 not allowed here")
 #define BAD_FLAGS      _("Instruction should not have flags")
 #define BAD_COND       _("Instruction is not conditional")
+#define ERR_NO_ACCUM   _("acc0 expected")
 
 static struct hash_control * arm_ops_hsh   = NULL;
 static struct hash_control * arm_tops_hsh  = NULL;
@@ -1119,6 +1217,8 @@ CONST pseudo_typeS md_pseudo_table[] =
   { "sect.s",      arm_s_section, 0 },
   { "word",        s_arm_elf_cons, 4 },
   { "long",        s_arm_elf_cons, 4 },
+  { "file",        dwarf2_directive_file, 0 },
+  { "loc",         dwarf2_directive_loc,  0 },
 #else
   { "word",        cons, 4},
 #endif
@@ -1610,7 +1710,7 @@ opcode_select (width)
     case 16:
       if (! thumb_mode)
        {
-         if (! (cpu_variant & ARM_THUMB))
+         if (! (cpu_variant & ARM_EXT_THUMB))
            as_bad (_("selected processor does not support THUMB opcodes"));
 
          thumb_mode = 1;
@@ -1623,7 +1723,7 @@ opcode_select (width)
     case 32:
       if (thumb_mode)
        {
-         if ((cpu_variant & ARM_ANY) == ARM_THUMB)
+         if ((cpu_variant & ARM_ANY) == ARM_EXT_THUMB)
            as_bad (_("selected processor does not support ARM opcodes"));
 
          thumb_mode = 0;
@@ -2178,207 +2278,1272 @@ do_msr (str, flags)
       return;
     }
 
-  if (inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
+  if ((cpu_variant & ARM_EXT_V5) != ARM_EXT_V5
+      && inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
+    {
+      inst.error = _("immediate value cannot be used to set this field");
+      return;
+    }
+
+  flags |= INST_IMMEDIATE;
+
+  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 == (unsigned) FAIL)
+       {
+         inst.error = _("Invalid constant");
+         return;
+       }
+
+      inst.instruction |= value;
+    }
+
+  inst.error = NULL;
+  inst.instruction |= flags;
+  end_of_line (str);
+}
+
+/* Long Multiply Parser
+   UMULL RdLo, RdHi, Rm, Rs
+   SMULL RdLo, RdHi, Rm, Rs
+   UMLAL RdLo, RdHi, Rm, Rs
+   SMLAL RdLo, RdHi, Rm, Rs.  */
+
+static void
+do_mull (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  int rdlo, rdhi, rm, rs;
+
+  /* Only one format "rdlo, rdhi, rm, rs".  */
+  skip_whitespace (str);
+
+  if ((rdlo = reg_required_here (&str, 12)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || (rdhi = reg_required_here (&str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  /* rdhi, rdlo and rm must all be different.  */
+  if (rdlo == rdhi || rdlo == rm || rdhi == rm)
+    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
+
+  if (skip_past_comma (&str) == FAIL
+      || (rs = reg_required_here (&str, 8)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  inst.instruction |= flags;
+  end_of_line (str);
+  return;
+}
+
+static void
+do_mul (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  int rd, rm;
+
+  /* Only one format "rd, rm, rs".  */
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (&str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rd == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  if (rm == rd)
+    as_tsktsk (_("rd and rm should be different in mul"));
+
+  if (skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 8)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  inst.instruction |= flags;
+  end_of_line (str);
+  return;
+}
+
+static void
+do_mla (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  int rd, rm;
+
+  /* Only one format "rd, rm, rs, rn".  */
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (&str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rd == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  if (rm == rd)
+    as_tsktsk (_("rd and rm should be different in mla"));
+
+  if (skip_past_comma (&str) == FAIL
+      || (rd = reg_required_here (&str, 8)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 12)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rd == REG_PC || rm == REG_PC)
     {
-      inst.error = _("can only set flag field with immediate value");
+      inst.error = BAD_PC;
       return;
     }
 
-  flags |= INST_IMMEDIATE;
+  inst.instruction |= flags;
+  end_of_line (str);
+  return;
+}
+
+/* Expects *str -> the characters "acc0", possibly with leading blanks.
+   Advances *str to the next non-alphanumeric.
+   Returns 0, or else FAIL (in which case sets inst.error).
+
+  (In a future XScale, there may be accumulators other than zero.
+  At that time this routine and its callers can be upgraded to suit.)  */
+
+static int
+accum0_required_here (str)
+     char ** str;
+{
+  static char buff [128];      /* Note the address is taken.  Hence, static.  */
+  char * p = * str;
+  char   c;
+  int result = 0;              /* The accum number.  */
+
+  skip_whitespace (p);
+
+  *str = p;                    /* Advance caller's string pointer too.  */
+  c = *p++;
+  while (isalnum (c))
+    c = *p++;
+
+  *--p = 0;                    /* Aap nul into input buffer at non-alnum.  */
+
+  if (! ( streq (*str, "acc0") || streq (*str, "ACC0")))
+    {
+      sprintf (buff, _("acc0 expected, not '%.100s'"), *str);
+      inst.error = buff;
+      result = FAIL;
+    }
+
+  *p = c;                      /* Unzap.  */
+  *str = p;                    /* Caller's string pointer to after match.  */
+  return result;
+}
+
+/* Expects **str -> after a comma. May be leading blanks.
+   Advances *str, recognizing a load  mode, and setting inst.instruction.
+   Returns rn, or else FAIL (in which case may set inst.error
+   and not advance str)
+
+   Note: doesn't know Rd, so no err checks that require such knowledge.  */
+
+static int
+ld_mode_required_here (string)
+     char ** string;
+{
+  char * str = * string;
+  int    rn;
+  int    pre_inc = 0;
+
+  skip_whitespace (str);
+
+  if (* str == '[')
+    {
+      str++;
+
+      skip_whitespace (str);
+
+      if ((rn = reg_required_here (& str, 16)) == FAIL)
+       return FAIL;
+
+      skip_whitespace (str);
+
+      if (* str == ']')
+       {
+         str ++;
+
+         if (skip_past_comma (& str) == SUCCESS)
+           {
+             /* [Rn],... (post inc) */
+             if (ldst_extend (& str, 1) == FAIL)
+               return FAIL;
+           }
+         else        /* [Rn] */
+           {
+              skip_whitespace (str);
+
+              if (* str == '!')
+               {
+                 str ++;
+                 inst.instruction |= WRITE_BACK;
+               }
+
+             inst.instruction |= INDEX_UP | HWOFFSET_IMM;
+             pre_inc = 1;
+           }
+       }
+      else       /* [Rn,...] */
+       {
+         if (skip_past_comma (& str) == FAIL)
+           {
+             inst.error = _("pre-indexed expression expected");
+             return FAIL;
+           }
+
+         pre_inc = 1;
+
+         if (ldst_extend (& str, 1) == FAIL)
+           return FAIL;
+
+         skip_whitespace (str);
+
+         if (* str ++ != ']')
+           {
+             inst.error = _("missing ]");
+             return FAIL;
+           }
+
+         skip_whitespace (str);
+
+         if (* str == '!')
+           {
+             str ++;
+             inst.instruction |= WRITE_BACK;
+           }
+       }
+    }
+  else if (* str == '=')       /* ldr's "r,=label" syntax */
+    /* We should never reach here, because <text> = <expression> is
+       caught gas/read.c read_a_source_file() as a .set operation.  */
+    return FAIL;
+  else                         /* PC +- 8 bit immediate offset.  */
+    {
+      if (my_get_expression (& inst.reloc.exp, & str))
+       return FAIL;
+
+      inst.instruction            |= HWOFFSET_IMM;     /* The I bit.  */
+      inst.reloc.type              = BFD_RELOC_ARM_OFFSET_IMM8;
+      inst.reloc.exp.X_add_number -= 8;                /* PC rel adjust.  */
+      inst.reloc.pc_rel            = 1;
+      inst.instruction            |= (REG_PC << 16);
+
+      rn = REG_PC;
+      pre_inc = 1;
+    }
+
+  inst.instruction |= (pre_inc ? PRE_INDEX : 0);
+  * string = str;
+
+  return rn;
+}
+
+/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
+   SMLAxy{cond} Rd,Rm,Rs,Rn
+   SMLAWy{cond} Rd,Rm,Rs,Rn
+   Error if any register is R15.  */
+
+static void
+do_smla (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  int rd, rm, rs, rn;
+
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (& str, 16)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rs = reg_required_here (& str, 8)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rn = reg_required_here (& str, 12)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (rd == REG_PC || rm == REG_PC || rs == REG_PC || rn == REG_PC)
+    inst.error = BAD_PC;
+
+  else if (flags)
+    inst.error = BAD_FLAGS;
+
+  else
+    end_of_line (str);
+}
+
+/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
+   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
+   Error if any register is R15.
+   Warning if Rdlo == Rdhi.  */
+
+static void
+do_smlal (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  int rdlo, rdhi, rm, rs;
+
+  skip_whitespace (str);
+
+  if ((rdlo = reg_required_here (& str, 12)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rdhi = reg_required_here (& str, 16)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rs = reg_required_here (& str, 8)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  if (rdlo == rdhi)
+    as_tsktsk (_("rdhi and rdlo must be different"));
+
+  if (flags)
+    inst.error = BAD_FLAGS;
+  else
+    end_of_line (str);
+}
+
+/* ARM V5E (El Segundo) signed-multiply (argument parse)
+   SMULxy{cond} Rd,Rm,Rs
+   Error if any register is R15.  */
+
+static void
+do_smul (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  int rd, rm, rs;
+
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (& str, 16)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rs = reg_required_here (& str, 8)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (rd == REG_PC || rm == REG_PC || rs == REG_PC)
+    inst.error = BAD_PC;
+
+  else if (flags)
+    inst.error = BAD_FLAGS;
+
+  else
+    end_of_line (str);
+}
+
+/* ARM V5E (El Segundo) saturating-add/subtract (argument parse)
+   Q[D]{ADD,SUB}{cond} Rd,Rm,Rn
+   Error if any register is R15.  */
+
+static void
+do_qadd (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  int rd, rm, rn;
+
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (& str, 12)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rn = reg_required_here (& str, 16)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
+    inst.error = BAD_PC;
+
+  else if (flags)
+    inst.error = BAD_FLAGS;
+
+  else
+    end_of_line (str);
+}
+
+/* ARM V5E (el Segundo)
+   MCRRcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
+   MRRCcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
+
+   These are equivalent to the XScale instructions MAR and MRA,
+   respectively, when coproc == 0, opcode == 0, and CRm == 0.
+
+   Result unpredicatable if Rd or Rn is R15.  */
+
+static void
+do_co_reg2c (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  int rd, rn;
+
+  skip_whitespace (str);
+
+  if (co_proc_number (& str) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_opc_expr (& str, 4, 4) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || (rd = reg_required_here (& str, 12)) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || (rn = reg_required_here (& str, 16)) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  /* Unpredictable result if rd or rn is R15.  */
+  if (rd == REG_PC || rn == REG_PC)
+    as_tsktsk
+      (_("Warning: Instruction unpredictable when using r15"));
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 0) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (flags)
+    inst.error = BAD_COND;
+
+  end_of_line (str);
+}
+
+/* ARM V5 count-leading-zeroes instruction (argument parse)
+     CLZ{<cond>} <Rd>, <Rm>
+     Condition defaults to COND_ALWAYS.
+     Error if Rd or Rm are R15.  */
+
+static void
+do_clz (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  int rd, rm;
+
+  if (flags)
+    {
+      as_bad (BAD_FLAGS);
+      return;
+    }
+
+  skip_whitespace (str);
+
+  if (((rd = reg_required_here (& str, 12)) == FAIL)
+      || (skip_past_comma (& str) == FAIL)
+      || ((rm = reg_required_here (& str, 0)) == FAIL))
+    inst.error = BAD_ARGS;
+
+  else if (rd == REG_PC || rm == REG_PC )
+    inst.error = BAD_PC;
+
+  else
+    end_of_line (str);
+}
+
+/* ARM V5 (argument parse)
+     LDC2{L} <coproc>, <CRd>, <addressing mode>
+     STC2{L} <coproc>, <CRd>, <addressing mode>
+     Instruction is not conditional, and has 0xf in the codition field.
+     Otherwise, it's the same as LDC/STC.  */
+
+static void
+do_lstc2 (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  if (flags)
+    inst.error = BAD_COND;
+
+  skip_whitespace (str);
+
+  if (co_proc_number (& str) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else if (skip_past_comma (& str) == FAIL
+          || cp_reg_required_here (& str, 12) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else if (skip_past_comma (& str) == FAIL
+          || cp_address_required_here (& str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else
+    end_of_line (str);
+}
+
+/* ARM V5 (argument parse)
+     CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
+     Instruction is not conditional, and has 0xf in the condition field.
+     Otherwise, it's the same as CDP.  */
+
+static void
+do_cdp2 (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  skip_whitespace (str);
+
+  if (co_proc_number (& str) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_opc_expr (& str, 20,4) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 12) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 16) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 0) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == SUCCESS)
+    {
+      if (cp_opc_expr (& str, 5, 3) == FAIL)
+       {
+         if (!inst.error)
+           inst.error = BAD_ARGS;
+         return;
+       }
+    }
+
+  if (flags)
+    inst.error = BAD_FLAGS;
+
+  end_of_line (str);
+}
+
+/* ARM V5 (argument parse)
+     MCR2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
+     MRC2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
+     Instruction is not conditional, and has 0xf in the condition field.
+     Otherwise, it's the same as MCR/MRC.  */
+
+static void
+do_co_reg2 (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  skip_whitespace (str);
+
+  if (co_proc_number (& str) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_opc_expr (& str, 21, 3) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || reg_required_here (& str, 12) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 16) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 0) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == SUCCESS)
+    {
+      if (cp_opc_expr (& str, 5, 3) == FAIL)
+       {
+         if (!inst.error)
+           inst.error = BAD_ARGS;
+         return;
+       }
+    }
+
+  if (flags)
+    inst.error = BAD_COND;
+
+  end_of_line (str);
+}
+
+/* THUMB V5 breakpoint instruction (argument parse)
+       BKPT <immed_8>.  */
+
+static void
+do_t_bkpt (str)
+     char * str;
+{
+  expressionS expr;
+  unsigned long number;
+
+  skip_whitespace (str);
+
+  /* Allow optional leading '#'.  */
+  if (is_immediate_prefix (*str))
+    str ++;
+
+  memset (& expr, '\0', sizeof (expr));
+  if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
+    {
+      inst.error = _("bad or missing expression");
+      return;
+    }
+
+  number = expr.X_add_number;
+
+  /* Check it fits an 8 bit unsigned.  */
+  if (number != (number & 0xff))
+    {
+      inst.error = _("immediate value out of range");
+      return;
+    }
+
+  inst.instruction |= number;
+
+  end_of_line (str);
+}
+
+/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only.
+   Expects inst.instruction is set for BLX(1).
+   Note: this is cloned from do_branch, and the reloc changed to be a
+       new one that can cope with setting one extra bit (the H bit).  */
+
+static void
+do_branch25 (str, flags)
+     char *        str;
+     unsigned long flags ATTRIBUTE_UNUSED;
+{
+  if (my_get_expression (& inst.reloc.exp, & str))
+    return;
+
+#ifdef OBJ_ELF
+  {
+    char * save_in;
+
+    /* ScottB: February 5, 1998 */
+    /* Check to see of PLT32 reloc required for the instruction.  */
+
+    /* arm_parse_reloc() works on input_line_pointer.
+       We actually want to parse the operands to the branch instruction
+       passed in 'str'.  Save the input pointer and restore it later.  */
+    save_in = input_line_pointer;
+    input_line_pointer = str;
+
+    if (inst.reloc.exp.X_op == O_symbol
+       && *str == '('
+       && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
+      {
+       inst.reloc.type   = BFD_RELOC_ARM_PLT32;
+       inst.reloc.pc_rel = 0;
+       /* Modify str to point to after parsed operands, otherwise
+          end_of_line() will complain about the (PLT) left in str.  */
+       str = input_line_pointer;
+      }
+    else
+      {
+       inst.reloc.type   = BFD_RELOC_ARM_PCREL_BLX;
+       inst.reloc.pc_rel = 1;
+      }
+
+    input_line_pointer = save_in;
+  }
+#else
+  inst.reloc.type   = BFD_RELOC_ARM_PCREL_BLX;
+  inst.reloc.pc_rel = 1;
+#endif /* OBJ_ELF */
+
+  end_of_line (str);
+}
+
+/* ARM V5 branch-link-exchange instruction (argument parse)
+     BLX <target_addr>         ie BLX(1)
+     BLX{<condition>} <Rm>     ie BLX(2)
+   Unfortunately, there are two different opcodes for this mnemonic.
+   So, the insns[].value is not used, and the code here zaps values
+       into inst.instruction.
+   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
+
+static void
+do_blx (str, flags)
+     char *        str;
+     unsigned long flags;
+{
+  char * mystr = str;
+  int rm;
+
+  if (flags)
+    {
+      as_bad (BAD_FLAGS);
+      return;
+    }
+
+  skip_whitespace (mystr);
+  rm = reg_required_here (& mystr, 0);
+
+  /* The above may set inst.error.  Ignore his opinion.  */
+  inst.error = 0;
+
+  if (rm != FAIL)
+    {
+      /* Arg is a register.
+        Use the condition code our caller put in inst.instruction.
+        Pass ourselves off as a BX with a funny opcode.  */
+      inst.instruction |= 0x012fff30;
+      do_bx (str, flags);
+    }
+  else
+    {
+      /* This must be is BLX <target address>, no condition allowed.  */
+      if (inst.instruction != COND_ALWAYS)
+       {
+         inst.error = BAD_COND;
+         return;
+       }
+
+      inst.instruction = 0xfafffffe;
+
+      /* Process like a B/BL, but with a different reloc.
+        Note that B/BL expecte fffffe, not 0, offset in the opcode table.  */
+      do_branch25 (str, flags);
+    }
+}
+
+/* ARM V5 Thumb BLX (argument parse)
+       BLX <target_addr>       which is BLX(1)
+       BLX <Rm>                which is BLX(2)
+   Unfortunately, there are two different opcodes for this mnemonic.
+   So, the tinsns[].value is not used, and the code here zaps values
+       into inst.instruction.  */
+
+static void
+do_t_blx (str)
+     char * str;
+{
+  char * mystr = str;
+  int rm;
+
+  skip_whitespace (mystr);
+  inst.instruction = 0x4780;
 
-  if (inst.reloc.exp.X_add_symbol)
+  /* Note that this call is to the ARM register recognizer.  BLX(2)
+     uses the ARM register space, not the Thumb one, so a call to
+     thumb_reg() would be wrong.  */
+  rm = reg_required_here (& mystr, 3);
+  inst.error = 0;
+
+  if (rm != FAIL)
     {
-      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-      inst.reloc.pc_rel = 0;
+      /* It's BLX(2).  The .instruction was zapped with rm & is final.  */
+      inst.size = 2;
     }
   else
     {
-      unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
+      /* No ARM register.  This must be BLX(1).  Change the .instruction.  */
+      inst.instruction = 0xf7ffeffe;
+      inst.size = 4;
 
-      if (value == (unsigned) FAIL)
-       {
-         inst.error = _("Invalid constant");
-         return;
-       }
+      if (my_get_expression (& inst.reloc.exp, & mystr))
+       return;
 
-      inst.instruction |= value;
+      inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BLX;
+      inst.reloc.pc_rel = 1;
     }
 
-  inst.error = NULL;
-  inst.instruction |= flags;
-  end_of_line (str);
+  end_of_line (mystr);
 }
 
-/* Long Multiply Parser
-   UMULL RdLo, RdHi, Rm, Rs
-   SMULL RdLo, RdHi, Rm, Rs
-   UMLAL RdLo, RdHi, Rm, Rs
-   SMLAL RdLo, RdHi, Rm, Rs.  */
+/* ARM V5 breakpoint instruction (argument parse)
+     BKPT <16 bit unsigned immediate>
+     Instruction is not conditional.
+       The bit pattern given in insns[] has the COND_ALWAYS condition,
+       and it is an error if the caller tried to override that.
+     Note "flags" is nonzero if a flag was supplied (which is an error).  */
 
 static void
-do_mull (str, flags)
-     char * str;
+do_bkpt (str, flags)
+     char *        str;
      unsigned long flags;
 {
-  int rdlo, rdhi, rm, rs;
+  expressionS expr;
+  unsigned long number;
 
-  /* Only one format "rdlo, rdhi, rm, rs".  */
   skip_whitespace (str);
 
-  if ((rdlo = reg_required_here (&str, 12)) == FAIL)
-    {
-      inst.error = BAD_ARGS;
-      return;
-    }
+  /* Allow optional leading '#'.  */
+  if (is_immediate_prefix (* str))
+    str++;
 
-  if (skip_past_comma (&str) == FAIL
-      || (rdhi = reg_required_here (&str, 16)) == FAIL)
-    {
-      inst.error = BAD_ARGS;
-      return;
-    }
+  memset (& expr, '\0', sizeof (expr));
 
-  if (skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 0)) == FAIL)
+  if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
     {
-      inst.error = BAD_ARGS;
+      inst.error = _("bad or missing expression");
       return;
     }
 
-  /* rdhi, rdlo and rm must all be different.  */
-  if (rdlo == rdhi || rdlo == rm || rdhi == rm)
-    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
+  number = expr.X_add_number;
 
-  if (skip_past_comma (&str) == FAIL
-      || (rs = reg_required_here (&str, 8)) == FAIL)
+  /* Check it fits a 16 bit unsigned.  */
+  if (number != (number & 0xffff))
     {
-      inst.error = BAD_ARGS;
+      inst.error = _("immediate value out of range");
       return;
     }
 
-  if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
-    {
-      inst.error = BAD_PC;
-      return;
-    }
+  /* Top 12 of 16 bits to bits 19:8.  */
+  inst.instruction |= (number & 0xfff0) << 4;
+
+  /* Bottom 4 of 16 bits to bits 3:0.  */
+  inst.instruction |= number & 0xf;
 
-  inst.instruction |= flags;
   end_of_line (str);
-  return;
+
+  if (flags)
+    inst.error = BAD_FLAGS;
 }
 
+/* Xscale multiply-accumulate (argument parse)
+     MIAcc   acc0,Rm,Rs
+     MIAPHcc acc0,Rm,Rs
+     MIAxycc acc0,Rm,Rs.  */
+
 static void
-do_mul (str, flags)
+do_mia (str, flags)
      char * str;
      unsigned long flags;
 {
-  int rd, rm;
+  int rs;
+  int rm;
 
-  /* Only one format "rd, rm, rs".  */
-  skip_whitespace (str);
+  if (flags)
+    as_bad (BAD_FLAGS);
 
-  if ((rd = reg_required_here (&str, 16)) == FAIL)
-    {
-      inst.error = BAD_ARGS;
-      return;
-    }
+  else if (accum0_required_here (& str) == FAIL)
+    inst.error = ERR_NO_ACCUM;
 
-  if (rd == REG_PC)
+  else if (skip_past_comma (& str) == FAIL
+          || (rm = reg_required_here (& str, 0)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (skip_past_comma (& str) == FAIL
+          || (rs = reg_required_here (& str, 12)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  /* inst.instruction has now been zapped with both rm and rs.  */
+  else if (rm == REG_PC || rs == REG_PC)
+    inst.error = BAD_PC;       /* Undefined result if rm or rs is R15.  */
+
+  else
+    end_of_line (str);
+}
+
+/* Xscale move-accumulator-register (argument parse)
+
+     MARcc   acc0,RdLo,RdHi.  */
+
+static void
+do_mar (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  int rdlo, rdhi;
+
+  if (flags)
+    as_bad (BAD_FLAGS);
+
+  else if (accum0_required_here (& str) == FAIL)
+    inst.error = ERR_NO_ACCUM;
+
+  else if (skip_past_comma (& str) == FAIL
+          || (rdlo = reg_required_here (& str, 12)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (skip_past_comma (& str) == FAIL
+          || (rdhi = reg_required_here (& str, 16)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  /* inst.instruction has now been zapped with both rdlo and rdhi.  */
+  else if (rdlo == REG_PC || rdhi == REG_PC)
+    inst.error = BAD_PC;       /* Undefined result if rdlo or rdhi is R15.  */
+
+  else
+    end_of_line (str);
+}
+
+/* Xscale move-register-accumulator (argument parse)
+
+     MRAcc   RdLo,RdHi,acc0.  */
+
+static void
+do_mra (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  int rdlo;
+  int rdhi;
+
+  if (flags)
     {
-      inst.error = BAD_PC;
+      as_bad (BAD_FLAGS);
       return;
     }
 
-  if (skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 0)) == FAIL)
+  skip_whitespace (str);
+
+  if ((rdlo = reg_required_here (& str, 12)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (skip_past_comma (& str) == FAIL
+          || (rdhi = reg_required_here (& str, 16)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if  (skip_past_comma (& str) == FAIL
+           || accum0_required_here (& str) == FAIL)
+    inst.error = ERR_NO_ACCUM;
+
+  /* inst.instruction has now been zapped with both rdlo and rdhi.  */
+  else if (rdlo == rdhi)
+    inst.error = BAD_ARGS;     /* Undefined result if 2 writes to same reg.  */
+
+  else if (rdlo == REG_PC || rdhi == REG_PC)
+    inst.error = BAD_PC;       /* Undefined result if rdlo or rdhi is R15.  */
+  else
+    end_of_line (str);
+}
+
+/* Xscale: Preload-Cache
+
+    PLD <addr_mode>
+
+  Syntactically, like LDR with B=1, W=0, L=1.  */
+
+static void
+do_pld (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  int rd;
+
+  if (flags)
     {
-      inst.error = BAD_ARGS;
+      as_bad (BAD_FLAGS);
       return;
     }
 
-  if (rm == REG_PC)
+  skip_whitespace (str);
+
+  if (* str != '[')
     {
-      inst.error = BAD_PC;
+      inst.error = _("'[' expected after PLD mnemonic");
       return;
     }
 
-  if (rm == rd)
-    as_tsktsk (_("rd and rm should be different in mul"));
+  ++ str;
+  skip_whitespace (str);
 
-  if (skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 8)) == FAIL)
+  if ((rd = reg_required_here (& str, 16)) == FAIL)
+    return;
+
+  skip_whitespace (str);
+
+  if (* str == ']')
     {
-      inst.error = BAD_ARGS;
-      return;
-    }
+      /* [Rn], ... ?  */
+      ++ str;
+      skip_whitespace (str);
 
-  if (rm == REG_PC)
+      if (skip_past_comma (& str) == SUCCESS)
+       {
+         if (ldst_extend (& str, 0) == FAIL)
+           return;
+       }
+      else if (* str == '!') /* [Rn]! */
+       {
+         inst.error = _("writeback used in preload instruction");
+         ++ str;
+       }
+      else /* [Rn] */
+       inst.instruction |= INDEX_UP | PRE_INDEX;
+    }
+  else /* [Rn, ...] */
     {
-      inst.error = BAD_PC;
-      return;
+      if (skip_past_comma (& str) == FAIL)
+       {
+         inst.error = _("pre-indexed expression expected");
+         return;
+       }
+
+      if (ldst_extend (& str, 0) == FAIL)
+       return;
+
+      skip_whitespace (str);
+
+      if (* str != ']')
+       {
+         inst.error = _("missing ]");
+         return;
+       }
+
+      ++ str;
+      skip_whitespace (str);
+
+      if (* str == '!') /* [Rn]! */
+       {
+         inst.error = _("writeback used in preload instruction");
+         ++ str;
+       }
+
+      inst.instruction |= PRE_INDEX;
     }
 
-  inst.instruction |= flags;
   end_of_line (str);
-  return;
 }
 
+/* Xscale load-consecutive (argument parse)
+   Mode is like LDRH.
+
+     LDRccD R, mode
+     STRccD R, mode.  */
+
 static void
-do_mla (str, flags)
+do_ldrd (str, flags)
      char * str;
      unsigned long flags;
 {
-  int rd, rm;
-
-  /* Only one format "rd, rm, rs, rn".  */
-  skip_whitespace (str);
+  int rd;
+  int rn;
 
-  if ((rd = reg_required_here (&str, 16)) == FAIL)
+  if (flags != DOUBLE_LOAD_FLAG)
     {
-      inst.error = BAD_ARGS;
+      /* Change instruction pattern to normal ldr/str.  */
+      if (inst.instruction & 0x20)
+       inst.instruction = (inst.instruction & COND_MASK) | 0x04000000; /* str */
+      else
+       inst.instruction = (inst.instruction & COND_MASK) | 0x04100000; /* ldr */
+
+      /* Perform a normal load/store instruction parse.  */
+      do_ldst (str, flags);
+
       return;
     }
 
-  if (rd == REG_PC)
+  if ((cpu_variant & ARM_EXT_XSCALE) != ARM_EXT_XSCALE)
     {
-      inst.error = BAD_PC;
+      static char buff[128];
+
+      --str;
+      while (isspace (*str))
+       --str;
+      str -= 4;
+
+      /* Deny all knowledge.  */
+      sprintf (buff, _("bad instruction '%.100s'"), str);
+      inst.error = buff;
       return;
     }
 
-  if (skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 0)) == FAIL)
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (& str, 12)) == FAIL)
     {
       inst.error = BAD_ARGS;
       return;
     }
 
-  if (rm == REG_PC)
+  if (skip_past_comma (& str) == FAIL
+      || (rn = ld_mode_required_here (& str)) == FAIL)
     {
-      inst.error = BAD_PC;
+      if (!inst.error)
+        inst.error = BAD_ARGS;
       return;
     }
 
-  if (rm == rd)
-    as_tsktsk (_("rd and rm should be different in mla"));
-
-  if (skip_past_comma (&str) == FAIL
-      || (rd = reg_required_here (&str, 8)) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 12)) == FAIL)
+  /* inst.instruction has now been zapped with Rd and the addressing mode.  */
+  if (rd & 1)          /* Unpredictable result if Rd is odd.  */
     {
-      inst.error = BAD_ARGS;
+      inst.error = _("Destination register must be even");
       return;
     }
 
-  if (rd == REG_PC || rm == REG_PC)
+  if (rd == REG_LR || rd == 12)
     {
-      inst.error = BAD_PC;
+      inst.error = _("r12 or r14 not allowed here");
       return;
     }
 
-  inst.instruction |= flags;
+  if (((rd == rn) || (rd + 1 == rn))
+      &&
+      ((inst.instruction & WRITE_BACK)
+       || (!(inst.instruction & PRE_INDEX))))
+    as_warn (_("pre/post-indexing used when modified address register is destination"));
+
   end_of_line (str);
-  return;
 }
 
 /* Returns the index into fp_values of a floating point number,
@@ -3104,7 +4269,7 @@ do_ldst (str, flags)
     {
       /* This is actually a load/store of a halfword, or a
          signed-extension load.  */
-      if ((cpu_variant & ARM_HALFWORD) == 0)
+      if ((cpu_variant & ARM_EXT_HALFWORD) == 0)
        {
          inst.error
            = _("Processor does not support halfwords or signed bytes");
@@ -3158,9 +4323,16 @@ do_ldst (str, flags)
              if (ldst_extend (&str, halfword) == FAIL)
                return;
              if (conflict_reg)
-               as_warn (_("%s register same as write-back base"),
-                        ((inst.instruction & LOAD_BIT)
-                         ? _("destination") : _("source")));
+               {
+                 if (flags & TRANS_BIT)
+                   as_warn (_("Rn and Rd must be different in %s"),
+                            ((inst.instruction & LOAD_BIT)
+                             ? "LDRT" : "STRT"));
+                 else
+                   as_warn (_("%s register same as write-back base"),
+                            ((inst.instruction & LOAD_BIT)
+                             ? _("destination") : _("source")));
+               }
            }
          else
            {
@@ -3181,8 +4353,15 @@ do_ldst (str, flags)
                }
 
              flags |= INDEX_UP;
-             if (! (flags & TRANS_BIT))
-               pre_inc = 1;
+             if (flags & TRANS_BIT)
+               {
+                 if (conflict_reg)
+                   as_warn (_("Rn and Rd must be different in %s"),
+                            ((inst.instruction & LOAD_BIT)
+                             ? "LDRT" : "STRT"));
+               }
+               else
+                 pre_inc = 1;
            }
        }
       else
@@ -5291,6 +6470,24 @@ md_begin ()
     if ((cpu_variant & FPU_ALL) == FPU_NONE) flags |= F_SOFT_FLOAT;
 
     bfd_set_private_flags (stdoutput, flags);
+
+    /* We have run out flags in the COFF header to encode the
+       status of ATPCS support, so instead we create a dummy,
+       empty, debug section called .arm.atpcs.  */
+    if (atpcs)
+      {
+       asection * sec;
+
+       sec = bfd_make_section (stdoutput, ".arm.atpcs");
+
+       if (sec != NULL)
+         {
+           bfd_set_section_flags
+             (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
+           bfd_set_section_size (stdoutput, sec, 0);
+           bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
+         }
+      }
   }
 #endif
 
@@ -5316,19 +6513,26 @@ md_begin ()
     }
 
   /* Catch special cases.  */
-  if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
+  if (cpu_variant & ARM_EXT_XSCALE)
+    mach = bfd_mach_arm_XScale;
+  else if (cpu_variant & ARM_EXT_V5E)
+    mach = bfd_mach_arm_5TE;
+  else if (cpu_variant & ARM_EXT_V5)
     {
-      if (cpu_variant & (ARM_EXT_V5 & ARM_THUMB))
+      if (cpu_variant & ARM_EXT_THUMB)
        mach = bfd_mach_arm_5T;
-      else if (cpu_variant & ARM_EXT_V5)
+      else
        mach = bfd_mach_arm_5;
-      else if (cpu_variant & ARM_THUMB)
+    }
+  else if (cpu_variant & ARM_EXT_HALFWORD)
+    {
+      if (cpu_variant & ARM_EXT_THUMB)
        mach = bfd_mach_arm_4T;
-      else if ((cpu_variant & ARM_ARCH_V4) == ARM_ARCH_V4)
+      else
        mach = bfd_mach_arm_4;
-      else if (cpu_variant & ARM_LONGMUL)
-       mach = bfd_mach_arm_3M;
     }
+  else if (cpu_variant & ARM_EXT_LONGMUL)
+    mach = bfd_mach_arm_3M;
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
 }
@@ -5675,7 +6879,7 @@ md_apply_fix3 (fixP, val, seg)
            else
              {
                as_bad_where (fixP->fx_file, fixP->fx_line,
-                             _("Unable to compute ADRL instructions for PC offset of 0x%x"),
+                             _("Unable to compute ADRL instructions for PC offset of 0x%lx"),
                              value);
                break;
              }
@@ -5942,6 +7146,15 @@ md_apply_fix3 (fixP, val, seg)
 
        newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
        newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
+       if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
+         /* Remove bit zero of the adjusted offset.  Bit zero can only be
+            set if the upper insn is at a half-word boundary, since the
+            destination address, an ARM instruction, must always be on a
+            word boundary.  The semantics of the BLX (1) instruction, however,
+            are that bit zero in the offset must always be zero, and the
+            corresponding bit one in the target address will be set from bit
+            one of the source address.  */
+         newval2 &= ~1;
        md_number_to_chars (buf, newval, THUMB_SIZE);
        md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
       }
@@ -6035,7 +7248,7 @@ md_apply_fix3 (fixP, val, seg)
 
          if ((value + 2) & ~0x3fe)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("Invalid offset, value too big (0x%08X)"), value);
+                         _("Invalid offset, value too big (0x%08lX)"), value);
 
          /* Round up, since pc will be rounded down.  */
          newval |= (value + 2) >> 2;
@@ -6044,28 +7257,28 @@ 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, value too big (0x%08X)"), value);
+                         _("Invalid offset, value too big (0x%08lX)"), value);
          newval |= value >> 2;
          break;
 
        case 6: /* Word load/store.  */
          if (value & ~0x7c)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("Invalid offset, value too big (0x%08X)"), value);
+                         _("Invalid offset, value too big (0x%08lX)"), 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, value too big (0x%08X)"), value);
+                         _("Invalid offset, value too big (0x%08lX)"), value);
          newval |= value << 6;
          break;
 
        case 8: /* Halfword load/store.  */
          if (value & ~0x3e)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("Invalid offset, value too big (0x%08X)"), value);
+                         _("Invalid offset, value too big (0x%08lX)"), value);
          newval |= value << 5; /* 6 - 1.  */
          break;
 
@@ -6268,8 +7481,7 @@ tc_gen_reloc (section, fixp)
 
     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);
+                   _("ADRL used for a symbol not defined in the same file"));
       return NULL;
 
     case BFD_RELOC_ARM_OFFSET_IMM:
@@ -6298,8 +7510,8 @@ tc_gen_reloc (section, fixp)
          default:                         type = _("<unknown>"); break;
          }
        as_bad_where (fixp->fx_file, fixp->fx_line,
-                     _("Can not represent %s relocation in this object file format (%d)"),
-                     type, fixp->fx_pcrel);
+                     _("Cannot represent %s relocation in this object file format"),
+                     type);
        return NULL;
       }
     }
@@ -6373,11 +7585,10 @@ output_inst PARAMS ((void))
     fix_new_arm (frag_now, to - frag_now->fr_literal,
                 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
                 inst.reloc.type);
+
 #ifdef OBJ_ELF
-  if (debug_type == DEBUG_DWARF2)
-    dwarf2_generate_asm_lineno (inst.size);
+  dwarf2_emit_insn (inst.size);
 #endif
-  return;
 }
 
 void
@@ -6613,9 +7824,14 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
   if (*q && !strncmp (q, ".req ", 4))
     {
       int    reg;
-      char * copy_of_str = str;
+      char * copy_of_str;
       char * r;
 
+#ifdef IGNORE_OPCODE_CASE
+      str = original_case_string;
+#endif
+      copy_of_str = str;
+
       q += 4;
       skip_whitespace (q);
 
@@ -6676,7 +7892,8 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
               -m[arm]8[10]            Arm 8 processors
               -m[arm]9[20][tdmi]      Arm 9 processors
               -mstrongarm[110[0]]     StrongARM processors
-              -m[arm]v[2345[t]]       Arm architectures
+              -mxscale                XScale processors
+              -m[arm]v[2345[t[e]]]    Arm architectures
               -mall                   All (except the ARM1)
       FP variants:
               -mfpa10, -mfpa11        FPA10 and 11 co-processor instructions
@@ -6691,6 +7908,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
              -mapcs-float            Pass floats in float regs
              -mapcs-reentrant        Position independent code
               -mthumb-interwork       Code supports Arm/Thumb interworking
+              -matpcs                 ARM/Thumb Procedure Call Standard
               -moabi                  Old ELF ABI  */
 
 CONST char * md_shortopts = "m:k";
@@ -6760,13 +7978,13 @@ md_parse_option (c, arg)
          /* Limit assembler to generating only Thumb instructions:  */
          if (streq (str, "thumb"))
            {
-             cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB;
+             cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_EXT_THUMB;
              cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE;
              thumb_mode = 1;
            }
          else if (streq (str, "thumb-interwork"))
            {
-             if ((cpu_variant & ARM_THUMB) == 0)
+             if ((cpu_variant & ARM_EXT_THUMB) == 0)
                cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4T;
 #if defined OBJ_COFF || defined OBJ_ELF
              support_interwork = true;
@@ -6837,6 +8055,12 @@ md_parse_option (c, arg)
              as_bad (_("Unrecognised APCS switch -m%s"), arg);
              return 0;
            }
+
+         if (! strcmp (str, "atpcs"))
+           {
+             atpcs = true;
+             return 1;
+           }
 #endif
          /* Strip off optional "arm".  */
          if (! strncmp (str, "arm", 3))
@@ -6903,11 +8127,11 @@ md_parse_option (c, arg)
                  switch (*str)
                    {
                    case 't':
-                     cpu_variant |= (ARM_THUMB | ARM_ARCH_V4);
+                     cpu_variant |= ARM_ARCH_V4T;
                      break;
 
                    case 'm':
-                     cpu_variant |= ARM_LONGMUL;
+                     cpu_variant |= ARM_EXT_LONGMUL;
                      break;
 
                    case 'f': /* fe => fp enabled cpu.  */
@@ -6931,7 +8155,7 @@ md_parse_option (c, arg)
            case '8':
              if (streq (str, "8") || streq (str, "810"))
                cpu_variant = (cpu_variant & ~ARM_ANY)
-                 | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
+                 | ARM_8 | ARM_ARCH_V4;
              else
                goto bad;
              break;
@@ -6939,16 +8163,16 @@ md_parse_option (c, arg)
            case '9':
              if (streq (str, "9"))
                cpu_variant = (cpu_variant & ~ARM_ANY)
-                 | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+                 | ARM_9 | ARM_ARCH_V4T;
              else if (streq (str, "920"))
                cpu_variant = (cpu_variant & ~ARM_ANY)
-                 | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL;
+                 | ARM_9 | ARM_ARCH_V4;
              else if (streq (str, "920t"))
                cpu_variant = (cpu_variant & ~ARM_ANY)
-                 | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+                 | ARM_9 | ARM_ARCH_V4T;
              else if (streq (str, "9tdmi"))
                cpu_variant = (cpu_variant & ~ARM_ANY)
-                 | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+                 | ARM_9 | ARM_ARCH_V4T;
              else
                goto bad;
              break;
@@ -6958,11 +8182,18 @@ md_parse_option (c, arg)
                  || streq (str, "strongarm110")
                  || streq (str, "strongarm1100"))
                cpu_variant = (cpu_variant & ~ARM_ANY)
-                 | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
+                 | ARM_8 | ARM_ARCH_V4;
              else
                goto bad;
              break;
 
+            case 'x':
+             if (streq (str, "xscale"))
+               cpu_variant = ARM_9 | ARM_ARCH_XSCALE;
+             else
+               goto bad;
+             break;
+
            case 'v':
              /* Select variant based on architecture rather than
                  processor.  */
@@ -6988,7 +8219,7 @@ md_parse_option (c, arg)
 
                  switch (*++str)
                    {
-                   case 'm': cpu_variant |= ARM_LONGMUL; break;
+                   case 'm': cpu_variant |= ARM_EXT_LONGMUL; break;
                    case 0:   break;
                    default:
                      as_bad (_("Invalid architecture variant -m%s"), arg);
@@ -6997,11 +8228,11 @@ md_parse_option (c, arg)
                  break;
 
                case '4':
-                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4;
+                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCH_V4;
 
                  switch (*++str)
                    {
-                   case 't': cpu_variant |= ARM_THUMB; break;
+                   case 't': cpu_variant |= ARM_EXT_THUMB; break;
                    case 0:   break;
                    default:
                      as_bad (_("Invalid architecture variant -m%s"), arg);
@@ -7010,10 +8241,11 @@ md_parse_option (c, arg)
                  break;
 
                case '5':
-                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V5;
+                 cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V5;
                  switch (*++str)
                    {
-                   case 't': cpu_variant |= ARM_THUMB; break;
+                   case 't': cpu_variant |= ARM_EXT_THUMB; break;
+                   case 'e': cpu_variant |= ARM_EXT_V5E; break;
                    case 0:   break;
                    default:
                      as_bad (_("Invalid architecture variant -m%s"), arg);
@@ -7066,6 +8298,7 @@ md_show_usage (fp)
 #if defined OBJ_COFF || defined OBJ_ELF
   fprintf (fp, _("\
   -mapcs-32, -mapcs-26      specify which ARM Procedure Calling Standard to use\n\
+  -matpcs                   use ARM/Thumb Procedure Calling Standard\n\
   -mapcs-float              floating point args are passed in FP regs\n\
   -mapcs-reentrant          the code is position independent/reentrant\n"));
 #endif
@@ -7191,7 +8424,38 @@ arm_frob_label (sym)
   ARM_SET_INTERWORK (sym, support_interwork);
 #endif
 
-  if (label_is_thumb_function_name)
+  /* Note - do not allow local symbols (.Lxxx) to be labeled
+     as Thumb functions.  This is because these labels, whilst
+     they exist inside Thumb code, are not the entry points for
+     possible ARM->Thumb calls.  Also, these labels can be used
+     as part of a computed goto or switch statement.  eg gcc
+     can generate code that looks like this:
+
+                ldr  r2, [pc, .Laaa]
+                lsl  r3, r3, #2
+                ldr  r2, [r3, r2]
+                mov  pc, r2
+               
+       .Lbbb:  .word .Lxxx
+       .Lccc:  .word .Lyyy
+       ..etc...
+       .Laaa:   .word Lbbb
+
+     The first instruction loads the address of the jump table.
+     The second instruction converts a table index into a byte offset.
+     The third instruction gets the jump address out of the table.
+     The fourth instruction performs the jump.
+     
+     If the address stored at .Laaa is that of a symbol which has the
+     Thumb_Func bit set, then the linker will arrange for this address
+     to have the bottom bit set, which in turn would mean that the
+     address computation performed by the third instruction would end
+     up with the bottom bit set.  Since the ARM is capable of unaligned
+     word loads, the instruction would then load the incorrect address
+     out of the jump table, and chaos would ensue.  */
+  if (label_is_thumb_function_name
+      && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
+      && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
     {
       /* When the address of a Thumb function is taken the bottom
         bit of that address should be set.  This will allow
@@ -7324,6 +8588,22 @@ arm_validate_fix (fixP)
   return false;
 }
 
+#ifdef OBJ_COFF
+/* This is a little hack to help the gas/arm/adrl.s test.  It prevents
+   local labels from being added to the output symbol table when they
+   are used with the ADRL pseudo op.  The ADRL relocation should always
+   be resolved before the binbary is emitted, so it is safe to say that
+   it is adjustable.  */
+
+boolean
+arm_fix_adjustable (fixP)
+   fixS * fixP;
+{
+  if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
+    return 1;
+  return 0;
+}
+#endif
 #ifdef OBJ_ELF
 /* Relocations against Thumb function names must be left unadjusted,
    so that the linker can use this information to correctly set the
@@ -7499,13 +8779,4 @@ s_arm_elf_cons (nbytes)
   demand_empty_rest_of_line ();
 }
 
-/* Stuff to do after assembling all of the source file.  */
-
-void
-arm_end_of_source ()
-{
-  if (debug_type == DEBUG_DWARF2)
-    dwarf2_finish ();
-}
-
 #endif /* OBJ_ELF */
This page took 0.048661 seconds and 4 git commands to generate.