X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=19ead2e3b7337f36ab59a1256f261345508ea4b9;hb=fa3061313cf6689dc5c4df66d29fe56209c689e0;hp=8739c26cbc56fa5554f2033709537419f1e8b863;hpb=38a29f02756ac516da522855f9c6b0169e30e53b;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 8739c26cbc..19ead2e3b7 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1,5 +1,5 @@ /* tc-arm.c -- Assemble for the ARM - Copyright (C) 1994, 95, 96, 97, 1998 Free Software Foundation, Inc. + Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modified by David Taylor (dtaylor@armltd.co.uk) @@ -36,14 +36,6 @@ #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 @@ -51,18 +43,26 @@ #define ARM_250 ARM_3 #define ARM_6 0x00000008 #define ARM_7 ARM_6 /* same core instruction set */ +#define ARM_8 ARM_6 /* same core instruction set */ +#define ARM_9 ARM_6 /* same core instruction set */ #define ARM_CPU_MASK 0x0000000f /* The following bitmasks control CPU extensions (ARM7 onwards): */ #define ARM_LONGMUL 0x00000010 /* allow long multiplies */ #define ARM_HALFWORD 0x00000020 /* allow half word loads */ #define ARM_THUMB 0x00000040 /* allow BX instruction */ +#define ARM_EXT_V5 0x00000080 /* allow CLZ etc */ +#define ARM_EXT_V5E 0x00000200 /* "El Segundo" */ -#define ARM_ARCHv4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD) +/* Architectures are the sum of the base and extensions */ +#define ARM_ARCH_V4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD) +#define ARM_ARCH_V4T (ARM_ARCH_V4 | ARM_THUMB) +#define ARM_ARCH_V5 (ARM_ARCH_V4 | ARM_EXT_V5) +#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_THUMB) /* Some useful combinations: */ #define ARM_ANY 0x00ffffff -#define ARM_2UP 0x00fffffe +#define ARM_2UP (ARM_ANY - ARM_1) #define ARM_ALL ARM_2UP /* Not arm1 only */ #define ARM_3UP 0x00fffffc #define ARM_6UP 0x00fffff8 /* Includes ARM7 */ @@ -79,7 +79,7 @@ #ifndef CPU_DEFAULT #if defined __thumb__ -#define CPU_DEFAULT (ARM_ARCHv4 | ARM_THUMB) +#define CPU_DEFAULT (ARM_ARCH_V4 | ARM_THUMB) #else #define CPU_DEFAULT ARM_ALL #endif @@ -89,7 +89,11 @@ #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 */ @@ -112,7 +116,11 @@ CONST char comment_chars[] = "@"; /* Also note that comments like this one will always work. */ CONST char line_comment_chars[] = "#"; +#ifdef TE_LINUX +CONST char line_separator_chars[] = ";"; +#else CONST char line_separator_chars[] = ""; +#endif /* Chars that can be used to separate mant from exp in floating point nums */ CONST char EXP_CHARS[] = "eE"; @@ -123,10 +131,19 @@ CONST char EXP_CHARS[] = "eE"; CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP"; -CONST int md_reloc_size = 8; /* Size of relocation record */ +/* Prefix characters that indicate the start of an immediate + value. */ +#define is_immediate_prefix(C) ((C) == '#' || (C) == '$') + +#ifdef OBJ_ELF +symbolS * GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ +#endif -static int thumb_mode = 0; /* non-zero if assembling thumb instructions */ +CONST int md_reloc_size = 8; /* Size of relocation record */ +static int thumb_mode = 0; /* 0: assemble for ARM, 1: assemble for Thumb, + 2: assemble for Thumb even though target cpu + does not support thumb instructions */ typedef struct arm_fix { int thumb_mode; @@ -134,15 +151,15 @@ typedef struct arm_fix 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; }; @@ -150,7 +167,7 @@ struct arm_it inst; struct asm_shift { - CONST char *template; + CONST char * template; unsigned long value; }; @@ -175,7 +192,7 @@ static CONST struct asm_shift shift[] = #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 }; @@ -205,7 +222,7 @@ LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS]; struct asm_cond { - CONST char *template; + CONST char * template; unsigned long value; }; @@ -237,7 +254,7 @@ static CONST struct asm_cond conds[] = 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 */ }; @@ -363,7 +380,7 @@ static CONST struct asm_flg cplong_flag[] = struct asm_psr { - CONST char *template; + CONST char * template; unsigned long number; }; @@ -401,52 +418,52 @@ static CONST struct asm_psr psrs[] = /* Functions called by parser */ /* ARM instructions */ -static void do_arit PARAMS ((char *operands, unsigned long flags)); -static void do_cmp PARAMS ((char *operands, unsigned long flags)); -static void do_mov PARAMS ((char *operands, unsigned long flags)); -static void do_ldst PARAMS ((char *operands, unsigned long flags)); -static void do_ldmstm PARAMS ((char *operands, unsigned long flags)); -static void do_branch PARAMS ((char *operands, unsigned long flags)); -static void do_swi PARAMS ((char *operands, unsigned long flags)); -/* Pseudo Op codes */ -static void do_adr PARAMS ((char *operands, unsigned long flags)); -static void do_nop PARAMS ((char *operands, unsigned long flags)); -/* ARM 2 */ -static void do_mul PARAMS ((char *operands, unsigned long flags)); -static void do_mla PARAMS ((char *operands, unsigned long flags)); -/* ARM 3 */ -static void do_swap PARAMS ((char *operands, unsigned long flags)); -/* ARM 6 */ -static void do_msr PARAMS ((char *operands, unsigned long flags)); -static void do_mrs PARAMS ((char *operands, unsigned long flags)); -/* ARM 7M */ -static void do_mull PARAMS ((char *operands, unsigned long flags)); -/* ARM THUMB */ -static void do_bx PARAMS ((char *operands, unsigned long flags)); - -/* Coprocessor Instructions */ -static void do_cdp PARAMS ((char *operands, unsigned long flags)); -static void do_lstc PARAMS ((char *operands, unsigned long flags)); -static void do_co_reg PARAMS ((char *operands, unsigned long flags)); -static void do_fp_ctrl PARAMS ((char *operands, unsigned long flags)); -static void do_fp_ldst PARAMS ((char *operands, unsigned long flags)); -static void do_fp_ldmstm PARAMS ((char *operands, unsigned long flags)); -static void do_fp_dyadic PARAMS ((char *operands, unsigned long flags)); -static void do_fp_monadic PARAMS ((char *operands, unsigned long flags)); -static void do_fp_cmp PARAMS ((char *operands, unsigned long flags)); -static void do_fp_from_reg PARAMS ((char *operands, unsigned long flags)); -static void do_fp_to_reg PARAMS ((char *operands, unsigned long flags)); - -static void fix_new_arm PARAMS ((fragS *frag, int where, - short int size, expressionS *exp, - int pc_rel, int reloc)); -static int arm_reg_parse PARAMS ((char **ccp)); -static int arm_psr_parse PARAMS ((char **ccp)); -static void symbol_locate PARAMS ((symbolS *, CONST char *, segT, - valueT, fragS *)); +static void do_arit PARAMS ((char *, unsigned long)); +static void do_cmp PARAMS ((char *, unsigned long)); +static void do_mov PARAMS ((char *, unsigned long)); +static void do_ldst PARAMS ((char *, unsigned long)); +static void do_ldmstm PARAMS ((char *, unsigned long)); +static void do_branch PARAMS ((char *, unsigned long)); +static void do_swi PARAMS ((char *, unsigned long)); +/* Pseudo Op codes */ +static void do_adr PARAMS ((char *, unsigned long)); +static void do_adrl PARAMS ((char *, unsigned long)); +static void do_nop PARAMS ((char *, unsigned long)); +/* ARM 2 */ +static void do_mul PARAMS ((char *, unsigned long)); +static void do_mla PARAMS ((char *, unsigned long)); +/* ARM 3 */ +static void do_swap PARAMS ((char *, unsigned long)); +/* ARM 6 */ +static void do_msr PARAMS ((char *, unsigned long)); +static void do_mrs PARAMS ((char *, unsigned long)); +/* ARM 7M */ +static void do_mull PARAMS ((char *, unsigned long)); +/* ARM THUMB */ +static void do_bx PARAMS ((char *, unsigned long)); + + +/* Coprocessor Instructions */ +static void do_cdp PARAMS ((char *, unsigned long)); +static void do_lstc PARAMS ((char *, unsigned long)); +static void do_co_reg PARAMS ((char *, unsigned long)); +static void do_fp_ctrl PARAMS ((char *, unsigned long)); +static void do_fp_ldst PARAMS ((char *, unsigned long)); +static void do_fp_ldmstm PARAMS ((char *, unsigned long)); +static void do_fp_dyadic PARAMS ((char *, unsigned long)); +static void do_fp_monadic PARAMS ((char *, unsigned long)); +static void do_fp_cmp PARAMS ((char *, unsigned long)); +static void do_fp_from_reg PARAMS ((char *, unsigned long)); +static void do_fp_to_reg PARAMS ((char *, unsigned long)); + +static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *, int, int)); +static int arm_reg_parse PARAMS ((char **)); +static int arm_psr_parse PARAMS ((char **)); +static void symbol_locate PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *)); static int add_to_lit_pool PARAMS ((void)); -static unsigned validate_immediate PARAMS ((unsigned)); -static int validate_offset_imm PARAMS ((int, int)); +static unsigned validate_immediate PARAMS ((unsigned)); +static unsigned validate_immediate_twopart PARAMS ((unsigned int, unsigned int *)); +static int validate_offset_imm PARAMS ((unsigned int, int)); static void opcode_select PARAMS ((int)); static void end_of_line PARAMS ((char *)); static int reg_required_here PARAMS ((char **, int)); @@ -460,8 +477,7 @@ static int cp_address_required_here PARAMS ((char **)); static int my_get_float_expression PARAMS ((char **)); static int skip_past_comma PARAMS ((char **)); static int walk_no_bignums PARAMS ((symbolS *)); -static int negate_data_op PARAMS ((unsigned long *, - unsigned long)); +static int negate_data_op PARAMS ((unsigned long *, unsigned long)); static int data_op2 PARAMS ((char **)); static int fp_op2 PARAMS ((char **)); static long reg_list PARAMS ((char **)); @@ -475,7 +491,10 @@ static void thumb_mov_compare PARAMS ((char *, int)); static void set_constant_flonums PARAMS ((void)); static valueT md_chars_to_number PARAMS ((char *, int)); static void insert_reg_alias PARAMS ((char *, int)); -static void output_inst PARAMS ((char *)); +static void output_inst PARAMS ((void)); +#ifdef OBJ_ELF +static bfd_reloc_code_real_type arm_parse_reloc PARAMS ((void)); +#endif /* ARM instructions take 4bytes in the object file, Thumb instructions take 2: */ @@ -488,15 +507,20 @@ static void output_inst PARAMS ((char *)); #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[] = @@ -528,6 +552,7 @@ static CONST struct asm_opcode insns[] = /* Pseudo ops */ {"adr", 0x028f0000, NULL, NULL, ARM_ANY, do_adr}, + {"adrl", 0x028f0000, NULL, NULL, ARM_ANY, do_adrl}, {"nop", 0x01a00000, NULL, NULL, ARM_ANY, do_nop}, /* ARM 2 multiplies */ @@ -540,6 +565,9 @@ static CONST struct asm_opcode insns[] = /* ARM 6 Coprocessor instructions */ {"mrs", 0x010f0000, NULL, NULL, ARM_6UP, do_mrs}, {"msr", 0x0120f000, NULL, NULL, ARM_6UP, do_msr}, +/* ScottB: our code uses 0x0128f000 for msr. + NickC: but this is wrong because the bits 16 and 19 are handled + by the PSR_xxx defines above. */ /* ARM 7M long multiplies - need signed/unsigned flags! */ {"smull", 0x00c00090, NULL, s_flag, ARM_LONGMUL, do_mull}, @@ -615,7 +643,7 @@ static CONST struct asm_opcode insns[] = #define PRE_INDEX 0x01000000 #define INDEX_UP 0x00800000 #define WRITE_BACK 0x00200000 -#define MULTI_SET_PSR 0x00400000 +#define LDM_TYPE_2_OR_3 0x00400000 #define LITERAL_MASK 0xf000f000 #define COND_MASK 0xf0000000 @@ -641,30 +669,30 @@ static CONST struct asm_opcode insns[] = #define OPCODE_BIC 14 #define OPCODE_MVN 15 -static void do_t_nop PARAMS ((char *operands)); -static void do_t_arit PARAMS ((char *operands)); -static void do_t_add PARAMS ((char *operands)); -static void do_t_asr PARAMS ((char *operands)); -static void do_t_branch9 PARAMS ((char *operands)); -static void do_t_branch12 PARAMS ((char *operands)); -static void do_t_branch23 PARAMS ((char *operands)); -static void do_t_bx PARAMS ((char *operands)); -static void do_t_compare PARAMS ((char *operands)); -static void do_t_ldmstm PARAMS ((char *operands)); -static void do_t_ldr PARAMS ((char *operands)); -static void do_t_ldrb PARAMS ((char *operands)); -static void do_t_ldrh PARAMS ((char *operands)); -static void do_t_lds PARAMS ((char *operands)); -static void do_t_lsl PARAMS ((char *operands)); -static void do_t_lsr PARAMS ((char *operands)); -static void do_t_mov PARAMS ((char *operands)); -static void do_t_push_pop PARAMS ((char *operands)); -static void do_t_str PARAMS ((char *operands)); -static void do_t_strb PARAMS ((char *operands)); -static void do_t_strh PARAMS ((char *operands)); -static void do_t_sub PARAMS ((char *operands)); -static void do_t_swi PARAMS ((char *operands)); -static void do_t_adr PARAMS ((char *operands)); +static void do_t_nop PARAMS ((char *)); +static void do_t_arit PARAMS ((char *)); +static void do_t_add PARAMS ((char *)); +static void do_t_asr PARAMS ((char *)); +static void do_t_branch9 PARAMS ((char *)); +static void do_t_branch12 PARAMS ((char *)); +static void do_t_branch23 PARAMS ((char *)); +static void do_t_bx PARAMS ((char *)); +static void do_t_compare PARAMS ((char *)); +static void do_t_ldmstm PARAMS ((char *)); +static void do_t_ldr PARAMS ((char *)); +static void do_t_ldrb PARAMS ((char *)); +static void do_t_ldrh PARAMS ((char *)); +static void do_t_lds PARAMS ((char *)); +static void do_t_lsl PARAMS ((char *)); +static void do_t_lsr PARAMS ((char *)); +static void do_t_mov PARAMS ((char *)); +static void do_t_push_pop PARAMS ((char *)); +static void do_t_str PARAMS ((char *)); +static void do_t_strb PARAMS ((char *)); +static void do_t_strh PARAMS ((char *)); +static void do_t_sub PARAMS ((char *)); +static void do_t_swi PARAMS ((char *)); +static void do_t_adr PARAMS ((char *)); #define T_OPCODE_MUL 0x4340 #define T_OPCODE_TST 0x4200 @@ -718,7 +746,7 @@ static void do_t_adr PARAMS ((char *operands)); #define T_OPCODE_BRANCH 0xe7fe -static int thumb_reg PARAMS ((char **str, int hi_lo)); +static int thumb_reg PARAMS ((char ** str, int hi_lo)); #define THUMB_SIZE 2 /* Size of thumb instruction */ #define THUMB_REG_LO 0x1 @@ -747,78 +775,78 @@ static int thumb_reg PARAMS ((char **str, int hi_lo)); struct thumb_opcode { - CONST char *template; /* Basic string to match */ + CONST char * template; /* Basic string to match */ unsigned long value; /* Basic instruction code */ - int size; - /* Function to call to parse args */ - void (*parms) PARAMS ((char *)); + int size; + unsigned long variants; /* Which CPU variants this exists for */ + void (* parms) PARAMS ((char *)); /* Function to call to parse args */ }; static CONST struct thumb_opcode tinsns[] = { - {"adc", 0x4140, 2, do_t_arit}, - {"add", 0x0000, 2, do_t_add}, - {"and", 0x4000, 2, do_t_arit}, - {"asr", 0x0000, 2, do_t_asr}, - {"b", T_OPCODE_BRANCH, 2, do_t_branch12}, - {"beq", 0xd0fe, 2, do_t_branch9}, - {"bne", 0xd1fe, 2, do_t_branch9}, - {"bcs", 0xd2fe, 2, do_t_branch9}, - {"bhs", 0xd2fe, 2, do_t_branch9}, - {"bcc", 0xd3fe, 2, do_t_branch9}, - {"bul", 0xd3fe, 2, do_t_branch9}, - {"blo", 0xd3fe, 2, do_t_branch9}, - {"bmi", 0xd4fe, 2, do_t_branch9}, - {"bpl", 0xd5fe, 2, do_t_branch9}, - {"bvs", 0xd6fe, 2, do_t_branch9}, - {"bvc", 0xd7fe, 2, do_t_branch9}, - {"bhi", 0xd8fe, 2, do_t_branch9}, - {"bls", 0xd9fe, 2, do_t_branch9}, - {"bge", 0xdafe, 2, do_t_branch9}, - {"blt", 0xdbfe, 2, do_t_branch9}, - {"bgt", 0xdcfe, 2, do_t_branch9}, - {"ble", 0xddfe, 2, do_t_branch9}, - {"bic", 0x4380, 2, do_t_arit}, - {"bl", 0xf7fffffe, 4, do_t_branch23}, - {"bx", 0x4700, 2, do_t_bx}, - {"cmn", T_OPCODE_CMN, 2, do_t_arit}, - {"cmp", 0x0000, 2, do_t_compare}, - {"eor", 0x4040, 2, do_t_arit}, - {"ldmia", 0xc800, 2, do_t_ldmstm}, - {"ldr", 0x0000, 2, do_t_ldr}, - {"ldrb", 0x0000, 2, do_t_ldrb}, - {"ldrh", 0x0000, 2, do_t_ldrh}, - {"ldrsb", 0x5600, 2, do_t_lds}, - {"ldrsh", 0x5e00, 2, do_t_lds}, - {"ldsb", 0x5600, 2, do_t_lds}, - {"ldsh", 0x5e00, 2, do_t_lds}, - {"lsl", 0x0000, 2, do_t_lsl}, - {"lsr", 0x0000, 2, do_t_lsr}, - {"mov", 0x0000, 2, do_t_mov}, - {"mul", T_OPCODE_MUL, 2, do_t_arit}, - {"mvn", T_OPCODE_MVN, 2, do_t_arit}, - {"neg", T_OPCODE_NEG, 2, do_t_arit}, - {"orr", 0x4300, 2, do_t_arit}, - {"pop", 0xbc00, 2, do_t_push_pop}, - {"push", 0xb400, 2, do_t_push_pop}, - {"ror", 0x41c0, 2, do_t_arit}, - {"sbc", 0x4180, 2, do_t_arit}, - {"stmia", 0xc000, 2, do_t_ldmstm}, - {"str", 0x0000, 2, do_t_str}, - {"strb", 0x0000, 2, do_t_strb}, - {"strh", 0x0000, 2, do_t_strh}, - {"swi", 0xdf00, 2, do_t_swi}, - {"sub", 0x0000, 2, do_t_sub}, - {"tst", T_OPCODE_TST, 2, do_t_arit}, + {"adc", 0x4140, 2, ARM_THUMB, do_t_arit}, + {"add", 0x0000, 2, ARM_THUMB, do_t_add}, + {"and", 0x4000, 2, ARM_THUMB, do_t_arit}, + {"asr", 0x0000, 2, ARM_THUMB, do_t_asr}, + {"b", T_OPCODE_BRANCH, 2, ARM_THUMB, do_t_branch12}, + {"beq", 0xd0fe, 2, ARM_THUMB, do_t_branch9}, + {"bne", 0xd1fe, 2, ARM_THUMB, do_t_branch9}, + {"bcs", 0xd2fe, 2, ARM_THUMB, do_t_branch9}, + {"bhs", 0xd2fe, 2, ARM_THUMB, do_t_branch9}, + {"bcc", 0xd3fe, 2, ARM_THUMB, do_t_branch9}, + {"bul", 0xd3fe, 2, ARM_THUMB, do_t_branch9}, + {"blo", 0xd3fe, 2, ARM_THUMB, do_t_branch9}, + {"bmi", 0xd4fe, 2, ARM_THUMB, do_t_branch9}, + {"bpl", 0xd5fe, 2, ARM_THUMB, do_t_branch9}, + {"bvs", 0xd6fe, 2, ARM_THUMB, do_t_branch9}, + {"bvc", 0xd7fe, 2, ARM_THUMB, do_t_branch9}, + {"bhi", 0xd8fe, 2, ARM_THUMB, do_t_branch9}, + {"bls", 0xd9fe, 2, ARM_THUMB, do_t_branch9}, + {"bge", 0xdafe, 2, ARM_THUMB, do_t_branch9}, + {"blt", 0xdbfe, 2, ARM_THUMB, do_t_branch9}, + {"bgt", 0xdcfe, 2, ARM_THUMB, do_t_branch9}, + {"ble", 0xddfe, 2, ARM_THUMB, do_t_branch9}, + {"bic", 0x4380, 2, ARM_THUMB, do_t_arit}, + {"bl", 0xf7fffffe, 4, ARM_THUMB, do_t_branch23}, + {"bx", 0x4700, 2, ARM_THUMB, do_t_bx}, + {"cmn", T_OPCODE_CMN, 2, ARM_THUMB, do_t_arit}, + {"cmp", 0x0000, 2, ARM_THUMB, do_t_compare}, + {"eor", 0x4040, 2, ARM_THUMB, do_t_arit}, + {"ldmia", 0xc800, 2, ARM_THUMB, do_t_ldmstm}, + {"ldr", 0x0000, 2, ARM_THUMB, do_t_ldr}, + {"ldrb", 0x0000, 2, ARM_THUMB, do_t_ldrb}, + {"ldrh", 0x0000, 2, ARM_THUMB, do_t_ldrh}, + {"ldrsb", 0x5600, 2, ARM_THUMB, do_t_lds}, + {"ldrsh", 0x5e00, 2, ARM_THUMB, do_t_lds}, + {"ldsb", 0x5600, 2, ARM_THUMB, do_t_lds}, + {"ldsh", 0x5e00, 2, ARM_THUMB, do_t_lds}, + {"lsl", 0x0000, 2, ARM_THUMB, do_t_lsl}, + {"lsr", 0x0000, 2, ARM_THUMB, do_t_lsr}, + {"mov", 0x0000, 2, ARM_THUMB, do_t_mov}, + {"mul", T_OPCODE_MUL, 2, ARM_THUMB, do_t_arit}, + {"mvn", T_OPCODE_MVN, 2, ARM_THUMB, do_t_arit}, + {"neg", T_OPCODE_NEG, 2, ARM_THUMB, do_t_arit}, + {"orr", 0x4300, 2, ARM_THUMB, do_t_arit}, + {"pop", 0xbc00, 2, ARM_THUMB, do_t_push_pop}, + {"push", 0xb400, 2, ARM_THUMB, do_t_push_pop}, + {"ror", 0x41c0, 2, ARM_THUMB, do_t_arit}, + {"sbc", 0x4180, 2, ARM_THUMB, do_t_arit}, + {"stmia", 0xc000, 2, ARM_THUMB, do_t_ldmstm}, + {"str", 0x0000, 2, ARM_THUMB, do_t_str}, + {"strb", 0x0000, 2, ARM_THUMB, do_t_strb}, + {"strh", 0x0000, 2, ARM_THUMB, do_t_strh}, + {"swi", 0xdf00, 2, ARM_THUMB, do_t_swi}, + {"sub", 0x0000, 2, ARM_THUMB, do_t_sub}, + {"tst", T_OPCODE_TST, 2, ARM_THUMB, do_t_arit}, /* Pseudo ops: */ - {"adr", 0x0000, 2, do_t_adr}, - {"nop", 0x46C0, 2, do_t_nop}, /* mov r8,r8 */ + {"adr", 0x0000, 2, ARM_THUMB, do_t_adr}, + {"nop", 0x46C0, 2, ARM_THUMB, do_t_nop}, /* mov r8,r8 */ }; struct reg_entry { - CONST char *name; - int number; + CONST char * name; + int number; }; #define int_register(reg) ((reg) >= 0 && (reg) <= 15) @@ -856,15 +884,17 @@ static CONST struct reg_entry reg_table[] = {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: @@ -883,27 +913,47 @@ static void s_thumb 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 @@ -926,14 +976,13 @@ static int label_is_thumb_function_name = false; 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 () @@ -941,7 +990,8 @@ add_to_lit_pool () int lit_count = 0; if (current_poolP == NULL) - current_poolP = symbol_make_empty(); + current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section, + (valueT) 0, &zero_address_frag); /* Check if this literal value is already in the pool: */ while (lit_count < next_literal_pool_place) @@ -967,24 +1017,24 @@ add_to_lit_pool () } 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_) */ - 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_) */ + 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); @@ -1005,18 +1055,16 @@ symbol_locate (symbolP, name, segment, valu, frag) 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); @@ -1025,51 +1073,75 @@ symbol_locate (symbolP, name, segment, valu, frag) #endif #ifdef DEBUG_SYMS - verify_symbol_chain(symbol_rootP, symbol_lastP); + verify_symbol_chain (symbol_rootP, symbol_lastP); #endif /* DEBUG_SYMS */ } -symbolS * -symbol_make_empty () -{ - symbolS *symbolP; - - symbolP = (symbolS *) obstack_alloc (¬es, sizeof (symbolS)); - - /* symbol must be born in some fixed state. This seems as good as any. */ - memset (symbolP, 0, sizeof (symbolS)); - - symbolP->bsym = bfd_make_empty_symbol (stdoutput); - assert (symbolP->bsym != 0); - symbolP->bsym->udata.p = (PTR) symbolP; +/* Check that an immediate is valid, and if so, convert it to the right format. */ - return symbolP; +static unsigned int +validate_immediate (val) + unsigned int val; +{ + unsigned int a; + unsigned int i; + +#define rotate_left(v, n) (v << n | v >> (32 - n)) + + for (i = 0; i < 32; i += 2) + if ((a = rotate_left (val, i)) <= 0xff) + return a | (i << 7); /* 12-bit pack: [shift-cnt,const] */ + + return FAIL; } -/* Check that an immediate is valid, and if so, convert it to the right format. */ +/* Check to see if an immediate can be computed as two seperate immediate + values, added together. We already know that this value cannot be + computed by just one ARM instruction. */ static unsigned int -validate_immediate (val) +validate_immediate_twopart (val, highpart) unsigned int val; + unsigned int * highpart; { - unsigned int a; - unsigned int i; + unsigned int a; + unsigned int i; + + for (i = 0; i < 32; i += 2) + if (((a = rotate_left (val, i)) & 0xff) != 0) + { + if (a & 0xff00) + { + if (a & ~ 0xffff) + continue; + * highpart = (a >> 8) | ((i + 24) << 7); + } + else if (a & 0xff0000) + { + if (a & 0xff000000) + continue; -#define rotate_left(v, n) (v << n | v >> (32 - n)) - - for (i = 0; i < 32; i += 2) - if ((a = rotate_left (val, i)) <= 0xff) - return a | (i << 7); /* 12-bit pack: [shift-cnt,const] */ - return FAIL; + * highpart = (a >> 16) | ((i + 16) << 7); + } + else + { + assert (a & 0xff000000); + + * highpart = (a >> 24) | ((i + 8) << 7); + } + + return (a & 0xff) | (i << 7); + } + + return FAIL; } static int validate_offset_imm (val, hwse) - int val; + unsigned int val; int hwse; { - if ((hwse && (val < -255 || val > 255)) - || (val < -4095 || val > 4095)) + if ((hwse && val > 255) || val > 4095) return FAIL; return val; } @@ -1098,24 +1170,21 @@ s_even (ignore) { if (!need_pass_2) /* Never make frag if expect extra pass. */ frag_align (1, 0, 0); + record_alignment (now_seg, 1); + demand_empty_rest_of_line (); } static void -s_ltorg (internal) - int internal; +s_ltorg (ignored) + int ignored; { int lit_count = 0; char sym_name[20]; if (current_poolP == NULL) - { - /* Nothing to do */ - if (!internal) - as_tsktsk (_("Nothing to put in the pool\n")); - return; - } + return; /* Align pool as you have word accesses */ /* Only make a frag if we have to ... */ @@ -1124,9 +1193,6 @@ s_ltorg (internal) 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, @@ -1134,6 +1200,7 @@ s_ltorg (internal) 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 @@ -1146,20 +1213,6 @@ s_ltorg (internal) 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; @@ -1208,7 +1261,7 @@ s_force_thumb (ignore) if (! thumb_mode) { - thumb_mode = 1; + thumb_mode = 2; record_alignment (now_seg, 1); } @@ -1225,8 +1278,147 @@ s_thumb_func (ignore) 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) @@ -1290,7 +1482,7 @@ s_code (unused) { case 16: case 32: - opcode_select(temp); + opcode_select (temp); break; default: @@ -1300,18 +1492,17 @@ s_code (unused) 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; @@ -1330,17 +1521,19 @@ skip_past_comma (str) return comma ? SUCCESS : FAIL; } -/* A standard register must be given at this point. Shift is the place to - put it in the instruction. */ +/* A standard register must be given at this point. + Shift is the place to put it in inst.instruction. + Restores input start point on err. + Returns the reg#, or FAIL. */ static int reg_required_here (str, shift) - char **str; - 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)) { @@ -1353,7 +1546,7 @@ reg_required_here (str, shift) *str = start; /* In the few cases where we might be able to accept something else - this error can be overridden */ + this error can be overridden. */ sprintf (buff, _("Register expected, not '%.100s'"), start); inst.error = buff; @@ -1379,7 +1572,7 @@ psr_required_here (str, cpsr, spsr) } /* 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 = _(" expected"); /* Restore the start point. */ @@ -1389,12 +1582,11 @@ psr_required_here (str, cpsr, spsr) static int co_proc_number (str) - char **str; + char ** str; { int processor, pchar; - while (**str == ' ') - (*str)++; + skip_whitespace (* str); /* The data sheet seems to imply that just a number on its own is valid here, but the RISC iX assembler seems to accept a prefix 'p'. We will @@ -1428,14 +1620,13 @@ co_proc_number (str) 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)); @@ -1459,11 +1650,11 @@ cp_opc_expr (str, where, length) 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)) { @@ -1473,21 +1664,21 @@ cp_reg_required_here (str, where) } /* In the few cases where we might be able to accept something else - this error can be overridden */ + this error can be overridden. */ inst.error = _("Co-processor register expected"); - /* Restore the start point */ + /* Restore the start point. */ *str = start; return FAIL; } 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)) { @@ -1497,35 +1688,37 @@ fp_reg_required_here (str, where) } /* In the few cases where we might be able to accept something else - this error can be overridden */ + this error can be overridden. */ inst.error = _("Floating point register expected"); - /* Restore the start point */ + /* Restore the start point. */ *str = start; return FAIL; } 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"); @@ -1553,40 +1746,40 @@ cp_address_offset (str) 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 @@ -1596,18 +1789,18 @@ cp_address_required_here (str) { /* '['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++ != ']') { @@ -1615,8 +1808,7 @@ cp_address_required_here (str) return FAIL; } - while (*p == ' ') - p++; + skip_whitespace (p); if (*p == '!') { @@ -1650,11 +1842,11 @@ cp_address_required_here (str) 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; } @@ -1664,13 +1856,12 @@ do_mrs (str, flags) char *str; unsigned long flags; { - /* Only one syntax */ - while (*str == ' ') - str++; + /* Only one syntax. */ + skip_whitespace (str); if (reg_required_here (&str, 12) == FAIL) { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -1686,16 +1877,15 @@ do_mrs (str, flags) return; } -/* Three possible forms: ", Rm", ", Rm", ", #expression" */ +/* Three possible forms: ", Rm", ", Rm", ", #expression". */ static void do_msr (str, flags) - char *str; + char * str; unsigned long flags; { int reg; - while (*str == ' ') - str ++; + skip_whitespace (str); if (psr_required_here (&str, CPSR_ALL, SPSR_ALL) == SUCCESS) { @@ -1705,41 +1895,39 @@ do_msr (str, flags) if (skip_past_comma (&str) == FAIL || (reg = reg_required_here (&str, 0)) == FAIL) { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } } else { if (psr_required_here (& str, CPSR_FLG, SPSR_FLG) == SUCCESS) - { - inst.instruction |= PSR_FLAGS; - } + inst.instruction |= PSR_FLAGS; else if (psr_required_here (& str, CPSR_CTL, SPSR_CTL) == SUCCESS) - { - inst.instruction |= PSR_CONTROL; - } + inst.instruction |= PSR_CONTROL; else { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } if (skip_past_comma (&str) == FAIL) { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } /* Syntax could be ", rm", ", #expression" */ - if ((reg = reg_required_here (&str, 0)) != FAIL) + if ((reg = reg_required_here (& str, 0)) != FAIL) ; - /* Immediate expression */ - else if (*(str++) == '#') + /* Immediate expression. */ + else if (is_immediate_prefix (* str)) { + str ++; inst.error = NULL; - if (my_get_expression (&inst.reloc.exp, &str)) + + if (my_get_expression (& inst.reloc.exp, & str)) { inst.error = _("Register or shift expression expected"); return; @@ -1785,32 +1973,31 @@ do_msr (str, flags) */ 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; } @@ -1821,13 +2008,13 @@ do_mull (str, flags) if (skip_past_comma (&str) == FAIL || (rs = reg_required_here (&str, 8)) == FAIL) { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC) { - inst.error = bad_pc; + inst.error = BAD_PC; return; } @@ -1838,37 +2025,36 @@ do_mull (str, flags) 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; } @@ -1878,13 +2064,13 @@ do_mul (str, flags) if (skip_past_comma (&str) == FAIL || (rm = reg_required_here (&str, 8)) == FAIL) { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } if (rm == REG_PC) { - inst.error = bad_pc; + inst.error = BAD_PC; return; } @@ -1895,37 +2081,36 @@ do_mul (str, flags) 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; } @@ -1937,13 +2122,13 @@ do_mla (str, flags) || skip_past_comma (&str) == FAIL || (rm = reg_required_here (&str, 12)) == FAIL) { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } if (rd == REG_PC || rm == REG_PC) { - inst.error = bad_pc; + inst.error = BAD_PC; return; } @@ -1956,12 +2141,13 @@ do_mla (str, flags) 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 */ @@ -2022,16 +2208,16 @@ my_get_float_expression (str) /* 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; @@ -2039,11 +2225,11 @@ walk_no_bignums (sp) 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; @@ -2088,15 +2274,14 @@ my_get_expression (ep, 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++) ; @@ -2121,16 +2306,15 @@ decode_shift (str, unrestrict) return SUCCESS; } - while (*p == ' ') - p++; - + skip_whitespace (p); + if (unrestrict && reg_required_here (&p, 8) != FAIL) { inst.instruction |= shft->value | SHIFT_BY_REG; *str = p; return SUCCESS; } - else if (*p == '#') + else if (is_immediate_prefix (* p)) { inst.error = NULL; p++; @@ -2197,8 +2381,8 @@ decode_shift (str, unrestrict) */ 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; @@ -2276,29 +2460,29 @@ negate_data_op (instruction, value) 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; @@ -2358,6 +2542,7 @@ data_op2 (str) return SUCCESS; } + (*str)++; inst.error = _("Register or shift expression expected"); return FAIL; } @@ -2365,10 +2550,9 @@ data_op2 (str) 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; @@ -2380,8 +2564,8 @@ fp_op2 (str) int i; inst.error = NULL; - while (**str == ' ') - (*str)++; + + skip_whitespace (* str); /* First try and match exact strings, this is to guarantee that some formats will work even for cross assembly */ @@ -2422,11 +2606,10 @@ fp_op2 (str) 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 @@ -2435,7 +2618,7 @@ do_arit (str, flags) || data_op2 (&str) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -2446,21 +2629,20 @@ do_arit (str, flags) static void do_adr (str, flags) - char *str; + char * str; unsigned long flags; { /* This is a pseudo-op of the form "adr rd, label" to be converted into a relative address of the form "add rd, pc, #label-.-8" */ - while (*str == ' ') - str++; + skip_whitespace (str); if (reg_required_here (&str, 12) == FAIL || skip_past_comma (&str) == FAIL || my_get_expression (&inst.reloc.exp, &str)) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } /* Frag hacking will turn this into a sub instruction if the offset turns @@ -2473,18 +2655,51 @@ do_adr (str, flags) return; } +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; } @@ -2492,7 +2707,7 @@ do_cmp (str, flags) || data_op2 (&str) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -2506,16 +2721,15 @@ do_cmp (str, flags) 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; } @@ -2523,7 +2737,7 @@ do_mov (str, flags) || data_op2 (&str) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -2534,16 +2748,17 @@ do_mov (str, flags) 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) @@ -2566,7 +2781,7 @@ ldst_extend (str, hwse) /* Halfword and signextension instructions have the immediate value split across bits 11..8 and bits 3..0 */ if (hwse) - inst.instruction |= add | HWOFFSET_IMM | (value >> 4) << 8 | value & 0xF; + inst.instruction |= add | HWOFFSET_IMM | ((value >> 4) << 8) | (value & 0xF); else inst.instruction |= add | value; } @@ -2606,7 +2821,7 @@ ldst_extend (str, hwse) static void do_ldst (str, flags) - char *str; + char * str; unsigned long flags; { int halfword = 0; @@ -2617,7 +2832,8 @@ do_ldst (str, flags) /* This is not ideal, but it is the simplest way of dealing with the ARM7T halfword instructions (since they use a different encoding, but the same mnemonic): */ - if (halfword = ((flags & 0x80000000) != 0)) + halfword = (flags & 0x80000000) != 0; + if (halfword) { /* This is actually a load/store of a halfword, or a signed-extension load */ @@ -2634,13 +2850,16 @@ do_ldst (str, flags) 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; @@ -2651,29 +2870,29 @@ do_ldst (str, flags) int reg; str++; - while (*str == ' ') - str++; + + skip_whitespace (str); if ((reg = reg_required_here (&str, 16)) == FAIL) return; - conflict_reg = (((conflict_reg == reg) - && (inst.instruction & LOAD_BIT)) - ? 1 : 0); + /* Conflicts can occur on stores as well as loads. */ + conflict_reg = (conflict_reg == reg); - while (*str == ' ') - str++; + skip_whitespace (str); if (*str == ']') { - str++; + str ++; + if (skip_past_comma (&str) == SUCCESS) { /* [Rn],... (post inc) */ if (ldst_extend (&str, halfword) == FAIL) return; if (conflict_reg) - as_warn (_("destination register same as write-back base\n")); + as_warn (_("%s register same as write-back base"), + (inst.instruction & LOAD_BIT) ? _("destination") : _("source") ); } else { @@ -2681,13 +2900,13 @@ do_ldst (str, flags) if (halfword) inst.instruction |= HWOFFSET_IMM; - while (*str == ' ') - str++; + skip_whitespace (str); if (*str == '!') { if (conflict_reg) - as_warn (_("destination register same as write-back base\n")); + as_warn (_("%s register same as write-back base"), + (inst.instruction & LOAD_BIT) ? _("destination") : _("source") ); str++; inst.instruction |= WRITE_BACK; } @@ -2710,8 +2929,7 @@ do_ldst (str, flags) if (ldst_extend (&str, halfword) == FAIL) return; - while (*str == ' ') - str++; + skip_whitespace (str); if (*str++ != ']') { @@ -2719,13 +2937,13 @@ do_ldst (str, flags) return; } - while (*str == ' ') - str++; + skip_whitespace (str); if (*str == '!') { if (conflict_reg) - as_tsktsk (_("destination register same as write-back base\n")); + as_warn (_("%s register same as write-back base"), + (inst.instruction & LOAD_BIT) ? _("destination") : _("source") ); str++; inst.instruction |= WRITE_BACK; } @@ -2736,8 +2954,7 @@ do_ldst (str, flags) /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */ str++; - while (*str == ' ') - str++; + skip_whitespace (str); if (my_get_expression (&inst.reloc.exp, &str)) return; @@ -2810,11 +3027,11 @@ do_ldst (str, flags) 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 @@ -2831,8 +3048,7 @@ reg_list (strp) { int reg; - while (*str == ' ') - str++; + skip_whitespace (str); if ((reg = reg_required_here (& str, -1)) == FAIL) return FAIL; @@ -2870,8 +3086,7 @@ reg_list (strp) } while (skip_past_comma (&str) != FAIL || (in_range = 1, *str++ == '-')); str--; - while (*str == ' ') - str++; + skip_whitespace (str); if (*str++ != '}') { @@ -2922,8 +3137,7 @@ reg_list (strp) } } - while (*str == ' ') - str++; + skip_whitespace (str); if (*str == '|' || *str == '+') { @@ -2938,14 +3152,13 @@ reg_list (strp) 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; @@ -2956,8 +3169,8 @@ do_ldmstm (str, flags) return; } - while (*str == ' ') - str++; + skip_whitespace (str); + if (*str == '!') { flags |= WRITE_BACK; @@ -2968,14 +3181,14 @@ do_ldmstm (str, flags) || (range = reg_list (&str)) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } if (*str == '^') { str++; - flags |= MULTI_SET_PSR; + flags |= LDM_TYPE_2_OR_3; } inst.instruction |= flags | range; @@ -2985,34 +3198,35 @@ do_ldmstm (str, flags) 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; @@ -3027,7 +3241,7 @@ do_swap (str, flags) || (reg = reg_required_here (&str, 0)) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3040,24 +3254,22 @@ do_swap (str, flags) if (skip_past_comma (&str) == FAIL || *str++ != '[') { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } - while (*str == ' ') - str++; + skip_whitespace (str); if ((reg = reg_required_here (&str, 16)) == FAIL) return; if (reg == REG_PC) { - inst.error = bad_pc; + inst.error = BAD_PC; return; } - while (*str == ' ') - str++; + skip_whitespace (str); if (*str++ != ']') { @@ -3072,51 +3284,84 @@ do_swap (str, flags) static void do_branch (str, flags) - char *str; + char * str; unsigned long flags; { if (my_get_expression (&inst.reloc.exp, &str)) return; - inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH; - inst.reloc.pc_rel = 1; - end_of_line (str); - return; -} - -static void + +#ifdef OBJ_ELF + { + char * save_in; + + /* ScottB: February 5, 1998 */ + /* Check to see of PLT32 reloc required for the instruction. */ + + /* arm_parse_reloc() works on input_line_pointer. + We actually want to parse the operands to the branch instruction + passed in 'str'. Save the input pointer and restore it later. */ + save_in = input_line_pointer; + input_line_pointer = str; + if (inst.reloc.exp.X_op == O_symbol + && *str == '(' + && arm_parse_reloc () == BFD_RELOC_ARM_PLT32) + { + inst.reloc.type = BFD_RELOC_ARM_PLT32; + inst.reloc.pc_rel = 0; + /* Modify str to point to after parsed operands, otherwise + end_of_line() will complain about the (PLT) left in str. */ + str = input_line_pointer; + } + else + { + inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH; + inst.reloc.pc_rel = 1; + } + input_line_pointer = save_in; + } +#else + inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH; + inst.reloc.pc_rel = 1; +#endif /* OBJ_ELF */ + + end_of_line (str); + return; +} + +static void do_bx (str, flags) - char *str; + char * str; unsigned long flags; { int reg; - while (*str == ' ') - str++; + skip_whitespace (str); if ((reg = reg_required_here (&str, 0)) == FAIL) - return; + { + inst.error = BAD_ARGS; + return; + } if (reg == REG_PC) - as_tsktsk (_("Use of r15 in bx has undefined behaviour")); + inst.error = BAD_PC; end_of_line (str); - return; } static void do_cdp (str, flags) - char *str; + char * str; unsigned long flags; { /* Co-processor data operation. Format: CDP{cond} CP#,,CRd,CRn,CRm{,} */ - while (*str == ' ') - str++; + skip_whitespace (str); if (co_proc_number (&str) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3124,7 +3369,7 @@ do_cdp (str, flags) || cp_opc_expr (&str, 20,4) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3132,7 +3377,7 @@ do_cdp (str, flags) || cp_reg_required_here (&str, 12) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3140,7 +3385,7 @@ do_cdp (str, flags) || cp_reg_required_here (&str, 16) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3148,7 +3393,7 @@ do_cdp (str, flags) || cp_reg_required_here (&str, 0) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3157,7 +3402,7 @@ do_cdp (str, flags) if (cp_opc_expr (&str, 5, 3) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } } @@ -3168,19 +3413,18 @@ do_cdp (str, flags) static void do_lstc (str, flags) - char *str; + char * str; unsigned long flags; { /* Co-processor register load/store. Format: */ - while (*str == ' ') - str++; + skip_whitespace (str); if (co_proc_number (&str) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3188,7 +3432,7 @@ do_lstc (str, flags) || cp_reg_required_here (&str, 12) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3196,7 +3440,7 @@ do_lstc (str, flags) || cp_address_required_here (&str) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3207,19 +3451,18 @@ do_lstc (str, flags) static void do_co_reg (str, flags) - char *str; + char * str; unsigned long flags; { /* Co-processor register transfer. Format: {cond} CP#,,Rd,CRn,CRm{,} */ - while (*str == ' ') - str++; + skip_whitespace (str); if (co_proc_number (&str) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3227,7 +3470,7 @@ do_co_reg (str, flags) || cp_opc_expr (&str, 21, 3) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3235,7 +3478,7 @@ do_co_reg (str, flags) || reg_required_here (&str, 12) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3243,7 +3486,7 @@ do_co_reg (str, flags) || cp_reg_required_here (&str, 16) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3251,7 +3494,7 @@ do_co_reg (str, flags) || cp_reg_required_here (&str, 0) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3260,10 +3503,14 @@ do_co_reg (str, flags) if (cp_opc_expr (&str, 5, 3) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } } + if (flags) + { + inst.error = BAD_COND; + } end_of_line (str); return; @@ -3271,19 +3518,18 @@ do_co_reg (str, flags) static void do_fp_ctrl (str, flags) - char *str; + char * str; unsigned long flags; { /* FP control registers. Format: {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; } @@ -3293,11 +3539,10 @@ do_fp_ctrl (str, flags) static void do_fp_ldst (str, flags) - char *str; + char * str; unsigned long flags; { - while (*str == ' ') - str++; + skip_whitespace (str); switch (inst.suffix) { @@ -3319,7 +3564,7 @@ do_fp_ldst (str, flags) if (fp_reg_required_here (&str, 12) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3327,7 +3572,7 @@ do_fp_ldst (str, flags) || cp_address_required_here (&str) == FAIL) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3336,18 +3581,17 @@ do_fp_ldst (str, flags) 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; } @@ -3405,23 +3649,21 @@ do_fp_ldmstm (str, flags) || *str != '[') { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } str++; - while (*str == ' ') - str++; + skip_whitespace (str); if ((reg = reg_required_here (&str, 16)) == FAIL) return; - while (*str == ' ') - str++; + skip_whitespace (str); if (*str != ']') { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3469,7 +3711,7 @@ do_fp_ldmstm (str, flags) || cp_address_required_here (&str) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3478,11 +3720,10 @@ do_fp_ldmstm (str, flags) static void do_fp_dyadic (str, flags) - char *str; + char * str; unsigned long flags; { - while (*str == ' ') - str++; + skip_whitespace (str); switch (inst.suffix) { @@ -3501,7 +3742,7 @@ do_fp_dyadic (str, flags) if (fp_reg_required_here (&str, 12) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3509,7 +3750,7 @@ do_fp_dyadic (str, flags) || fp_reg_required_here (&str, 16) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3517,7 +3758,7 @@ do_fp_dyadic (str, flags) || fp_op2 (&str) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3528,11 +3769,10 @@ do_fp_dyadic (str, flags) static void do_fp_monadic (str, flags) - char *str; + char * str; unsigned long flags; { - while (*str == ' ') - str++; + skip_whitespace (str); switch (inst.suffix) { @@ -3551,7 +3791,7 @@ do_fp_monadic (str, flags) if (fp_reg_required_here (&str, 12) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3559,7 +3799,7 @@ do_fp_monadic (str, flags) || fp_op2 (&str) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3570,16 +3810,15 @@ do_fp_monadic (str, flags) 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; } @@ -3587,7 +3826,7 @@ do_fp_cmp (str, flags) || fp_op2 (&str) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3598,11 +3837,10 @@ do_fp_cmp (str, flags) static void do_fp_from_reg (str, flags) - char *str; + char * str; unsigned long flags; { - while (*str == ' ') - str++; + skip_whitespace (str); switch (inst.suffix) { @@ -3621,7 +3859,7 @@ do_fp_from_reg (str, flags) if (fp_reg_required_here (&str, 16) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3629,7 +3867,7 @@ do_fp_from_reg (str, flags) || reg_required_here (&str, 12) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3640,11 +3878,10 @@ do_fp_from_reg (str, flags) 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; @@ -3653,7 +3890,7 @@ do_fp_to_reg (str, flags) || fp_reg_required_here (&str, 0) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -3671,8 +3908,8 @@ do_fp_to_reg (str, flags) has been parsed. */ static int thumb_reg (strp, hi_lo) - char **strp; - int hi_lo; + char ** strp; + int hi_lo; { int reg; @@ -3708,23 +3945,22 @@ thumb_reg (strp, hi_lo) 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++; @@ -3743,7 +3979,7 @@ thumb_add_sub (str, subtract) Rn = Rs; Rs = Rd; } - else if (*str == '#') + else if (is_immediate_prefix (*str)) { str++; if (my_get_expression (&inst.reloc.exp, &str)) @@ -3876,23 +4112,22 @@ thumb_add_sub (str, subtract) 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; @@ -3912,7 +4147,7 @@ thumb_shift (str, shift) Rn = Rs; Rs = Rd; } - else if (*str == '#') + else if (is_immediate_prefix (*str)) { str++; if (my_get_expression (&inst.reloc.exp, &str)) @@ -3986,23 +4221,22 @@ thumb_shift (str, shift) 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)) @@ -4075,20 +4309,19 @@ thumb_mov_compare (str, move) 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; } @@ -4100,7 +4333,7 @@ thumb_load_store (str, load_store, size) if (skip_past_comma (&str) != FAIL) { - if (*str == '#') + if (is_immediate_prefix (*str)) { str++; if (my_get_expression (&inst.reloc.exp, &str)) @@ -4127,8 +4360,7 @@ thumb_load_store (str, load_store, size) /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */ str++; - while (*str == ' ') - str++; + skip_whitespace (str); if (my_get_expression (& inst.reloc.exp, & str)) return; @@ -4276,7 +4508,7 @@ thumb_load_store (str, load_store, size) static void do_t_nop (str) - char *str; + char * str; { /* Do nothing */ end_of_line (str); @@ -4288,22 +4520,18 @@ do_t_nop (str) BIC and MVN. */ static void do_t_arit (str) - char *str; + char * str; { int Rd, Rs, Rn; - while (*str == ' ') - str++; + skip_whitespace (str); - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL + if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL + || skip_past_comma (&str) == FAIL || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL) { - if (! inst.error) - inst.error = bad_args; - return; + inst.error = BAD_ARGS; + return; } if (skip_past_comma (&str) != FAIL) @@ -4316,7 +4544,7 @@ do_t_arit (str) || inst.instruction == T_OPCODE_NEG || inst.instruction == T_OPCODE_MVN) { - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -4341,21 +4569,21 @@ do_t_arit (str) 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; @@ -4366,7 +4594,7 @@ do_t_branch9 (str) static void do_t_branch12 (str) - char *str; + char * str; { if (my_get_expression (&inst.reloc.exp, &str)) return; @@ -4385,7 +4613,7 @@ find_real_start (symbolP) const char * name = S_GET_NAME (symbolP); symbolS * new_target; - /* This definitonmust agree with the one in gcc/config/arm/thumb.c */ + /* This definiton must agree with the one in gcc/config/arm/thumb.c */ #define STUB_NAME ".real_start_of" if (name == NULL) @@ -4416,10 +4644,11 @@ find_real_start (symbolP) 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); @@ -4437,12 +4666,11 @@ do_t_branch23 (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; @@ -4459,20 +4687,19 @@ do_t_bx (str) 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; @@ -4486,7 +4713,7 @@ do_t_ldmstm (str) || (range = reg_list (&str)) == FAIL) { if (! inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -4510,33 +4737,32 @@ do_t_ldmstm (str) 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 @@ -4557,38 +4783,37 @@ do_t_lds (str) 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; } @@ -4623,38 +4848,37 @@ do_t_push_pop (str) 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; @@ -4666,19 +4890,18 @@ do_t_swi (str) static void do_t_adr (str) - char *str; + char * str; { /* This is a pseudo-op of the form "adr rd, label" to be converted into a relative address of the form "add rd, pc, #label-.-4" */ - while (*str == ' ') - str++; + skip_whitespace (str); if (reg_required_here (&str, 4) == FAIL /* Store Rd in temporary location inside instruction. */ || skip_past_comma (&str) == FAIL || my_get_expression (&inst.reloc.exp, &str)) { if (!inst.error) - inst.error = bad_args; + inst.error = BAD_ARGS; return; } @@ -4693,10 +4916,10 @@ static void 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; @@ -4744,7 +4967,7 @@ md_begin () { 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 @@ -4777,6 +5000,7 @@ md_begin () 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); } @@ -4806,12 +5030,16 @@ md_begin () break; } - /* Catch special cases */ + /* Catch special cases. */ if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT)) { - if (cpu_variant & ARM_THUMB) + if (cpu_variant & (ARM_EXT_V5 & ARM_THUMB)) + mach = bfd_mach_arm_5T; + else if (cpu_variant & ARM_EXT_V5) + mach = bfd_mach_arm_5; + else if (cpu_variant & ARM_THUMB) mach = bfd_mach_arm_4T; - else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4) + else if ((cpu_variant & ARM_ARCH_V4) == ARM_ARCH_V4) mach = bfd_mach_arm_4; else if (cpu_variant & ARM_LONGMUL) mach = bfd_mach_arm_3M; @@ -4826,13 +5054,12 @@ md_begin () This knows about the endian-ness of the target machine and does THE RIGHT THING, whatever it is. Possible values for n are 1 (byte) 2 (short) and 4 (long) Floating numbers are put out as a series of - LITTLENUMS (shorts, here at least) - */ + LITTLENUMS (shorts, here at least). */ void md_number_to_chars (buf, val, n) - char *buf; + char * buf; valueT val; - int n; + int n; { if (target_big_endian) number_to_chars_bigendian (buf, val, n); @@ -4842,11 +5069,11 @@ md_number_to_chars (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) { @@ -4884,9 +5111,9 @@ md_chars_to_number (buf, n) 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]; @@ -4952,22 +5179,21 @@ md_atof (type, litP, sizeP) 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; } @@ -4977,27 +5203,42 @@ md_pcrel_from (fixP) /* Round up a section size to the appropriate boundary. */ valueT md_section_align (segment, size) - segT segment; + segT segment; valueT size; { -/* start-sanitize-armelf */ #ifdef OBJ_ELF - /* Don't align the dwarf2 debug sections */ - if (!strncmp(segment->name,".debug",5)) - return size; -#endif -/* end-sanitize-armelf */ + return size; +#else /* Round all sects to multiple of 4 */ return (size + 3) & ~3; +#endif } -/* We have no need to default values of symbols. */ +/* Under ELF we need to default _GLOBAL_OFFSET_TABLE. Otherwise + we have no need to default values of symbols. */ /* ARGSUSED */ symbolS * md_undefined_symbol (name) - char *name; + char * name; { +#ifdef OBJ_ELF + if (name[0] == '_' && name[1] == 'G' + && streq (name, GLOBAL_OFFSET_TABLE_NAME)) + { + if (!GOT_symbol) + { + if (symbol_find (name)) + as_bad ("GOT already in the symbol table"); + + GOT_symbol = symbol_new (name, undefined_section, + (valueT)0, & zero_address_frag); + } + + return GOT_symbol; + } +#endif + return 0; } @@ -5006,12 +5247,12 @@ md_undefined_symbol (name) 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) @@ -5046,11 +5287,12 @@ arm_reg_parse (ccp) static int arm_psr_parse (ccp) - register char **ccp; + register char ** ccp; { - char *start = *ccp; - char c, *p; - CONST struct asm_psr *psr; + char * start = * ccp; + char c; + char * p; + CONST struct asm_psr * psr; p = start; c = *p++; @@ -5072,23 +5314,23 @@ arm_psr_parse (ccp) 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) @@ -5104,14 +5346,16 @@ md_apply_fix3 (fixP, val, seg) && S_IS_DEFINED (fixP->fx_addsy) && S_GET_SEGMENT (fixP->fx_addsy) != seg) { - if (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH) + if (target_oabi + && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH + )) value = 0; else value += md_pcrel_from (fixP); } } - fixP->fx_addnumber = value; /* Remember value for emit_reloc */ + fixP->fx_addnumber = value; /* Remember value for emit_reloc. */ switch (fixP->fx_r_type) { @@ -5125,7 +5369,8 @@ md_apply_fix3 (fixP, val, seg) && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL) { as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid constant after fixup\n")); + _("invalid constant (%lx) after fixup"), + (unsigned long) value); break; } @@ -5133,15 +5378,62 @@ md_apply_fix3 (fixP, val, seg) md_number_to_chars (buf, (valueT) newimm, INSN_SIZE); break; - case BFD_RELOC_ARM_OFFSET_IMM: + case BFD_RELOC_ARM_ADRL_IMMEDIATE: + { + unsigned int highpart = 0; + unsigned int newinsn = 0xe1a00000; /* nop */ + newimm = validate_immediate (value); + temp = md_chars_to_number (buf, INSN_SIZE); + + /* If the instruction will fail, see if we can fix things up by + changing the opcode. */ + if (newimm == (unsigned int) FAIL + && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL) + { + /* No ? OK - try using two ADD instructions to generate the value. */ + newimm = validate_immediate_twopart (value, & highpart); + + /* Yes - then make sure that the second instruction is also an add. */ + if (newimm != (unsigned int) FAIL) + newinsn = temp; + /* Still No ? Try using a negated value. */ + else if (validate_immediate_twopart (- value, & highpart) != (unsigned int) FAIL) + temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT; + /* Otherwise - give up. */ + else + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("Unable to compute ADRL instructions for PC offset of 0x%x"), value); + break; + } + + /* Replace the first operand in the 2nd instruction (which is the PC) + with the destination register. We have already added in the PC in the + first instruction and we do not want to do it again. */ + newinsn &= ~ 0xf0000; + newinsn |= ((newinsn & 0x0f000) << 4); + } + + newimm |= (temp & 0xfffff000); + md_number_to_chars (buf, (valueT) newimm, INSN_SIZE); + + highpart |= (newinsn & 0xfffff000); + md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE); + } + break; + + case BFD_RELOC_ARM_OFFSET_IMM: sign = value >= 0; - if ((value = validate_offset_imm (value, 0)) == FAIL) + + if (value < 0) + value = - value; + + if (validate_offset_imm (value, 0) == FAIL) { - as_bad (_("bad immediate value for offset (%d)"), val); + as_bad_where (fixP->fx_file, fixP->fx_line, + _("bad immediate value for offset (%ld)"), (long) value); break; } - if (value < 0) - value = -value; newval = md_chars_to_number (buf, INSN_SIZE); newval &= 0xff7ff000; @@ -5152,34 +5444,37 @@ md_apply_fix3 (fixP, val, seg) case BFD_RELOC_ARM_OFFSET_IMM8: case BFD_RELOC_ARM_HWLITERAL: sign = value >= 0; - if ((value = validate_offset_imm (value, 1)) == FAIL) + + if (value < 0) + value = - value; + + if (validate_offset_imm (value, 1) == FAIL) { if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid literal constant: pool needs to be closer\n")); + _("invalid literal constant: pool needs to be closer")); else - as_bad (_("bad immediate value for offset (%d)"), value); + as_bad (_("bad immediate value for half-word offset (%ld)"), + (long) value); break; } - if (value < 0) - value = -value; - newval = md_chars_to_number (buf, INSN_SIZE); newval &= 0xff7ff0f0; - newval |= ((value >> 4) << 8) | value & 0xf | (sign ? INDEX_UP : 0); + newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0); md_number_to_chars (buf, newval, INSN_SIZE); break; case BFD_RELOC_ARM_LITERAL: sign = value >= 0; + if (value < 0) - value = -value; + value = - value; - if ((value = validate_offset_imm (value, 0)) == FAIL) + if (validate_offset_imm (value, 0) == FAIL) { as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid literal constant: pool needs to be closer\n")); + _("invalid literal constant: pool needs to be closer")); break; } @@ -5239,13 +5534,19 @@ md_apply_fix3 (fixP, val, seg) break; case BFD_RELOC_ARM_PCREL_BRANCH: - value = (value >> 2) & 0x00ffffff; newval = md_chars_to_number (buf, INSN_SIZE); - value = (value + (newval & 0x00ffffff)) & 0x00ffffff; + +#ifdef OBJ_ELF + if (! target_oabi) + value = fixP->fx_offset; +#endif + value = (value >> 2) & 0x00ffffff; + value = (value + (newval & 0x00ffffff)) & 0x00ffffff; newval = value | (newval & 0xff000000); md_number_to_chars (buf, newval, INSN_SIZE); break; + case BFD_RELOC_THUMB_PCREL_BRANCH9: /* conditional branch */ newval = md_chars_to_number (buf, THUMB_SIZE); { @@ -5282,12 +5583,15 @@ md_apply_fix3 (fixP, val, seg) { 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, @@ -5303,19 +5607,57 @@ md_apply_fix3 (fixP, val, seg) 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)) @@ -5348,7 +5690,7 @@ md_apply_fix3 (fixP, val, seg) if ((value + 2) & ~0x3fe) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset")); + _("Invalid offset, value too big (0x%08X)"), value); /* Round up, since pc will be rounded down. */ newval |= (value + 2) >> 2; @@ -5357,34 +5699,35 @@ md_apply_fix3 (fixP, val, seg) case 9: /* SP load/store */ if (value & ~0x3fc) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset")); + _("Invalid offset, value too big (0x%08X)"), value); newval |= value >> 2; break; case 6: /* Word load/store */ if (value & ~0x7c) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset")); + _("Invalid offset, value too big (0x%08X)"), value); newval |= value << 4; /* 6 - 2 */ break; case 7: /* Byte load/store */ if (value & ~0x1f) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset")); + _("Invalid offset, value too big (0x%08X)"), value); newval |= value << 6; break; case 8: /* Halfword load/store */ if (value & ~0x3e) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset")); + _("Invalid offset, value too big (0x%08X)"), value); newval |= value << 5; /* 6 - 1 */ break; default: as_bad_where (fixP->fx_file, fixP->fx_line, - "Unable to process relocation for thumb opcode: %x", newval); + "Unable to process relocation for thumb opcode: %lx", + (unsigned long) newval); break; } md_number_to_chars (buf, newval, THUMB_SIZE); @@ -5423,7 +5766,8 @@ md_apply_fix3 (fixP, val, seg) if (subtract || value & ~0x3fc) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid immediate for address calculation (value = 0x%08X)"), value); + _("Invalid immediate for address calculation (value = 0x%08lX)"), + (unsigned long) value); newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP); newval |= rd << 8; newval |= value >> 2; @@ -5456,7 +5800,8 @@ md_apply_fix3 (fixP, val, seg) case 0x05: /* 8bit immediate CMP */ if (value < 0 || value > 255) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid immediate: %d is too large"), value); + _("Invalid immediate: %ld is too large"), + (long) value); newval |= value; break; @@ -5470,16 +5815,21 @@ md_apply_fix3 (fixP, val, seg) /* 5bit shift value (0..31) */ if (value < 0 || value > 31) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Illegal Thumb shift value: %d"), value); + _("Illegal Thumb shift value: %ld"), (long) value); newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f; newval |= value << 6; md_number_to_chars (buf, newval , THUMB_SIZE); 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; @@ -5489,15 +5839,16 @@ md_apply_fix3 (fixP, val, seg) format. */ arelent * tc_gen_reloc (section, fixp) - asection *section; - fixS *fixp; + asection * section; + fixS * fixp; { - arelent *reloc; + arelent * reloc; bfd_reloc_code_real_type code; reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; /* @@ Why fx_addnumber sometimes and fx_offset other times? */ @@ -5538,23 +5889,39 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_THUMB_PCREL_BRANCH9: case BFD_RELOC_THUMB_PCREL_BRANCH12: case BFD_RELOC_THUMB_PCREL_BRANCH23: + case BFD_RELOC_VTABLE_ENTRY: + case BFD_RELOC_VTABLE_INHERIT: code = fixp->fx_r_type; break; case BFD_RELOC_ARM_LITERAL: case BFD_RELOC_ARM_HWLITERAL: /* If this is called then the a literal has been referenced across - a section boundry - possibly due to an implicit dump */ + a section boundary - possibly due to an implicit dump */ as_bad_where (fixp->fx_file, fixp->fx_line, - _("Literal referenced across section boundry (Implicit dump?)")); + _("Literal referenced across section boundary (Implicit dump?)")); return NULL; +#ifdef OBJ_ELF + case BFD_RELOC_ARM_GOT32: + case BFD_RELOC_ARM_GOTOFF: + case BFD_RELOC_ARM_PLT32: + code = fixp->fx_r_type; + break; +#endif + case BFD_RELOC_ARM_IMMEDIATE: as_bad_where (fixp->fx_file, fixp->fx_line, _("Internal_relocation (type %d) not fixed up (IMMEDIATE)"), fixp->fx_r_type); return NULL; + case BFD_RELOC_ARM_ADRL_IMMEDIATE: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("ADRL used for a symbol not defined in the same file"), + fixp->fx_r_type); + return NULL; + case BFD_RELOC_ARM_OFFSET_IMM: as_bad_where (fixp->fx_file, fixp->fx_line, _("Internal_relocation (type %d) not fixed up (OFFSET_IMM)"), @@ -5577,7 +5944,7 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break; case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break; case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break; - default: type = ""; break; + default: type = _(""); break; } as_bad_where (fixp->fx_file, fixp->fx_line, _("Can not represent %s relocation in this object file format (%d)"), @@ -5586,6 +5953,16 @@ tc_gen_reloc (section, fixp) } } +#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) @@ -5596,23 +5973,27 @@ tc_gen_reloc (section, fixp) return NULL; } + /* HACK: Since arm ELF uses Rel instead of Rela, encode the + vtable entry to be used in the relocation's section offset. */ + if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + reloc->address = fixp->fx_offset; + return reloc; } int md_estimate_size_before_relax (fragP, segtype) - fragS *fragP; - segT segtype; + fragS * fragP; + segT segtype; { as_fatal (_("md_estimate_size_before_relax\n")); - return (1); + return 1; } static void -output_inst (str) - char *str; +output_inst PARAMS ((void)) { - char *to = NULL; + char * to = NULL; if (inst.error) { @@ -5621,18 +6002,25 @@ output_inst (str) } to = frag_more (inst.size); + if (thumb_mode && (inst.size > THUMB_SIZE)) { assert (inst.size == (2 * THUMB_SIZE)); md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE); - md_number_to_chars (to + 2, inst.instruction, THUMB_SIZE); + md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE); + } + else if (inst.size > INSN_SIZE) + { + assert (inst.size == (2 * INSN_SIZE)); + md_number_to_chars (to, inst.instruction, INSN_SIZE); + md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE); } else md_number_to_chars (to, inst.instruction, inst.size); 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; @@ -5640,20 +6028,22 @@ output_inst (str) 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); } @@ -5661,11 +6051,10 @@ md_assemble (str) 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; @@ -5678,30 +6067,39 @@ md_assemble (str) if (thumb_mode) { - CONST struct thumb_opcode *opcode; + CONST struct thumb_opcode * opcode; c = *p; *p = '\0'; opcode = (CONST struct thumb_opcode *) hash_find (arm_tops_hsh, str); *p = c; + if (opcode) { + /* Check that this instruction is supported for this CPU. */ + if (thumb_mode == 1 && (opcode->variants & cpu_variant) == 0) + { + as_bad (_("selected processor does not support this opcode")); + return; + } + inst.instruction = opcode->value; inst.size = opcode->size; (*opcode->parms)(p); - output_inst (start); + output_inst (); return; } } else { - CONST struct asm_opcode *opcode; + CONST struct asm_opcode * opcode; + unsigned long cond_code; inst.size = INSN_SIZE; /* p now points to the end of the opcode, probably white space, but we have to break the opcode up in case it contains condionals and flags; keep trying with progressively smaller basic instructions until one - matches, or we run out of opcode. */ + matches, or we run out of opcode. */ q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p; for (; q != str; q--) { @@ -5709,31 +6107,39 @@ md_assemble (str) *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) { @@ -5749,18 +6155,33 @@ md_assemble (str) as_tsktsk ( _("Warning: Use of the 'nv' conditional is deprecated\n")); - inst.instruction |= cond->value; + cond_code = cond->value; r += 2; } else - inst.instruction |= COND_ALWAYS; + cond_code = COND_ALWAYS; } else - inst.instruction |= COND_ALWAYS; + cond_code = COND_ALWAYS; - /* if there is a compulsory suffix, it should come here, before - any optional flags. */ - if (opcode->comp_suffix) + /* Apply the conditional, or complain it's not allowed. */ + if (opcode->comp_suffix && *opcode->comp_suffix == '\0') + { + /* Instruction isn't conditional */ + if (cond_code != COND_ALWAYS) + { + as_bad (_("Opcode `%s' is unconditional\n"), str); + return; + } + } + else + /* Instruction is conditional: set the condition into it. */ + inst.instruction |= cond_code; + + + /* If there is a compulsory suffix, it should come here, before + any optional flags. */ + if (opcode->comp_suffix && *opcode->comp_suffix != '\0') { CONST char *s = opcode->comp_suffix; @@ -5798,7 +6219,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n")); 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; @@ -5814,7 +6235,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n")); } (*opcode->parms) (p, flag_bits); - output_inst (start); + output_inst (); return; } @@ -5824,11 +6245,9 @@ _("Warning: Use of the 'nv' conditional is deprecated\n")); } /* It wasn't an instruction, but it might be a register alias of the form - alias .req reg - */ + alias .req reg */ q = p; - while (*q == ' ') - q++; + skip_whitespace (q); c = *p; *p = '\0'; @@ -5840,8 +6259,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n")); char * r; q += 4; - while (*q == ' ') - q++; + skip_whitespace (q); for (r = q; *r != '\0'; r++) if (*r == ' ') @@ -5861,20 +6279,16 @@ _("Warning: Use of the 'nv' conditional is deprecated\n")); if (reg == FAIL) { if (regnum != FAIL) - { - insert_reg_alias (str, regnum); - } + insert_reg_alias (str, regnum); else - { - as_warn (_("register '%s' does not exist\n"), q); - } + as_warn (_("register '%s' does not exist\n"), q); } else if (regnum != FAIL) { if (reg != regnum) as_warn (_("ignoring redefinition of register alias '%s'"), copy_of_str ); - /* 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'"), @@ -5899,8 +6313,12 @@ _("Warning: Use of the 'nv' conditional is deprecated\n")); * -m[arm]1 Currently not supported. * -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor * -m[arm]3 Arm 3 processor - * -m[arm]6, Arm 6 processors - * -m[arm]7[t][[d]m] Arm 7 processors + * -m[arm]6[xx], Arm 6 processors + * -m[arm]7[xx][t][[d]m] Arm 7 processors + * -m[arm]8[10] Arm 8 processors + * -m[arm]9[20][tdmi] Arm 9 processors + * -mstrongarm[110[0]] StrongARM processors + * -m[arm]v[2345] Arm architectures * -mall All (except the ARM1) * FP variants: * -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions @@ -5915,9 +6333,10 @@ _("Warning: Use of the 'nv' conditional is deprecated\n")); * -mapcs-float Pass floats in float regs * -mapcs-reentrant Position independent code * -mthumb-interwork Code supports Arm/Thumb interworking + * -moabi Old ELF ABI */ -CONST char *md_shortopts = "m:"; +CONST char * md_shortopts = "m:k"; struct option md_longopts[] = { #ifdef ARM_BI_ENDIAN @@ -5925,6 +6344,10 @@ struct option md_longopts[] = {"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} }; @@ -5932,10 +6355,10 @@ size_t md_longopts_size = sizeof (md_longopts); int md_parse_option (c, arg) - int c; - char *arg; + int c; + char * arg; { - char *str = arg; + char * str = arg; switch (c) { @@ -5952,32 +6375,40 @@ md_parse_option (c, arg) 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 @@ -5987,7 +6418,7 @@ md_parse_option (c, arg) break; default: - if (! strcmp (str, "all")) + if (streq (str, "all")) { cpu_variant = ARM_ALL | FPU_ALL; return 1; @@ -6000,23 +6431,23 @@ md_parse_option (c, arg) 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 @@ -6025,7 +6456,7 @@ md_parse_option (c, arg) 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 @@ -6035,7 +6466,7 @@ md_parse_option (c, arg) 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/ @@ -6055,58 +6486,64 @@ md_parse_option (c, arg) 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': @@ -6119,9 +6556,9 @@ md_parse_option (c, arg) 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; @@ -6131,6 +6568,36 @@ md_parse_option (c, arg) } break; + case '8': + if (streq (str, "8") || streq (str, "810")) + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL; + else + goto bad; + break; + + case '9': + if (streq (str, "9")) + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB; + else if (streq (str, "920")) + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL; + else if (streq (str, "920t")) + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB; + else if (streq (str, "9tdmi")) + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB; + else + goto bad; + break; + + + case 's': + if (streq (str, "strongarm") + || streq (str, "strongarm110") + || streq (str, "strongarm1100")) + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL; + else + goto bad; + break; + case 'v': /* Select variant based on architecture rather than processor */ switch (*++str) @@ -6156,7 +6623,7 @@ md_parse_option (c, arg) break; case '4': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCHv4; + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4; switch (*++str) { @@ -6165,6 +6632,17 @@ md_parse_option (c, arg) default: as_bad (_("Invalid architecture variant -m%s"), arg); break; } break; + + case '5': + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V5; + switch (*++str) + { + case 't': cpu_variant |= ARM_THUMB; break; + case 'e': cpu_variant |= ARM_EXT_V5E; break; + case 0: break; + default: as_bad (_("Invalid architecture variant -m%s"), arg); break; + } + break; default: as_bad (_("Invalid architecture variant -m%s"), arg); @@ -6180,6 +6658,12 @@ md_parse_option (c, arg) } break; +#if defined OBJ_ELF || defined OBJ_COFF + case 'k': + pic_code = 1; + break; +#endif + default: return 0; } @@ -6189,28 +6673,37 @@ md_parse_option (c, arg) void md_show_usage (fp) - FILE *fp; + FILE * fp; { fprintf (fp, _("\ + ARM Specific Assembler Options:\n\ -m[arm][] select processor variant\n\ - -m[arm]v[2|2a|3|3m|4|4t] select architecture variant\n\ + -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] select architecture variant\n\ -mthumb only allow Thumb instructions\n\ -mthumb-interwork mark the assembled code as supporting interworking\n\ -mall allow any instruction\n\ -mfpa10, -mfpa11 select floating point architecture\n\ -mfpe-old don't allow floating-point multiple instructions\n\ -mno-fpu don't allow any floating-point instructions.\n")); + fprintf (fp, +_("\ + -k generate PIC code.\n")); #if defined OBJ_COFF || defined OBJ_ELF fprintf (fp, _("\ - -mapcs-32, -mapcs-26 specify which ARM Procedure Calling Standard is in use\n")); + -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, _("\ - -mapcs-float floating point args are passed in floating point regs\n")); + -mapcs-reentrant the code is position independent/reentrant\n")); + #endif +#ifdef OBJ_ELF fprintf (fp, _("\ - -mapcs-reentrant position independent/reentrant code has been generated\n")); + -moabi support the old ELF ABI\n")); #endif #ifdef ARM_BI_ENDIAN fprintf (fp, @@ -6229,15 +6722,15 @@ _("\ 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) { @@ -6255,25 +6748,58 @@ fix_new_arm (frag, where, size, exp, pc_rel, reloc) } /* 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 @@ -6284,10 +6810,12 @@ arm_start_line_hook () 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 @@ -6308,14 +6836,10 @@ arm_frob_label (sym) /* 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_other) -#define S_SET_STORAGE_CLASS(S,V) (elf_symbol ((S)->bsym)->internal_elf_sym.st_other = (V)) -#endif void arm_adjust_symtab () { -#if defined OBJ_COFF || defined OBJ_ELF +#ifdef OBJ_COFF symbolS * sym; for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) @@ -6328,10 +6852,12 @@ arm_adjust_symtab () if ( S_GET_STORAGE_CLASS (sym) == C_STAT || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */ S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC); + 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)) { @@ -6349,36 +6875,30 @@ arm_adjust_symtab () } } -#ifdef OBJ_COFF if (ARM_IS_INTERWORK (sym)) - coffsymbol(sym->bsym)->native->u.syment.n_flags = 0xFF; -#endif + coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF; } #endif -} - #ifdef OBJ_ELF -void -armelf_frob_symbol (symp, puntp) - symbolS *symp; - int *puntp; - -{ - elf_frob_symbol (symp, puntp); + symbolS * sym; + elf_symbol_type * elf_sym; + char bind; - if (S_IS_EXTERNAL (symp)) - S_SET_STORAGE_CLASS(symp, C_EXT); - - if (S_GET_STORAGE_CLASS (symp) == C_NULL) - { - if (S_GET_SEGMENT (symp) == text_section - && symp != seg_info (text_section)->sym) - S_SET_STORAGE_CLASS (symp, C_LABEL); - else - S_SET_STORAGE_CLASS (symp, C_STAT); - } -} + for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) + { + if (ARM_IS_THUMB (sym)) + { + if (THUMB_IS_FUNC (sym)) + { + elf_sym = elf_symbol (symbol_get_bfdsym (sym)); + bind = ELF_ST_BIND (elf_sym); + elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC); + } + } + } #endif +} + int arm_data_in_code () { @@ -6389,31 +6909,22 @@ 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")) - { - *(name + len - 5) = 0; - } + && streq (name + len - 5, "/data")) + *(name + len - 5) = 0; return name; } -/* start-sanitize-armelf */ -boolean -arm_fix_adjustable(fixP) - fixS *fixP; -{ - return 1; -} -/* end-sanitize-armelf */ boolean arm_validate_fix (fixP) @@ -6435,3 +6946,172 @@ arm_validate_fix (fixP) return false; } +#ifdef OBJ_ELF +/* Relocations against Thumb function names must be left unadjusted, + so that the linker can use this information to correctly set the + bottom bit of their addresses. The MIPS version of this function + also prevents relocations that are mips-16 specific, but I do not + know why it does this. + + FIXME: + 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 + 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; +{ + 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; +} + +const char * +elf32_arm_target_format () +{ + if (target_big_endian) + if (target_oabi) + return "elf32-bigarm-oabi"; + else + return "elf32-bigarm"; + else + if (target_oabi) + return "elf32-littlearm-oabi"; + else + return "elf32-littlearm"; +} + +void +armelf_frob_symbol (symp, puntp) + symbolS * symp; + int * puntp; +{ + elf_frob_symbol (symp, puntp); +} + +int +arm_force_relocation (fixp) + struct fix * fixp; +{ + if ( fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY + || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH + || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23) + return 1; + + return 0; +} + +static bfd_reloc_code_real_type +arm_parse_reloc () +{ + char id[16]; + char * ip; + int i; + static struct + { + char * str; + int len; + bfd_reloc_code_real_type reloc; + } + reloc_map[] = + { +#define MAP(str,reloc) { str, sizeof (str)-1, reloc } + MAP ("(got)", BFD_RELOC_ARM_GOT32), + MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF), + /* ScottB: Jan 30, 1998 */ + /* Added support for parsing "var(PLT)" branch instructions */ + /* generated by GCC for PLT relocs */ + MAP ("(plt)", BFD_RELOC_ARM_PLT32), + { NULL, 0, BFD_RELOC_UNUSED } +#undef MAP + }; + + for (i = 0, ip = input_line_pointer; + i < sizeof (id) && (isalnum (*ip) || ispunct (*ip)); + i++, ip++) + id[i] = tolower (*ip); + + for (i = 0; reloc_map[i].str; i++) + if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0) + break; + + input_line_pointer += reloc_map[i].len; + + return reloc_map[i].reloc; +} + +static void +s_arm_elf_cons (nbytes) + int nbytes; +{ + expressionS exp; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + +#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 */