/* tc-arm.c -- Assemble for the ARM
- Copyright (C) 1994, 95, 96, 97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
Modified by David Taylor (dtaylor@armltd.co.uk)
#include "elf/arm.h"
#endif
-/* ??? This is currently unused. */
-#ifdef __STDC__
-#define internalError() \
- as_fatal (_("ARM Internal Error, line %d, %s"), __LINE__, __FILE__)
-#else
-#define internalError() as_fatal (_("ARM Internal Error"))
-#endif
-
/* Types of processor to assemble for. */
#define ARM_1 0x00000001
#define ARM_2 0x00000002
#define ARM_250 ARM_3
#define ARM_6 0x00000008
#define ARM_7 ARM_6 /* same core instruction set */
+#define ARM_8 ARM_6 /* same core instruction set */
+#define ARM_9 ARM_6 /* same core instruction set */
#define ARM_CPU_MASK 0x0000000f
/* The following bitmasks control CPU extensions (ARM7 onwards): */
#define ARM_LONGMUL 0x00000010 /* allow long multiplies */
#define ARM_HALFWORD 0x00000020 /* allow half word loads */
#define ARM_THUMB 0x00000040 /* allow BX instruction */
+#define ARM_EXT_V5 0x00000080 /* allow CLZ etc */
+#define ARM_EXT_V5E 0x00000200 /* "El Segundo" */
-#define ARM_ARCHv4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
+/* Architectures are the sum of the base and extensions */
+#define ARM_ARCH_V4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
+#define ARM_ARCH_V4T (ARM_ARCH_V4 | ARM_THUMB)
+#define ARM_ARCH_V5 (ARM_ARCH_V4 | ARM_EXT_V5)
+#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_THUMB)
/* Some useful combinations: */
#define ARM_ANY 0x00ffffff
-#define ARM_2UP 0x00fffffe
+#define ARM_2UP (ARM_ANY - ARM_1)
#define ARM_ALL ARM_2UP /* Not arm1 only */
#define ARM_3UP 0x00fffffc
#define ARM_6UP 0x00fffff8 /* Includes ARM7 */
#ifndef CPU_DEFAULT
#if defined __thumb__
-#define CPU_DEFAULT (ARM_ARCHv4 | ARM_THUMB)
+#define CPU_DEFAULT (ARM_ARCH_V4 | ARM_THUMB)
#else
#define CPU_DEFAULT ARM_ALL
#endif
#define FPU_DEFAULT FPU_ALL
#endif
+#define streq(a, b) (strcmp (a, b) == 0)
+#define skip_whitespace(str) while (* (str) == ' ') ++ (str)
+
static unsigned long cpu_variant = CPU_DEFAULT | FPU_DEFAULT;
+static int target_oabi = 0;
#if defined OBJ_COFF || defined OBJ_ELF
/* Flags stored in private area of BFD structure */
/* Also note that comments like this one will always work. */
CONST char line_comment_chars[] = "#";
+#ifdef TE_LINUX
+CONST char line_separator_chars[] = ";";
+#else
CONST char line_separator_chars[] = "";
+#endif
/* Chars that can be used to separate mant from exp in floating point nums */
CONST char EXP_CHARS[] = "eE";
CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
-CONST int md_reloc_size = 8; /* Size of relocation record */
+/* Prefix characters that indicate the start of an immediate
+ value. */
+#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')
+
+#ifdef OBJ_ELF
+symbolS * GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
+#endif
-static int thumb_mode = 0; /* non-zero if assembling thumb instructions */
+CONST int md_reloc_size = 8; /* Size of relocation record */
+static int thumb_mode = 0; /* 0: assemble for ARM, 1: assemble for Thumb,
+ 2: assemble for Thumb even though target cpu
+ does not support thumb instructions */
typedef struct arm_fix
{
int thumb_mode;
struct arm_it
{
- CONST char *error;
+ CONST char * error;
unsigned long instruction;
- int suffix;
- int size;
+ int suffix;
+ int size;
struct
{
bfd_reloc_code_real_type type;
- expressionS exp;
- int pc_rel;
+ expressionS exp;
+ int pc_rel;
} reloc;
};
struct asm_shift
{
- CONST char *template;
+ CONST char * template;
unsigned long value;
};
#define NUM_FLOAT_VALS 8
-CONST char *fp_const[] =
+CONST char * fp_const[] =
{
"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
};
struct asm_cond
{
- CONST char *template;
+ CONST char * template;
unsigned long value;
};
the set_bits: */
struct asm_flg
{
- CONST char *template; /* Basic flag string */
+ CONST char * template; /* Basic flag string */
unsigned long set_bits; /* Bits to set */
};
struct asm_psr
{
- CONST char *template;
+ CONST char * template;
unsigned long number;
};
/* 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
/* ARM instructions take 4bytes in the object file, Thumb instructions
take 2: */
#define LONGEST_INST 5
+
struct asm_opcode
{
- CONST char *template; /* Basic string to match */
- unsigned long value; /* Basic instruction code */
- CONST char *comp_suffix; /* Compulsory suffix that must follow conds */
- CONST struct asm_flg *flags; /* Bits to toggle if flag 'n' set */
- unsigned long variants; /* Which CPU variants this exists for */
+ CONST char * template; /* Basic string to match */
+ unsigned long value; /* Basic instruction code */
+
+ /* Compulsory suffix that must follow conds. If "", then the
+ instruction is not conditional and must have no suffix. */
+ CONST char * comp_suffix;
+
+ CONST struct asm_flg * flags; /* Bits to toggle if flag 'n' set */
+ unsigned long variants; /* Which CPU variants this exists for */
/* Function to call to parse args */
- void (*parms) PARAMS ((char *, unsigned long));
+ void (* parms) PARAMS ((char *, unsigned long));
};
static CONST struct asm_opcode insns[] =
/* 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 */
/* ARM 6 Coprocessor instructions */
{"mrs", 0x010f0000, NULL, NULL, ARM_6UP, do_mrs},
{"msr", 0x0120f000, NULL, NULL, ARM_6UP, do_msr},
+/* ScottB: our code uses 0x0128f000 for msr.
+ NickC: but this is wrong because the bits 16 and 19 are handled
+ by the PSR_xxx defines above. */
/* ARM 7M long multiplies - need signed/unsigned flags! */
{"smull", 0x00c00090, NULL, s_flag, ARM_LONGMUL, do_mull},
#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
#define T_OPCODE_BRANCH 0xe7fe
-static int thumb_reg PARAMS ((char **str, int hi_lo));
+static int thumb_reg PARAMS ((char ** str, int hi_lo));
#define THUMB_SIZE 2 /* Size of thumb instruction */
#define THUMB_REG_LO 0x1
struct thumb_opcode
{
- CONST char *template; /* Basic string to match */
+ CONST char * template; /* Basic string to match */
unsigned long value; /* Basic instruction code */
- int size;
- /* Function to call to parse args */
- void (*parms) PARAMS ((char *));
+ int size;
+ unsigned long variants; /* Which CPU variants this exists for */
+ void (* parms) PARAMS ((char *)); /* Function to call to parse args */
};
static CONST struct thumb_opcode tinsns[] =
{
- {"adc", 0x4140, 2, do_t_arit},
- {"add", 0x0000, 2, do_t_add},
- {"and", 0x4000, 2, do_t_arit},
- {"asr", 0x0000, 2, do_t_asr},
- {"b", T_OPCODE_BRANCH, 2, do_t_branch12},
- {"beq", 0xd0fe, 2, do_t_branch9},
- {"bne", 0xd1fe, 2, do_t_branch9},
- {"bcs", 0xd2fe, 2, do_t_branch9},
- {"bhs", 0xd2fe, 2, do_t_branch9},
- {"bcc", 0xd3fe, 2, do_t_branch9},
- {"bul", 0xd3fe, 2, do_t_branch9},
- {"blo", 0xd3fe, 2, do_t_branch9},
- {"bmi", 0xd4fe, 2, do_t_branch9},
- {"bpl", 0xd5fe, 2, do_t_branch9},
- {"bvs", 0xd6fe, 2, do_t_branch9},
- {"bvc", 0xd7fe, 2, do_t_branch9},
- {"bhi", 0xd8fe, 2, do_t_branch9},
- {"bls", 0xd9fe, 2, do_t_branch9},
- {"bge", 0xdafe, 2, do_t_branch9},
- {"blt", 0xdbfe, 2, do_t_branch9},
- {"bgt", 0xdcfe, 2, do_t_branch9},
- {"ble", 0xddfe, 2, do_t_branch9},
- {"bic", 0x4380, 2, do_t_arit},
- {"bl", 0xf7fffffe, 4, do_t_branch23},
- {"bx", 0x4700, 2, do_t_bx},
- {"cmn", T_OPCODE_CMN, 2, do_t_arit},
- {"cmp", 0x0000, 2, do_t_compare},
- {"eor", 0x4040, 2, do_t_arit},
- {"ldmia", 0xc800, 2, do_t_ldmstm},
- {"ldr", 0x0000, 2, do_t_ldr},
- {"ldrb", 0x0000, 2, do_t_ldrb},
- {"ldrh", 0x0000, 2, do_t_ldrh},
- {"ldrsb", 0x5600, 2, do_t_lds},
- {"ldrsh", 0x5e00, 2, do_t_lds},
- {"ldsb", 0x5600, 2, do_t_lds},
- {"ldsh", 0x5e00, 2, do_t_lds},
- {"lsl", 0x0000, 2, do_t_lsl},
- {"lsr", 0x0000, 2, do_t_lsr},
- {"mov", 0x0000, 2, do_t_mov},
- {"mul", T_OPCODE_MUL, 2, do_t_arit},
- {"mvn", T_OPCODE_MVN, 2, do_t_arit},
- {"neg", T_OPCODE_NEG, 2, do_t_arit},
- {"orr", 0x4300, 2, do_t_arit},
- {"pop", 0xbc00, 2, do_t_push_pop},
- {"push", 0xb400, 2, do_t_push_pop},
- {"ror", 0x41c0, 2, do_t_arit},
- {"sbc", 0x4180, 2, do_t_arit},
- {"stmia", 0xc000, 2, do_t_ldmstm},
- {"str", 0x0000, 2, do_t_str},
- {"strb", 0x0000, 2, do_t_strb},
- {"strh", 0x0000, 2, do_t_strh},
- {"swi", 0xdf00, 2, do_t_swi},
- {"sub", 0x0000, 2, do_t_sub},
- {"tst", T_OPCODE_TST, 2, do_t_arit},
+ {"adc", 0x4140, 2, ARM_THUMB, do_t_arit},
+ {"add", 0x0000, 2, ARM_THUMB, do_t_add},
+ {"and", 0x4000, 2, ARM_THUMB, do_t_arit},
+ {"asr", 0x0000, 2, ARM_THUMB, do_t_asr},
+ {"b", T_OPCODE_BRANCH, 2, ARM_THUMB, do_t_branch12},
+ {"beq", 0xd0fe, 2, ARM_THUMB, do_t_branch9},
+ {"bne", 0xd1fe, 2, ARM_THUMB, do_t_branch9},
+ {"bcs", 0xd2fe, 2, ARM_THUMB, do_t_branch9},
+ {"bhs", 0xd2fe, 2, ARM_THUMB, do_t_branch9},
+ {"bcc", 0xd3fe, 2, ARM_THUMB, do_t_branch9},
+ {"bul", 0xd3fe, 2, ARM_THUMB, do_t_branch9},
+ {"blo", 0xd3fe, 2, ARM_THUMB, do_t_branch9},
+ {"bmi", 0xd4fe, 2, ARM_THUMB, do_t_branch9},
+ {"bpl", 0xd5fe, 2, ARM_THUMB, do_t_branch9},
+ {"bvs", 0xd6fe, 2, ARM_THUMB, do_t_branch9},
+ {"bvc", 0xd7fe, 2, ARM_THUMB, do_t_branch9},
+ {"bhi", 0xd8fe, 2, ARM_THUMB, do_t_branch9},
+ {"bls", 0xd9fe, 2, ARM_THUMB, do_t_branch9},
+ {"bge", 0xdafe, 2, ARM_THUMB, do_t_branch9},
+ {"blt", 0xdbfe, 2, ARM_THUMB, do_t_branch9},
+ {"bgt", 0xdcfe, 2, ARM_THUMB, do_t_branch9},
+ {"ble", 0xddfe, 2, ARM_THUMB, do_t_branch9},
+ {"bic", 0x4380, 2, ARM_THUMB, do_t_arit},
+ {"bl", 0xf7fffffe, 4, ARM_THUMB, do_t_branch23},
+ {"bx", 0x4700, 2, ARM_THUMB, do_t_bx},
+ {"cmn", T_OPCODE_CMN, 2, ARM_THUMB, do_t_arit},
+ {"cmp", 0x0000, 2, ARM_THUMB, do_t_compare},
+ {"eor", 0x4040, 2, ARM_THUMB, do_t_arit},
+ {"ldmia", 0xc800, 2, ARM_THUMB, do_t_ldmstm},
+ {"ldr", 0x0000, 2, ARM_THUMB, do_t_ldr},
+ {"ldrb", 0x0000, 2, ARM_THUMB, do_t_ldrb},
+ {"ldrh", 0x0000, 2, ARM_THUMB, do_t_ldrh},
+ {"ldrsb", 0x5600, 2, ARM_THUMB, do_t_lds},
+ {"ldrsh", 0x5e00, 2, ARM_THUMB, do_t_lds},
+ {"ldsb", 0x5600, 2, ARM_THUMB, do_t_lds},
+ {"ldsh", 0x5e00, 2, ARM_THUMB, do_t_lds},
+ {"lsl", 0x0000, 2, ARM_THUMB, do_t_lsl},
+ {"lsr", 0x0000, 2, ARM_THUMB, do_t_lsr},
+ {"mov", 0x0000, 2, ARM_THUMB, do_t_mov},
+ {"mul", T_OPCODE_MUL, 2, ARM_THUMB, do_t_arit},
+ {"mvn", T_OPCODE_MVN, 2, ARM_THUMB, do_t_arit},
+ {"neg", T_OPCODE_NEG, 2, ARM_THUMB, do_t_arit},
+ {"orr", 0x4300, 2, ARM_THUMB, do_t_arit},
+ {"pop", 0xbc00, 2, ARM_THUMB, do_t_push_pop},
+ {"push", 0xb400, 2, ARM_THUMB, do_t_push_pop},
+ {"ror", 0x41c0, 2, ARM_THUMB, do_t_arit},
+ {"sbc", 0x4180, 2, ARM_THUMB, do_t_arit},
+ {"stmia", 0xc000, 2, ARM_THUMB, do_t_ldmstm},
+ {"str", 0x0000, 2, ARM_THUMB, do_t_str},
+ {"strb", 0x0000, 2, ARM_THUMB, do_t_strb},
+ {"strh", 0x0000, 2, ARM_THUMB, do_t_strh},
+ {"swi", 0xdf00, 2, ARM_THUMB, do_t_swi},
+ {"sub", 0x0000, 2, ARM_THUMB, do_t_sub},
+ {"tst", T_OPCODE_TST, 2, ARM_THUMB, do_t_arit},
/* Pseudo ops: */
- {"adr", 0x0000, 2, do_t_adr},
- {"nop", 0x46C0, 2, do_t_nop}, /* mov r8,r8 */
+ {"adr", 0x0000, 2, ARM_THUMB, do_t_adr},
+ {"nop", 0x46C0, 2, ARM_THUMB, do_t_nop}, /* mov r8,r8 */
};
struct reg_entry
{
- CONST char *name;
- int number;
+ CONST char * name;
+ int number;
};
#define int_register(reg) ((reg) >= 0 && (reg) <= 15)
#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;
-static struct hash_control *arm_cond_hsh = NULL;
-static struct hash_control *arm_shift_hsh = NULL;
-static struct hash_control *arm_reg_hsh = NULL;
-static struct hash_control *arm_psr_hsh = NULL;
+static struct hash_control * arm_ops_hsh = NULL;
+static struct hash_control * arm_tops_hsh = NULL;
+static struct hash_control * arm_cond_hsh = NULL;
+static struct hash_control * arm_shift_hsh = NULL;
+static struct hash_control * arm_reg_hsh = NULL;
+static struct hash_control * arm_psr_hsh = NULL;
/* This table describes all the machine specific pseudo-ops the assembler
has to support. The fields are:
static void s_code PARAMS ((int));
static void s_force_thumb PARAMS ((int));
static void s_thumb_func PARAMS ((int));
+static void s_thumb_set PARAMS ((int));
+static void arm_s_text PARAMS ((int));
+static void arm_s_data PARAMS ((int));
+#ifdef OBJ_ELF
+static void arm_s_section PARAMS ((int));
+static void s_arm_elf_cons PARAMS ((int));
+#endif
static int my_get_expression PARAMS ((expressionS *, char **));
CONST pseudo_typeS md_pseudo_table[] =
{
- {"req", s_req, 0}, /* Never called becasue '.req' does not start line */
- {"bss", s_bss, 0},
- {"align", s_align, 0},
- {"arm", s_arm, 0},
- {"thumb", s_thumb, 0},
- {"code", s_code, 0},
- {"force_thumb", s_force_thumb, 0},
- {"thumb_func", s_thumb_func, 0},
- {"even", s_even, 0},
- {"ltorg", s_ltorg, 0},
- {"pool", s_ltorg, 0},
- {"word", cons, 4},
- {"extend", float_cons, 'x'},
- {"ldouble", float_cons, 'x'},
- {"packed", float_cons, 'p'},
- {0, 0, 0}
+ { "req", s_req, 0 }, /* Never called becasue '.req' does not start line */
+ { "bss", s_bss, 0 },
+ { "align", s_align, 0 },
+ { "arm", s_arm, 0 },
+ { "thumb", s_thumb, 0 },
+ { "code", s_code, 0 },
+ { "force_thumb", s_force_thumb, 0 },
+ { "thumb_func", s_thumb_func, 0 },
+ { "thumb_set", s_thumb_set, 0 },
+ { "even", s_even, 0 },
+ { "ltorg", s_ltorg, 0 },
+ { "pool", s_ltorg, 0 },
+ /* Allow for the effect of section changes. */
+ { "text", arm_s_text, 0 },
+ { "data", arm_s_data, 0 },
+#ifdef OBJ_ELF
+ { "section", arm_s_section, 0 },
+ { "section.s", arm_s_section, 0 },
+ { "sect", arm_s_section, 0 },
+ { "sect.s", arm_s_section, 0 },
+ { "word", s_arm_elf_cons, 4 },
+ { "long", s_arm_elf_cons, 4 },
+#else
+ { "word", cons, 4},
+#endif
+ { "extend", float_cons, 'x' },
+ { "ldouble", float_cons, 'x' },
+ { "packed", float_cons, 'p' },
+ { 0, 0, 0 }
};
/* Stuff needed to resolve the label ambiguity
typedef struct literalS
{
struct expressionS exp;
- struct arm_it *inst;
+ struct arm_it * inst;
} literalT;
-literalT literals[MAX_LITERAL_POOL_SIZE];
-int next_literal_pool_place = 0; /* Next free entry in the pool */
-int lit_pool_num = 1; /* Next literal pool number */
-symbolS *current_poolP = NULL;
-symbolS *symbol_make_empty PARAMS ((void));
+literalT literals[MAX_LITERAL_POOL_SIZE];
+int next_literal_pool_place = 0; /* Next free entry in the pool */
+int lit_pool_num = 1; /* Next literal pool number */
+symbolS * current_poolP = NULL;
static int
add_to_lit_pool ()
int lit_count = 0;
if (current_poolP == NULL)
- current_poolP = symbol_make_empty();
+ current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section,
+ (valueT) 0, &zero_address_frag);
/* Check if this literal value is already in the pool: */
while (lit_count < next_literal_pool_place)
}
inst.reloc.exp.X_op = O_symbol;
- inst.reloc.exp.X_add_number = (lit_count)*4-8;
+ inst.reloc.exp.X_add_number = (lit_count) * 4 - 8;
inst.reloc.exp.X_add_symbol = current_poolP;
return SUCCESS;
}
/* Can't use symbol_new here, so have to create a symbol and then at
- a later date assign it a value. Thats what these functions do */
+ a later date assign it a value. Thats what these functions do. */
static void
symbol_locate (symbolP, name, segment, valu, frag)
- symbolS *symbolP;
- CONST char *name; /* It is copied, the caller can modify */
- segT segment; /* Segment identifier (SEG_<something>) */
- valueT valu; /* Symbol value */
- fragS *frag; /* Associated fragment */
+ symbolS * symbolP;
+ CONST char * name; /* It is copied, the caller can modify */
+ segT segment; /* Segment identifier (SEG_<something>) */
+ valueT valu; /* Symbol value */
+ fragS * frag; /* Associated fragment */
{
unsigned int name_length;
- char *preserved_copy_of_name;
+ char * preserved_copy_of_name;
name_length = strlen (name) + 1; /* +1 for \0 */
obstack_grow (¬es, name, name_length);
S_SET_VALUE (symbolP, valu);
symbol_clear_list_pointers(symbolP);
- symbolP->sy_frag = frag;
+ symbol_set_frag (symbolP, frag);
- /*
- * Link to end of symbol chain.
- */
+ /* Link to end of symbol chain. */
{
extern int symbol_table_frozen;
if (symbol_table_frozen)
abort ();
}
- symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP);
+ symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
obj_symbol_new_hook (symbolP);
#endif
#ifdef DEBUG_SYMS
- verify_symbol_chain(symbol_rootP, symbol_lastP);
+ verify_symbol_chain (symbol_rootP, symbol_lastP);
#endif /* DEBUG_SYMS */
}
-symbolS *
-symbol_make_empty ()
-{
- symbolS *symbolP;
-
- symbolP = (symbolS *) obstack_alloc (¬es, sizeof (symbolS));
-
- /* symbol must be born in some fixed state. This seems as good as any. */
- memset (symbolP, 0, sizeof (symbolS));
-
- symbolP->bsym = bfd_make_empty_symbol (stdoutput);
- assert (symbolP->bsym != 0);
- symbolP->bsym->udata.p = (PTR) symbolP;
+/* Check that an immediate is valid, and if so, convert it to the right format. */
- return symbolP;
+static unsigned int
+validate_immediate (val)
+ unsigned int val;
+{
+ unsigned int a;
+ unsigned int i;
+
+#define rotate_left(v, n) (v << n | v >> (32 - n))
+
+ for (i = 0; i < 32; i += 2)
+ if ((a = rotate_left (val, i)) <= 0xff)
+ return a | (i << 7); /* 12-bit pack: [shift-cnt,const] */
+
+ return FAIL;
}
-/* Check that an immediate is valid, and if so, convert it to the right format. */
+/* Check to see if an immediate can be computed as two seperate immediate
+ values, added together. We already know that this value cannot be
+ computed by just one ARM instruction. */
static unsigned int
-validate_immediate (val)
+validate_immediate_twopart (val, highpart)
unsigned int val;
+ unsigned int * highpart;
{
- unsigned int a;
- unsigned int i;
+ unsigned int a;
+ unsigned int i;
+
+ for (i = 0; i < 32; i += 2)
+ if (((a = rotate_left (val, i)) & 0xff) != 0)
+ {
+ if (a & 0xff00)
+ {
+ if (a & ~ 0xffff)
+ continue;
+ * highpart = (a >> 8) | ((i + 24) << 7);
+ }
+ else if (a & 0xff0000)
+ {
+ if (a & 0xff000000)
+ continue;
-#define rotate_left(v, n) (v << n | v >> (32 - n))
-
- for (i = 0; i < 32; i += 2)
- if ((a = rotate_left (val, i)) <= 0xff)
- return a | (i << 7); /* 12-bit pack: [shift-cnt,const] */
- return FAIL;
+ * highpart = (a >> 16) | ((i + 16) << 7);
+ }
+ else
+ {
+ assert (a & 0xff000000);
+
+ * highpart = (a >> 24) | ((i + 8) << 7);
+ }
+
+ return (a & 0xff) | (i << 7);
+ }
+
+ return FAIL;
}
static int
validate_offset_imm (val, hwse)
- int val;
+ unsigned int val;
int hwse;
{
- if ((hwse && (val < -255 || val > 255))
- || (val < -4095 || val > 4095))
+ if ((hwse && val > 255) || val > 4095)
return FAIL;
return val;
}
{
if (!need_pass_2) /* Never make frag if expect extra pass. */
frag_align (1, 0, 0);
+
record_alignment (now_seg, 1);
+
demand_empty_rest_of_line ();
}
static void
-s_ltorg (internal)
- int internal;
+s_ltorg (ignored)
+ int ignored;
{
int lit_count = 0;
char sym_name[20];
if (current_poolP == NULL)
- {
- /* Nothing to do */
- if (!internal)
- as_tsktsk (_("Nothing to put in the pool\n"));
- return;
- }
+ return;
/* Align pool as you have word accesses */
/* Only make a frag if we have to ... */
record_alignment (now_seg, 2);
- if (internal)
- as_tsktsk (_("Inserting implicit pool at change of section"));
-
sprintf (sym_name, "$$lit_\002%x", lit_pool_num++);
symbol_locate (current_poolP, sym_name, now_seg,
symbol_table_insert (current_poolP);
ARM_SET_THUMB (current_poolP, thumb_mode);
+
#if defined OBJ_COFF || defined OBJ_ELF
ARM_SET_INTERWORK (current_poolP, support_interwork);
#endif
current_poolP = NULL;
}
-#if 0 /* not used */
-static void
-arm_align (power, fill)
- int power;
- int fill;
-{
- /* Only make a frag if we HAVE to ... */
- if (power && !need_pass_2)
- frag_align (power, fill, 0);
-
- record_alignment (now_seg, power);
-}
-#endif
-
static void
s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */
int unused;
if (! thumb_mode)
{
- thumb_mode = 1;
+ thumb_mode = 2;
record_alignment (now_seg, 1);
}
label_is_thumb_function_name = true;
- demand_empty_rest_of_line();
+ demand_empty_rest_of_line ();
+}
+
+/* Perform a .set directive, but also mark the alias as
+ being a thumb function. */
+
+static void
+s_thumb_set (equiv)
+ int equiv;
+{
+ /* XXX the following is a duplicate of the code for s_set() in read.c
+ We cannot just call that code as we need to get at the symbol that
+ is created. */
+ register char * name;
+ register char delim;
+ register char * end_name;
+ register symbolS * symbolP;
+
+ /*
+ * Especial apologies for the random logic:
+ * this just grew, and could be parsed much more simply!
+ * Dean in haste.
+ */
+ name = input_line_pointer;
+ delim = get_symbol_end ();
+ end_name = input_line_pointer;
+ *end_name = delim;
+
+ SKIP_WHITESPACE ();
+
+ if (*input_line_pointer != ',')
+ {
+ *end_name = 0;
+ as_bad (_("Expected comma after name \"%s\""), name);
+ *end_name = delim;
+ ignore_rest_of_line ();
+ return;
+ }
+
+ input_line_pointer++;
+ *end_name = 0;
+
+ if (name[0] == '.' && name[1] == '\0')
+ {
+ /* XXX - this should not happen to .thumb_set */
+ abort ();
+ }
+
+ if ((symbolP = symbol_find (name)) == NULL
+ && (symbolP = md_undefined_symbol (name)) == NULL)
+ {
+#ifndef NO_LISTING
+ /* When doing symbol listings, play games with dummy fragments living
+ outside the normal fragment chain to record the file and line info
+ for this symbol. */
+ if (listing & LISTING_SYMBOLS)
+ {
+ extern struct list_info_struct * listing_tail;
+ fragS * dummy_frag = (fragS *) xmalloc (sizeof(fragS));
+ memset (dummy_frag, 0, sizeof(fragS));
+ dummy_frag->fr_type = rs_fill;
+ dummy_frag->line = listing_tail;
+ symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
+ dummy_frag->fr_symbol = symbolP;
+ }
+ else
+#endif
+ symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
+
+#ifdef OBJ_COFF
+ /* "set" symbols are local unless otherwise specified. */
+ SF_SET_LOCAL (symbolP);
+#endif /* OBJ_COFF */
+ } /* make a new symbol */
+
+ symbol_table_insert (symbolP);
+
+ * end_name = delim;
+
+ if (equiv
+ && S_IS_DEFINED (symbolP)
+ && S_GET_SEGMENT (symbolP) != reg_section)
+ as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
+
+ pseudo_set (symbolP);
+
+ demand_empty_rest_of_line ();
+
+ /* XXX Now we come to the Thumb specific bit of code. */
+
+ THUMB_SET_FUNC (symbolP, 1);
+ ARM_SET_THUMB (symbolP, 1);
+#if defined OBJ_ELF || defined OBJ_COFF
+ ARM_SET_INTERWORK (symbolP, support_interwork);
+#endif
+}
+
+/* If we change section we must dump the literal pool first. */
+static void
+arm_s_text (ignore)
+ int ignore;
+{
+ if (now_seg != text_section)
+ s_ltorg (0);
+
+#ifdef OBJ_ELF
+ obj_elf_text (ignore);
+#else
+ s_text (ignore);
+#endif
+}
+
+static void
+arm_s_data (ignore)
+ int ignore;
+{
+ if (flag_readonly_data_in_text)
+ {
+ if (now_seg != text_section)
+ s_ltorg (0);
+ }
+ else if (now_seg != data_section)
+ s_ltorg (0);
+
+#ifdef OBJ_ELF
+ obj_elf_data (ignore);
+#else
+ s_data (ignore);
+#endif
+}
+
+#ifdef OBJ_ELF
+static void
+arm_s_section (ignore)
+ int ignore;
+{
+ s_ltorg (0);
+
+ obj_elf_section (ignore);
}
+#endif
static void
opcode_select (width)
{
case 16:
case 32:
- opcode_select(temp);
+ opcode_select (temp);
break;
default:
static void
end_of_line (str)
- char *str;
+ char * str;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
- if (*str != '\0')
+ if (* str != '\0')
inst.error = _("Garbage following instruction");
}
static int
skip_past_comma (str)
- char **str;
+ char ** str;
{
char *p = *str, c;
int comma = 0;
return comma ? SUCCESS : FAIL;
}
-/* A standard register must be given at this point. Shift is the place to
- put it in the instruction. */
+/* A standard register must be given at this point.
+ Shift is the place to put it in inst.instruction.
+ Restores input start point on err.
+ Returns the reg#, or FAIL. */
static int
reg_required_here (str, shift)
- char **str;
- int shift;
+ char ** str;
+ int shift;
{
static char buff [128]; /* XXX */
- int reg;
- char *start = *str;
+ int reg;
+ char * start = *str;
if ((reg = arm_reg_parse (str)) != FAIL && int_register (reg))
{
*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
static int
cp_opc_expr (str, where, length)
- char **str;
+ char ** str;
int where;
int length;
{
expressionS expr;
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
memset (&expr, '\0', sizeof (expr));
static int
cp_reg_required_here (str, where)
- char **str;
- int where;
+ char ** str;
+ int where;
{
- int reg;
- char *start = *str;
+ int reg;
+ char * start = *str;
if ((reg = arm_reg_parse (str)) != FAIL && cp_register (reg))
{
}
/* 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;
}
static int
fp_reg_required_here (str, where)
- char **str;
- int where;
+ char ** str;
+ int where;
{
int reg;
- char *start = *str;
+ char * start = *str;
if ((reg = arm_reg_parse (str)) != FAIL && fp_register (reg))
{
}
/* 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;
}
static int
cp_address_offset (str)
- char **str;
+ char ** str;
{
int offset;
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
- if (**str != '#')
+ if (! is_immediate_prefix (**str))
{
inst.error = _("immediate expression expected");
return FAIL;
}
(*str)++;
- if (my_get_expression (&inst.reloc.exp, str))
+
+ if (my_get_expression (& inst.reloc.exp, str))
return FAIL;
+
if (inst.reloc.exp.X_op == O_constant)
{
offset = inst.reloc.exp.X_add_number;
+
if (offset & 3)
{
inst.error = _("co-processor address must be word aligned");
static int
cp_address_required_here (str)
- char **str;
+ char ** str;
{
- char *p = *str;
- int pre_inc = 0;
- int write_back = 0;
+ char * p = * str;
+ int pre_inc = 0;
+ int write_back = 0;
if (*p == '[')
{
int reg;
p++;
- while (*p == ' ')
- p++;
+ skip_whitespace (p);
- if ((reg = reg_required_here (&p, 16)) == FAIL)
+ if ((reg = reg_required_here (& p, 16)) == FAIL)
return FAIL;
- while (*p == ' ')
- p++;
+ skip_whitespace (p);
if (*p == ']')
{
p++;
- if (skip_past_comma (&p) == SUCCESS)
+
+ if (skip_past_comma (& p) == SUCCESS)
{
/* [Rn], #expr */
write_back = WRITE_BACK;
+
if (reg == REG_PC)
{
inst.error = _("pc may not be used in post-increment");
return FAIL;
}
- if (cp_address_offset (&p) == FAIL)
+ if (cp_address_offset (& p) == FAIL)
return FAIL;
}
else
{
/* '['Rn, #expr']'[!] */
- if (skip_past_comma (&p) == FAIL)
+ if (skip_past_comma (& p) == FAIL)
{
inst.error = _("pre-indexed expression expected");
return FAIL;
}
pre_inc = PRE_INDEX;
- if (cp_address_offset (&p) == FAIL)
+
+ if (cp_address_offset (& p) == FAIL)
return FAIL;
- while (*p == ' ')
- p++;
+ skip_whitespace (p);
if (*p++ != ']')
{
return FAIL;
}
- while (*p == ' ')
- p++;
+ skip_whitespace (p);
if (*p == '!')
{
static void
do_nop (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
- /* Do nothing really */
- inst.instruction |= flags; /* This is pointless */
+ /* Do nothing really. */
+ inst.instruction |= flags; /* This is pointless. */
end_of_line (str);
return;
}
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;
+ char * str;
unsigned long flags;
{
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;
}
}
else
{
if (psr_required_here (& str, CPSR_FLG, SPSR_FLG) == SUCCESS)
- {
- inst.instruction |= PSR_FLAGS;
- }
+ inst.instruction |= PSR_FLAGS;
else if (psr_required_here (& str, CPSR_CTL, SPSR_CTL) == SUCCESS)
- {
- inst.instruction |= PSR_CONTROL;
- }
+ 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;
}
/* Syntax could be "<psrf>, rm", "<psrf>, #expression" */
- if ((reg = reg_required_here (&str, 0)) != FAIL)
+ if ((reg = reg_required_here (& str, 0)) != FAIL)
;
- /* Immediate expression */
- else if (*(str++) == '#')
+ /* Immediate expression. */
+ else if (is_immediate_prefix (* str))
{
+ str ++;
inst.error = NULL;
- if (my_get_expression (&inst.reloc.exp, &str))
+
+ if (my_get_expression (& inst.reloc.exp, & str))
{
inst.error = _("Register or shift expression expected");
return;
*/
static void
do_mull (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
int rdlo, rdhi, rm, rs;
- /* only one format "rdlo, rdhi, rm, rs" */
- while (*str == ' ')
- str++;
+ /* Only one format "rdlo, rdhi, rm, rs" */
+ skip_whitespace (str);
if ((rdlo = reg_required_here (&str, 12)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (skip_past_comma (&str) == FAIL
|| (rdhi = reg_required_here (&str, 16)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (skip_past_comma (&str) == FAIL
|| (rm = reg_required_here (&str, 0)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
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;
}
static void
do_mul (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
int rd, rm;
- /* only one format "rd, rm, rs" */
- while (*str == ' ')
- str++;
+ /* Only one format "rd, rm, rs" */
+ skip_whitespace (str);
if ((rd = reg_required_here (&str, 16)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (rd == REG_PC)
{
- inst.error = bad_pc;
+ inst.error = BAD_PC;
return;
}
if (skip_past_comma (&str) == FAIL
|| (rm = reg_required_here (&str, 0)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (rm == REG_PC)
{
- inst.error = bad_pc;
+ inst.error = BAD_PC;
return;
}
if (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;
}
static void
do_mla (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
int rd, rm;
- /* only one format "rd, rm, rs, rn" */
- while (*str == ' ')
- str++;
+ /* Only one format "rd, rm, rs, rn" */
+ skip_whitespace (str);
if ((rd = reg_required_here (&str, 16)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (rd == REG_PC)
{
- inst.error = bad_pc;
+ inst.error = BAD_PC;
return;
}
if (skip_past_comma (&str) == FAIL
|| (rm = reg_required_here (&str, 0)) == FAIL)
{
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (rm == REG_PC)
{
- inst.error = bad_pc;
+ inst.error = BAD_PC;
return;
}
|| 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;
}
not in the table. */
static int
my_get_float_expression (str)
- char **str;
+ char ** str;
{
LITTLENUM_TYPE words[MAX_LITTLENUMS];
- char *save_in;
- expressionS exp;
- int i, j;
+ char * save_in;
+ expressionS exp;
+ int i;
+ int j;
memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
/* Look for a raw floating point number */
/* Return true if anything in the expression is a bignum */
static int
walk_no_bignums (sp)
- symbolS *sp;
+ symbolS * sp;
{
- if (sp->sy_value.X_op == O_big)
+ if (symbol_get_value_expression (sp)->X_op == O_big)
return 1;
- if (sp->sy_value.X_add_symbol)
+ if (symbol_get_value_expression (sp)->X_add_symbol)
{
- return (walk_no_bignums (sp->sy_value.X_add_symbol)
- || (sp->sy_value.X_op_symbol
- && walk_no_bignums (sp->sy_value.X_op_symbol)));
+ return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
+ || (symbol_get_value_expression (sp)->X_op_symbol
+ && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
}
return 0;
static int
my_get_expression (ep, str)
- expressionS *ep;
- char **str;
+ expressionS * ep;
+ char ** str;
{
- char *save_in;
- segT seg;
+ char * save_in;
+ segT seg;
save_in = input_line_pointer;
input_line_pointer = *str;
static int
decode_shift (str, unrestrict)
- char **str;
- int unrestrict;
+ char ** str;
+ int unrestrict;
{
- struct asm_shift *shft;
- char *p;
- char c;
+ struct asm_shift * shft;
+ char * p;
+ char c;
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
for (p = *str; isalpha (*p); p++)
;
return SUCCESS;
}
- while (*p == ' ')
- p++;
-
+ skip_whitespace (p);
+
if (unrestrict && reg_required_here (&p, 8) != FAIL)
{
inst.instruction |= shft->value | SHIFT_BY_REG;
*str = p;
return SUCCESS;
}
- else if (*p == '#')
+ else if (is_immediate_prefix (* p))
{
inst.error = NULL;
p++;
*/
static int
negate_data_op (instruction, value)
- unsigned long *instruction;
- unsigned long value;
+ unsigned long * instruction;
+ unsigned long value;
{
int op, new_inst;
unsigned long negated, inverted;
static int
data_op2 (str)
- char **str;
+ char ** str;
{
int value;
expressionS expr;
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
if (reg_required_here (str, 0) != FAIL)
{
if (skip_past_comma (str) == SUCCESS)
- {
- /* Shift operation on register */
- return decode_shift (str, NO_SHIFT_RESTRICT);
- }
+ /* Shift operation on register. */
+ return decode_shift (str, NO_SHIFT_RESTRICT);
+
return SUCCESS;
}
else
{
/* Immediate expression */
- if (*((*str)++) == '#')
+ if (is_immediate_prefix (**str))
{
+ (*str)++;
inst.error = NULL;
+
if (my_get_expression (&inst.reloc.exp, str))
return FAIL;
return SUCCESS;
}
+ (*str)++;
inst.error = _("Register or shift expression expected");
return FAIL;
}
static int
fp_op2 (str)
- char **str;
+ char ** str;
{
- while (**str == ' ')
- (*str)++;
+ skip_whitespace (* str);
if (fp_reg_required_here (str, 0) != FAIL)
return SUCCESS;
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 */
static void
do_arit (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL
|| skip_past_comma (&str) == FAIL
|| data_op2 (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
static void
do_adr (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
/* This is a pseudo-op of the form "adr rd, label" to be converted
into a relative address of the form "add rd, pc, #label-.-8" */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL
|| skip_past_comma (&str) == FAIL
|| my_get_expression (&inst.reloc.exp, &str))
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
/* Frag hacking will turn this into a sub instruction if the offset turns
}
static void
+do_adrl (str, flags)
+ char * str;
+ unsigned long flags;
+{
+ /* This is a pseudo-op of the form "adrl rd, label" to be converted
+ into a relative address of the form:
+ add rd, pc, #low(label-.-8)"
+ add rd, rd, #high(label-.-8)" */
+
+ skip_whitespace (str);
+
+ if (reg_required_here (& str, 12) == FAIL
+ || skip_past_comma (& str) == FAIL
+ || my_get_expression (& inst.reloc.exp, & str))
+ {
+ if (!inst.error)
+ inst.error = BAD_ARGS;
+ return;
+ }
+
+ end_of_line (str);
+
+ /* Frag hacking will turn this into a sub instruction if the offset turns
+ out to be negative. */
+ inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
+ inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+ inst.reloc.pc_rel = 1;
+ inst.instruction |= flags;
+ inst.size = INSN_SIZE * 2;
+
+ return;
+}
+
+static void
do_cmp (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 16) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| data_op2 (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
static void
do_mov (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| data_op2 (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
static int
ldst_extend (str, hwse)
- char **str;
- int hwse;
+ char ** str;
+ int hwse;
{
int add = INDEX_UP;
switch (**str)
{
case '#':
+ case '$':
(*str)++;
- if (my_get_expression (&inst.reloc.exp, str))
+ if (my_get_expression (& inst.reloc.exp, str))
return FAIL;
if (inst.reloc.exp.X_op == O_constant)
/* Halfword and signextension instructions have the
immediate value split across bits 11..8 and bits 3..0 */
if (hwse)
- inst.instruction |= add | HWOFFSET_IMM | (value >> 4) << 8 | value & 0xF;
+ inst.instruction |= add | HWOFFSET_IMM | ((value >> 4) << 8) | (value & 0xF);
else
inst.instruction |= add | value;
}
static void
do_ldst (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
int halfword = 0;
/* This is not ideal, but it is the simplest way of dealing with the
ARM7T halfword instructions (since they use a different
encoding, but the same mnemonic): */
- if (halfword = ((flags & 0x80000000) != 0))
+ halfword = (flags & 0x80000000) != 0;
+ if (halfword)
{
/* This is actually a load/store of a halfword, or a
signed-extension load */
flags = 0;
}
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
- if ((conflict_reg = reg_required_here (&str, 12)) == FAIL)
- return;
+ if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
+ {
+ if (!inst.error)
+ inst.error = BAD_ARGS;
+ return;
+ }
- if (skip_past_comma (&str) == FAIL)
+ if (skip_past_comma (& str) == FAIL)
{
inst.error = _("Address expected");
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;
static long
reg_list (strp)
- char **strp;
+ char ** strp;
{
- char *str = *strp;
- long range = 0;
- int another_range;
+ char * str = *strp;
+ long range = 0;
+ int another_range;
/* We come back here if we get ranges concatenated by '+' or '|' */
do
{
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 == '+')
{
static void
do_ldmstm (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
int base_reg;
long range;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((base_reg = reg_required_here (&str, 16)) == FAIL)
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;
static void
do_swi (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
+ skip_whitespace (str);
+
/* Allow optional leading '#'. */
- while (*str == ' ')
- str++;
- if (*str == '#')
+ if (is_immediate_prefix (*str))
str++;
- if (my_get_expression (&inst.reloc.exp, &str))
+ if (my_get_expression (& inst.reloc.exp, & str))
return;
inst.reloc.type = BFD_RELOC_ARM_SWI;
inst.reloc.pc_rel = 0;
inst.instruction |= flags;
+
end_of_line (str);
+
return;
}
static void
do_swap (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
int reg;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((reg = reg_required_here (&str, 12)) == FAIL)
return;
|| (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++ != ']')
{
static void
do_branch (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
if (my_get_expression (&inst.reloc.exp, &str))
return;
- inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
- inst.reloc.pc_rel = 1;
- end_of_line (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_BRANCH;
+ inst.reloc.pc_rel = 1;
+ }
+ input_line_pointer = save_in;
+ }
+#else
+ inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
+ inst.reloc.pc_rel = 1;
+#endif /* OBJ_ELF */
+
+ end_of_line (str);
+ return;
+}
+
static void
do_bx (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
int reg;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((reg = reg_required_here (&str, 0)) == FAIL)
- return;
+ {
+ inst.error = BAD_ARGS;
+ return;
+ }
if (reg == REG_PC)
- as_tsktsk (_("Use of r15 in bx has undefined behaviour"));
+ inst.error = BAD_PC;
end_of_line (str);
- return;
}
static void
do_cdp (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
/* Co-processor data operation.
Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (co_proc_number (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| 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;
}
}
static void
do_lstc (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
/* Co-processor register load/store.
Format: <LDC|STC{cond}[L] CP#,CRd,<address> */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (co_proc_number (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| 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;
}
static void
do_co_reg (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
/* Co-processor register transfer.
Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>} */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (co_proc_number (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| 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;
static void
do_fp_ctrl (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
/* FP control registers.
Format: <WFS|RFS|WFC|RFC>{cond} Rn */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
static void
do_fp_ldst (str, flags)
- char *str;
+ 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;
}
static void
do_fp_ldmstm (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
int num_regs;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (fp_reg_required_here (&str, 12) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| *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;
}
static void
do_fp_dyadic (str, flags)
- char *str;
+ 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;
}
static void
do_fp_monadic (str, flags)
- char *str;
+ 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;
}
static void
do_fp_cmp (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (fp_reg_required_here (&str, 16) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| fp_op2 (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
static void
do_fp_from_reg (str, flags)
- char *str;
+ 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;
}
static void
do_fp_to_reg (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL)
return;
|| fp_reg_required_here (&str, 0) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
has been parsed. */
static int
thumb_reg (strp, hi_lo)
- char **strp;
- int hi_lo;
+ char ** strp;
+ int hi_lo;
{
int reg;
was SUB. */
static void
thumb_add_sub (str, subtract)
- char *str;
- int subtract;
+ char * str;
+ int subtract;
{
int Rd, Rs, Rn = FAIL;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
|| skip_past_comma (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
- if (*str == '#')
+ if (is_immediate_prefix (*str))
{
Rs = Rd;
str++;
Rn = Rs;
Rs = Rd;
}
- else if (*str == '#')
+ else if (is_immediate_prefix (*str))
{
str++;
if (my_get_expression (&inst.reloc.exp, &str))
static void
thumb_shift (str, shift)
- char *str;
- int shift;
+ char * str;
+ int shift;
{
int Rd, Rs, Rn = FAIL;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
|| skip_past_comma (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
- if (*str == '#')
+ if (is_immediate_prefix (*str))
{
/* Two operand immediate format, set Rs to Rd. */
Rs = Rd;
Rn = Rs;
Rs = Rd;
}
- else if (*str == '#')
+ else if (is_immediate_prefix (*str))
{
str++;
if (my_get_expression (&inst.reloc.exp, &str))
static void
thumb_mov_compare (str, move)
- char *str;
- int move;
+ char * str;
+ int move;
{
int Rd, Rs = FAIL;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
|| skip_past_comma (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
- if (*str == '#')
+ if (is_immediate_prefix (*str))
{
str++;
if (my_get_expression (&inst.reloc.exp, &str))
static void
thumb_load_store (str, load_store, size)
- char *str;
- int load_store;
- int size;
+ char * str;
+ int load_store;
+ int size;
{
int Rd, Rb, Ro = FAIL;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
|| skip_past_comma (&str) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
if (skip_past_comma (&str) != FAIL)
{
- if (*str == '#')
+ if (is_immediate_prefix (*str))
{
str++;
if (my_get_expression (&inst.reloc.exp, &str))
/* 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;
static void
do_t_nop (str)
- char *str;
+ char * str;
{
/* Do nothing */
end_of_line (str);
BIC and MVN. */
static void
do_t_arit (str)
- char *str;
+ char * str;
{
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;
}
static void
do_t_add (str)
- char *str;
+ char * str;
{
thumb_add_sub (str, 0);
}
static void
do_t_asr (str)
- char *str;
+ char * str;
{
thumb_shift (str, THUMB_ASR);
}
static void
do_t_branch9 (str)
- char *str;
+ char * str;
{
if (my_get_expression (&inst.reloc.exp, &str))
return;
static void
do_t_branch12 (str)
- char *str;
+ char * str;
{
if (my_get_expression (&inst.reloc.exp, &str))
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)
static void
do_t_branch23 (str)
- char *str;
+ char * str;
{
- if (my_get_expression (&inst.reloc.exp, &str))
+ if (my_get_expression (& inst.reloc.exp, & str))
return;
+
inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
inst.reloc.pc_rel = 1;
end_of_line (str);
static void
do_t_bx (str)
- char *str;
+ char * str;
{
int reg;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
return;
static void
do_t_compare (str)
- char *str;
+ char * str;
{
thumb_mov_compare (str, THUMB_COMPARE);
}
static void
do_t_ldmstm (str)
- char *str;
+ char * str;
{
int Rb;
long range;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
return;
|| (range = reg_list (&str)) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
static void
do_t_ldr (str)
- char *str;
+ char * str;
{
thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
}
static void
do_t_ldrb (str)
- char *str;
+ char * str;
{
thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
}
static void
do_t_ldrh (str)
- char *str;
+ char * str;
{
thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
}
static void
do_t_lds (str)
- char *str;
+ char * str;
{
int Rd, Rb, Ro;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
|| skip_past_comma (&str) == FAIL
static void
do_t_lsl (str)
- char *str;
+ char * str;
{
thumb_shift (str, THUMB_LSL);
}
static void
do_t_lsr (str)
- char *str;
+ char * str;
{
thumb_shift (str, THUMB_LSR);
}
static void
do_t_mov (str)
- char *str;
+ char * str;
{
thumb_mov_compare (str, THUMB_MOVE);
}
static void
do_t_push_pop (str)
- char *str;
+ char * str;
{
long range;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((range = reg_list (&str)) == FAIL)
{
if (! inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
static void
do_t_str (str)
- char *str;
+ char * str;
{
thumb_load_store (str, THUMB_STORE, THUMB_WORD);
}
static void
do_t_strb (str)
- char *str;
+ char * str;
{
thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
}
static void
do_t_strh (str)
- char *str;
+ char * str;
{
thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
}
static void
do_t_sub (str)
- char *str;
+ char * str;
{
thumb_add_sub (str, 1);
}
static void
do_t_swi (str)
- char *str;
+ char * str;
{
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (my_get_expression (&inst.reloc.exp, &str))
return;
static void
do_t_adr (str)
- char *str;
+ char * str;
{
/* This is a pseudo-op of the form "adr rd, label" to be converted
into a relative address of the form "add rd, pc, #label-.-4" */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 4) == FAIL /* Store Rd in temporary location inside instruction. */
|| skip_past_comma (&str) == FAIL
|| my_get_expression (&inst.reloc.exp, &str))
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
insert_reg (entry)
int entry;
{
- int len = strlen (reg_table[entry].name) + 2;
- char *buf = (char *) xmalloc (len);
- char *buf2 = (char *) xmalloc (len);
- int i = 0;
+ int len = strlen (reg_table[entry].name) + 2;
+ char * buf = (char *) xmalloc (len);
+ char * buf2 = (char *) xmalloc (len);
+ int i = 0;
#ifdef REGISTER_PREFIX
buf[i++] = REGISTER_PREFIX;
{
int i;
- if ((arm_ops_hsh = hash_new ()) == NULL
+ if ( (arm_ops_hsh = hash_new ()) == NULL
|| (arm_tops_hsh = hash_new ()) == NULL
|| (arm_cond_hsh = hash_new ()) == NULL
|| (arm_shift_hsh = hash_new ()) == NULL
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;
+ char * buf;
valueT val;
- int n;
+ int n;
{
if (target_big_endian)
number_to_chars_bigendian (buf, val, n);
static valueT
md_chars_to_number (buf, n)
- char *buf;
+ char * buf;
int n;
{
valueT result = 0;
- unsigned char *where = (unsigned char *) buf;
+ unsigned char * where = (unsigned char *) buf;
if (target_big_endian)
{
char *
md_atof (type, litP, sizeP)
- char type;
- char *litP;
- int *sizeP;
+ char type;
+ char * litP;
+ int * sizeP;
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
return 0;
}
-/* We have already put the pipeline compensation in the instruction */
-
+/* The knowledge of the PC's pipeline offset is built into the insns themselves. */
long
md_pcrel_from (fixP)
- fixS *fixP;
+ fixS * fixP;
{
if ( fixP->fx_addsy
&& S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
&& fixP->fx_subsy == NULL)
- return 0; /* HACK */
-
+ return 0;
+
if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD))
{
/* PC relative addressing on the Thumb is slightly odd
as the bottom two bits of the PC are forced to zero
- for the calculation */
+ for the calculation. */
return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
}
/* Round up a section size to the appropriate boundary. */
valueT
md_section_align (segment, size)
- segT segment;
+ segT segment;
valueT size;
{
-/* start-sanitize-armelf */
#ifdef OBJ_ELF
- /* Don't align the dwarf2 debug sections */
- if (!strncmp(segment->name,".debug",5))
- return size;
-#endif
-/* end-sanitize-armelf */
+ return size;
+#else
/* Round all sects to multiple of 4 */
return (size + 3) & ~3;
+#endif
}
-/* We have no need to default values of symbols. */
+/* Under ELF we need to default _GLOBAL_OFFSET_TABLE. Otherwise
+ we have no need to default values of symbols. */
/* ARGSUSED */
symbolS *
md_undefined_symbol (name)
- char *name;
+ char * name;
{
+#ifdef OBJ_ELF
+ if (name[0] == '_' && name[1] == 'G'
+ && streq (name, GLOBAL_OFFSET_TABLE_NAME))
+ {
+ if (!GOT_symbol)
+ {
+ if (symbol_find (name))
+ as_bad ("GOT already in the symbol table");
+
+ GOT_symbol = symbol_new (name, undefined_section,
+ (valueT)0, & zero_address_frag);
+ }
+
+ return GOT_symbol;
+ }
+#endif
+
return 0;
}
static int
arm_reg_parse (ccp)
- register char **ccp;
+ register char ** ccp;
{
- char *start = *ccp;
- char c;
- char *p;
- struct reg_entry *reg;
+ char * start = * ccp;
+ char c;
+ char * p;
+ struct reg_entry * reg;
#ifdef REGISTER_PREFIX
if (*start != REGISTER_PREFIX)
static int
arm_psr_parse (ccp)
- register char **ccp;
+ register char ** ccp;
{
- char *start = *ccp;
- char c, *p;
- CONST struct asm_psr *psr;
+ char * start = * ccp;
+ char c;
+ char * p;
+ CONST struct asm_psr * psr;
p = start;
c = *p++;
int
md_apply_fix3 (fixP, val, seg)
- fixS *fixP;
- valueT *val;
- segT seg;
-{
- offsetT value = *val;
- offsetT newval;
- unsigned int newimm;
- unsigned long temp;
- int sign;
- char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
- arm_fix_data *arm_data = (arm_fix_data *) fixP->tc_fix_data;
+ fixS * fixP;
+ valueT * val;
+ segT seg;
+{
+ offsetT value = * val;
+ offsetT newval;
+ unsigned int newimm;
+ unsigned long temp;
+ int sign;
+ char * buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+ arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data;
assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
/* Note whether this will delete the relocation. */
#if 0 /* patch from REarnshaw to JDavis (disabled for the moment, since it doesn't work fully) */
- if ((fixP->fx_addsy == 0 || fixP->fx_addsy->sy_value.X_op == O_constant)
+ if ((fixP->fx_addsy == 0 || symbol_constant_p (fixP->fx_addsy))
&& !fixP->fx_pcrel)
#else
if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
&& S_IS_DEFINED (fixP->fx_addsy)
&& S_GET_SEGMENT (fixP->fx_addsy) != seg)
{
- if (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
+ if (target_oabi
+ && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+ ))
value = 0;
else
value += md_pcrel_from (fixP);
}
}
- fixP->fx_addnumber = value; /* Remember value for emit_reloc */
+ fixP->fx_addnumber = value; /* Remember value for emit_reloc. */
switch (fixP->fx_r_type)
{
&& (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
{
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("invalid constant after fixup\n"));
+ _("invalid constant (%lx) after fixup"),
+ (unsigned long) value);
break;
}
md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
break;
- case BFD_RELOC_ARM_OFFSET_IMM:
+ case BFD_RELOC_ARM_ADRL_IMMEDIATE:
+ {
+ unsigned int highpart = 0;
+ unsigned int newinsn = 0xe1a00000; /* nop */
+ newimm = validate_immediate (value);
+ temp = md_chars_to_number (buf, INSN_SIZE);
+
+ /* If the instruction will fail, see if we can fix things up by
+ changing the opcode. */
+ if (newimm == (unsigned int) FAIL
+ && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
+ {
+ /* No ? OK - try using two ADD instructions to generate the value. */
+ newimm = validate_immediate_twopart (value, & highpart);
+
+ /* Yes - then make sure that the second instruction is also an add. */
+ if (newimm != (unsigned int) FAIL)
+ newinsn = temp;
+ /* Still No ? Try using a negated value. */
+ else if (validate_immediate_twopart (- value, & highpart) != (unsigned int) FAIL)
+ temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
+ /* Otherwise - give up. */
+ else
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Unable to compute ADRL instructions for PC offset of 0x%x"), value);
+ break;
+ }
+
+ /* Replace the first operand in the 2nd instruction (which is the PC)
+ with the destination register. We have already added in the PC in the
+ first instruction and we do not want to do it again. */
+ newinsn &= ~ 0xf0000;
+ newinsn |= ((newinsn & 0x0f000) << 4);
+ }
+
+ newimm |= (temp & 0xfffff000);
+ md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
+
+ highpart |= (newinsn & 0xfffff000);
+ md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
+ }
+ break;
+
+ case BFD_RELOC_ARM_OFFSET_IMM:
sign = value >= 0;
- if ((value = validate_offset_imm (value, 0)) == FAIL)
+
+ if (value < 0)
+ value = - value;
+
+ if (validate_offset_imm (value, 0) == FAIL)
{
- as_bad (_("bad immediate value for offset (%d)"), val);
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("bad immediate value for offset (%ld)"), (long) value);
break;
}
- if (value < 0)
- value = -value;
newval = md_chars_to_number (buf, INSN_SIZE);
newval &= 0xff7ff000;
case BFD_RELOC_ARM_OFFSET_IMM8:
case BFD_RELOC_ARM_HWLITERAL:
sign = value >= 0;
- if ((value = validate_offset_imm (value, 1)) == FAIL)
+
+ if (value < 0)
+ value = - value;
+
+ if (validate_offset_imm (value, 1) == FAIL)
{
if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("invalid literal constant: pool needs to be closer\n"));
+ _("invalid literal constant: pool needs to be closer"));
else
- as_bad (_("bad immediate value for offset (%d)"), value);
+ as_bad (_("bad immediate value for half-word offset (%ld)"),
+ (long) value);
break;
}
- if (value < 0)
- value = -value;
-
newval = md_chars_to_number (buf, INSN_SIZE);
newval &= 0xff7ff0f0;
- newval |= ((value >> 4) << 8) | value & 0xf | (sign ? INDEX_UP : 0);
+ newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
md_number_to_chars (buf, newval, INSN_SIZE);
break;
case BFD_RELOC_ARM_LITERAL:
sign = value >= 0;
+
if (value < 0)
- value = -value;
+ value = - value;
- if ((value = validate_offset_imm (value, 0)) == FAIL)
+ if (validate_offset_imm (value, 0) == FAIL)
{
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("invalid literal constant: pool needs to be closer\n"));
+ _("invalid literal constant: pool needs to be closer"));
break;
}
break;
case BFD_RELOC_ARM_PCREL_BRANCH:
- value = (value >> 2) & 0x00ffffff;
newval = md_chars_to_number (buf, INSN_SIZE);
- value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
+
+#ifdef OBJ_ELF
+ if (! target_oabi)
+ value = fixP->fx_offset;
+#endif
+ value = (value >> 2) & 0x00ffffff;
+ value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
newval = value | (newval & 0xff000000);
md_number_to_chars (buf, newval, INSN_SIZE);
break;
+
case BFD_RELOC_THUMB_PCREL_BRANCH9: /* conditional branch */
newval = md_chars_to_number (buf, THUMB_SIZE);
{
{
offsetT newval2;
addressT diff;
-
+
newval = md_chars_to_number (buf, THUMB_SIZE);
newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
if (diff & 0x400000)
diff |= ~0x3fffff;
+#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,
case BFD_RELOC_8:
if (fixP->fx_done || fixP->fx_pcrel)
md_number_to_chars (buf, value, 1);
+#ifdef OBJ_ELF
+ else if (!target_oabi)
+ {
+ value = fixP->fx_offset;
+ md_number_to_chars (buf, value, 1);
+ }
+#endif
break;
case BFD_RELOC_16:
if (fixP->fx_done || fixP->fx_pcrel)
md_number_to_chars (buf, value, 2);
+#ifdef OBJ_ELF
+ else if (!target_oabi)
+ {
+ value = fixP->fx_offset;
+ md_number_to_chars (buf, value, 2);
+ }
+#endif
break;
+#ifdef OBJ_ELF
+ case BFD_RELOC_ARM_GOT32:
+ case BFD_RELOC_ARM_GOTOFF:
+ md_number_to_chars (buf, 0, 4);
+ break;
+#endif
+
case BFD_RELOC_RVA:
case BFD_RELOC_32:
if (fixP->fx_done || fixP->fx_pcrel)
md_number_to_chars (buf, value, 4);
+#ifdef OBJ_ELF
+ else if (!target_oabi)
+ {
+ value = fixP->fx_offset;
+ md_number_to_chars (buf, value, 4);
+ }
+#endif
+ break;
+
+#ifdef OBJ_ELF
+ case BFD_RELOC_ARM_PLT32:
+ /* It appears the instruction is fully prepared at this point. */
break;
+#endif
+ case BFD_RELOC_ARM_GOTPC:
+ md_number_to_chars (buf, value, 4);
+ break;
+
case BFD_RELOC_ARM_CP_OFF_IMM:
sign = value >= 0;
if (value < -1023 || value > 1023 || (value & 3))
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;
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
- "Unable to process relocation for thumb opcode: %x", newval);
+ "Unable to process relocation for thumb opcode: %lx",
+ (unsigned long) newval);
break;
}
md_number_to_chars (buf, newval, THUMB_SIZE);
if (subtract ||
value & ~0x3fc)
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Invalid immediate for address calculation (value = 0x%08X)"), value);
+ _("Invalid immediate for address calculation (value = 0x%08lX)"),
+ (unsigned long) value);
newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
newval |= rd << 8;
newval |= value >> 2;
case 0x05: /* 8bit immediate CMP */
if (value < 0 || value > 255)
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Invalid immediate: %d is too large"), value);
+ _("Invalid immediate: %ld is too large"),
+ (long) value);
newval |= value;
break;
/* 5bit shift value (0..31) */
if (value < 0 || value > 31)
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Illegal Thumb shift value: %d"), value);
+ _("Illegal Thumb shift value: %ld"), (long) value);
newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f;
newval |= value << 6;
md_number_to_chars (buf, newval , THUMB_SIZE);
break;
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ fixP->fx_done = 0;
+ return 1;
+
case BFD_RELOC_NONE:
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Bad relocation fixup type (%d)\n"), fixP->fx_r_type);
+ _("Bad relocation fixup type (%d)"), fixP->fx_r_type);
}
return 1;
format. */
arelent *
tc_gen_reloc (section, fixp)
- asection *section;
- fixS *fixp;
+ asection * section;
+ fixS * fixp;
{
- arelent *reloc;
+ arelent * reloc;
bfd_reloc_code_real_type code;
reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
/* @@ Why fx_addnumber sometimes and fx_offset other times? */
case BFD_RELOC_THUMB_PCREL_BRANCH9:
case BFD_RELOC_THUMB_PCREL_BRANCH12:
case BFD_RELOC_THUMB_PCREL_BRANCH23:
+ case BFD_RELOC_VTABLE_ENTRY:
+ case BFD_RELOC_VTABLE_INHERIT:
code = fixp->fx_r_type;
break;
case BFD_RELOC_ARM_LITERAL:
case BFD_RELOC_ARM_HWLITERAL:
/* If this is called then the a literal has been referenced across
- a section boundry - possibly due to an implicit dump */
+ a section boundary - possibly due to an implicit dump */
as_bad_where (fixp->fx_file, fixp->fx_line,
- _("Literal referenced across section boundry (Implicit dump?)"));
+ _("Literal referenced across section boundary (Implicit dump?)"));
return NULL;
+#ifdef OBJ_ELF
+ case BFD_RELOC_ARM_GOT32:
+ case BFD_RELOC_ARM_GOTOFF:
+ case BFD_RELOC_ARM_PLT32:
+ code = fixp->fx_r_type;
+ break;
+#endif
+
case BFD_RELOC_ARM_IMMEDIATE:
as_bad_where (fixp->fx_file, fixp->fx_line,
_("Internal_relocation (type %d) not fixed up (IMMEDIATE)"),
fixp->fx_r_type);
return NULL;
+ case BFD_RELOC_ARM_ADRL_IMMEDIATE:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("ADRL used for a symbol not defined in the same file"),
+ fixp->fx_r_type);
+ return NULL;
+
case BFD_RELOC_ARM_OFFSET_IMM:
as_bad_where (fixp->fx_file, fixp->fx_line,
_("Internal_relocation (type %d) not fixed up (OFFSET_IMM)"),
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)"),
}
}
+#ifdef OBJ_ELF
+ if (code == BFD_RELOC_32_PCREL
+ && GOT_symbol
+ && fixp->fx_addsy == GOT_symbol)
+ {
+ code = BFD_RELOC_ARM_GOTPC;
+ reloc->addend = fixp->fx_offset = reloc->address;
+ }
+#endif
+
reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
if (reloc->howto == NULL)
return NULL;
}
+ /* HACK: Since arm ELF uses Rel instead of Rela, encode the
+ vtable entry to be used in the relocation's section offset. */
+ if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ reloc->address = fixp->fx_offset;
+
return reloc;
}
int
md_estimate_size_before_relax (fragP, segtype)
- fragS *fragP;
- segT segtype;
+ fragS * fragP;
+ segT segtype;
{
as_fatal (_("md_estimate_size_before_relax\n"));
- return (1);
+ return 1;
}
static void
-output_inst (str)
- char *str;
+output_inst PARAMS ((void))
{
- char *to = NULL;
+ char * to = NULL;
if (inst.error)
{
}
to = frag_more (inst.size);
+
if (thumb_mode && (inst.size > THUMB_SIZE))
{
assert (inst.size == (2 * THUMB_SIZE));
md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE);
- md_number_to_chars (to + 2, inst.instruction, THUMB_SIZE);
+ md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE);
+ }
+ else if (inst.size > INSN_SIZE)
+ {
+ assert (inst.size == (2 * INSN_SIZE));
+ md_number_to_chars (to, inst.instruction, INSN_SIZE);
+ md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
}
else
md_number_to_chars (to, inst.instruction, inst.size);
if (inst.reloc.type != BFD_RELOC_NONE)
fix_new_arm (frag_now, to - frag_now->fr_literal,
- inst.size, &inst.reloc.exp, inst.reloc.pc_rel,
+ inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
inst.reloc.type);
return;
void
md_assemble (str)
- char *str;
+ char * str;
{
- char c;
- char *p, *q, *start;
+ char c;
+ char * p;
+ char * q;
+ char * start;
- /* Align the instruction */
- /* this may not be the right thing to do but ... */
+ /* Align the instruction.
+ This may not be the right thing to do but ... */
/* arm_align (2, 0); */
listing_prev_line (); /* Defined in listing.h */
- /* Align the previous label if needed */
+ /* Align the previous label if needed. */
if (last_label_seen != NULL)
{
- last_label_seen->sy_frag = frag_now;
+ symbol_set_frag (last_label_seen, frag_now);
S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
S_SET_SEGMENT (last_label_seen, now_seg);
}
memset (&inst, '\0', sizeof (inst));
inst.reloc.type = BFD_RELOC_NONE;
- if (*str == ' ')
- str++; /* Skip leading white space */
-
- /* scan up to the end of the op-code, which must end in white space or
- end of string */
+ skip_whitespace (str);
+
+ /* Scan up to the end of the op-code, which must end in white space or
+ end of string. */
for (start = p = str; *p != '\0'; p++)
if (*p == ' ')
break;
if (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;
for (flagno = 0; flag[flagno].template; flagno++)
{
- if (! strcmp (r, flag[flagno].template))
+ if (streq (r, flag[flagno].template))
{
flag_bits |= flag[flagno].set_bits;
break;
}
(*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]1 Currently not supported.
* -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor
* -m[arm]3 Arm 3 processor
- * -m[arm]6, Arm 6 processors
- * -m[arm]7[t][[d]m] Arm 7 processors
+ * -m[arm]6[xx], Arm 6 processors
+ * -m[arm]7[xx][t][[d]m] Arm 7 processors
+ * -m[arm]8[10] Arm 8 processors
+ * -m[arm]9[20][tdmi] Arm 9 processors
+ * -mstrongarm[110[0]] StrongARM processors
+ * -m[arm]v[2345] Arm architectures
* -mall All (except the ARM1)
* FP variants:
* -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions
* -mapcs-float Pass floats in float regs
* -mapcs-reentrant Position independent code
* -mthumb-interwork Code supports Arm/Thumb interworking
+ * -moabi Old ELF ABI
*/
-CONST char *md_shortopts = "m:";
+CONST char * md_shortopts = "m:k";
struct option md_longopts[] =
{
#ifdef ARM_BI_ENDIAN
{"EB", no_argument, NULL, OPTION_EB},
#define OPTION_EL (OPTION_MD_BASE + 1)
{"EL", no_argument, NULL, OPTION_EL},
+#ifdef OBJ_ELF
+#define OPTION_OABI (OPTION_MD_BASE +2)
+ {"oabi", no_argument, NULL, OPTION_OABI},
+#endif
#endif
{NULL, no_argument, NULL, 0}
};
int
md_parse_option (c, arg)
- int c;
- char *arg;
+ int c;
+ char * arg;
{
- char *str = arg;
+ char * str = arg;
switch (c)
{
switch (*str)
{
case 'f':
- if (! strcmp (str, "fpa10"))
+ if (streq (str, "fpa10"))
cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA10;
- else if (! strcmp (str, "fpa11"))
+ else if (streq (str, "fpa11"))
cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA11;
- else if (! strcmp (str, "fpe-old"))
+ else if (streq (str, "fpe-old"))
cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_CORE;
else
goto bad;
break;
case 'n':
- if (! strcmp (str, "no-fpu"))
+ if (streq (str, "no-fpu"))
cpu_variant &= ~FPU_ALL;
break;
+#ifdef OBJ_ELF
+ case 'o':
+ if (streq (str, "oabi"))
+ target_oabi = true;
+ break;
+#endif
+
case 't':
/* Limit assembler to generating only Thumb instructions: */
- if (! strcmp (str, "thumb"))
+ if (streq (str, "thumb"))
{
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB;
cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE;
thumb_mode = 1;
}
- else if (! strcmp (str, "thumb-interwork"))
+ else if (streq (str, "thumb-interwork"))
{
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCHv4;
+ 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
break;
default:
- if (! strcmp (str, "all"))
+ if (streq (str, "all"))
{
cpu_variant = ARM_ALL | FPU_ALL;
return 1;
str += 5;
- if (! strcmp (str, "32"))
+ if (streq (str, "32"))
{
uses_apcs_26 = false;
return 1;
}
- else if (! strcmp (str, "26"))
+ else if (streq (str, "26"))
{
uses_apcs_26 = true;
return 1;
}
- else if (! strcmp (str, "frame"))
+ else if (streq (str, "frame"))
{
/* Stack frames are being generated - does not affect
linkage of code. */
return 1;
}
- else if (! strcmp (str, "stack-check"))
+ else if (streq (str, "stack-check"))
{
/* Stack checking is being performed - does not affect
linkage, but does require that the functions
return 1;
}
- else if (! strcmp (str, "float"))
+ else if (streq (str, "float"))
{
/* Floating point arguments are being passed in the floating
point registers. This does affect linking, since this
uses_apcs_float = true;
return 1;
}
- else if (! strcmp (str, "reentrant"))
+ else if (streq (str, "reentrant"))
{
/* Reentrant code has been generated. This does affect
linking, since there is no point in linking reentrant/
switch (*str)
{
case '1':
- if (! strcmp (str, "1"))
+ if (streq (str, "1"))
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_1;
else
goto bad;
break;
case '2':
- if (! strcmp (str, "2"))
+ if (streq (str, "2"))
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2;
- else if (! strcmp (str, "250"))
+ else if (streq (str, "250"))
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_250;
else
goto bad;
break;
case '3':
- if (! strcmp (str, "3"))
+ if (streq (str, "3"))
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3;
else
goto bad;
break;
- case 's':
- if (! strcmp (str, "strongarm") || ! strcmp (str, "strongarm110"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL;
- else
- goto bad;
- break;
-
- case '8':
- if (! strcmp (str, "8"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL;
- else
- goto bad;
- break;
-
case '6':
- if (! strcmp (str, "6"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6;
- else
- goto bad;
+ switch (strtol (str, NULL, 10))
+ {
+ case 6:
+ case 60:
+ case 600:
+ case 610:
+ case 620:
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6;
+ break;
+ default:
+ goto bad;
+ }
break;
case '7':
- str++; /* eat the '7' */
+ switch (strtol (str, & str, 10)) /* Eat the processor name */
+ {
+ case 7:
+ case 70:
+ case 700:
+ case 710:
+ case 720:
+ case 7100:
+ case 7500:
+ break;
+ default:
+ goto bad;
+ }
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7;
for (; *str; str++)
{
switch (* str)
{
case 't':
- cpu_variant |= (ARM_THUMB | ARM_ARCHv4);
+ cpu_variant |= (ARM_THUMB | ARM_ARCH_V4);
break;
case 'm':
else
goto bad;
- case 'c': /* Unknown */
- case 'd': /* debug */
- case 'i': /* embedded ice */
+ case 'c': /* Left over from 710c processor name. */
+ case 'd': /* Debug */
+ case 'i': /* Embedded ICE */
/* Included for completeness in ARM processor naming. */
break;
}
break;
+ case '8':
+ if (streq (str, "8") || streq (str, "810"))
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
+ else
+ goto bad;
+ break;
+
+ case '9':
+ if (streq (str, "9"))
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+ else if (streq (str, "920"))
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL;
+ else if (streq (str, "920t"))
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+ else if (streq (str, "9tdmi"))
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+ else
+ goto bad;
+ break;
+
+
+ case 's':
+ if (streq (str, "strongarm")
+ || streq (str, "strongarm110")
+ || streq (str, "strongarm1100"))
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
+ else
+ goto bad;
+ break;
+
case 'v':
/* Select variant based on architecture rather than processor */
switch (*++str)
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;
}
void
md_show_usage (fp)
- FILE *fp;
+ FILE * fp;
{
fprintf (fp,
_("\
ARM Specific Assembler Options:\n\
-m[arm][<processor name>] select processor variant\n\
- -m[arm]v[2|2a|3|3m|4|4t] select architecture variant\n\
+ -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] select architecture variant\n\
-mthumb only allow Thumb instructions\n\
-mthumb-interwork mark the assembled code as supporting interworking\n\
-mall allow any instruction\n\
-mfpa10, -mfpa11 select floating point architecture\n\
-mfpe-old don't allow floating-point multiple instructions\n\
-mno-fpu don't allow any floating-point instructions.\n"));
+ fprintf (fp,
+_("\
+ -k generate PIC code.\n"));
#if defined OBJ_COFF || defined OBJ_ELF
fprintf (fp,
_("\
fprintf (fp,
_("\
-mapcs-reentrant the code is position independent/reentrant\n"));
+ #endif
+#ifdef OBJ_ELF
+ fprintf (fp,
+_("\
+ -moabi support the old ELF ABI\n"));
#endif
#ifdef ARM_BI_ENDIAN
fprintf (fp,
static void
fix_new_arm (frag, where, size, exp, pc_rel, reloc)
- fragS *frag;
- int where;
- short int size;
- expressionS *exp;
- int pc_rel;
- int reloc;
+ fragS * frag;
+ int where;
+ short int size;
+ expressionS * exp;
+ int pc_rel;
+ int reloc;
{
- fixS *new_fix;
- arm_fix_data *arm_data;
+ fixS * new_fix;
+ arm_fix_data * arm_data;
switch (exp->X_op)
{
}
/* Mark whether the fix is to a THUMB instruction, or an ARM instruction */
- arm_data = (arm_fix_data *) obstack_alloc (¬es, sizeof (arm_fix_data));
+ arm_data = (arm_fix_data *) obstack_alloc (& notes, sizeof (arm_fix_data));
new_fix->tc_fix_data = (PTR) arm_data;
arm_data->thumb_mode = thumb_mode;
return;
}
+
+/* This fix_new is called by cons via TC_CONS_FIX_NEW. */
+void
+cons_fix_new_arm (frag, where, size, exp)
+ fragS * frag;
+ int where;
+ int size;
+ expressionS * exp;
+{
+ bfd_reloc_code_real_type type;
+ int pcrel = 0;
+
+ /* Pick a reloc ...
+ *
+ * @@ Should look at CPU word size.
+ */
+ switch (size)
+ {
+ case 2:
+ type = BFD_RELOC_16;
+ break;
+ case 4:
+ default:
+ type = BFD_RELOC_32;
+ break;
+ case 8:
+ type = BFD_RELOC_64;
+ break;
+ }
+
+ fix_new_exp (frag, where, (int) size, exp, pcrel, type);
+}
+
/* A good place to do this, although this was probably not intended
- * for this kind of use. We need to dump the literal pool before
- * references are made to a null symbol pointer. */
+ 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
void
arm_frob_label (sym)
- symbolS *sym;
+ symbolS * sym;
{
last_label_seen = sym;
+
ARM_SET_THUMB (sym, thumb_mode);
+
#if defined OBJ_COFF || defined OBJ_ELF
ARM_SET_INTERWORK (sym, support_interwork);
#endif
/* Adjust the symbol table. This marks Thumb symbols as distinct from
ARM ones. */
-#ifdef OBJ_ELF
-#define S_GET_STORAGE_CLASS(S) (elf_symbol ((S)->bsym)->internal_elf_sym.st_info)
-#define S_SET_STORAGE_CLASS(S,V) (elf_symbol ((S)->bsym)->internal_elf_sym.st_info = (V))
-#endif
void
arm_adjust_symtab ()
{
- symbolS * sym;
#ifdef OBJ_COFF
+ symbolS * sym;
for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
{
else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
else
- as_bad (_("%s: unexpected function type: %d"), S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
+ as_bad (_("%s: unexpected function type: %d"),
+ S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
}
else switch (S_GET_STORAGE_CLASS (sym))
{
}
if (ARM_IS_INTERWORK (sym))
- coffsymbol(sym->bsym)->native->u.syment.n_flags = 0xFF;
+ coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
}
-#endif /* OBJ_COFF */
-}
+#endif
#ifdef OBJ_ELF
-void
-armelf_adjust_symtab ()
-{
- symbolS * sym;
+ symbolS * sym;
+ elf_symbol_type * elf_sym;
+ char bind;
for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
{
- if (ARM_IS_THUMB (sym) && (THUMB_IS_FUNC (sym)))
- {
- elf_symbol_type * elf_sym;
- unsigned char bind;
-
- elf_sym = elf_symbol (sym->bsym);
- bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info);
+ if (ARM_IS_THUMB (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);
- }
- }
-}
-
-void
-armelf_frob_symbol (symp, puntp)
- symbolS * symp;
- int * puntp;
-{
- elf_frob_symbol (symp, puntp);
+ /* If it's a .thumb_func, declare it as so, else tag label as .code 16. */
+ if (THUMB_IS_FUNC (sym))
+ elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
+ else
+ elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_16BIT);
+ }
+ }
+#endif
}
-#endif /* OBJ_ELF */
-
int
arm_data_in_code ()
{
*input_line_pointer = 0;
return 1;
}
+
return 0;
}
char *
arm_canonicalize_symbol_name (name)
- char *name;
+ char * name;
{
int len;
if (thumb_mode && (len = strlen (name)) > 5
- && ! strcmp (name + len - 5, "/data"))
+ && streq (name + len - 5, "/data"))
+ *(name + len - 5) = 0;
+
+ return name;
+}
+
+boolean
+arm_validate_fix (fixP)
+ fixS * fixP;
+{
+ /* If the destination of the branch is a defined symbol which does not have
+ the THUMB_FUNC attribute, then we must be calling a function which has
+ the (interfacearm) attribute. We look for the Thumb entry point to that
+ function and change the branch to refer to that function instead. */
+ if ( fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
+ && fixP->fx_addsy != NULL
+ && S_IS_DEFINED (fixP->fx_addsy)
+ && ! THUMB_IS_FUNC (fixP->fx_addsy))
{
- *(name + len - 5) = 0;
+ fixP->fx_addsy = find_real_start (fixP->fx_addsy);
+ return true;
}
- return name;
+ return false;
}
-/* start-sanitize-armelf */
+
#ifdef OBJ_ELF
/* Relocations against Thumb function names must be left unadjusted,
so that the linker can use this information to correctly set the
There is one other problem that ought to be addressed here, but
which currently is not: Taking the address of a label (rather
than a function) and then later jumping to that address. Such
- address also ought to have their bottom bit set (assuming that
+ addresses also ought to have their bottom bit set (assuming that
they reside in Thumb code), but at the moment they will not. */
boolean
arm_fix_adjustable (fixP)
- fixS *fixP;
+ fixS * fixP;
{
if (fixP->fx_addsy == NULL)
return 1;
+ /* Prevent all adjustments to global symbols. */
+ if (S_IS_EXTERN (fixP->fx_addsy))
+ return 0;
+
+ if (S_IS_WEAK (fixP->fx_addsy))
+ return 0;
+
if (THUMB_IS_FUNC (fixP->fx_addsy)
&& fixP->fx_subsy == NULL)
return 0;
+ /* We need the symbol name for the VTABLE entries */
+ if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 0;
+
return 1;
}
-#endif /* OBJ_ELF */
-/* end-sanitize-armelf */
-boolean
-arm_validate_fix (fixP)
- fixS * fixP;
+const char *
+elf32_arm_target_format ()
{
- /* If the destination of the branch is a defined symbol which does not have
- the THUMB_FUNC attribute, then we must be calling a function which has
- the (interfacearm) attribute. We look for the Thumb entry point to that
- function and change the branch to refer to that function instead. */
- if ( fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
- && fixP->fx_addsy != NULL
- && S_IS_DEFINED (fixP->fx_addsy)
- && ! THUMB_IS_FUNC (fixP->fx_addsy))
+ if (target_big_endian)
+ if (target_oabi)
+ return "elf32-bigarm-oabi";
+ else
+ return "elf32-bigarm";
+ else
+ if (target_oabi)
+ return "elf32-littlearm-oabi";
+ else
+ return "elf32-littlearm";
+}
+
+void
+armelf_frob_symbol (symp, puntp)
+ symbolS * symp;
+ int * puntp;
+{
+ elf_frob_symbol (symp, puntp);
+}
+
+int
+arm_force_relocation (fixp)
+ struct fix * fixp;
+{
+ if ( fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+ || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+ || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
+ return 1;
+
+ return 0;
+}
+
+static bfd_reloc_code_real_type
+arm_parse_reloc ()
+{
+ char id[16];
+ char * ip;
+ int i;
+ static struct
+ {
+ char * str;
+ int len;
+ bfd_reloc_code_real_type reloc;
+ }
+ reloc_map[] =
+ {
+#define MAP(str,reloc) { str, sizeof (str)-1, reloc }
+ MAP ("(got)", BFD_RELOC_ARM_GOT32),
+ MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF),
+ /* ScottB: Jan 30, 1998 */
+ /* Added support for parsing "var(PLT)" branch instructions */
+ /* generated by GCC for PLT relocs */
+ MAP ("(plt)", BFD_RELOC_ARM_PLT32),
+ { NULL, 0, BFD_RELOC_UNUSED }
+#undef MAP
+ };
+
+ for (i = 0, ip = input_line_pointer;
+ i < sizeof (id) && (isalnum (*ip) || ispunct (*ip));
+ i++, ip++)
+ id[i] = tolower (*ip);
+
+ for (i = 0; reloc_map[i].str; i++)
+ if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0)
+ break;
+
+ input_line_pointer += reloc_map[i].len;
+
+ return reloc_map[i].reloc;
+}
+
+static void
+s_arm_elf_cons (nbytes)
+ int nbytes;
+{
+ expressionS exp;
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ if (is_it_end_of_statement ())
{
- fixP->fx_addsy = find_real_start (fixP->fx_addsy);
- return true;
+ demand_empty_rest_of_line ();
+ return;
}
- return false;
+#ifdef md_cons_align
+ md_cons_align (nbytes);
+#endif
+
+ do
+ {
+ bfd_reloc_code_real_type reloc;
+
+ expression (& exp);
+
+ if (exp.X_op == O_symbol
+ && * input_line_pointer == '('
+ && (reloc = arm_parse_reloc()) != BFD_RELOC_UNUSED)
+ {
+ reloc_howto_type * howto = bfd_reloc_type_lookup (stdoutput, reloc);
+ int size = bfd_get_reloc_size (howto);
+
+ if (size > nbytes)
+ as_bad ("%s relocations do not fit in %d bytes", howto->name, nbytes);
+ else
+ {
+ register char * p = frag_more ((int) nbytes);
+ int offset = nbytes - size;
+
+ fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
+ & exp, 0, reloc);
+ }
+ }
+ else
+ emit_expr (& exp, (unsigned int) nbytes);
+ }
+ while (*input_line_pointer++ == ',');
+
+ input_line_pointer--; /* Put terminator back into stream. */
+ demand_empty_rest_of_line ();
}
+#endif /* OBJ_ELF */