X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=117fe16d31b686a5f003f3ee304932976a1ebffb;hb=4396b6862a60b1add68552ddac6b8d68513e51e8;hp=06dba438468840115726286ce77c92b9939cf476;hpb=428e3f1f4e7539e2706c12f2f2880c42a7948a92;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 06dba43846..117fe16d31 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1,6 +1,6 @@ /* tc-arm.c -- Assemble for the ARM Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006 + 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modified by David Taylor (dtaylor@armltd.co.uk) @@ -12,7 +12,7 @@ GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -155,6 +155,7 @@ static const arm_feature_set *mcpu_fpu_opt = NULL; static const arm_feature_set *march_cpu_opt = NULL; static const arm_feature_set *march_fpu_opt = NULL; static const arm_feature_set *mfpu_opt = NULL; +static const arm_feature_set *object_arch = NULL; /* Constants for known architecture features. */ static const arm_feature_set fpu_default = FPU_DEFAULT; @@ -201,6 +202,8 @@ static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1); static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2; static const arm_feature_set arm_arch_none = ARM_ARCH_NONE; +static const arm_feature_set arm_cext_iwmmxt2 = + ARM_FEATURE (0, ARM_CEXT_IWMMXT2); static const arm_feature_set arm_cext_iwmmxt = ARM_FEATURE (0, ARM_CEXT_IWMMXT); static const arm_feature_set arm_cext_xscale = @@ -229,6 +232,12 @@ static int meabi_flags = EABI_DEFAULT; # else static int meabi_flags = EF_ARM_EABI_UNKNOWN; # endif + +bfd_boolean +arm_is_eabi(void) +{ + return (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4); +} #endif #ifdef OBJ_ELF @@ -324,6 +333,7 @@ struct arm_it unsigned immisreg : 1; /* .imm field is a second register. */ unsigned isscalar : 1; /* Operand is a (Neon) scalar. */ unsigned immisalign : 1; /* Immediate is an alignment specifier. */ + unsigned immisfloat : 1; /* Immediate was parsed as a float. */ /* Note: we abuse "regisimm" to mean "is Neon register" in VMOV instructions. This allows us to disambiguate ARM <-> vector insns. */ unsigned regisimm : 1; /* 64-bit immediate, reg forms high 32 bits. */ @@ -539,11 +549,14 @@ struct asm_opcode #define INDEX_UP 0x00800000 #define WRITE_BACK 0x00200000 #define LDM_TYPE_2_OR_3 0x00400000 +#define CPSI_MMOD 0x00020000 #define LITERAL_MASK 0xf000f000 #define OPCODE_MASK 0xfe1fffff #define V4_STR_BIT 0x00000020 +#define T2_SUBS_PC_LR 0xf3de8f00 + #define DATA_OP_SHIFT 21 #define T2_OPCODE_MASK 0xfe1fffff @@ -1261,7 +1274,9 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type, && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD)) || (type == REG_TYPE_NSDQ && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD - || reg->type == REG_TYPE_NQ))) + || reg->type == REG_TYPE_NQ)) + || (type == REG_TYPE_MMXWC + && (reg->type == REG_TYPE_MMXWCG))) type = reg->type; if (type != reg->type) @@ -1956,7 +1971,7 @@ insert_reg_alias (char *str, int number, int type) else if (new->number != number || new->type != type) as_warn (_("ignoring redefinition of register alias '%s'"), str); - return 0; + return NULL; } name = xstrdup (str); @@ -1998,9 +2013,9 @@ insert_neon_reg_alias (char *str, int number, int type, new_register_name .req existing_register_name If we find one, or if it looks sufficiently like one that we want to - handle any error here, return non-zero. Otherwise return zero. */ + handle any error here, return TRUE. Otherwise return FALSE. */ -static int +static bfd_boolean create_register_alias (char * newname, char *p) { struct reg_entry *old; @@ -2011,17 +2026,17 @@ create_register_alias (char * newname, char *p) collapsed to single spaces. */ oldname = p; if (strncmp (oldname, " .req ", 6) != 0) - return 0; + return FALSE; oldname += 6; if (*oldname == '\0') - return 0; + return FALSE; old = hash_find (arm_reg_hsh, oldname); if (!old) { as_warn (_("unknown register '%s' -- .req ignored"), oldname); - return 1; + return TRUE; } /* If TC_CASE_SENSITIVE is defined, then newname already points to @@ -2041,21 +2056,34 @@ create_register_alias (char * newname, char *p) /* Create aliases under the new name as stated; an all-lowercase version of the new name; and an all-uppercase version of the new name. */ - insert_reg_alias (nbuf, old->number, old->type); + if (insert_reg_alias (nbuf, old->number, old->type) != NULL) + { + for (p = nbuf; *p; p++) + *p = TOUPPER (*p); - for (p = nbuf; *p; p++) - *p = TOUPPER (*p); + if (strncmp (nbuf, newname, nlen)) + { + /* If this attempt to create an additional alias fails, do not bother + trying to create the all-lower case alias. We will fail and issue + a second, duplicate error message. This situation arises when the + programmer does something like: + foo .req r0 + Foo .req r1 + The second .req creates the "Foo" alias but then fails to create + the artifical FOO alias because it has already been created by the + first .req. */ + if (insert_reg_alias (nbuf, old->number, old->type) == NULL) + return TRUE; + } - if (strncmp (nbuf, newname, nlen)) - insert_reg_alias (nbuf, old->number, old->type); + for (p = nbuf; *p; p++) + *p = TOLOWER (*p); - for (p = nbuf; *p; p++) - *p = TOLOWER (*p); - - if (strncmp (nbuf, newname, nlen)) - insert_reg_alias (nbuf, old->number, old->type); + if (strncmp (nbuf, newname, nlen)) + insert_reg_alias (nbuf, old->number, old->type); + } - return 1; + return TRUE; } /* Create a Neon typed/indexed register alias using directives, e.g.: @@ -2255,11 +2283,45 @@ s_unreq (int a ATTRIBUTE_UNUSED) name); else { + char * p; + char * nbuf; + hash_delete (arm_reg_hsh, name); free ((char *) reg->name); if (reg->neon) free (reg->neon); free (reg); + + /* Also locate the all upper case and all lower case versions. + Do not complain if we cannot find one or the other as it + was probably deleted above. */ + + nbuf = strdup (name); + for (p = nbuf; *p; p++) + *p = TOUPPER (*p); + reg = hash_find (arm_reg_hsh, nbuf); + if (reg) + { + hash_delete (arm_reg_hsh, nbuf); + free ((char *) reg->name); + if (reg->neon) + free (reg->neon); + free (reg); + } + + for (p = nbuf; *p; p++) + *p = TOLOWER (*p); + reg = hash_find (arm_reg_hsh, nbuf); + if (reg) + { + hash_delete (arm_reg_hsh, nbuf); + free ((char *) reg->name); + if (reg->neon) + free (reg->neon); + free (reg); + } + + free (nbuf); } } @@ -2277,7 +2339,7 @@ s_unreq (int a ATTRIBUTE_UNUSED) static enum mstate mapstate = MAP_UNDEFINED; -static void +void mapping_state (enum mstate state) { symbolS * symbolP; @@ -2598,6 +2660,7 @@ static void s_align (int unused ATTRIBUTE_UNUSED) { int temp; + bfd_boolean fill_p; long temp_fill; long max_alignment = 15; @@ -2614,16 +2677,25 @@ s_align (int unused ATTRIBUTE_UNUSED) { input_line_pointer++; temp_fill = get_absolute_expression (); + fill_p = TRUE; } else - temp_fill = 0; + { + fill_p = FALSE; + temp_fill = 0; + } if (!temp) temp = 2; /* Only make a frag if we HAVE to. */ if (temp && !need_pass_2) - frag_align (temp, (int) temp_fill, 0); + { + if (!fill_p && subseg_text_p (now_seg)) + frag_align_code (temp, 0); + else + frag_align (temp, (int) temp_fill, 0); + } demand_empty_rest_of_line (); record_alignment (now_seg, temp); @@ -3626,6 +3698,7 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED) { int reg; valueT op; + int offset; reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN); if (reg == FAIL) @@ -3634,6 +3707,16 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED) ignore_rest_of_line (); return; } + + /* Optional constant. */ + if (skip_past_comma (&input_line_pointer) != FAIL) + { + if (immediate_for_directive (&offset) == FAIL) + return; + } + else + offset = 0; + demand_empty_rest_of_line (); if (reg == REG_SP || reg == REG_PC) @@ -3651,7 +3734,7 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED) /* Record the information for later. */ unwind.fp_reg = reg; - unwind.fp_offset = unwind.frame_size; + unwind.fp_offset = unwind.frame_size - offset; unwind.sp_restored = 1; } @@ -3793,88 +3876,12 @@ s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED) static void s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED) { - expressionS exp; - bfd_boolean is_string; - int tag; - unsigned int i = 0; - char *s = NULL; - char saved_char; - - expression (& exp); - if (exp.X_op != O_constant) - goto bad; - - tag = exp.X_add_number; - if (tag == 4 || tag == 5 || tag == 32 || (tag > 32 && (tag & 1) != 0)) - is_string = 1; - else - is_string = 0; - - if (skip_past_comma (&input_line_pointer) == FAIL) - goto bad; - if (tag == 32 || !is_string) - { - expression (& exp); - if (exp.X_op != O_constant) - { - as_bad (_("expected numeric constant")); - ignore_rest_of_line (); - return; - } - i = exp.X_add_number; - } - if (tag == Tag_compatibility - && skip_past_comma (&input_line_pointer) == FAIL) - { - as_bad (_("expected comma")); - ignore_rest_of_line (); - return; - } - if (is_string) - { - skip_whitespace(input_line_pointer); - if (*input_line_pointer != '"') - goto bad_string; - input_line_pointer++; - s = input_line_pointer; - while (*input_line_pointer && *input_line_pointer != '"') - input_line_pointer++; - if (*input_line_pointer != '"') - goto bad_string; - saved_char = *input_line_pointer; - *input_line_pointer = 0; - } - else - { - s = NULL; - saved_char = 0; - } - - if (tag == Tag_compatibility) - elf32_arm_add_eabi_attr_compat (stdoutput, i, s); - else if (is_string) - elf32_arm_add_eabi_attr_string (stdoutput, tag, s); - else - elf32_arm_add_eabi_attr_int (stdoutput, tag, i); - - if (s) - { - *input_line_pointer = saved_char; - input_line_pointer++; - } - demand_empty_rest_of_line (); - return; -bad_string: - as_bad (_("bad string constant")); - ignore_rest_of_line (); - return; -bad: - as_bad (_("expected , ")); - ignore_rest_of_line (); + s_vendor_attribute (OBJ_ATTR_PROC); } #endif /* OBJ_ELF */ static void s_arm_arch (int); +static void s_arm_object_arch (int); static void s_arm_cpu (int); static void s_arm_fpu (int); @@ -3928,6 +3935,7 @@ const pseudo_typeS md_pseudo_table[] = { "syntax", s_syntax, 0 }, { "cpu", s_arm_cpu, 0 }, { "arch", s_arm_arch, 0 }, + { "object_arch", s_arm_object_arch, 0 }, { "fpu", s_arm_fpu, 0 }, #ifdef OBJ_ELF { "word", s_arm_elf_cons, 4 }, @@ -3998,7 +4006,7 @@ parse_immediate (char **str, int *val, int min, int max, } /* Less-generic immediate-value read function with the possibility of loading a - big (64-bit) immediate, as required by Neon VMOV and VMVN immediate + big (64-bit) immediate, as required by Neon VMOV, VMVN and logic immediate instructions. Puts the result directly in inst.operands[i]. */ static int @@ -4010,7 +4018,18 @@ parse_big_immediate (char **str, int i) my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG); if (exp.X_op == O_constant) - inst.operands[i].imm = exp.X_add_number; + { + inst.operands[i].imm = exp.X_add_number & 0xffffffff; + /* If we're on a 64-bit host, then a 64-bit number can be returned using + O_constant. We have to be careful not to break compilation for + 32-bit X_add_number, though. */ + if ((exp.X_add_number & ~0xffffffffl) != 0) + { + /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4. */ + inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff; + inst.operands[i].regisimm = 1; + } + } else if (exp.X_op == O_big && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32 && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number <= 64) @@ -4141,18 +4160,43 @@ is_quarter_float (unsigned imm) /* Parse an 8-bit "quarter-precision" floating point number of the form: 0baBbbbbbc defgh000 00000000 00000000. - The minus-zero case needs special handling, since it can't be encoded in the - "quarter-precision" float format, but can nonetheless be loaded as an integer - constant. */ + The zero and minus-zero cases need special handling, since they can't be + encoded in the "quarter-precision" float format, but can nonetheless be + loaded as integer constants. */ static unsigned parse_qfloat_immediate (char **ccp, int *immed) { char *str = *ccp; + char *fpnum; LITTLENUM_TYPE words[MAX_LITTLENUMS]; + int found_fpchar = 0; skip_past_char (&str, '#'); + /* We must not accidentally parse an integer as a floating-point number. Make + sure that the value we parse is not an integer by checking for special + characters '.' or 'e'. + FIXME: This is a horrible hack, but doing better is tricky because type + information isn't in a very usable state at parse time. */ + fpnum = str; + skip_whitespace (fpnum); + + if (strncmp (fpnum, "0x", 2) == 0) + return FAIL; + else + { + for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++) + if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E') + { + found_fpchar = 1; + break; + } + + if (!found_fpchar) + return FAIL; + } + if ((str = atof_ieee (str, 's', words)) != NULL) { unsigned fpword = 0; @@ -4165,7 +4209,7 @@ parse_qfloat_immediate (char **ccp, int *immed) fpword |= words[i]; } - if (is_quarter_float (fpword) || fpword == 0x80000000) + if (is_quarter_float (fpword) || (fpword & 0x7fffffff) == 0) *immed = fpword; else return FAIL; @@ -5165,7 +5209,7 @@ parse_neon_mov (char **str, int *which_operand) Case 3: VMOV.
, # Case 10: VMOV.F32 , # Case 11: VMOV.F64
, # */ - ; + inst.operands[i].immisfloat = 1; else if (parse_big_immediate (&ptr, i) == SUCCESS) /* Case 2: VMOV.
, # Case 3: VMOV.
, # */ @@ -5358,6 +5402,7 @@ enum operand_parse_code OP_VMOV, /* Neon VMOV operands. */ OP_RNDQ_IMVNb,/* Neon D or Q reg, or immediate good for VMVN. */ OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift. */ + OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2. */ OP_I0, /* immediate zero */ OP_I7, /* immediate value 0 .. 7 */ @@ -5415,6 +5460,7 @@ enum operand_parse_code OP_oRR, /* ARM register */ OP_oRRnpc, /* ARM register, not the PC */ + OP_oRRw, /* ARM register, not r15, optional trailing ! */ OP_oRND, /* Optional Neon double precision register */ OP_oRNQ, /* Optional Neon quad precision register */ OP_oRNDQ, /* Optional Neon double or quad precision register */ @@ -5519,7 +5565,7 @@ parse_operands (char *str, const unsigned char *pattern) backtrack_index = i; } - if (i > 0) + if (i > 0 && (i > 1 || inst.operands[0].present)) po_char_or_fail (','); switch (upat[i]) @@ -5536,7 +5582,13 @@ parse_operands (char *str, const unsigned char *pattern) case OP_RVD: po_reg_or_fail (REG_TYPE_VFD); break; case OP_oRND: case OP_RND: po_reg_or_fail (REG_TYPE_VFD); break; - case OP_RVC: po_reg_or_fail (REG_TYPE_VFC); break; + case OP_RVC: + po_reg_or_goto (REG_TYPE_VFC, coproc_reg); + break; + /* Also accept generic coprocessor regs for unknown registers. */ + coproc_reg: + po_reg_or_fail (REG_TYPE_CN); + break; case OP_RMF: po_reg_or_fail (REG_TYPE_MVF); break; case OP_RMD: po_reg_or_fail (REG_TYPE_MVD); break; case OP_RMFX: po_reg_or_fail (REG_TYPE_MVFX); break; @@ -5566,6 +5618,7 @@ parse_operands (char *str, const unsigned char *pattern) case OP_NILO: { po_reg_or_goto (REG_TYPE_NDQ, try_imm); + inst.operands[i].present = 1; i++; skip_past_comma (&str); po_reg_or_goto (REG_TYPE_NDQ, one_reg_only); @@ -5578,8 +5631,13 @@ parse_operands (char *str, const unsigned char *pattern) inst.operands[i-1].present = 0; break; try_imm: - /* Immediate gets verified properly later, so accept any now. */ - po_imm_or_fail (INT_MIN, INT_MAX, TRUE); + /* There's a possibility of getting a 64-bit immediate here, so + we need special handling. */ + if (parse_big_immediate (&str, i) == FAIL) + { + inst.error = _("immediate value is out of range"); + goto failure; + } } break; @@ -5669,6 +5727,7 @@ parse_operands (char *str, const unsigned char *pattern) break; case OP_RRw: + case OP_oRRw: po_reg_or_fail (REG_TYPE_RN); if (skip_past_char (&str, '!') == SUCCESS) inst.operands[i].writeback = 1; @@ -5779,6 +5838,9 @@ parse_operands (char *str, const unsigned char *pattern) inst.operands[i].isreg = 1; break; + case OP_RIWR_I32z: po_reg_or_goto (REG_TYPE_MMXWR, I32z); break; + I32z: po_imm_or_fail (0, 32, FALSE); break; + /* Two kinds of register */ case OP_RIWR_RIWC: { @@ -5953,6 +6015,7 @@ parse_operands (char *str, const unsigned char *pattern) case OP_RRnpc: case OP_RRnpcb: case OP_RRw: + case OP_oRRw: case OP_RRnpc_I0: if (inst.operands[i].isreg && inst.operands[i].reg == REG_PC) inst.error = BAD_PC; @@ -6783,7 +6846,11 @@ static void do_cpsi (void) { inst.instruction |= inst.operands[0].imm << 6; - inst.instruction |= inst.operands[1].imm; + if (inst.operands[1].present) + { + inst.instruction |= CPSI_MMOD; + inst.instruction |= inst.operands[1].imm; + } } static void @@ -7001,17 +7068,16 @@ do_lstc (void) static void do_mlas (void) { - /* This restriction does not apply to mls (nor to mla in v6, but - that's hard to detect at present). */ + /* This restriction does not apply to mls (nor to mla in v6 or later). */ if (inst.operands[0].reg == inst.operands[1].reg + && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6) && !(inst.instruction & 0x00400000)) - as_tsktsk (_("rd and rm should be different in mla")); + as_tsktsk (_("Rd and Rm should be different in mla")); inst.instruction |= inst.operands[0].reg << 16; inst.instruction |= inst.operands[1].reg; inst.instruction |= inst.operands[2].reg << 8; inst.instruction |= inst.operands[3].reg << 12; - } static void @@ -7119,8 +7185,9 @@ do_mul (void) inst.instruction |= inst.operands[1].reg; inst.instruction |= inst.operands[2].reg << 8; - if (inst.operands[0].reg == inst.operands[1].reg) - as_tsktsk (_("rd and rm should be different in mul")); + if (inst.operands[0].reg == inst.operands[1].reg + && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)) + as_tsktsk (_("Rd and Rm should be different in mul")); } /* Long Multiply Parser @@ -7386,13 +7453,25 @@ do_smul (void) inst.instruction |= inst.operands[2].reg << 8; } -/* ARM V6 srs (argument parse). */ +/* ARM V6 srs (argument parse). The variable fields in the encoding are + the same for both ARM and Thumb-2. */ static void do_srs (void) { - inst.instruction |= inst.operands[0].imm; - if (inst.operands[0].writeback) + int reg; + + if (inst.operands[0].present) + { + reg = inst.operands[0].reg; + constraint (reg != 13, _("SRS base register must be r13")); + } + else + reg = 13; + + inst.instruction |= reg << 16; + inst.instruction |= inst.operands[1].imm; + if (inst.operands[0].writeback || inst.operands[1].writeback) inst.instruction |= WRITE_BACK; } @@ -7680,16 +7759,16 @@ static void do_vfp_sp_const (void) { encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd); - inst.instruction |= (inst.operands[1].imm & 15) << 16; - inst.instruction |= (inst.operands[1].imm >> 4); + inst.instruction |= (inst.operands[1].imm & 0xf0) << 12; + inst.instruction |= (inst.operands[1].imm & 0x0f); } static void do_vfp_dp_const (void) { encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd); - inst.instruction |= (inst.operands[1].imm & 15) << 16; - inst.instruction |= (inst.operands[1].imm >> 4); + inst.instruction |= (inst.operands[1].imm & 0xf0) << 12; + inst.instruction |= (inst.operands[1].imm & 0x0f); } static void @@ -7826,6 +7905,15 @@ do_iwmmxt_waligni (void) inst.instruction |= inst.operands[3].imm << 20; } +static void +do_iwmmxt_wmerge (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + inst.instruction |= inst.operands[3].imm << 21; +} + static void do_iwmmxt_wmov (void) { @@ -7865,7 +7953,23 @@ static void do_iwmmxt_wldstd (void) { inst.instruction |= inst.operands[0].reg << 12; - encode_arm_cp_address (1, TRUE, FALSE, 0); + if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2) + && inst.operands[1].immisreg) + { + inst.instruction &= ~0x1a000ff; + inst.instruction |= (0xf << 28); + if (inst.operands[1].preind) + inst.instruction |= PRE_INDEX; + if (!inst.operands[1].negative) + inst.instruction |= INDEX_UP; + if (inst.operands[1].writeback) + inst.instruction |= WRITE_BACK; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.reloc.exp.X_add_number << 4; + inst.instruction |= inst.operands[1].imm; + } + else + encode_arm_cp_address (1, TRUE, FALSE, 0); } static void @@ -7885,6 +7989,56 @@ do_iwmmxt_wzero (void) inst.instruction |= inst.operands[0].reg << 12; inst.instruction |= inst.operands[0].reg << 16; } + +static void +do_iwmmxt_wrwrwr_or_imm5 (void) +{ + if (inst.operands[2].isreg) + do_rd_rn_rm (); + else { + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2), + _("immediate operand requires iWMMXt2")); + do_rd_rn (); + if (inst.operands[2].imm == 0) + { + switch ((inst.instruction >> 20) & 0xf) + { + case 4: + case 5: + case 6: + case 7: + /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16. */ + inst.operands[2].imm = 16; + inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20); + break; + case 8: + case 9: + case 10: + case 11: + /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32. */ + inst.operands[2].imm = 32; + inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20); + break; + case 12: + case 13: + case 14: + case 15: + { + /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn. */ + unsigned long wrn; + wrn = (inst.instruction >> 16) & 0xf; + inst.instruction &= 0xff0fff0f; + inst.instruction |= wrn; + /* Bail out here; the instruction is now assembled. */ + return; + } + } + } + /* Map 32 -> 0, etc. */ + inst.operands[2].imm &= 0x1f; + inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf); + } +} /* Cirrus Maverick instructions. Simple 2-, 3-, and 4-register operations first, then control, shift, and load/store. */ @@ -8119,7 +8273,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) X(cpsie, b660, f3af8400), \ X(cpsid, b670, f3af8600), \ X(cpy, 4600, ea4f0000), \ - X(dec_sp,80dd, f1bd0d00), \ + X(dec_sp,80dd, f1ad0d00), \ X(eor, 4040, ea800000), \ X(eors, 4040, ea900000), \ X(inc_sp,00dd, f10d0d00), \ @@ -8273,7 +8427,21 @@ do_t_add_sub (void) if (inst.size_req == 4 || (inst.size_req != 2 && !opcode)) { - if (Rs == REG_PC) + if (Rd == REG_PC) + { + constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs, + _("only SUBS PC, LR, #const allowed")); + constraint (inst.reloc.exp.X_op != O_constant, + _("expression too complex")); + constraint (inst.reloc.exp.X_add_number < 0 + || inst.reloc.exp.X_add_number > 0xff, + _("immediate value out of range")); + inst.instruction = T2_SUBS_PC_LR + | inst.reloc.exp.X_add_number; + inst.reloc.type = BFD_RELOC_UNUSED; + return; + } + else if (Rs == REG_PC) { /* Always use addw/subw. */ inst.instruction = add ? 0xf20f0000 : 0xf2af0000; @@ -8289,8 +8457,8 @@ do_t_add_sub (void) else inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM; } - inst.instruction |= inst.operands[0].reg << 8; - inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= Rd << 8; + inst.instruction |= Rs << 16; } } else @@ -8856,7 +9024,7 @@ do_t_cpy (void) } static void -do_t_czb (void) +do_t_cbz (void) { constraint (current_it_mask, BAD_NOT_IT); constraint (inst.operands[0].reg > 7, BAD_HIREG); @@ -8920,6 +9088,68 @@ do_t_it (void) inst.instruction |= cond << 4; } +/* Helper function used for both push/pop and ldm/stm. */ +static void +encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback) +{ + bfd_boolean load; + + load = (inst.instruction & (1 << 20)) != 0; + + if (mask & (1 << 13)) + inst.error = _("SP not allowed in register list"); + if (load) + { + if (mask & (1 << 14) + && mask & (1 << 15)) + inst.error = _("LR and PC should not both be in register list"); + + if ((mask & (1 << base)) != 0 + && writeback) + as_warn (_("base register should not be in register list " + "when written back")); + } + else + { + if (mask & (1 << 15)) + inst.error = _("PC not allowed in register list"); + + if (mask & (1 << base)) + as_warn (_("value stored for r%d is UNPREDICTABLE"), base); + } + + if ((mask & (mask - 1)) == 0) + { + /* Single register transfers implemented as str/ldr. */ + if (writeback) + { + if (inst.instruction & (1 << 23)) + inst.instruction = 0x00000b04; /* ia! -> [base], #4 */ + else + inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */ + } + else + { + if (inst.instruction & (1 << 23)) + inst.instruction = 0x00800000; /* ia -> [base] */ + else + inst.instruction = 0x00000c04; /* db -> [base, #-4] */ + } + + inst.instruction |= 0xf8400000; + if (load) + inst.instruction |= 0x00100000; + + mask = ffs(mask) - 1; + mask <<= 12; + } + else if (writeback) + inst.instruction |= WRITE_BACK; + + inst.instruction |= mask; + inst.instruction |= base << 16; +} + static void do_t_ldmstm (void) { @@ -8931,60 +9161,60 @@ do_t_ldmstm (void) if (unified_syntax) { + bfd_boolean narrow; + unsigned mask; + + narrow = FALSE; /* See if we can use a 16-bit instruction. */ if (inst.instruction < 0xffff /* not ldmdb/stmdb */ && inst.size_req != 4 - && inst.operands[0].reg <= 7 - && !(inst.operands[1].imm & ~0xff) - && (inst.instruction == T_MNEM_stmia - ? inst.operands[0].writeback - : (inst.operands[0].writeback - == !(inst.operands[1].imm & (1 << inst.operands[0].reg))))) + && !(inst.operands[1].imm & ~0xff)) { - if (inst.instruction == T_MNEM_stmia - && (inst.operands[1].imm & (1 << inst.operands[0].reg)) - && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1))) - as_warn (_("value stored for r%d is UNPREDICTABLE"), - inst.operands[0].reg); + mask = 1 << inst.operands[0].reg; - inst.instruction = THUMB_OP16 (inst.instruction); - inst.instruction |= inst.operands[0].reg << 8; - inst.instruction |= inst.operands[1].imm; - } - else - { - if (inst.operands[1].imm & (1 << 13)) - as_warn (_("SP should not be in register list")); - if (inst.instruction == T_MNEM_stmia) + if (inst.operands[0].reg <= 7 + && (inst.instruction == T_MNEM_stmia + ? inst.operands[0].writeback + : (inst.operands[0].writeback + == !(inst.operands[1].imm & mask)))) { - if (inst.operands[1].imm & (1 << 15)) - as_warn (_("PC should not be in register list")); - if (inst.operands[1].imm & (1 << inst.operands[0].reg)) + if (inst.instruction == T_MNEM_stmia + && (inst.operands[1].imm & mask) + && (inst.operands[1].imm & (mask - 1))) as_warn (_("value stored for r%d is UNPREDICTABLE"), inst.operands[0].reg); + + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm; + narrow = TRUE; } - else + else if (inst.operands[0] .reg == REG_SP + && inst.operands[0].writeback) { - if (inst.operands[1].imm & (1 << 14) - && inst.operands[1].imm & (1 << 15)) - as_warn (_("LR and PC should not both be in register list")); - if ((inst.operands[1].imm & (1 << inst.operands[0].reg)) - && inst.operands[0].writeback) - as_warn (_("base register should not be in register list " - "when written back")); + inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia + ? T_MNEM_push : T_MNEM_pop); + inst.instruction |= inst.operands[1].imm; + narrow = TRUE; } + } + + if (!narrow) + { if (inst.instruction < 0xffff) inst.instruction = THUMB_OP32 (inst.instruction); - inst.instruction |= inst.operands[0].reg << 16; - inst.instruction |= inst.operands[1].imm; - if (inst.operands[0].writeback) - inst.instruction |= WRITE_BACK; + + encode_thumb2_ldmstm(inst.operands[0].reg, inst.operands[1].imm, + inst.operands[0].writeback); } } else { constraint (inst.operands[0].reg > 7 || (inst.operands[1].imm & ~0xff), BAD_HIREG); + constraint (inst.instruction != T_MNEM_ldmia + && inst.instruction != T_MNEM_stmia, + _("Thumb-2 instruction only valid in unified syntax")); if (inst.instruction == T_MNEM_stmia) { if (!inst.operands[0].writeback) @@ -9258,6 +9488,16 @@ do_t_mov_cmp (void) || inst.operands[1].shifted) narrow = FALSE; + /* MOVS PC, LR is encoded as SUBS PC, LR, #0. */ + if (opcode == T_MNEM_movs && inst.operands[1].isreg + && !inst.operands[1].shifted + && inst.operands[0].reg == REG_PC + && inst.operands[1].reg == REG_LR) + { + inst.instruction = T2_SUBS_PC_LR; + return; + } + if (!inst.operands[1].isreg) { /* Immediate operand. */ @@ -9280,11 +9520,98 @@ do_t_mov_cmp (void) inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; } } + else if (inst.operands[1].shifted && inst.operands[1].immisreg + && (inst.instruction == T_MNEM_mov + || inst.instruction == T_MNEM_movs)) + { + /* Register shifts are encoded as separate shift instructions. */ + bfd_boolean flags = (inst.instruction == T_MNEM_movs); + + if (current_it_mask) + narrow = !flags; + else + narrow = flags; + + if (inst.size_req == 4) + narrow = FALSE; + + if (!low_regs || inst.operands[1].imm > 7) + narrow = FALSE; + + if (inst.operands[0].reg != inst.operands[1].reg) + narrow = FALSE; + + switch (inst.operands[1].shift_kind) + { + case SHIFT_LSL: + opcode = narrow ? T_OPCODE_LSL_R : THUMB_OP32 (T_MNEM_lsl); + break; + case SHIFT_ASR: + opcode = narrow ? T_OPCODE_ASR_R : THUMB_OP32 (T_MNEM_asr); + break; + case SHIFT_LSR: + opcode = narrow ? T_OPCODE_LSR_R : THUMB_OP32 (T_MNEM_lsr); + break; + case SHIFT_ROR: + opcode = narrow ? T_OPCODE_ROR_R : THUMB_OP32 (T_MNEM_ror); + break; + default: + abort(); + } + + inst.instruction = opcode; + if (narrow) + { + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].imm << 3; + } + else + { + if (flags) + inst.instruction |= CONDS_BIT; + + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[1].imm; + } + } else if (!narrow) { - inst.instruction = THUMB_OP32 (inst.instruction); - inst.instruction |= inst.operands[0].reg << r0off; - encode_thumb32_shifted_operand (1); + /* Some mov with immediate shift have narrow variants. + Register shifts are handled above. */ + if (low_regs && inst.operands[1].shifted + && (inst.instruction == T_MNEM_mov + || inst.instruction == T_MNEM_movs)) + { + if (current_it_mask) + narrow = (inst.instruction == T_MNEM_mov); + else + narrow = (inst.instruction == T_MNEM_movs); + } + + if (narrow) + { + switch (inst.operands[1].shift_kind) + { + case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break; + case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break; + case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break; + default: narrow = FALSE; break; + } + } + + if (narrow) + { + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT; + } + else + { + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << r0off; + encode_thumb32_shifted_operand (1); + } } else switch (inst.instruction) @@ -9664,7 +9991,7 @@ do_t_push_pop (void) mask = inst.operands[0].imm; if ((mask & ~0xff) == 0) - inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction = THUMB_OP16 (inst.instruction) | mask; else if ((inst.instruction == T_MNEM_push && (mask & ~0xff) == 1 << REG_LR) || (inst.instruction == T_MNEM_pop @@ -9672,43 +9999,18 @@ do_t_push_pop (void) { inst.instruction = THUMB_OP16 (inst.instruction); inst.instruction |= THUMB_PP_PC_LR; - mask &= 0xff; + inst.instruction |= mask & 0xff; } else if (unified_syntax) { - if (mask & (1 << 13)) - inst.error = _("SP not allowed in register list"); - if (inst.instruction == T_MNEM_push) - { - if (mask & (1 << 15)) - inst.error = _("PC not allowed in register list"); - } - else - { - if (mask & (1 << 14) - && mask & (1 << 15)) - inst.error = _("LR and PC should not both be in register list"); - } - if ((mask & (mask - 1)) == 0) - { - /* Single register push/pop implemented as str/ldr. */ - if (inst.instruction == T_MNEM_push) - inst.instruction = 0xf84d0d04; /* str reg, [sp, #-4]! */ - else - inst.instruction = 0xf85d0b04; /* ldr reg, [sp], #4 */ - mask = ffs(mask) - 1; - mask <<= 12; - } - else - inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction = THUMB_OP32 (inst.instruction); + encode_thumb2_ldmstm(13, mask, TRUE); } else { inst.error = _("invalid register list to push/pop instruction"); return; } - - inst.instruction |= mask; } static void @@ -9753,8 +10055,37 @@ do_t_rsb (void) inst.instruction |= Rs << 16; if (!inst.operands[2].isreg) { - inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; - inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + bfd_boolean narrow; + + if ((inst.instruction & 0x00100000) != 0) + narrow = (current_it_mask == 0); + else + narrow = (current_it_mask != 0); + + if (Rd > 7 || Rs > 7) + narrow = FALSE; + + if (inst.size_req == 4 || !unified_syntax) + narrow = FALSE; + + if (inst.reloc.exp.X_op != O_constant + || inst.reloc.exp.X_add_number != 0) + narrow = FALSE; + + /* Turn rsb #0 into 16-bit neg. We should probably do this via + relaxation, but it doesn't seem worth the hassle. */ + if (narrow) + { + inst.reloc.type = BFD_RELOC_UNUSED; + inst.instruction = THUMB_OP16 (T_MNEM_negs); + inst.instruction |= Rs << 3; + inst.instruction |= Rd; + } + else + { + inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; + inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + } } else encode_thumb32_shifted_operand (2); @@ -10102,8 +10433,8 @@ struct neon_tab_entry X(vcgt, 0x0000300, 0x1200e00, 0x1b10000), \ /* Register variants of the following two instructions are encoded as vcge / vcgt with the operands reversed. */ \ - X(vclt, 0x0000310, 0x1000e00, 0x1b10200), \ - X(vcle, 0x0000300, 0x1200e00, 0x1b10180), \ + X(vclt, 0x0000300, 0x1200e00, 0x1b10200), \ + X(vcle, 0x0000310, 0x1000e00, 0x1b10180), \ X(vmla, 0x0000900, 0x0000d10, 0x0800040), \ X(vmls, 0x1000900, 0x0200d10, 0x0800440), \ X(vmul, 0x0000910, 0x1000d10, 0x0800840), \ @@ -11132,9 +11463,9 @@ do_vfp_nsyn_pop (void) { nsyn_insert_sp (); if (inst.operands[1].issingle) - do_vfp_nsyn_opcode ("fldmdbs"); + do_vfp_nsyn_opcode ("fldmias"); else - do_vfp_nsyn_opcode ("fldmdbd"); + do_vfp_nsyn_opcode ("fldmiad"); } /* Fix up Neon data-processing instructions, ORing in the correct bits for @@ -11273,6 +11604,18 @@ do_neon_shl_imm (void) enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL); struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN); + unsigned int tmp; + + /* VSHL/VQSHL 3-register variants have syntax such as: + vshl.xx Dd, Dm, Dn + whereas other 3-register operations encoded by neon_three_same have + syntax like: + vadd.xx Dd, Dn, Dm + (i.e. with Dn & Dm reversed). Swap operands[1].reg and operands[2].reg + here. */ + tmp = inst.operands[2].reg; + inst.operands[2].reg = inst.operands[1].reg; + inst.operands[1].reg = tmp; inst.instruction = NEON_ENC_INTEGER (inst.instruction); neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size); } @@ -11285,6 +11628,7 @@ do_neon_qshl_imm (void) { enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL); struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY); + inst.instruction = NEON_ENC_IMMED (inst.instruction); neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et, inst.operands[2].imm); @@ -11294,53 +11638,80 @@ do_neon_qshl_imm (void) enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL); struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN); + unsigned int tmp; + + /* See note in do_neon_shl_imm. */ + tmp = inst.operands[2].reg; + inst.operands[2].reg = inst.operands[1].reg; + inst.operands[1].reg = tmp; inst.instruction = NEON_ENC_INTEGER (inst.instruction); neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size); } } +static void +do_neon_rshl (void) +{ + enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL); + struct neon_type_el et = neon_check_type (3, rs, + N_EQK, N_EQK, N_SU_ALL | N_KEY); + unsigned int tmp; + + tmp = inst.operands[2].reg; + inst.operands[2].reg = inst.operands[1].reg; + inst.operands[1].reg = tmp; + neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size); +} + static int neon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size) { - /* Handle .I8 and .I64 as pseudo-instructions. */ - switch (size) + /* Handle .I8 pseudo-instructions. */ + if (size == 8) { - case 8: /* Unfortunately, this will make everything apart from zero out-of-range. FIXME is this the intended semantics? There doesn't seem much point in accepting .I8 if so. */ immediate |= immediate << 8; size = 16; - break; - case 64: - /* Similarly, anything other than zero will be replicated in bits [63:32], - which probably isn't want we want if we specified .I64. */ - if (immediate != 0) - goto bad_immediate; - size = 32; - break; - default: ; + } + + if (size >= 32) + { + if (immediate == (immediate & 0x000000ff)) + { + *immbits = immediate; + return 0x1; + } + else if (immediate == (immediate & 0x0000ff00)) + { + *immbits = immediate >> 8; + return 0x3; + } + else if (immediate == (immediate & 0x00ff0000)) + { + *immbits = immediate >> 16; + return 0x5; + } + else if (immediate == (immediate & 0xff000000)) + { + *immbits = immediate >> 24; + return 0x7; + } + if ((immediate & 0xffff) != (immediate >> 16)) + goto bad_immediate; + immediate &= 0xffff; } if (immediate == (immediate & 0x000000ff)) { *immbits = immediate; - return (size == 16) ? 0x9 : 0x1; + return 0x9; } else if (immediate == (immediate & 0x0000ff00)) { *immbits = immediate >> 8; - return (size == 16) ? 0xb : 0x3; - } - else if (immediate == (immediate & 0x00ff0000)) - { - *immbits = immediate >> 16; - return 0x5; - } - else if (immediate == (immediate & 0xff000000)) - { - *immbits = immediate >> 24; - return 0x7; + return 0xb; } bad_immediate: @@ -11381,12 +11752,19 @@ neon_qfloat_bits (unsigned imm) the instruction. *OP is passed as the initial value of the op field, and may be set to a different value depending on the constant (i.e. "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not - MVN). */ + MVN). If the immediate looks like a repeated parttern then also + try smaller element sizes. */ static int -neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, unsigned *immbits, - int *op, int size, enum neon_el_type type) +neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p, + unsigned *immbits, int *op, int size, + enum neon_el_type type) { + /* Only permit float immediates (including 0.0/-0.0) if the operand type is + float. */ + if (type == NT_float && !float_p) + return FAIL; + if (type == NT_float && is_quarter_float (immlo) && immhi == 0) { if (size != 32 || *op == 1) @@ -11394,63 +11772,87 @@ neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, unsigned *immbits, *immbits = neon_qfloat_bits (immlo); return 0xf; } - else if (size == 64 && neon_bits_same_in_bytes (immhi) - && neon_bits_same_in_bytes (immlo)) - { - /* Check this one first so we don't have to bother with immhi in later - tests. */ - if (*op == 1) - return FAIL; - *immbits = (neon_squash_bits (immhi) << 4) | neon_squash_bits (immlo); - *op = 1; - return 0xe; - } - else if (immhi != 0) - return FAIL; - else if (immlo == (immlo & 0x000000ff)) - { - /* 64-bit case was already handled. Don't allow MVN with 8-bit - immediate. */ - if ((size != 8 && size != 16 && size != 32) - || (size == 8 && *op == 1)) - return FAIL; - *immbits = immlo; - return (size == 8) ? 0xe : (size == 16) ? 0x8 : 0x0; - } - else if (immlo == (immlo & 0x0000ff00)) - { - if (size != 16 && size != 32) - return FAIL; - *immbits = immlo >> 8; - return (size == 16) ? 0xa : 0x2; - } - else if (immlo == (immlo & 0x00ff0000)) + + if (size == 64) { - if (size != 32) - return FAIL; - *immbits = immlo >> 16; - return 0x4; + if (neon_bits_same_in_bytes (immhi) + && neon_bits_same_in_bytes (immlo)) + { + if (*op == 1) + return FAIL; + *immbits = (neon_squash_bits (immhi) << 4) + | neon_squash_bits (immlo); + *op = 1; + return 0xe; + } + + if (immhi != immlo) + return FAIL; } - else if (immlo == (immlo & 0xff000000)) + + if (size >= 32) { - if (size != 32) - return FAIL; - *immbits = immlo >> 24; - return 0x6; + if (immlo == (immlo & 0x000000ff)) + { + *immbits = immlo; + return 0x0; + } + else if (immlo == (immlo & 0x0000ff00)) + { + *immbits = immlo >> 8; + return 0x2; + } + else if (immlo == (immlo & 0x00ff0000)) + { + *immbits = immlo >> 16; + return 0x4; + } + else if (immlo == (immlo & 0xff000000)) + { + *immbits = immlo >> 24; + return 0x6; + } + else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff)) + { + *immbits = (immlo >> 8) & 0xff; + return 0xc; + } + else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff)) + { + *immbits = (immlo >> 16) & 0xff; + return 0xd; + } + + if ((immlo & 0xffff) != (immlo >> 16)) + return FAIL; + immlo &= 0xffff; } - else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff)) + + if (size >= 16) { - if (size != 32) - return FAIL; - *immbits = (immlo >> 8) & 0xff; - return 0xc; + if (immlo == (immlo & 0x000000ff)) + { + *immbits = immlo; + return 0x8; + } + else if (immlo == (immlo & 0x0000ff00)) + { + *immbits = immlo >> 8; + return 0xa; + } + + if ((immlo & 0xff) != (immlo >> 8)) + return FAIL; + immlo &= 0xff; } - else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff)) + + if (immlo == (immlo & 0x000000ff)) { - if (size != 32) - return FAIL; - *immbits = (immlo >> 16) & 0xff; - return 0xd; + /* Don't allow MVN with 8-bit immediate. */ + if (*op == 1) + return FAIL; + *immbits = immlo; + return 0xe; } return FAIL; @@ -11533,28 +11935,37 @@ do_neon_logic (void) inst.instruction = NEON_ENC_IMMED (inst.instruction); + immbits = inst.operands[1].imm; + if (et.size == 64) + { + /* .i64 is a pseudo-op, so the immediate must be a repeating + pattern. */ + if (immbits != (inst.operands[1].regisimm ? + inst.operands[1].reg : 0)) + { + /* Set immbits to an invalid constant. */ + immbits = 0xdeadbeef; + } + } + switch (opcode) { case N_MNEM_vbic: - cmode = neon_cmode_for_logic_imm (inst.operands[1].imm, &immbits, - et.size); + cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size); break; case N_MNEM_vorr: - cmode = neon_cmode_for_logic_imm (inst.operands[1].imm, &immbits, - et.size); + cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size); break; case N_MNEM_vand: /* Pseudo-instruction for VBIC. */ - immbits = inst.operands[1].imm; neon_invert_size (&immbits, 0, et.size); cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size); break; case N_MNEM_vorn: /* Pseudo-instruction for VORR. */ - immbits = inst.operands[1].imm; neon_invert_size (&immbits, 0, et.size); cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size); break; @@ -12349,7 +12760,7 @@ neon_move_immediate (void) struct neon_type_el et = neon_check_type (2, rs, N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK); unsigned immlo, immhi = 0, immbits; - int op, cmode; + int op, cmode, float_p; constraint (et.type == NT_invtype, _("operand size must be specified for immediate VMOV")); @@ -12364,7 +12775,9 @@ neon_move_immediate (void) constraint (et.size < 32 && (immlo & ~((1 << et.size) - 1)) != 0, _("immediate has bits set outside the operand size")); - if ((cmode = neon_cmode_for_move_imm (immlo, immhi, &immbits, &op, + float_p = inst.operands[1].immisfloat; + + if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits, &op, et.size, et.type)) == FAIL) { /* Invert relevant bits only. */ @@ -12373,8 +12786,8 @@ neon_move_immediate (void) with one or the other; those cases are caught by neon_cmode_for_move_imm. */ op = !op; - if ((cmode = neon_cmode_for_move_imm (immlo, immhi, &immbits, &op, - et.size, et.type)) == FAIL) + if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits, + &op, et.size, et.type)) == FAIL) { first_error (_("immediate out of range")); return; @@ -12530,6 +12943,7 @@ do_neon_ext (void) struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY); unsigned imm = (inst.operands[3].imm * et.size) / 8; + constraint (imm >= (neon_quad (rs) ? 16 : 8), _("shift out of range")); inst.instruction |= LOW4 (inst.operands[0].reg) << 12; inst.instruction |= HI1 (inst.operands[0].reg) << 22; inst.instruction |= LOW4 (inst.operands[1].reg) << 16; @@ -13795,6 +14209,14 @@ md_assemble (char *str) return; } + if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2) && !inst.size_req) + { + /* Implicit require narrow instructions on Thumb-1. This avoids + relaxation accidentally introducing Thumb-2 instructions. */ + if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23) + inst.size_req = 2; + } + /* Check conditional suffixes. */ if (current_it_mask) { @@ -13836,6 +14258,11 @@ md_assemble (char *str) return; } } + + /* Something has gone badly wrong if we try to relax a fixed size + instruction. */ + assert (inst.size_req == 0 || !inst.relax); + ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, *opcode->tvariant); /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly @@ -14055,6 +14482,10 @@ static const struct reg_entry reg_names[] = /* VFP control registers. */ REGDEF(fpsid,0,VFC), REGDEF(fpscr,1,VFC), REGDEF(fpexc,8,VFC), REGDEF(FPSID,0,VFC), REGDEF(FPSCR,1,VFC), REGDEF(FPEXC,8,VFC), + REGDEF(fpinst,9,VFC), REGDEF(fpinst2,10,VFC), + REGDEF(FPINST,9,VFC), REGDEF(FPINST2,10,VFC), + REGDEF(mvfr0,7,VFC), REGDEF(mvfr1,6,VFC), + REGDEF(MVFR0,7,VFC), REGDEF(MVFR1,6,VFC), /* Maverick DSP coprocessor registers. */ REGSET(mvf,MVF), REGSET(mvd,MVD), REGSET(mvfx,MVFX), REGSET(mvdx,MVDX), @@ -14171,20 +14602,21 @@ static const struct asm_psr psrs[] = /* Table of V7M psr names. */ static const struct asm_psr v7m_psrs[] = { - {"apsr", 0 }, - {"iapsr", 1 }, - {"eapsr", 2 }, - {"psr", 3 }, - {"ipsr", 5 }, - {"epsr", 6 }, - {"iepsr", 7 }, - {"msp", 8 }, - {"psp", 9 }, - {"primask", 16}, - {"basepri", 17}, - {"basepri_max", 18}, - {"faultmask", 19}, - {"control", 20} + {"apsr", 0 }, {"APSR", 0 }, + {"iapsr", 1 }, {"IAPSR", 1 }, + {"eapsr", 2 }, {"EAPSR", 2 }, + {"psr", 3 }, {"PSR", 3 }, + {"xpsr", 3 }, {"XPSR", 3 }, {"xPSR", 3 }, + {"ipsr", 5 }, {"IPSR", 5 }, + {"epsr", 6 }, {"EPSR", 6 }, + {"iepsr", 7 }, {"IEPSR", 7 }, + {"msp", 8 }, {"MSP", 8 }, + {"psp", 9 }, {"PSP", 9 }, + {"primask", 16}, {"PRIMASK", 16}, + {"basepri", 17}, {"BASEPRI", 17}, + {"basepri_max", 18}, {"BASEPRI_MAX", 18}, + {"faultmask", 19}, {"FAULTMASK", 19}, + {"control", 20}, {"CONTROL", 20} }; /* Table of all shift-in-operand names. */ @@ -14512,6 +14944,10 @@ static const struct asm_opcode insns[] = tCE(push, 92d0000, push, 1, (REGLST), push_pop, t_push_pop), tCE(pop, 8bd0000, pop, 1, (REGLST), push_pop, t_push_pop), + /* These may simplify to neg. */ + TCE(rsb, 0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb), + TC3(rsbs, 0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb), + #undef THUMB_VARIANT #define THUMB_VARIANT &arm_ext_v6 TCE(cpy, 1a00000, 4600, 2, (RR, RR), rd_rm, t_cpy), @@ -14519,8 +14955,6 @@ static const struct asm_opcode insns[] = /* V1 instructions with no Thumb analogue prior to V6T2. */ #undef THUMB_VARIANT #define THUMB_VARIANT &arm_ext_v6t2 - TCE(rsb, 0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb), - TC3(rsbs, 0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb), TCE(teq, 1300000, ea900f00, 2, (RR, SH), cmp, t_mvn_tst), TC3w(teqs, 1300000, ea900f00, 2, (RR, SH), cmp, t_mvn_tst), CL(teqp, 130f000, 2, (RR, SH), cmp), @@ -14660,8 +15094,8 @@ static const struct asm_opcode insns[] = #undef ARM_VARIANT #define ARM_VARIANT &arm_ext_v5e /* ARM Architecture 5TE. */ TUF(pld, 450f000, f810f000, 1, (ADDR), pld, t_pld), - TC3(ldrd, 00000d0, e9500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd), - TC3(strd, 00000f0, e9400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd), + TC3(ldrd, 00000d0, e8500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd), + TC3(strd, 00000f0, e8400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd), TCE(mcrr, c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), TCE(mrrc, c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), @@ -14688,6 +15122,7 @@ static const struct asm_opcode insns[] = #undef THUMB_VARIANT #define THUMB_VARIANT &arm_ext_v6t2 TCE(ldrex, 1900f9f, e8500f00, 2, (RRnpc, ADDR), ldrex, t_ldrex), + TCE(strex, 1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR), strex, t_strex), TUF(mcrr2, c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), TUF(mrrc2, c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), @@ -14771,12 +15206,11 @@ static const struct asm_opcode insns[] = TCE(smuadx, 700f030, fb20f010, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), TCE(smusd, 700f050, fb40f000, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), TCE(smusdx, 700f070, fb40f010, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), - TUF(srsia, 8cd0500, e980c000, 1, (I31w), srs, srs), - UF(srsib, 9cd0500, 1, (I31w), srs), - UF(srsda, 84d0500, 1, (I31w), srs), - TUF(srsdb, 94d0500, e800c000, 1, (I31w), srs, srs), + TUF(srsia, 8c00500, e980c000, 2, (oRRw, I31w), srs, srs), + UF(srsib, 9c00500, 2, (oRRw, I31w), srs), + UF(srsda, 8400500, 2, (oRRw, I31w), srs), + TUF(srsdb, 9400500, e800c000, 2, (oRRw, I31w), srs, srs), TCE(ssat16, 6a00f30, f3200000, 3, (RRnpc, I16, RRnpc), ssat16, t_ssat16), - TCE(strex, 1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR), strex, t_strex), TCE(umaal, 0400090, fbe00060, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal, t_mlal), TCE(usad8, 780f010, fb70f000, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), TCE(usada8, 7800010, fb700000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), @@ -14825,9 +15259,11 @@ static const struct asm_opcode insns[] = TC3(ldrsbt, 03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt), TC3(strht, 02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt), - UT(cbnz, b900, 2, (RR, EXP), t_czb), - UT(cbz, b100, 2, (RR, EXP), t_czb), - /* ARM does not really have an IT instruction. */ + UT(cbnz, b900, 2, (RR, EXP), t_cbz), + UT(cbz, b100, 2, (RR, EXP), t_cbz), + /* ARM does not really have an IT instruction, so always allow it. */ +#undef ARM_VARIANT +#define ARM_VARIANT &arm_ext_v1 TUE(it, 0, bf08, 1, (COND), it, t_it), TUE(itt, 0, bf0c, 1, (COND), it, t_it), TUE(ite, 0, bf04, 1, (COND), it, t_it), @@ -15490,10 +15926,10 @@ static const struct asm_opcode insns[] = NUF(vqaddq, 0000010, 3, (RNQ, oRNQ, RNQ), neon_dyadic_i64_su), NUF(vqsub, 0000210, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su), NUF(vqsubq, 0000210, 3, (RNQ, oRNQ, RNQ), neon_dyadic_i64_su), - NUF(vrshl, 0000500, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su), - NUF(vrshlq, 0000500, 3, (RNQ, oRNQ, RNQ), neon_dyadic_i64_su), - NUF(vqrshl, 0000510, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su), - NUF(vqrshlq, 0000510, 3, (RNQ, oRNQ, RNQ), neon_dyadic_i64_su), + NUF(vrshl, 0000500, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl), + NUF(vrshlq, 0000500, 3, (RNQ, oRNQ, RNQ), neon_rshl), + NUF(vqrshl, 0000510, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl), + NUF(vqrshlq, 0000510, 3, (RNQ, oRNQ, RNQ), neon_rshl), /* If not immediate, fall back to neon_dyadic_i64_su. shl_imm should accept I8 I16 I32 I64, qshl_imm should accept S8 S16 S32 S64 U8 U16 U32 U64. */ @@ -15563,10 +15999,10 @@ static const struct asm_opcode insns[] = NUF(vacgeq, 0000e10, 3, (RNQ, oRNQ, RNQ), neon_fcmp_absolute), NUF(vacgt, 0200e10, 3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute), NUF(vacgtq, 0200e10, 3, (RNQ, oRNQ, RNQ), neon_fcmp_absolute), - NUF(vaclt, 0000e10, 3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv), - NUF(vacltq, 0000e10, 3, (RNQ, oRNQ, RNQ), neon_fcmp_absolute_inv), - NUF(vacle, 0200e10, 3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv), - NUF(vacleq, 0200e10, 3, (RNQ, oRNQ, RNQ), neon_fcmp_absolute_inv), + NUF(vaclt, 0200e10, 3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv), + NUF(vacltq, 0200e10, 3, (RNQ, oRNQ, RNQ), neon_fcmp_absolute_inv), + NUF(vacle, 0000e10, 3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv), + NUF(vacleq, 0000e10, 3, (RNQ, oRNQ, RNQ), neon_fcmp_absolute_inv), NUF(vrecps, 0000f10, 3, (RNDQ, oRNDQ, RNDQ), neon_step), NUF(vrecpsq, 0000f10, 3, (RNQ, oRNQ, RNQ), neon_step), NUF(vrsqrts, 0200f10, 3, (RNDQ, oRNDQ, RNDQ), neon_step), @@ -15640,8 +16076,8 @@ static const struct asm_opcode insns[] = nUF(vmull, vmull, 3, (RNQ, RND, RND_RNSC), neon_vmull), /* Extract. Size 8. */ - NUF(vext, 0b00000, 4, (RNDQ, oRNDQ, RNDQ, I7), neon_ext), - NUF(vextq, 0b00000, 4, (RNQ, oRNQ, RNQ, I7), neon_ext), + NUF(vext, 0b00000, 4, (RNDQ, oRNDQ, RNDQ, I15), neon_ext), + NUF(vextq, 0b00000, 4, (RNQ, oRNQ, RNQ, I15), neon_ext), /* Two registers, miscellaneous. */ /* Reverse. Sizes 8 16 32 (must be < size in opcode). */ @@ -15853,34 +16289,34 @@ static const struct asm_opcode insns[] = cCE(wpackwus, e900080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wpackdss, ef00080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wpackdus, ed00080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), - cCE(wrorh, e700040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wrorh, e700040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wrorhg, e700148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wrorw, eb00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wrorw, eb00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wrorwg, eb00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wrord, ef00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wrord, ef00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wrordg, ef00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), cCE(wsadb, e000120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wsadbz, e100120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wsadh, e400120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wsadhz, e500120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wshufh, e0001e0, 3, (RIWR, RIWR, I255), iwmmxt_wshufh), - cCE(wsllh, e500040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsllh, e500040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsllhg, e500148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsllw, e900040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsllw, e900040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsllwg, e900148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wslld, ed00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wslld, ed00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wslldg, ed00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrah, e400040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrah, e400040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrahg, e400148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsraw, e800040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsraw, e800040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrawg, e800148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrad, ec00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrad, ec00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsradg, ec00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrlh, e600040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrlh, e600040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrlhg, e600148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrlw, ea00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrlw, ea00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrlwg, ea00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrld, ee00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrld, ee00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrldg, ee00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), cCE(wstrb, c000000, 2, (RIWR, ADDR), iwmmxt_wldstbh), cCE(wstrh, c400000, 2, (RIWR, ADDR), iwmmxt_wldstbh), @@ -15916,6 +16352,66 @@ static const struct asm_opcode insns[] = cCE(wxor, e100000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wzero, e300000, 1, (RIWR), iwmmxt_wzero), +#undef ARM_VARIANT +#define ARM_VARIANT &arm_cext_iwmmxt2 /* Intel Wireless MMX technology, version 2. */ + cCE(torvscb, e13f190, 1, (RR), iwmmxt_tandorc), + cCE(torvsch, e53f190, 1, (RR), iwmmxt_tandorc), + cCE(torvscw, e93f190, 1, (RR), iwmmxt_tandorc), + cCE(wabsb, e2001c0, 2, (RIWR, RIWR), rd_rn), + cCE(wabsh, e6001c0, 2, (RIWR, RIWR), rd_rn), + cCE(wabsw, ea001c0, 2, (RIWR, RIWR), rd_rn), + cCE(wabsdiffb, e1001c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wabsdiffh, e5001c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wabsdiffw, e9001c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddbhusl, e2001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddbhusm, e6001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddhc, e600180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddwc, ea00180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddsubhx, ea001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wavg4, e400000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wavg4r, e500000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmaddsn, ee00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmaddsx, eb00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmaddun, ec00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmaddux, e900100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmerge, e000080, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_wmerge), + cCE(wmiabb, e0000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiabt, e1000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiatb, e2000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiatt, e3000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiabbn, e4000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiabtn, e5000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiatbn, e6000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiattn, e7000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawbb, e800120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawbt, e900120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawtb, ea00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawtt, eb00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawbbn, ec00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawbtn, ed00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawtbn, ee00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawttn, ef00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulsmr, ef00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulumr, ed00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwumr, ec000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwsmr, ee000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwum, ed000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwsm, ef000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwl, eb000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiabb, e8000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiabt, e9000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiatb, ea000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiatt, eb000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiabbn, ec000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiabtn, ed000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiatbn, ee000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiattn, ef000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmulm, e100080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmulmr, e300080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmulwm, ec000e0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmulwmr, ee000e0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsubaddhx, ed001c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + #undef ARM_VARIANT #define ARM_VARIANT &arm_cext_maverick /* Cirrus Maverick instructions. */ cCE(cfldrs, c100400, 2, (RMF, ADDRGLDC), rd_cpaddr), @@ -16264,16 +16760,66 @@ relax_immediate (fragS *fragp, int size, int shift) offset = fragp->fr_offset; /* Force misaligned offsets to 32-bit variant. */ if (offset & low) - return -4; + return 4; if (offset & ~mask) return 4; return 2; } +/* Get the address of a symbol during relaxation. */ +static addressT +relaxed_symbol_addr(fragS *fragp, long stretch) +{ + fragS *sym_frag; + addressT addr; + symbolS *sym; + + sym = fragp->fr_symbol; + sym_frag = symbol_get_frag (sym); + know (S_GET_SEGMENT (sym) != absolute_section + || sym_frag == &zero_address_frag); + addr = S_GET_VALUE (sym) + fragp->fr_offset; + + /* If frag has yet to be reached on this pass, assume it will + move by STRETCH just as we did. If this is not so, it will + be because some frag between grows, and that will force + another pass. */ + + if (stretch != 0 + && sym_frag->relax_marker != fragp->relax_marker) + { + fragS *f; + + /* Adjust stretch for any alignment frag. Note that if have + been expanding the earlier code, the symbol may be + defined in what appears to be an earlier frag. FIXME: + This doesn't handle the fr_subtype field, which specifies + a maximum number of bytes to skip when doing an + alignment. */ + for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next) + { + if (f->fr_type == rs_align || f->fr_type == rs_align_code) + { + if (stretch < 0) + stretch = - ((- stretch) + & ~ ((1 << (int) f->fr_offset) - 1)); + else + stretch &= ~ ((1 << (int) f->fr_offset) - 1); + if (stretch == 0) + break; + } + } + if (f != NULL) + addr += stretch; + } + + return addr; +} + /* Return the size of a relaxable adr pseudo-instruction or PC-relative load. */ static int -relax_adr (fragS *fragp, asection *sec) +relax_adr (fragS *fragp, asection *sec, long stretch) { addressT addr; offsetT val; @@ -16283,14 +16829,12 @@ relax_adr (fragS *fragp, asection *sec) || sec != S_GET_SEGMENT (fragp->fr_symbol)) return 4; - val = S_GET_VALUE(fragp->fr_symbol) + fragp->fr_offset; + val = relaxed_symbol_addr(fragp, stretch); addr = fragp->fr_address + fragp->fr_fix; addr = (addr + 4) & ~3; - /* Fix the insn as the 4-byte version if the target address is not - sufficiently aligned. This is prevents an infinite loop when two - instructions have contradictory range/alignment requirements. */ + /* Force misaligned targets to 32-bit variant. */ if (val & 3) - return -4; + return 4; val -= addr; if (val < 0 || val > 1020) return 4; @@ -16317,7 +16861,7 @@ relax_addsub (fragS *fragp, asection *sec) size of the offset field in the narrow instruction. */ static int -relax_branch (fragS *fragp, asection *sec, int bits) +relax_branch (fragS *fragp, asection *sec, int bits, long stretch) { addressT addr; offsetT val; @@ -16328,7 +16872,7 @@ relax_branch (fragS *fragp, asection *sec, int bits) || sec != S_GET_SEGMENT (fragp->fr_symbol)) return 4; - val = S_GET_VALUE(fragp->fr_symbol) + fragp->fr_offset; + val = relaxed_symbol_addr(fragp, stretch); addr = fragp->fr_address + fragp->fr_fix + 4; val -= addr; @@ -16344,7 +16888,7 @@ relax_branch (fragS *fragp, asection *sec, int bits) the current size of the frag should change. */ int -arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) +arm_relax_frag (asection *sec, fragS *fragp, long stretch) { int oldsize; int newsize; @@ -16353,7 +16897,7 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) switch (fragp->fr_subtype) { case T_MNEM_ldr_pc2: - newsize = relax_adr(fragp, sec); + newsize = relax_adr(fragp, sec, stretch); break; case T_MNEM_ldr_pc: case T_MNEM_ldr_sp: @@ -16373,7 +16917,7 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) newsize = relax_immediate(fragp, 5, 0); break; case T_MNEM_adr: - newsize = relax_adr(fragp, sec); + newsize = relax_adr(fragp, sec, stretch); break; case T_MNEM_mov: case T_MNEM_movs: @@ -16382,10 +16926,10 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) newsize = relax_immediate(fragp, 8, 0); break; case T_MNEM_b: - newsize = relax_branch(fragp, sec, 11); + newsize = relax_branch(fragp, sec, 11, stretch); break; case T_MNEM_bcond: - newsize = relax_branch(fragp, sec, 8); + newsize = relax_branch(fragp, sec, 8, stretch); break; case T_MNEM_add_sp: case T_MNEM_add_pc: @@ -16404,14 +16948,18 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) default: abort(); } - if (newsize < 0) + + fragp->fr_var = newsize; + /* Freeze wide instructions that are at or before the same location as + in the previous pass. This avoids infinite loops. + Don't freeze them unconditionally because targets may be artificialy + misaligned by the expansion of preceeding frags. */ + if (stretch <= 0 && newsize > 2) { - fragp->fr_var = -newsize; md_convert_frag (sec->owner, sec, fragp); frag_wane(fragp); - return -(newsize + oldsize); } - fragp->fr_var = newsize; + return newsize - oldsize; } @@ -17231,11 +17779,11 @@ negate_data_op (unsigned long * instruction, /* Like negate_data_op, but for Thumb-2. */ static unsigned int -thumb32_negate_data_op (offsetT *instruction, offsetT value) +thumb32_negate_data_op (offsetT *instruction, unsigned int value) { int op, new_inst; int rd; - offsetT negated, inverted; + unsigned int negated, inverted; negated = encode_thumb32_immediate (-value); inverted = encode_thumb32_immediate (~value); @@ -17296,7 +17844,7 @@ thumb32_negate_data_op (offsetT *instruction, offsetT value) return FAIL; } - if (value == FAIL) + if (value == (unsigned int)FAIL) return FAIL; *instruction &= T2_OPCODE_MASK; @@ -17502,7 +18050,7 @@ md_apply_fix (fixS * fixP, as_bad_where (fixP->fx_file, fixP->fx_line, _("invalid literal constant: pool needs to be closer")); else - as_bad (_("bad immediate value for half-word offset (%ld)"), + as_bad (_("bad immediate value for 8-bit offset (%ld)"), (long) value); break; } @@ -17810,18 +18358,34 @@ md_apply_fix (fixS * fixP, } break; - case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CZB */ - /* CZB can only branch forward. */ - if (value & ~0x7e) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("branch out of range")); + case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CBZ */ + /* CBZ can only branch forward. */ - if (fixP->fx_done || !seg->use_rela_p) + /* Attempts to use CBZ to branch to the next instruction + (which, strictly speaking, are prohibited) will be turned into + no-ops. + + FIXME: It may be better to remove the instruction completely and + perform relaxation. */ + if (value == -2) { newval = md_chars_to_number (buf, THUMB_SIZE); - newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3); + newval = 0xbf00; /* NOP encoding T1 */ md_number_to_chars (buf, newval, THUMB_SIZE); } + else + { + if (value & ~0x7e) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("branch out of range")); + + if (fixP->fx_done || !seg->use_rela_p) + { + newval = md_chars_to_number (buf, THUMB_SIZE); + newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3); + md_number_to_chars (buf, newval, THUMB_SIZE); + } + } break; case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */ @@ -18005,8 +18569,6 @@ md_apply_fix (fixS * fixP, newval = get_thumb32_insn (buf); newval &= 0xff7fff00; newval |= (value >> 2) | (sign ? INDEX_UP : 0); - if (value == 0) - newval &= ~WRITE_BACK; if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2) md_number_to_chars (buf, newval, INSN_SIZE); @@ -18741,39 +19303,16 @@ arm_force_relocation (struct fix * fixp) || fixp->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0) return 1; - return generic_force_reloc (fixp); -} - -#ifdef OBJ_COFF -bfd_boolean -arm_fix_adjustable (fixS * fixP) -{ - /* This is a little hack to help the gas/arm/adrl.s test. It prevents - local labels from being added to the output symbol table when they - are used with the ADRL pseudo op. The ADRL relocation should always - be resolved before the binbary is emitted, so it is safe to say that - it is adjustable. */ - if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE) + /* Always generate relocations against function symbols. */ + if (fixp->fx_r_type == BFD_RELOC_32 + && fixp->fx_addsy + && (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION)) return 1; - /* This is a hack for the gas/all/redef2.s test. This test causes symbols - to be cloned, and without this test relocs would still be generated - against the original, pre-cloned symbol. Such symbols would not appear - in the symbol table however, and so a valid reloc could not be - generated. So check to see if the fixup is against a symbol which has - been removed from the symbol chain, and if it is, then allow it to be - adjusted into a reloc against a section symbol. */ - if (fixP->fx_addsy != NULL - && ! S_IS_LOCAL (fixP->fx_addsy) - && symbol_next (fixP->fx_addsy) == NULL - && symbol_next (fixP->fx_addsy) == symbol_previous (fixP->fx_addsy)) - return 1; - - return 0; + return generic_force_reloc (fixp); } -#endif -#ifdef OBJ_ELF +#if defined (OBJ_ELF) || defined (OBJ_COFF) /* Relocations against function names must be left unadjusted, so that the linker can use this information to generate interworking stubs. The MIPS version of this function @@ -18826,6 +19365,9 @@ arm_fix_adjustable (fixS * fixP) return 1; } +#endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */ + +#ifdef OBJ_ELF const char * elf32_arm_target_format (void) @@ -18944,7 +19486,7 @@ arm_adjust_symtab (void) if (THUMB_IS_FUNC (sym)) elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC); - else + else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4) elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_16BIT); } @@ -19052,9 +19594,9 @@ md_begin (void) if (!mfpu_opt) { - if (!mcpu_cpu_opt) + if (mcpu_cpu_opt != NULL) mfpu_opt = &fpu_default; - else if (ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5)) + else if (mcpu_fpu_opt != NULL && ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5)) mfpu_opt = &fpu_arch_vfp_v2; else mfpu_opt = &fpu_arch_fpa; @@ -19152,7 +19694,9 @@ md_begin (void) #endif /* Record the CPU type as well. */ - if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt)) + if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)) + mach = bfd_mach_arm_iWMMXt2; + else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt)) mach = bfd_mach_arm_iWMMXt; else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_xscale)) mach = bfd_mach_arm_XScale; @@ -19531,6 +20075,7 @@ static const struct arm_cpu_option_table arm_cpus[] = {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL}, /* ??? iwmmxt is not a processor. */ {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL}, + {"iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL}, {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL}, /* Maverick */ {"ep9312", ARM_FEATURE(ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"}, @@ -19575,11 +20120,17 @@ static const struct arm_arch_option_table arm_archs[] = {"armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP}, {"armv6zkt2", ARM_ARCH_V6ZKT2, FPU_ARCH_VFP}, {"armv7", ARM_ARCH_V7, FPU_ARCH_VFP}, + /* The official spelling of the ARMv7 profile variants is the dashed form. + Accept the non-dashed form for compatibility with old toolchains. */ {"armv7a", ARM_ARCH_V7A, FPU_ARCH_VFP}, {"armv7r", ARM_ARCH_V7R, FPU_ARCH_VFP}, {"armv7m", ARM_ARCH_V7M, FPU_ARCH_VFP}, + {"armv7-a", ARM_ARCH_V7A, FPU_ARCH_VFP}, + {"armv7-r", ARM_ARCH_V7R, FPU_ARCH_VFP}, + {"armv7-m", ARM_ARCH_V7M, FPU_ARCH_VFP}, {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP}, {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP}, + {"iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP}, {NULL, ARM_ARCH_NONE, ARM_ARCH_NONE} }; @@ -19595,6 +20146,7 @@ static const struct arm_option_cpu_value_table arm_extensions[] = {"maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK)}, {"xscale", ARM_FEATURE (0, ARM_CEXT_XSCALE)}, {"iwmmxt", ARM_FEATURE (0, ARM_CEXT_IWMMXT)}, + {"iwmmxt2", ARM_FEATURE (0, ARM_CEXT_IWMMXT2)}, {NULL, ARM_ARCH_NONE} }; @@ -20019,7 +20571,13 @@ aeabi_set_public_attributes (void) ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used); ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt); ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu); - + /*Allow the user to override the reported architecture. */ + if (object_arch) + { + ARM_CLEAR_FEATURE (flags, flags, arm_arch_any); + ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch); + } + tmp = flags; arch = 0; for (p = cpu_arch_ver; p->val; p++) @@ -20045,65 +20603,54 @@ aeabi_set_public_attributes (void) for (i = 0; p[i]; i++) p[i] = TOUPPER (p[i]); } - elf32_arm_add_eabi_attr_string (stdoutput, 5, p); + bfd_elf_add_proc_attr_string (stdoutput, 5, p); } /* Tag_CPU_arch. */ - elf32_arm_add_eabi_attr_int (stdoutput, 6, arch); + bfd_elf_add_proc_attr_int (stdoutput, 6, arch); /* Tag_CPU_arch_profile. */ if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)) - elf32_arm_add_eabi_attr_int (stdoutput, 7, 'A'); + bfd_elf_add_proc_attr_int (stdoutput, 7, 'A'); else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r)) - elf32_arm_add_eabi_attr_int (stdoutput, 7, 'R'); + bfd_elf_add_proc_attr_int (stdoutput, 7, 'R'); else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m)) - elf32_arm_add_eabi_attr_int (stdoutput, 7, 'M'); + bfd_elf_add_proc_attr_int (stdoutput, 7, 'M'); /* Tag_ARM_ISA_use. */ if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_full)) - elf32_arm_add_eabi_attr_int (stdoutput, 8, 1); + bfd_elf_add_proc_attr_int (stdoutput, 8, 1); /* Tag_THUMB_ISA_use. */ if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_full)) - elf32_arm_add_eabi_attr_int (stdoutput, 9, + bfd_elf_add_proc_attr_int (stdoutput, 9, ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2) ? 2 : 1); /* Tag_VFP_arch. */ if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3) || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v3)) - elf32_arm_add_eabi_attr_int (stdoutput, 10, 3); + bfd_elf_add_proc_attr_int (stdoutput, 10, 3); else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v2) || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v2)) - elf32_arm_add_eabi_attr_int (stdoutput, 10, 2); + bfd_elf_add_proc_attr_int (stdoutput, 10, 2); else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1) || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1) || ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1xd) || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1xd)) - elf32_arm_add_eabi_attr_int (stdoutput, 10, 1); + bfd_elf_add_proc_attr_int (stdoutput, 10, 1); /* Tag_WMMX_arch. */ if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_cext_iwmmxt) || ARM_CPU_HAS_FEATURE (arm_arch_used, arm_cext_iwmmxt)) - elf32_arm_add_eabi_attr_int (stdoutput, 11, 1); + bfd_elf_add_proc_attr_int (stdoutput, 11, 1); /* Tag_NEON_arch. */ if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_neon_ext_v1) || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_neon_ext_v1)) - elf32_arm_add_eabi_attr_int (stdoutput, 12, 1); + bfd_elf_add_proc_attr_int (stdoutput, 12, 1); } -/* Add the .ARM.attributes section. */ +/* Add the default contents for the .ARM.attributes section. */ void arm_md_end (void) { - segT s; - char *p; - addressT addr; - offsetT size; - if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4) return; aeabi_set_public_attributes (); - size = elf32_arm_eabi_attr_size (stdoutput); - s = subseg_new (".ARM.attributes", 0); - bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA); - addr = frag_now_fix (); - p = frag_more (size); - elf32_arm_set_eabi_attr_contents (stdoutput, (bfd_byte *)p, size); } #endif /* OBJ_ELF */ @@ -20183,6 +20730,37 @@ s_arm_arch (int ignored ATTRIBUTE_UNUSED) } +/* Parse a .object_arch directive. */ + +static void +s_arm_object_arch (int ignored ATTRIBUTE_UNUSED) +{ + const struct arm_arch_option_table *opt; + char saved_char; + char *name; + + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE(*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + /* Skip the first "all" entry. */ + for (opt = arm_archs + 1; opt->name != NULL; opt++) + if (streq (opt->name, name)) + { + object_arch = &opt->value; + *input_line_pointer = saved_char; + demand_empty_rest_of_line (); + return; + } + + as_bad (_("unknown architecture `%s'\n"), name); + *input_line_pointer = saved_char; + ignore_rest_of_line (); +} + + /* Parse a .fpu directive. */ static void @@ -20213,3 +20791,9 @@ s_arm_fpu (int ignored ATTRIBUTE_UNUSED) ignore_rest_of_line (); } +/* Copy symbol information. */ +void +arm_copy_symbol_attributes (symbolS *dest, symbolS *src) +{ + ARM_GET_FLAG (dest) = ARM_GET_FLAG (src); +}