X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=117fe16d31b686a5f003f3ee304932976a1ebffb;hb=4396b6862a60b1add68552ddac6b8d68513e51e8;hp=2cb28d4eee4b36e2ffc619662ef7dcfdbc25589f;hpb=efd81785d9f5514e7923ad65b452d5a704989707;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 2cb28d4eee..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, @@ -1971,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); @@ -2013,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; @@ -2026,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 @@ -2056,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); - - for (p = nbuf; *p; p++) - *p = TOUPPER (*p); + if (insert_reg_alias (nbuf, old->number, old->type) != NULL) + { + for (p = nbuf; *p; p++) + *p = TOUPPER (*p); - if (strncmp (nbuf, newname, nlen)) - insert_reg_alias (nbuf, old->number, old->type); + 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; + } - 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.: @@ -2270,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); } } @@ -2613,6 +2660,7 @@ static void s_align (int unused ATTRIBUTE_UNUSED) { int temp; + bfd_boolean fill_p; long temp_fill; long max_alignment = 15; @@ -2629,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); @@ -3819,84 +3876,7 @@ 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 */ @@ -5602,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; @@ -9534,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) @@ -14409,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), @@ -15017,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), @@ -15045,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), @@ -15133,7 +15211,6 @@ static const struct asm_opcode insns[] = 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), @@ -16710,7 +16787,31 @@ relaxed_symbol_addr(fragS *fragp, long stretch) if (stretch != 0 && sym_frag->relax_marker != fragp->relax_marker) - addr += stretch; + { + 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; } @@ -20502,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 */