#define ARM_LONGMUL 0x00000010 /* allow long multiplies */
#define ARM_HALFWORD 0x00000020 /* allow half word loads */
#define ARM_THUMB 0x00000040 /* allow BX instruction */
+#define ARM_EXT_V5 0x00000080 /* allow CLZ etc */
+#define ARM_EXT_V5E 0x00000200 /* "El Segundo" */
-#define ARM_ARCHv4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
+/* Architectures are the sum of the base and extensions */
+#define ARM_ARCH_V4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
+#define ARM_ARCH_V4T (ARM_ARCH_V4 | ARM_THUMB)
+#define ARM_ARCH_V5 (ARM_ARCH_V4 | ARM_EXT_V5)
+#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_THUMB)
/* Some useful combinations: */
#define ARM_ANY 0x00ffffff
-#define ARM_2UP 0x00fffffe
+#define ARM_2UP (ARM_ANY - ARM_1)
#define ARM_ALL ARM_2UP /* Not arm1 only */
#define ARM_3UP 0x00fffffc
#define ARM_6UP 0x00fffff8 /* Includes ARM7 */
#ifndef CPU_DEFAULT
#if defined __thumb__
-#define CPU_DEFAULT (ARM_ARCHv4 | ARM_THUMB)
+#define CPU_DEFAULT (ARM_ARCH_V4 | ARM_THUMB)
#else
#define CPU_DEFAULT ARM_ALL
#endif
#define FPU_DEFAULT FPU_ALL
#endif
-#define streq(a,b) (strcmp (a, b) == 0)
+#define 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;
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;
/* Functions called by parser */
/* ARM instructions */
-static void do_arit PARAMS ((char *operands, unsigned long flags));
-static void do_cmp PARAMS ((char *operands, unsigned long flags));
-static void do_mov PARAMS ((char *operands, unsigned long flags));
-static void do_ldst PARAMS ((char *operands, unsigned long flags));
-static void do_ldmstm PARAMS ((char *operands, unsigned long flags));
-static void do_branch PARAMS ((char *operands, unsigned long flags));
-static void do_swi PARAMS ((char *operands, unsigned long flags));
-/* Pseudo Op codes */
-static void do_adr PARAMS ((char *operands, unsigned long flags));
-static void do_nop PARAMS ((char *operands, unsigned long flags));
-/* ARM 2 */
-static void do_mul PARAMS ((char *operands, unsigned long flags));
-static void do_mla PARAMS ((char *operands, unsigned long flags));
-/* ARM 3 */
-static void do_swap PARAMS ((char *operands, unsigned long flags));
-/* ARM 6 */
-static void do_msr PARAMS ((char *operands, unsigned long flags));
-static void do_mrs PARAMS ((char *operands, unsigned long flags));
-/* ARM 7M */
-static void do_mull PARAMS ((char *operands, unsigned long flags));
-/* ARM THUMB */
-static void do_bx PARAMS ((char *operands, unsigned long flags));
-
-/* Coprocessor Instructions */
-static void do_cdp PARAMS ((char *operands, unsigned long flags));
-static void do_lstc PARAMS ((char *operands, unsigned long flags));
-static void do_co_reg PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ctrl PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ldst PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ldmstm PARAMS ((char *operands, unsigned long flags));
-static void do_fp_dyadic PARAMS ((char *operands, unsigned long flags));
-static void do_fp_monadic PARAMS ((char *operands, unsigned long flags));
-static void do_fp_cmp PARAMS ((char *operands, unsigned long flags));
-static void do_fp_from_reg PARAMS ((char *operands, unsigned long flags));
-static void do_fp_to_reg PARAMS ((char *operands, unsigned long flags));
-
-static void fix_new_arm PARAMS ((fragS *frag, int where,
- short int size, expressionS *exp,
- int pc_rel, int reloc));
-static int arm_reg_parse PARAMS ((char **ccp));
-static int arm_psr_parse PARAMS ((char **ccp));
-static void symbol_locate PARAMS ((symbolS *, CONST char *, segT,
- valueT, fragS *));
+static void do_arit PARAMS ((char *, unsigned long));
+static void do_cmp PARAMS ((char *, unsigned long));
+static void do_mov PARAMS ((char *, unsigned long));
+static void do_ldst PARAMS ((char *, unsigned long));
+static void do_ldmstm PARAMS ((char *, unsigned long));
+static void do_branch PARAMS ((char *, unsigned long));
+static void do_swi PARAMS ((char *, unsigned long));
+/* Pseudo Op codes */
+static void do_adr PARAMS ((char *, unsigned long));
+static void do_adrl PARAMS ((char *, unsigned long));
+static void do_nop PARAMS ((char *, unsigned long));
+/* ARM 2 */
+static void do_mul PARAMS ((char *, unsigned long));
+static void do_mla PARAMS ((char *, unsigned long));
+/* ARM 3 */
+static void do_swap PARAMS ((char *, unsigned long));
+/* ARM 6 */
+static void do_msr PARAMS ((char *, unsigned long));
+static void do_mrs PARAMS ((char *, unsigned long));
+/* ARM 7M */
+static void do_mull PARAMS ((char *, unsigned long));
+/* ARM THUMB */
+static void do_bx PARAMS ((char *, unsigned long));
+
+
+/* Coprocessor Instructions */
+static void do_cdp PARAMS ((char *, unsigned long));
+static void do_lstc PARAMS ((char *, unsigned long));
+static void do_co_reg PARAMS ((char *, unsigned long));
+static void do_fp_ctrl PARAMS ((char *, unsigned long));
+static void do_fp_ldst PARAMS ((char *, unsigned long));
+static void do_fp_ldmstm PARAMS ((char *, unsigned long));
+static void do_fp_dyadic PARAMS ((char *, unsigned long));
+static void do_fp_monadic PARAMS ((char *, unsigned long));
+static void do_fp_cmp PARAMS ((char *, unsigned long));
+static void do_fp_from_reg PARAMS ((char *, unsigned long));
+static void do_fp_to_reg PARAMS ((char *, unsigned long));
+
+static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *, int, int));
+static int arm_reg_parse PARAMS ((char **));
+static int arm_psr_parse PARAMS ((char **));
+static void symbol_locate PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *));
static int add_to_lit_pool PARAMS ((void));
-static unsigned validate_immediate PARAMS ((unsigned));
-static int validate_offset_imm PARAMS ((int, int));
+static unsigned validate_immediate PARAMS ((unsigned));
+static unsigned validate_immediate_twopart PARAMS ((unsigned int, unsigned int *));
+static int validate_offset_imm PARAMS ((unsigned int, int));
static void opcode_select PARAMS ((int));
static void end_of_line PARAMS ((char *));
static int reg_required_here PARAMS ((char **, int));
static int 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 **));
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
#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 */
/* 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 */
#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_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
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},
+ {"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
#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},
{"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;
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;
}
if (! thumb_mode)
{
- thumb_mode = 1;
+ thumb_mode = 2;
record_alignment (now_seg, 1);
}
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. */
if (now_seg != text_section)
s_ltorg (0);
+#ifdef OBJ_ELF
+ obj_elf_text (ignore);
+#else
s_text (ignore);
+#endif
}
static void
else if (now_seg != data_section)
s_ltorg (0);
+#ifdef OBJ_ELF
+ obj_elf_data (ignore);
+#else
s_data (ignore);
+#endif
}
#ifdef OBJ_ELF
end_of_line (str)
char * str;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
- if (*str != '\0')
+ if (* str != '\0')
inst.error = _("Garbage following instruction");
}
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)
*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;
}
/* 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 = _("<psr(f)> expected");
/* Restore the start point. */
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
{
expressionS expr;
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
memset (&expr, '\0', sizeof (expr));
}
/* 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;
}
}
/* 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;
}
{
int offset;
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
if (! is_immediate_prefix (**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 == ']')
{
if (cp_address_offset (& p) == FAIL)
return FAIL;
- while (*p == ' ')
- p++;
+ skip_whitespace (p);
if (*p++ != ']')
{
return FAIL;
}
- while (*p == ' ')
- p++;
+ skip_whitespace (p);
if (*p == '!')
{
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;
}
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;
}
return;
}
-/* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression" */
+/* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression". */
static void
do_msr (str, flags)
char * str;
{
int reg;
- while (*str == ' ')
- str ++;
+ skip_whitespace (str);
if (psr_required_here (&str, CPSR_ALL, SPSR_ALL) == SUCCESS)
{
if (skip_past_comma (&str) == FAIL
|| (reg = reg_required_here (&str, 0)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
}
inst.instruction |= PSR_CONTROL;
else
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (skip_past_comma (&str) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if ((reg = reg_required_here (& str, 0)) != FAIL)
;
- /* Immediate expression */
+ /* Immediate expression. */
else if (is_immediate_prefix (* str))
{
str ++;
{
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;
}
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;
}
{
int rd, rm;
- /* only one format "rd, rm, rs" */
- while (*str == ' ')
- str++;
+ /* Only one format "rd, rm, rs" */
+ skip_whitespace (str);
if ((rd = reg_required_here (&str, 16)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (rd == REG_PC)
{
- inst.error = bad_pc;
+ inst.error = BAD_PC;
return;
}
if (skip_past_comma (&str) == FAIL
|| (rm = reg_required_here (&str, 0)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (rm == REG_PC)
{
- inst.error = bad_pc;
+ inst.error = BAD_PC;
return;
}
if (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;
}
{
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;
}
|| 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;
}
char * p;
char c;
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
for (p = *str; isalpha (*p); p++)
;
return SUCCESS;
}
- while (*p == ' ')
- p++;
-
+ skip_whitespace (p);
+
if (unrestrict && reg_required_here (&p, 8) != FAIL)
{
inst.instruction |= shft->value | SHIFT_BY_REG;
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
{
(*str)++;
inst.error = NULL;
+
if (my_get_expression (&inst.reloc.exp, str))
return FAIL;
fp_op2 (str)
char ** str;
{
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
if (fp_reg_required_here (str, 0) != FAIL)
return SUCCESS;
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 */
char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL
|| skip_past_comma (&str) == FAIL
|| data_op2 (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
/* This is a pseudo-op of the form "adr rd, label" to be converted
into a relative address of the form "add rd, pc, #label-.-8" */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL
|| skip_past_comma (&str) == FAIL
|| my_get_expression (&inst.reloc.exp, &str))
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
/* Frag hacking will turn this into a sub instruction if the offset turns
}
static void
+do_adrl (str, flags)
+ char * str;
+ unsigned long flags;
+{
+ /* This is a pseudo-op of the form "adrl rd, label" to be converted
+ into a relative address of the form:
+ add rd, pc, #low(label-.-8)"
+ add rd, rd, #high(label-.-8)" */
+
+ skip_whitespace (str);
+
+ if (reg_required_here (& str, 12) == FAIL
+ || skip_past_comma (& str) == FAIL
+ || my_get_expression (& inst.reloc.exp, & str))
+ {
+ if (!inst.error)
+ inst.error = BAD_ARGS;
+ return;
+ }
+
+ end_of_line (str);
+
+ /* Frag hacking will turn this into a sub instruction if the offset turns
+ out to be negative. */
+ inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
+ inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+ inst.reloc.pc_rel = 1;
+ inst.instruction |= flags;
+ inst.size = INSN_SIZE * 2;
+
+ return;
+}
+
+static void
do_cmp (str, flags)
char * str;
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;
}
|| data_op2 (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
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;
}
|| data_op2 (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
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;
}
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
{
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;
}
if (ldst_extend (&str, halfword) == FAIL)
return;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (*str++ != ']')
{
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;
}
/* 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;
{
int reg;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((reg = reg_required_here (& str, -1)) == FAIL)
return FAIL;
} while (skip_past_comma (&str) != FAIL
|| (in_range = 1, *str++ == '-'));
str--;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (*str++ != '}')
{
}
}
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (*str == '|' || *str == '+')
{
int base_reg;
long range;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((base_reg = reg_required_here (&str, 16)) == FAIL)
return;
return;
}
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
+
if (*str == '!')
{
flags |= WRITE_BACK;
|| (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;
char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
/* Allow optional leading '#'. */
if (is_immediate_prefix (*str))
{
int reg;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((reg = reg_required_here (&str, 12)) == FAIL)
return;
|| (reg = reg_required_here (&str, 0)) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (skip_past_comma (&str) == FAIL
|| *str++ != '[')
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((reg = reg_required_here (&str, 16)) == FAIL)
return;
if (reg == REG_PC)
{
- inst.error = bad_pc;
+ inst.error = BAD_PC;
return;
}
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (*str++ != ']')
{
{
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
{
/* 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;
}
|| cp_opc_expr (&str, 20,4) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| cp_reg_required_here (&str, 12) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| cp_reg_required_here (&str, 16) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| cp_reg_required_here (&str, 0) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (cp_opc_expr (&str, 5, 3) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
}
/* 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;
}
|| cp_reg_required_here (&str, 12) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| cp_address_required_here (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
/* 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;
}
|| cp_opc_expr (&str, 21, 3) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| reg_required_here (&str, 12) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| cp_reg_required_here (&str, 16) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| cp_reg_required_here (&str, 0) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
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;
/* 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;
}
char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
switch (inst.suffix)
{
if (fp_reg_required_here (&str, 12) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| cp_address_required_here (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
{
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;
}
|| *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;
}
|| cp_address_required_here (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
switch (inst.suffix)
{
if (fp_reg_required_here (&str, 12) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| fp_reg_required_here (&str, 16) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| fp_op2 (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
switch (inst.suffix)
{
if (fp_reg_required_here (&str, 12) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| fp_op2 (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
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;
}
|| fp_op2 (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
switch (inst.suffix)
{
if (fp_reg_required_here (&str, 16) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| reg_required_here (&str, 12) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL)
return;
|| fp_reg_required_here (&str, 0) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
/* 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;
{
int Rd, Rs, Rn;
- while (*str == ' ')
- str++;
-
- if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
- return;
+ skip_whitespace (str);
- 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)
|| inst.instruction == T_OPCODE_NEG
|| inst.instruction == T_OPCODE_MVN)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
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)
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);
{
int reg;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
return;
int Rb;
long range;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
return;
|| (range = reg_list (&str)) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
{
int Rd, Rb, Ro;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
|| skip_past_comma (&str) == FAIL
{
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;
}
do_t_swi (str)
char * str;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (my_get_expression (&inst.reloc.exp, &str))
return;
{
/* This is a pseudo-op of the form "adr rd, label" to be converted
into a relative address of the form "add rd, pc, #label-.-4" */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 4) == FAIL /* Store Rd in temporary location inside instruction. */
|| skip_past_comma (&str) == FAIL
|| my_get_expression (&inst.reloc.exp, &str))
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
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);
}
break;
}
- /* Catch special cases */
+ /* Catch special cases. */
if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
{
- if (cpu_variant & ARM_THUMB)
+ if (cpu_variant & (ARM_EXT_V5 & ARM_THUMB))
+ mach = bfd_mach_arm_5T;
+ else if (cpu_variant & ARM_EXT_V5)
+ mach = bfd_mach_arm_5;
+ else if (cpu_variant & ARM_THUMB)
mach = bfd_mach_arm_4T;
- else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4)
+ else if ((cpu_variant & ARM_ARCH_V4) == ARM_ARCH_V4)
mach = bfd_mach_arm_4;
else if (cpu_variant & ARM_LONGMUL)
mach = bfd_mach_arm_3M;
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;
{
/* 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;
}
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
&& S_GET_SEGMENT (fixP->fx_addsy) != seg)
{
if (target_oabi
- && fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
+ && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+ ))
value = 0;
else
value += md_pcrel_from (fixP);
}
}
- fixP->fx_addnumber = value; /* Remember value for emit_reloc */
+ fixP->fx_addnumber = value; /* Remember value for emit_reloc. */
switch (fixP->fx_r_type)
{
&& (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
{
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("invalid constant (%lx) after fixup\n"),
+ _("invalid constant (%lx) after fixup"),
(unsigned long) value);
break;
}
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 (%ld)"), (long) value);
+ 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;
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 (%ld)"), (long) 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);
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;
}
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);
{
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,
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;
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;
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;
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:
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)"),
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)"),
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;
}
}
static void
-output_inst (str)
- char * str;
+output_inst PARAMS ((void))
{
char * to = NULL;
}
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);
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++)
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--)
{
*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)
{
as_tsktsk (
_("Warning: Use of the 'nv' conditional is deprecated\n"));
- inst.instruction |= cond->value;
+ cond_code = cond->value;
r += 2;
}
else
- inst.instruction |= COND_ALWAYS;
+ cond_code = COND_ALWAYS;
+ }
+ else
+ cond_code = COND_ALWAYS;
+
+ /* Apply the conditional, or complain it's not allowed. */
+ if (opcode->comp_suffix && *opcode->comp_suffix == '\0')
+ {
+ /* Instruction isn't conditional */
+ if (cond_code != COND_ALWAYS)
+ {
+ as_bad (_("Opcode `%s' is unconditional\n"), str);
+ return;
+ }
}
else
- inst.instruction |= COND_ALWAYS;
+ /* Instruction is conditional: set the condition into it. */
+ inst.instruction |= cond_code;
- /* if there is a compulsory suffix, it should come here, before
- any optional flags. */
- if (opcode->comp_suffix)
+
+ /* If 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;
}
(*opcode->parms) (p, flag_bits);
- output_inst (start);
+ output_inst ();
return;
}
}
/* 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';
char * r;
q += 4;
- while (*q == ' ')
- q++;
+ skip_whitespace (q);
for (r = q; *r != '\0'; r++)
if (*r == ' ')
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 );
- /* 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'"),
* -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] Arm architectures
* -mall All (except the ARM1)
* FP variants:
* -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions
}
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
case 70:
case 700:
case 710:
+ case 720:
case 7100:
case 7500:
break;
switch (* str)
{
case 't':
- cpu_variant |= (ARM_THUMB | ARM_ARCHv4);
+ cpu_variant |= (ARM_THUMB | ARM_ARCH_V4);
break;
case 'm':
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;
break;
case '4':
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCHv4;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4;
switch (*++str)
{
default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
}
break;
+
+ case '5':
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V5;
+ switch (*++str)
+ {
+ case 't': cpu_variant |= ARM_THUMB; break;
+ case 'e': cpu_variant |= ARM_EXT_V5E; break;
+ case 0: break;
+ default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ }
+ break;
default:
as_bad (_("Invalid architecture variant -m%s"), arg);
}
break;
+#if defined OBJ_ELF || defined OBJ_COFF
case 'k':
pic_code = 1;
break;
+#endif
default:
return 0;
_("\
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\
}
-/*
- * 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;
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
{
if (ARM_IS_THUMB (sym))
{
+ elf_sym = elf_symbol (symbol_get_bfdsym (sym));
+ bind = ELF_ST_BIND (elf_sym);
+
+ /* If it's a .thumb_func, declare it as so, else tag label as .code 16. */
if (THUMB_IS_FUNC (sym))
- {
- elf_sym = elf_symbol (symbol_get_bfdsym (sym));
- bind = ELF_ST_BIND (elf_sym);
- elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
- }
+ elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
+ else
+ elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_16BIT);
}
}
#endif
if (thumb_mode && (len = strlen (name)) > 5
&& streq (name + len - 5, "/data"))
- {
- *(name + len - 5) = 0;
- }
+ *(name + len - 5) = 0;
return name;
}
arm_fix_adjustable (fixP)
fixS * fixP;
{
-
if (fixP->fx_addsy == NULL)
return 1;
{
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_THUMB_PCREL_BRANCH23)
return 1;
return 0;
/* 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
};