/* 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, 2000 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_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 */
#endif
/* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful */
+ pre-processor is disabled, these aren't very useful. */
CONST char comment_chars[] = "@";
/* This array holds the chars that only start a comment at the beginning of
a line. If the line seems to have the form '# 123 filename'
- .line and .file directives will appear in the pre-processed output */
+ .line and .file directives will appear in the pre-processed output. */
/* Note that input_file.c hand checks for '#' at the beginning of the
first line of the input file. This is because the compiler outputs
- #NO_APP at the beginning of its output. */
-/* Also note that comments like this one will always work. */
+ #NO_APP at the beginning of its output. */
+/* Also note that comments like this one will always work. */
CONST char line_comment_chars[] = "#";
+#ifdef TE_LINUX
+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 */
+/* Chars that can be used to separate mant
+ from exp in floating point numbers. */
CONST char EXP_CHARS[] = "eE";
/* Chars that mean this number is a floating point constant */
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
};
-/* Number of littlenums required to hold an extended precision number */
+/* Number of littlenums required to hold an extended precision number. */
#define MAX_LITTLENUMS 6
LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
struct asm_cond
{
- CONST char *template;
+ CONST char * template;
unsigned long value;
};
-/* This is to save a hash look-up in the common case */
+/* This is to save a hash look-up in the common case. */
#define COND_ALWAYS 0xe0000000
static CONST struct asm_cond conds[] =
/* Warning: If the top bit of the set_bits is set, then the standard
instruction bitmask is ignored, and the new bitmask is taken from
- the set_bits: */
+ the set_bits: */
struct asm_flg
{
- CONST char *template; /* Basic flag string */
+ CONST char * template; /* Basic flag string */
unsigned long set_bits; /* Bits to set */
};
struct asm_psr
{
- CONST char *template;
- unsigned long number;
+ CONST char * template;
+ boolean cpsr;
+ unsigned long field;
};
-#define PSR_FIELD_MASK 0x000f0000
-
-#define PSR_FLAGS 0x00080000
-#define PSR_CONTROL 0x00010000 /* Undocumented instruction, its use is discouraged by ARM */
-#define PSR_ALL 0x00090000
+#define SPSR_BIT (1 << 22) /* The bit that distnguishes CPSR and SPSR. */
+#define PSR_SHIFT 16 /* How many bits to shift the PSR_xxx bits up by. */
-#define CPSR_ALL 0
-#define SPSR_ALL 1
-#define CPSR_FLG 2
-#define SPSR_FLG 3
-#define CPSR_CTL 4
-#define SPSR_CTL 5
+#define PSR_c (1 << 0)
+#define PSR_x (1 << 1)
+#define PSR_s (1 << 2)
+#define PSR_f (1 << 3)
static CONST struct asm_psr psrs[] =
{
- /* Valid <psr>'s */
- {"cpsr", CPSR_ALL},
- {"cpsr_all", CPSR_ALL},
- {"spsr", SPSR_ALL},
- {"spsr_all", SPSR_ALL},
-
- /* Valid <psrf>'s */
- {"cpsr_flg", CPSR_FLG},
- {"spsr_flg", SPSR_FLG},
-
- /* Valid <psrc>'s */
- {"cpsr_c", CPSR_CTL},
- {"cpsr_ctl", CPSR_CTL},
- {"spsr_c", SPSR_CTL},
- {"spsr_ctl", SPSR_CTL}
+ {"CPSR", true, PSR_c | PSR_f},
+ {"CPSR_all", true, PSR_c | PSR_f},
+ {"SPSR", false, PSR_c | PSR_f},
+ {"SPSR_all", false, PSR_c | PSR_f},
+ {"CPSR_flg", true, PSR_f},
+ {"CPSR_f", true, PSR_f},
+ {"SPSR_flg", false, PSR_f},
+ {"SPSR_f", false, PSR_f},
+ {"CPSR_c", true, PSR_c},
+ {"CPSR_ctl", true, PSR_c},
+ {"SPSR_c", false, PSR_c},
+ {"SPSR_ctl", false, PSR_c},
+ {"CPSR_x", true, PSR_x},
+ {"CPSR_s", true, PSR_s},
+ {"SPSR_x", false, PSR_x},
+ {"SPSR_s", false, PSR_s},
+ /* For backwards compatability with older toolchain we also
+ support lower case versions of some of these flags. */
+ {"cpsr", true, PSR_c | PSR_f},
+ {"cpsr_all", true, PSR_c | PSR_f},
+ {"spsr", false, PSR_c | PSR_f},
+ {"spsr_all", false, PSR_c | PSR_f},
+ {"cpsr_flg", true, PSR_f},
+ {"cpsr_f", true, PSR_f},
+ {"spsr_flg", false, PSR_f},
+ {"spsr_f", false, PSR_f},
+ {"cpsr_c", true, PSR_c},
+ {"cpsr_ctl", true, PSR_c},
+ {"spsr_c", false, PSR_c},
+ {"spsr_ctl", false, PSR_c}
};
-/* Functions called by parser */
+/* Functions called by parser. */
/* ARM instructions */
-static void do_arit PARAMS ((char *operands, unsigned long flags));
-static void do_cmp PARAMS ((char *operands, unsigned long flags));
-static void do_mov PARAMS ((char *operands, unsigned long flags));
-static void do_ldst PARAMS ((char *operands, unsigned long flags));
-static void do_ldmstm PARAMS ((char *operands, unsigned long flags));
-static void do_branch PARAMS ((char *operands, unsigned long flags));
-static void do_swi PARAMS ((char *operands, unsigned long flags));
-/* Pseudo Op codes */
-static void do_adr PARAMS ((char *operands, unsigned long flags));
-static void do_nop PARAMS ((char *operands, unsigned long flags));
-/* ARM 2 */
-static void do_mul PARAMS ((char *operands, unsigned long flags));
-static void do_mla PARAMS ((char *operands, unsigned long flags));
-/* ARM 3 */
-static void do_swap PARAMS ((char *operands, unsigned long flags));
-/* ARM 6 */
-static void do_msr PARAMS ((char *operands, unsigned long flags));
-static void do_mrs PARAMS ((char *operands, unsigned long flags));
-/* ARM 7M */
-static void do_mull PARAMS ((char *operands, unsigned long flags));
-/* ARM THUMB */
-static void do_bx PARAMS ((char *operands, unsigned long flags));
-
-/* Coprocessor Instructions */
-static void do_cdp PARAMS ((char *operands, unsigned long flags));
-static void do_lstc PARAMS ((char *operands, unsigned long flags));
-static void do_co_reg PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ctrl PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ldst PARAMS ((char *operands, unsigned long flags));
-static void do_fp_ldmstm PARAMS ((char *operands, unsigned long flags));
-static void do_fp_dyadic PARAMS ((char *operands, unsigned long flags));
-static void do_fp_monadic PARAMS ((char *operands, unsigned long flags));
-static void do_fp_cmp PARAMS ((char *operands, unsigned long flags));
-static void do_fp_from_reg PARAMS ((char *operands, unsigned long flags));
-static void do_fp_to_reg PARAMS ((char *operands, unsigned long flags));
-
-static void fix_new_arm PARAMS ((fragS *frag, int where,
- short int size, expressionS *exp,
- int pc_rel, int reloc));
-static int arm_reg_parse PARAMS ((char **ccp));
-static int arm_psr_parse PARAMS ((char **ccp));
-static void symbol_locate PARAMS ((symbolS *, CONST char *, segT,
- valueT, fragS *));
+static void do_arit PARAMS ((char *, unsigned long));
+static void do_cmp PARAMS ((char *, unsigned long));
+static void do_mov PARAMS ((char *, unsigned long));
+static void do_ldst PARAMS ((char *, unsigned long));
+static void do_ldmstm PARAMS ((char *, unsigned long));
+static void do_branch PARAMS ((char *, unsigned long));
+static void do_swi PARAMS ((char *, unsigned long));
+/* Pseudo Op codes */
+static void do_adr PARAMS ((char *, unsigned long));
+static void do_adrl PARAMS ((char *, unsigned long));
+static void do_nop PARAMS ((char *, unsigned long));
+/* ARM 2 */
+static void do_mul PARAMS ((char *, unsigned long));
+static void do_mla PARAMS ((char *, unsigned long));
+/* ARM 3 */
+static void do_swap PARAMS ((char *, unsigned long));
+/* ARM 6 */
+static void do_msr PARAMS ((char *, unsigned long));
+static void do_mrs PARAMS ((char *, unsigned long));
+/* ARM 7M */
+static void do_mull PARAMS ((char *, unsigned long));
+/* ARM THUMB */
+static void do_bx PARAMS ((char *, unsigned long));
+
+
+/* Coprocessor Instructions */
+static void do_cdp PARAMS ((char *, unsigned long));
+static void do_lstc PARAMS ((char *, unsigned long));
+static void do_co_reg PARAMS ((char *, unsigned long));
+static void do_fp_ctrl PARAMS ((char *, unsigned long));
+static void do_fp_ldst PARAMS ((char *, unsigned long));
+static void do_fp_ldmstm PARAMS ((char *, unsigned long));
+static void do_fp_dyadic PARAMS ((char *, unsigned long));
+static void do_fp_monadic PARAMS ((char *, unsigned long));
+static void do_fp_cmp PARAMS ((char *, unsigned long));
+static void do_fp_from_reg PARAMS ((char *, unsigned long));
+static void do_fp_to_reg PARAMS ((char *, unsigned long));
+
+static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *, int, int));
+static int arm_reg_parse PARAMS ((char **));
+static CONST struct asm_psr * arm_psr_parse PARAMS ((char **));
+static void symbol_locate PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *));
static int add_to_lit_pool PARAMS ((void));
-static unsigned validate_immediate PARAMS ((unsigned));
-static int validate_offset_imm PARAMS ((int, int));
+static unsigned validate_immediate PARAMS ((unsigned));
+static unsigned validate_immediate_twopart PARAMS ((unsigned int, unsigned int *));
+static int validate_offset_imm PARAMS ((unsigned int, int));
static void opcode_select PARAMS ((int));
static void end_of_line PARAMS ((char *));
static int reg_required_here PARAMS ((char **, int));
-static int psr_required_here PARAMS ((char **, int, int));
+static int psr_required_here PARAMS ((char **));
static int co_proc_number PARAMS ((char **));
static int cp_opc_expr PARAMS ((char **, int, int));
static int cp_reg_required_here PARAMS ((char **, int));
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: */
+ take 2: */
#define INSN_SIZE 4
/* LONGEST_INST is the longest basic instruction name without conditions or
- * flags.
- * ARM7M has 4 of length 5
- */
+ flags. ARM7M has 4 of length 5. */
#define LONGEST_INST 5
+
struct asm_opcode
{
- CONST char *template; /* Basic string to match */
- unsigned long value; /* Basic instruction code */
- CONST char *comp_suffix; /* Compulsory suffix that must follow conds */
- 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[] =
{"stm", 0x08000000, NULL, stm_flags, ARM_ANY, do_ldmstm},
{"ldm", 0x08100000, NULL, ldm_flags, ARM_ANY, do_ldmstm},
{"swi", 0x0f000000, NULL, NULL, ARM_ANY, do_swi},
+#ifdef TE_WINCE
+ {"bl", 0x0b000000, NULL, NULL, ARM_ANY, do_branch},
+ {"b", 0x0a000000, NULL, NULL, ARM_ANY, do_branch},
+#else
{"bl", 0x0bfffffe, NULL, NULL, ARM_ANY, do_branch},
{"b", 0x0afffffe, NULL, NULL, ARM_ANY, do_branch},
-
+#endif
+
/* Pseudo ops */
{"adr", 0x028f0000, NULL, NULL, ARM_ANY, do_adr},
+ {"adrl", 0x028f0000, NULL, NULL, ARM_ANY, do_adrl},
{"nop", 0x01a00000, NULL, NULL, ARM_ANY, do_nop},
/* ARM 2 multiplies */
/* 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 through 19 are
+ handled by the PSR_xxx defines above. */
/* ARM 7M long multiplies - need signed/unsigned flags! */
{"smull", 0x00c00090, NULL, s_flag, ARM_LONGMUL, do_mull},
{"flt", 0x0e000110, "sde", round_flags, FPU_ALL, do_fp_from_reg},
{"fix", 0x0e100110, NULL, fix_flags, FPU_ALL, do_fp_to_reg},
-/* Generic copressor instructions */
+/* Generic copressor instructions. */
{"cdp", 0x0e000000, NULL, NULL, ARM_2UP, do_cdp},
{"ldc", 0x0c100000, NULL, cplong_flag, ARM_2UP, do_lstc},
{"stc", 0x0c000000, NULL, cplong_flag, ARM_2UP, do_lstc},
{"mrc", 0x0e100010, NULL, NULL, ARM_2UP, do_co_reg},
};
-/* defines for various bits that we will want to toggle */
-
+/* Defines for various bits that we will want to toggle. */
#define INST_IMMEDIATE 0x02000000
#define OFFSET_REG 0x02000000
#define HWOFFSET_IMM 0x00400000
#define PRE_INDEX 0x01000000
#define INDEX_UP 0x00800000
#define WRITE_BACK 0x00200000
-#define MULTI_SET_PSR 0x00400000
+#define LDM_TYPE_2_OR_3 0x00400000
#define LITERAL_MASK 0xf000f000
#define COND_MASK 0xf0000000
#define OPCODE_MASK 0xfe1fffff
#define DATA_OP_SHIFT 21
-/* Codes to distinguish the arithmetic instructions */
-
+/* Codes to distinguish the arithmetic instructions. */
#define OPCODE_AND 0
#define OPCODE_EOR 1
#define OPCODE_SUB 2
#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_SIZE 2 /* Size of thumb instruction. */
#define THUMB_REG_LO 0x1
#define THUMB_REG_HI 0x2
#define THUMB_REG_ANY 0x3
#define THUMB_PP_PC_LR 0x0100
-/* These three are used for immediate shifts, do not alter */
+/* These three are used for immediate shifts, do not alter. */
#define THUMB_WORD 2
#define THUMB_HALFWORD 1
#define THUMB_BYTE 0
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},
+ {"bal", 0xdefe, 2, ARM_THUMB, do_t_branch9},
+ {"bic", 0x4380, 2, ARM_THUMB, do_t_arit},
+ {"bl", 0xf7fffffe, 4, ARM_THUMB, do_t_branch23},
+ {"bx", 0x4700, 2, ARM_THUMB, do_t_bx},
+ {"cmn", T_OPCODE_CMN, 2, ARM_THUMB, do_t_arit},
+ {"cmp", 0x0000, 2, ARM_THUMB, do_t_compare},
+ {"eor", 0x4040, 2, ARM_THUMB, do_t_arit},
+ {"ldmia", 0xc800, 2, ARM_THUMB, do_t_ldmstm},
+ {"ldr", 0x0000, 2, ARM_THUMB, do_t_ldr},
+ {"ldrb", 0x0000, 2, ARM_THUMB, do_t_ldrb},
+ {"ldrh", 0x0000, 2, ARM_THUMB, do_t_ldrh},
+ {"ldrsb", 0x5600, 2, ARM_THUMB, do_t_lds},
+ {"ldrsh", 0x5e00, 2, ARM_THUMB, do_t_lds},
+ {"ldsb", 0x5600, 2, ARM_THUMB, do_t_lds},
+ {"ldsh", 0x5e00, 2, ARM_THUMB, do_t_lds},
+ {"lsl", 0x0000, 2, ARM_THUMB, do_t_lsl},
+ {"lsr", 0x0000, 2, ARM_THUMB, do_t_lsr},
+ {"mov", 0x0000, 2, ARM_THUMB, do_t_mov},
+ {"mul", T_OPCODE_MUL, 2, ARM_THUMB, do_t_arit},
+ {"mvn", T_OPCODE_MVN, 2, ARM_THUMB, do_t_arit},
+ {"neg", T_OPCODE_NEG, 2, ARM_THUMB, do_t_arit},
+ {"orr", 0x4300, 2, ARM_THUMB, do_t_arit},
+ {"pop", 0xbc00, 2, ARM_THUMB, do_t_push_pop},
+ {"push", 0xb400, 2, ARM_THUMB, do_t_push_pop},
+ {"ror", 0x41c0, 2, ARM_THUMB, do_t_arit},
+ {"sbc", 0x4180, 2, ARM_THUMB, do_t_arit},
+ {"stmia", 0xc000, 2, ARM_THUMB, do_t_ldmstm},
+ {"str", 0x0000, 2, ARM_THUMB, do_t_str},
+ {"strb", 0x0000, 2, ARM_THUMB, do_t_strb},
+ {"strh", 0x0000, 2, ARM_THUMB, do_t_strh},
+ {"swi", 0xdf00, 2, ARM_THUMB, do_t_swi},
+ {"sub", 0x0000, 2, ARM_THUMB, do_t_sub},
+ {"tst", T_OPCODE_TST, 2, ARM_THUMB, do_t_arit},
/* Pseudo ops: */
- {"adr", 0x0000, 2, do_t_adr},
- {"nop", 0x46C0, 2, do_t_nop}, /* mov r8,r8 */
+ {"adr", 0x0000, 2, ARM_THUMB, do_t_adr},
+ {"nop", 0x46C0, 2, ARM_THUMB, do_t_nop}, /* mov r8,r8 */
};
struct reg_entry
{
- 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:
- pseudo-op name without dot
- function to call to execute this pseudo-op
- Integer arg to pass to the function
- */
+ pseudo-op name without dot
+ function to call to execute this pseudo-op
+ Integer arg to pass to the function. */
static void s_req PARAMS ((int));
static void s_align PARAMS ((int));
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: */
+ /* Check if this literal value is already in the pool: */
while (lit_count < next_literal_pool_place)
{
if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
&& inst.reloc.exp.X_op == O_constant
- && literals[lit_count].exp.X_add_number == inst.reloc.exp.X_add_number
+ && literals[lit_count].exp.X_add_number
+ == inst.reloc.exp.X_add_number
&& literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned)
break;
lit_count++;
}
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 ()
+/* Check that an immediate is valid, and if so,
+ convert it to the right format. */
+static unsigned int
+validate_immediate (val)
+ unsigned int val;
{
- 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;
-
- return symbolP;
+ 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;
}
static void
s_req (a)
- int a;
+ int a ATTRIBUTE_UNUSED;
{
as_bad (_("Invalid syntax for .req directive."));
}
static void
s_bss (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
/* We don't support putting frags in the BSS segment, we fake it by
marking in_bss, then looking at s_skip for clues?.. */
static void
s_even (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
if (!need_pass_2) /* Never make frag if expect extra pass. */
frag_align (1, 0, 0);
+
record_alignment (now_seg, 1);
+
demand_empty_rest_of_line ();
}
static void
-s_ltorg (internal)
- int internal;
+s_ltorg (ignored)
+ int ignored ATTRIBUTE_UNUSED;
{
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
while (lit_count < next_literal_pool_place)
- /* First output the expression in the instruction to the pool */
+ /* First output the expression in the instruction to the pool. */
emit_expr (&(literals[lit_count++].exp), 4); /* .word */
next_literal_pool_place = 0;
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;
+ int unused ATTRIBUTE_UNUSED;
{
register int temp;
register long temp_fill;
static void
s_force_thumb (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
/* If we are not already in thumb mode go into it, EVEN if
the target processor does not support thumb instructions.
if (! thumb_mode)
{
- thumb_mode = 1;
+ thumb_mode = 2;
record_alignment (now_seg, 1);
}
static void
s_thumb_func (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
/* The following label is the name/address of the start of a Thumb function.
We need to know this for the interworking support. */
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)
static void
s_arm (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
opcode_select (32);
demand_empty_rest_of_line ();
static void
s_thumb (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
opcode_select (16);
demand_empty_rest_of_line ();
static void
s_code (unused)
- int unused;
+ int unused ATTRIBUTE_UNUSED;
{
register int temp;
{
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;
return FAIL;
}
+static CONST struct asm_psr *
+arm_psr_parse (ccp)
+ register char ** ccp;
+{
+ char * start = * ccp;
+ char c;
+ char * p;
+ CONST struct asm_psr * psr;
+
+ p = start;
+
+ /* Skip to the end of the next word in the input stream. */
+ do
+ {
+ c = *p++;
+ }
+ while (isalpha (c) || c == '_');
+
+ /* Terminate the word. */
+ *--p = 0;
+
+ /* Now locate the word in the psr hash table. */
+ psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
+
+ /* Restore the input stream. */
+ *p = c;
+
+ /* If we found a valid match, advance the
+ stream pointer past the end of the word. */
+ *ccp = p;
+
+ return psr;
+}
+
+/* Parse the input looking for a PSR flag. */
static int
-psr_required_here (str, cpsr, spsr)
+psr_required_here (str)
char ** str;
- int cpsr;
- int spsr;
{
- int psr;
char * start = *str;
- psr = arm_psr_parse (str);
+ CONST struct asm_psr * psr;
- if (psr == cpsr || psr == spsr)
+ psr = arm_psr_parse (str);
+
+ if (psr)
{
- if (psr == spsr)
- inst.instruction |= 1 << 22;
+ /* If this is the SPSR that is being modified, set the R bit. */
+ if (! psr->cpsr)
+ inst.instruction |= SPSR_BIT;
+
+ /* Set the psr flags in the MSR instruction. */
+ inst.instruction |= psr->field << PSR_SHIFT;
return SUCCESS;
}
- /* In the few cases where we might be able to accept something else
- this error can be overridden */
- inst.error = _("<psr(f)> expected");
+ /* In the few cases where we might be able to accept
+ something else this error can be overridden. */
+ inst.error = _("flag for {c}psr instruction expected");
/* Restore the start point. */
*str = start;
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;
}
- if (skip_past_comma (&str) == FAIL
- || psr_required_here (& str, CPSR_ALL, SPSR_ALL) == FAIL)
+ if (skip_past_comma (&str) == FAIL)
+ {
+ inst.error = _("comma expected after register name");
+ return;
+ }
+
+ skip_whitespace (str);
+
+ if ( strcmp (str, "CPSR") == 0
+ || strcmp (str, "SPSR") == 0
+ /* Lower case versions for backwards compatability. */
+ || strcmp (str, "cpsr") == 0
+ || strcmp (str, "spsr") == 0)
+ str += 4;
+ /* This is for backwards compatability with older toolchains. */
+ else if (strcmp (str, "cpsr_all") == 0
+ || strcmp (str, "spsr_all") == 0)
+ str += 7;
+ else
{
- inst.error = _("<psr> expected");
+ inst.error = _("{C|S}PSR expected");
return;
}
+ if (* str == 's' || * str == 'S')
+ inst.instruction |= SPSR_BIT;
+
inst.instruction |= flags;
end_of_line (str);
- return;
}
-/* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression" */
+/* Two possible forms:
+ "{C|S}PSR_<field>, Rm",
+ "{C|S}PSR_f, #expression". */
static void
do_msr (str, flags)
- char *str;
+ char * str;
unsigned long flags;
{
- int reg;
+ skip_whitespace (str);
+
+ if (psr_required_here (& str) == FAIL)
+ return;
+
+ if (skip_past_comma (& str) == FAIL)
+ {
+ inst.error = _("comma missing after psr flags");
+ return;
+ }
+
+ skip_whitespace (str);
- while (*str == ' ')
- str ++;
+ if (reg_required_here (& str, 0) != FAIL)
+ {
+ inst.error = NULL;
+ inst.instruction |= flags;
+ end_of_line (str);
+ return;
+ }
- if (psr_required_here (&str, CPSR_ALL, SPSR_ALL) == SUCCESS)
+ if (! is_immediate_prefix (* str))
{
- inst.instruction |= PSR_ALL;
+ inst.error = _("only a register or immediate value can follow a psr flag");
+ return;
+ }
- /* Sytax should be "<psr>, Rm" */
- if (skip_past_comma (&str) == FAIL
- || (reg = reg_required_here (&str, 0)) == FAIL)
- {
- inst.error = bad_args;
- return;
- }
+ str ++;
+ inst.error = NULL;
+
+ if (my_get_expression (& inst.reloc.exp, & str))
+ {
+ inst.error = _("only a register or immediate value can follow a psr flag");
+ return;
+ }
+
+ if (inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
+ {
+ inst.error = _("can only set flag field with immediate value");
+ return;
+ }
+
+ flags |= INST_IMMEDIATE;
+
+ if (inst.reloc.exp.X_add_symbol)
+ {
+ inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+ inst.reloc.pc_rel = 0;
}
else
{
- if (psr_required_here (& str, CPSR_FLG, SPSR_FLG) == SUCCESS)
- {
- inst.instruction |= PSR_FLAGS;
- }
- else if (psr_required_here (& str, CPSR_CTL, SPSR_CTL) == SUCCESS)
- {
- inst.instruction |= PSR_CONTROL;
- }
- else
- {
- inst.error = bad_args;
- return;
- }
+ unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
- if (skip_past_comma (&str) == FAIL)
+ if (value == (unsigned) FAIL)
{
- inst.error = bad_args;
+ inst.error = _("Invalid constant");
return;
}
- /* Syntax could be "<psrf>, rm", "<psrf>, #expression" */
-
- if ((reg = reg_required_here (&str, 0)) != FAIL)
- ;
- /* Immediate expression */
- else if (*(str++) == '#')
- {
- inst.error = NULL;
- if (my_get_expression (&inst.reloc.exp, &str))
- {
- inst.error = _("Register or shift expression expected");
- return;
- }
-
- if (inst.reloc.exp.X_add_symbol)
- {
- inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
- inst.reloc.pc_rel = 0;
- }
- else
- {
- unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
- if (value == FAIL)
- {
- inst.error = _("Invalid constant");
- return;
- }
-
- inst.instruction |= value;
- }
-
- flags |= INST_IMMEDIATE;
- }
- else
- {
- inst.error = _("Error: unrecognised syntax for second argument to msr instruction");
- return;
- }
+ inst.instruction |= value;
}
inst.error = NULL;
inst.instruction |= flags;
end_of_line (str);
- return;
}
/* Long Multiply Parser
*/
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;
return FAIL;
}
- if (value == FAIL)
+ if (value == (unsigned) FAIL)
return FAIL;
*instruction &= OPCODE_MASK;
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++;
+ into a relative address of the form "add rd, pc, #label-.-8". */
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL
|| skip_past_comma (&str) == FAIL
|| my_get_expression (&inst.reloc.exp, &str))
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
+
/* Frag hacking will turn this into a sub instruction if the offset turns
out to be negative. */
inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
- inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+ inst.reloc.exp.X_add_number -= 8; /* PC relative adjust. */
inst.reloc.pc_rel = 1;
inst.instruction |= flags;
+
+ end_of_line (str);
+}
+
+static void
+do_adrl (str, flags)
+ char * str;
+ unsigned long flags;
+{
+ /* This is a pseudo-op of the form "adrl rd, label" to be converted
+ into a relative address of the form:
+ add rd, pc, #low(label-.-8)"
+ add rd, rd, #high(label-.-8)" */
+
+ skip_whitespace (str);
+
+ if (reg_required_here (& str, 12) == FAIL
+ || skip_past_comma (& str) == FAIL
+ || my_get_expression (& inst.reloc.exp, & str))
+ {
+ if (!inst.error)
+ inst.error = BAD_ARGS;
+ return;
+ }
+
end_of_line (str);
+
+ /* Frag hacking will turn this into a sub instruction if the offset turns
+ out to be negative. */
+ inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
+ inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+ inst.reloc.pc_rel = 1;
+ inst.instruction |= flags;
+ inst.size = INSN_SIZE * 2;
+
return;
}
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;
}
else
inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+#ifndef TE_WINCE
inst.reloc.exp.X_add_number -= 8; /* PC rel adjust */
+#endif
inst.reloc.pc_rel = 1;
inst.instruction |= (REG_PC << 16);
pre_inc = 1;
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;
- unsigned long flags;
+ char * str;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
if (my_get_expression (&inst.reloc.exp, &str))
return;
- inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
+
+#ifdef OBJ_ELF
+ {
+ char * save_in;
+
+ /* ScottB: February 5, 1998 */
+ /* Check to see of PLT32 reloc required for the instruction. */
+
+ /* arm_parse_reloc() works on input_line_pointer.
+ We actually want to parse the operands to the branch instruction
+ passed in 'str'. Save the input pointer and restore it later. */
+ save_in = input_line_pointer;
+ input_line_pointer = str;
+ if (inst.reloc.exp.X_op == O_symbol
+ && *str == '('
+ && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
+ {
+ inst.reloc.type = BFD_RELOC_ARM_PLT32;
+ inst.reloc.pc_rel = 0;
+ /* Modify str to point to after parsed operands, otherwise
+ end_of_line() will complain about the (PLT) left in str. */
+ str = input_line_pointer;
+ }
+ else
+ {
+ inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
+ inst.reloc.pc_rel = 1;
+ }
+ input_line_pointer = save_in;
+ }
+#else
+ inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
inst.reloc.pc_rel = 1;
+#endif /* OBJ_ELF */
+
end_of_line (str);
return;
}
static void
do_bx (str, flags)
- char *str;
- unsigned long flags;
+ char * str;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
int reg;
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if ((reg = reg_required_here (&str, 0)) == FAIL)
- return;
+ {
+ inst.error = BAD_ARGS;
+ return;
+ }
if (reg == REG_PC)
- as_tsktsk (_("Use of r15 in bx has undefined behaviour"));
+ inst.error = BAD_PC;
end_of_line (str);
- return;
}
static void
do_cdp (str, flags)
- char *str;
- unsigned long flags;
+ char * str;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
/* Co-processor data operation.
Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (co_proc_number (&str) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
|| 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;
- unsigned long flags;
+ char * str;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
/* FP control registers.
Format: <WFS|RFS|WFC|RFC>{cond} Rn */
- while (*str == ' ')
- str++;
+ skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL)
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
static void
do_fp_ldst (str, flags)
- char *str;
- unsigned long flags;
+ char * str;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
- 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))
}
}
}
+
end_of_line (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;
- str++;
+ str ++;
if (my_get_expression (&inst.reloc.exp, &str))
return;
}
Rn = Rs;
Rs = Rd;
}
- else if (*str == '#')
+ else if (is_immediate_prefix (*str))
{
str++;
if (my_get_expression (&inst.reloc.exp, &str))
inst.instruction |= Rd | (Rs << 3);
}
+
end_of_line (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;
{
+ int reg;
+
/* This is a pseudo-op of the form "adr rd, label" to be converted
- into a relative address of the form "add rd, pc, #label-.-4" */
- while (*str == ' ')
- str++;
+ into a relative address of the form "add rd, pc, #label-.-4". */
+ skip_whitespace (str);
- if (reg_required_here (&str, 4) == FAIL /* Store Rd in temporary location inside instruction. */
+ /* Store Rd in temporary location inside instruction. */
+ if ((reg = reg_required_here (&str, 4)) == FAIL
+ || (reg > 7) /* For Thumb reg must be r0..r7. */
|| skip_past_comma (&str) == FAIL
|| my_get_expression (&inst.reloc.exp, &str))
{
if (!inst.error)
- inst.error = bad_args;
+ inst.error = BAD_ARGS;
return;
}
inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
- inst.reloc.exp.X_add_number -= 4; /* PC relative adjust */
+ inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */
inst.reloc.pc_rel = 1;
- inst.instruction |= REG_PC; /* Rd is already placed into the instruction */
+ inst.instruction |= REG_PC; /* Rd is already placed into the instruction. */
+
end_of_line (str);
}
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;
void
md_begin ()
{
- int i;
+ unsigned mach;
+ unsigned 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
{
unsigned int flags = 0;
- /* Set the flags in the private structure */
+ /* Set the flags in the private structure. */
if (uses_apcs_26) flags |= F_APCS26;
if (support_interwork) flags |= F_INTERWORK;
if (uses_apcs_float) flags |= F_APCS_FLOAT;
if (pic_code) flags |= F_PIC;
+ if ((cpu_variant & FPU_ALL) == FPU_NONE) flags |= F_SOFT_FLOAT;
bfd_set_private_flags (stdoutput, flags);
}
#endif
- {
- unsigned mach;
-
- /* Record the CPU type as well */
- switch (cpu_variant & ARM_CPU_MASK)
- {
- case ARM_2:
- mach = bfd_mach_arm_2;
- break;
-
- case ARM_3: /* also ARM_250 */
- mach = bfd_mach_arm_2a;
- break;
-
- default:
- case ARM_6 | ARM_3 | ARM_2: /* Actually no CPU type defined */
+ /* Record the CPU type as well. */
+ switch (cpu_variant & ARM_CPU_MASK)
+ {
+ case ARM_2:
+ mach = bfd_mach_arm_2;
+ break;
+
+ case ARM_3: /* Also ARM_250. */
+ mach = bfd_mach_arm_2a;
+ break;
+
+ default:
+ case ARM_6 | ARM_3 | ARM_2: /* Actually no CPU type defined. */
+ mach = bfd_mach_arm_4;
+ break;
+
+ case ARM_7: /* Also ARM_6. */
+ mach = bfd_mach_arm_3;
+ break;
+ }
+
+ /* Catch special cases. */
+ if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
+ {
+ if (cpu_variant & (ARM_EXT_V5 & ARM_THUMB))
+ mach = bfd_mach_arm_5T;
+ else if (cpu_variant & ARM_EXT_V5)
+ mach = bfd_mach_arm_5;
+ else if (cpu_variant & ARM_THUMB)
+ mach = bfd_mach_arm_4T;
+ else if ((cpu_variant & ARM_ARCH_V4) == ARM_ARCH_V4)
mach = bfd_mach_arm_4;
- break;
-
- case ARM_7: /* also ARM_6 */
- mach = bfd_mach_arm_3;
- break;
- }
-
- /* Catch special cases */
- if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
- {
- if (cpu_variant & ARM_THUMB)
- mach = bfd_mach_arm_4T;
- else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4)
- mach = bfd_mach_arm_4;
- else if (cpu_variant & ARM_LONGMUL)
- mach = bfd_mach_arm_3M;
- }
-
- bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
- }
+ else if (cpu_variant & ARM_LONGMUL)
+ mach = bfd_mach_arm_3M;
+ }
+
+ bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
}
/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
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;
}
+#ifdef TE_WINCE
+ /* The pattern was adjusted to accomodate CE's off-by-one fixups,
+ so we un-adjust here to compensate for the accomodation. */
+ return fixP->fx_where + fixP->fx_frag->fr_address + 8;
+#else
return fixP->fx_where + fixP->fx_frag->fr_address;
+#endif
}
/* Round up a section size to the appropriate boundary. */
valueT
md_section_align (segment, size)
- segT segment;
+ segT segment ATTRIBUTE_UNUSED;
valueT size;
{
-/* 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 ATTRIBUTE_UNUSED;
{
- return 0;
-}
+#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;
+}
/* arm_reg_parse () := if it looks like a register, return its token and
advance the pointer. */
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)
return FAIL;
}
-static int
-arm_psr_parse (ccp)
- register char **ccp;
-{
- char *start = *ccp;
- char c, *p;
- CONST struct asm_psr *psr;
-
- p = start;
- c = *p++;
- while (isalpha (c) || c == '_')
- c = *p++;
-
- *--p = 0;
- psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
- *p = c;
-
- if (psr)
- {
- *ccp = p;
- return psr->number;
- }
-
- return FAIL;
-}
-
int
md_apply_fix3 (fixP, val, seg)
- fixS *fixP;
- 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
+ || fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
+ ))
value = 0;
else
value += md_pcrel_from (fixP);
}
}
- fixP->fx_addnumber = value; /* Remember value for emit_reloc */
+ fixP->fx_addnumber = value; /* Remember value for emit_reloc. */
switch (fixP->fx_r_type)
{
&& (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;
- newval = value | (newval & 0xff000000);
+
+ /* Sign-extend a 24-bit number. */
+#define SEXT24(x) ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
+
+#ifdef OBJ_ELF
+ if (! target_oabi)
+ value = fixP->fx_offset;
+#endif
+
+ /* We are going to store value (shifted right by two) in the
+ instruction, in a 24 bit, signed field. Thus we need to check
+ that none of the top 8 bits of the shifted value (top 7 bits of
+ the unshifted, unsigned value) are set, or that they are all set. */
+ if ((value & ~ ((offsetT) 0x1ffffff)) != 0
+ && ((value & ~ ((offsetT) 0x1ffffff)) != ~ ((offsetT) 0x1ffffff)))
+ {
+#ifdef OBJ_ELF
+ /* Normally we would be stuck at this point, since we cannot store
+ the absolute address that is the destination of the branch in the
+ 24 bits of the branch instruction. If however, we happen to know
+ that the destination of the branch is in the same section as the
+ branch instruciton itself, then we can compute the relocation for
+ ourselves and not have to bother the linker with it.
+
+ FIXME: The tests for OBJ_ELF and ! target_oabi are only here
+ because I have not worked out how to do this for OBJ_COFF or
+ target_oabi. */
+ if (! target_oabi
+ && fixP->fx_addsy != NULL
+ && S_IS_DEFINED (fixP->fx_addsy)
+ && S_GET_SEGMENT (fixP->fx_addsy) == seg)
+ {
+ /* Get pc relative value to go into the branch. */
+ value = * val;
+
+ /* Permit a backward branch provided that enough bits are set.
+ Allow a forwards branch, provided that enough bits are clear. */
+ if ((value & ~ ((offsetT) 0x1ffffff)) == ~ ((offsetT) 0x1ffffff)
+ || (value & ~ ((offsetT) 0x1ffffff)) == 0)
+ fixP->fx_done = 1;
+ }
+
+ if (! fixP->fx_done)
+#endif
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("gas can't handle same-section branch dest >= 0x04000000"));
+ }
+
+ value >>= 2;
+ value += SEXT24 (newval);
+
+ if ((value & ~ ((offsetT) 0xffffff)) != 0
+ && ((value & ~ ((offsetT) 0xffffff)) != ~ ((offsetT) 0xffffff)))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("out of range branch"));
+
+ newval = (value & 0x00ffffff) | (newval & 0xff000000);
md_number_to_chars (buf, newval, INSN_SIZE);
break;
+ case BFD_RELOC_ARM_PCREL_BLX:
+ {
+ offsetT hbit;
+ newval = md_chars_to_number (buf, INSN_SIZE);
+
+#ifdef OBJ_ELF
+ if (! target_oabi)
+ value = fixP->fx_offset;
+#endif
+ hbit = (value >> 1) & 1;
+ value = (value >> 2) & 0x00ffffff;
+ value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
+ newval = value | (newval & 0xfe000000) | (hbit << 24);
+ md_number_to_chars (buf, newval, INSN_SIZE);
+ }
+ break;
+
case BFD_RELOC_THUMB_PCREL_BRANCH9: /* conditional branch */
newval = md_chars_to_number (buf, THUMB_SIZE);
{
md_number_to_chars (buf, newval, THUMB_SIZE);
break;
+ case BFD_RELOC_THUMB_PCREL_BLX:
case BFD_RELOC_THUMB_PCREL_BRANCH23:
{
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 ATTRIBUTE_UNUSED;
+ 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_ARM_PCREL_BRANCH:
+ case BFD_RELOC_ARM_PCREL_BLX:
case BFD_RELOC_RVA:
case BFD_RELOC_THUMB_PCREL_BRANCH9:
case BFD_RELOC_THUMB_PCREL_BRANCH12:
case BFD_RELOC_THUMB_PCREL_BRANCH23:
+ case BFD_RELOC_THUMB_PCREL_BLX:
+ case BFD_RELOC_VTABLE_ENTRY:
+ case BFD_RELOC_VTABLE_INHERIT:
code = fixp->fx_r_type;
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 ATTRIBUTE_UNUSED;
+ segT segtype ATTRIBUTE_UNUSED;
{
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--)
{
c = *q;
*q = '\0';
+
opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
*q = c;
+
if (opcode && opcode->template)
{
unsigned long flag_bits = 0;
- char *r;
+ char * r;
- /* Check that this instruction is supported for this CPU */
+ /* Check that this instruction is supported for this CPU. */
if ((opcode->variants & cpu_variant) == 0)
goto try_shorter;
inst.instruction = opcode->value;
- if (q == p) /* Just a simple opcode */
+ if (q == p) /* Just a simple opcode. */
{
- if (opcode->comp_suffix != 0)
- as_bad (_("Opcode `%s' must have suffix from <%s>\n"), str,
- opcode->comp_suffix);
+ if (opcode->comp_suffix)
+ {
+ if (*opcode->comp_suffix != '\0')
+ as_bad (_("Opcode `%s' must have suffix from list: <%s>"),
+ str, opcode->comp_suffix);
+ else
+ /* Not a conditional instruction. */
+ (*opcode->parms)(q, 0);
+ }
else
{
+ /* A conditional instruction with default condition. */
inst.instruction |= COND_ALWAYS;
(*opcode->parms)(q, 0);
}
- output_inst (start);
+ output_inst ();
return;
}
- /* Now check for a conditional */
+ /* Not just a simple opcode. Check if extra is a conditional. */
r = q;
if (p - r >= 2)
{
as_tsktsk (
_("Warning: Use of the 'nv' conditional is deprecated\n"));
- inst.instruction |= cond->value;
+ cond_code = cond->value;
r += 2;
}
else
- inst.instruction |= COND_ALWAYS;
+ cond_code = COND_ALWAYS;
}
else
- inst.instruction |= COND_ALWAYS;
+ cond_code = COND_ALWAYS;
- /* if there is a compulsory suffix, it should come here, before
- any optional flags. */
- if (opcode->comp_suffix)
+ /* Apply the conditional, or complain it's not allowed. */
+ if (opcode->comp_suffix && *opcode->comp_suffix == '\0')
+ {
+ /* Instruction isn't conditional */
+ if (cond_code != COND_ALWAYS)
+ {
+ as_bad (_("Opcode `%s' is unconditional\n"), str);
+ return;
+ }
+ }
+ else
+ /* Instruction is conditional: set the condition into it. */
+ inst.instruction |= cond_code;
+
+
+ /* If there is a compulsory suffix, it should come here, before
+ any optional flags. */
+ if (opcode->comp_suffix && *opcode->comp_suffix != '\0')
{
CONST char *s = opcode->comp_suffix;
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 );
+ 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[t]] 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 */
+ /* Select variant based on architecture rather than processor. */
switch (*++str)
{
case '2':
switch (*++str)
{
- case 'a': cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3; break;
- case 0: cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2; break;
- default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ case 'a':
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3;
+ break;
+ case 0:
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2;
+ break;
+ default:
+ as_bad (_("Invalid architecture variant -m%s"), arg);
+ break;
}
break;
{
case 'm': cpu_variant |= ARM_LONGMUL; break;
case 0: break;
- default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ default:
+ as_bad (_("Invalid architecture variant -m%s"), arg);
+ break;
}
break;
case '4':
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCHv4;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4;
switch (*++str)
{
case 't': cpu_variant |= ARM_THUMB; break;
case 0: break;
- default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ default:
+ as_bad (_("Invalid architecture variant -m%s"), arg);
+ break;
+ }
+ break;
+
+ case '5':
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V5;
+ switch (*++str)
+ {
+ case 't': cpu_variant |= ARM_THUMB; break;
+ case 0: break;
+ default:
+ as_bad (_("Invalid architecture variant -m%s"), arg);
+ break;
}
break;
}
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,
-_("\
+ 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"));
+ -mno-fpu don't allow any floating-point instructions.\n\
+ -k generate PIC code.\n"));
#if defined OBJ_COFF || defined OBJ_ELF
- fprintf (fp,
-_("\
- -mapcs-32, -mapcs-26 specify which ARM Procedure Calling Standard to use\n"));
- fprintf (fp,
-_("\
- -mapcs-float floating point args are passed in FP regs\n"));
- fprintf (fp,
-_("\
+ fprintf (fp, _("\
+ -mapcs-32, -mapcs-26 specify which ARM Procedure Calling Standard to use\n\
+ -mapcs-float floating point args are passed in FP regs\n\
-mapcs-reentrant the code is position independent/reentrant\n"));
+ #endif
+#ifdef OBJ_ELF
+ fprintf (fp, _("\
+ -moabi support the old ELF ABI\n"));
#endif
#ifdef ARM_BI_ENDIAN
- fprintf (fp,
-_("\
+ fprintf (fp, _("\
-EB assemble code for a big endian cpu\n\
-EL assemble code for a little endian cpu\n"));
#endif
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;
+ char bind;
for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
{
- if (ARM_IS_THUMB (sym) && (THUMB_IS_FUNC (sym)))
- {
+ if (ARM_IS_THUMB (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);
- 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);
+ elf_sym = elf_symbol (symbol_get_bfdsym (sym));
+ bind = ELF_ST_BIND (elf_sym);
+
+ /* If it's a .thumb_func, declare it as so,
+ otherwise tag label as .code 16. */
+ if (THUMB_IS_FUNC (sym))
+ elf_sym->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_ARM_PCREL_BLX
+ || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
+ || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
+ return 1;
+
+ return 0;
+}
+
+static bfd_reloc_code_real_type
+arm_parse_reloc ()
+{
+ char id[16];
+ char * ip;
+ unsigned 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 */