X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-ppc.c;h=be745abbf65aa56b2e9fecbd6a7bc0ffe4993fb9;hb=b84bf58a;hp=c7ad970672443ee9547c5ed92bb0af278080dfc0;hpb=ac8058268341e27c245411cba2a80e6c8b8918c6;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index c7ad970672..be745abbf6 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -1,6 +1,6 @@ /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000) Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005 Free Software Foundation, Inc. + 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of GAS, the GNU Assembler. @@ -20,7 +20,6 @@ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include #include "as.h" #include "safe-ctype.h" #include "subsegs.h" @@ -183,11 +182,9 @@ const char EXP_CHARS[] = "eE"; as in 0d1.0. */ const char FLT_CHARS[] = "dD"; -/* '+' and '-' can be used as postfix predicate predictors for conditional - branches. So they need to be accepted as symbol characters. - Also, anything that can start an operand needs to be mentioned here, +/* Anything that can start an operand needs to be mentioned here, to stop the input scrubber eating whitespace. */ -const char ppc_symbol_chars[] = "+-%["; +const char ppc_symbol_chars[] = "%["; /* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ int ppc_cie_data_alignment; @@ -917,6 +914,18 @@ parse_cpu (const char *arg) | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5); } + else if (strcmp (arg, "power6") == 0) + { + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC + | PPC_OPCODE_64 | PPC_OPCODE_POWER4 + | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6); + } + else if (strcmp (arg, "cell") == 0) + { + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC + | PPC_OPCODE_64 | PPC_OPCODE_POWER4 + | PPC_OPCODE_CELL); + } /* -mcom means assemble for the common intersection between Power and PowerPC. At present, we just allow the union, rather than the intersection. */ @@ -1112,6 +1121,8 @@ PowerPC options:\n\ -mbooke, mbooke32 generate code for 32-bit PowerPC BookE\n\ -mpower4 generate code for Power4 architecture\n\ -mpower5 generate code for Power5 architecture\n\ +-mpower6 generate code for Power6 architecture\n\ +-mcell generate code for Cell Broadband Engine architecture\n\ -mcom generate code Power/PowerPC common instructions\n\ -many generate code for any architecture (PWR/PWRX/PPC)\n")); fprintf (stream, _("\ @@ -1237,7 +1248,8 @@ ppc_setup_opcodes (void) const struct powerpc_opcode *op_end; const struct powerpc_macro *macro; const struct powerpc_macro *macro_end; - bfd_boolean dup_insn = FALSE; + unsigned int i; + bfd_boolean bad_insn = FALSE; if (ppc_hash != NULL) hash_die (ppc_hash); @@ -1247,10 +1259,60 @@ ppc_setup_opcodes (void) /* Insert the opcodes into a hash table. */ ppc_hash = hash_new (); + /* Check operand masks. Code here and in the disassembler assumes + all the 1's in the mask are contiguous. */ + for (i = 0; i < num_powerpc_operands; ++i) + { + unsigned long mask = powerpc_operands[i].bitm; + unsigned long right_bit; + + right_bit = mask & -mask; + mask += right_bit; + right_bit = mask & -mask; + if (mask != right_bit) + { + as_bad (_("powerpc_operands[%d].bitm invalid"), i); + bad_insn = TRUE; + } + } + op_end = powerpc_opcodes + powerpc_num_opcodes; for (op = powerpc_opcodes; op < op_end; op++) { - know ((op->opcode & op->mask) == op->opcode); + const unsigned char *o; + unsigned long omask = op->mask; + + /* The mask had better not trim off opcode bits. */ + if ((op->opcode & omask) != op->opcode) + { + as_bad (_("mask trims opcode bits for %s"), + op->name); + bad_insn = TRUE; + } + + /* The operands must not overlap the opcode or each other. */ + for (o = op->operands; *o; ++o) + if (*o >= num_powerpc_operands) + { + as_bad (_("operand index error for %s"), + op->name); + bad_insn = TRUE; + } + else + { + const struct powerpc_operand *operand = &powerpc_operands[*o]; + if (operand->shift >= 0) + { + unsigned long mask = operand->bitm << operand->shift; + if (omask & mask) + { + as_bad (_("operand %d overlap in %s"), + (int) (o - op->operands), op->name); + bad_insn = TRUE; + } + omask |= mask; + } + } if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0 && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0 @@ -1270,7 +1332,10 @@ ppc_setup_opcodes (void) == (ppc_cpu & PPC_OPCODE_POWER4))) && ((op->flags & PPC_OPCODE_POWER5) == 0 || ((op->flags & PPC_OPCODE_POWER5) - == (ppc_cpu & PPC_OPCODE_POWER5)))) + == (ppc_cpu & PPC_OPCODE_POWER5))) + && ((op->flags & PPC_OPCODE_POWER6) == 0 + || ((op->flags & PPC_OPCODE_POWER6) + == (ppc_cpu & PPC_OPCODE_POWER6)))) { const char *retval; @@ -1282,9 +1347,9 @@ ppc_setup_opcodes (void) && (op->flags & PPC_OPCODE_POWER) != 0) continue; - as_bad (_("Internal assembler error for instruction %s"), + as_bad (_("duplicate instruction %s"), op->name); - dup_insn = TRUE; + bad_insn = TRUE; } } } @@ -1306,13 +1371,13 @@ ppc_setup_opcodes (void) retval = hash_insert (ppc_macro_hash, macro->name, (PTR) macro); if (retval != (const char *) NULL) { - as_bad (_("Internal assembler error for macro %s"), macro->name); - dup_insn = TRUE; + as_bad (_("duplicate macro %s"), macro->name); + bad_insn = TRUE; } } } - if (dup_insn) + if (bad_insn) abort (); } @@ -1433,49 +1498,52 @@ ppc_insert_operand (insn, operand, val, file, line) char *file; unsigned int line; { - if (operand->bits != 32) + long min, max, right; + offsetT test; + + max = operand->bitm; + right = max & -max; + min = 0; + + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) { - long min, max; - offsetT test; + if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0) + max >>= 1; + min = ~(max | ((max & -max) - 1)) ; - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + if (!ppc_obj64) { - if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0) - max = (1 << operand->bits) - 1; - else - max = (1 << (operand->bits - 1)) - 1; - min = - (1 << (operand->bits - 1)); - - if (!ppc_obj64) + /* Some people write 32 bit hex constants with the sign + extension done by hand. This shouldn't really be + valid, but, to permit this code to assemble on a 64 + bit host, we sign extend the 32 bit value. */ + if (val > 0 + && (val & (offsetT) 0x80000000) != 0 + && (val & (offsetT) 0xffffffff) == val) { - /* Some people write 32 bit hex constants with the sign - extension done by hand. This shouldn't really be - valid, but, to permit this code to assemble on a 64 - bit host, we sign extend the 32 bit value. */ - if (val > 0 - && (val & (offsetT) 0x80000000) != 0 - && (val & (offsetT) 0xffffffff) == val) - { - val -= 0x80000000; - val -= 0x80000000; - } + val -= 0x80000000; + val -= 0x80000000; } } - else - { - max = (1 << operand->bits) - 1; - min = 0; - } - - if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) - test = - val; - else - test = val; + } - if (test < (offsetT) min || test > (offsetT) max) - as_bad_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line); + if ((operand->flags & PPC_OPERAND_PLUS1) != 0) + { + max++; + min++; } + if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) + test = - val; + else + test = val; + + if (test < (offsetT) min + || test > (offsetT) max + || (test & (right - 1)) != 0) + as_bad_value_out_of_range (_("operand"), + test, (offsetT) min, (offsetT) max, file, line); + if (operand->insert) { const char *errmsg; @@ -1486,8 +1554,7 @@ ppc_insert_operand (insn, operand, val, file, line) as_bad_where (file, line, errmsg); } else - insn |= (((long) val & ((1 << operand->bits) - 1)) - << operand->shift); + insn |= ((long) val & operand->bitm) << operand->shift; return insn; } @@ -1931,7 +1998,7 @@ ppc_frob_file_before_adjust () dotname = xmalloc (len + 1); dotname[0] = '.'; memcpy (dotname + 1, name, len); - dotsym = symbol_find (dotname); + dotsym = symbol_find_noref (dotname, 1); free (dotname); if (dotsym != NULL && (symbol_used_p (dotsym) || symbol_used_in_reloc_p (dotsym))) @@ -4416,6 +4483,7 @@ ppc_pe_comm (lcomm) { S_SET_VALUE (symbolP, (valueT) temp); S_SET_EXTERNAL (symbolP); + S_SET_SEGMENT (symbolP, bfd_com_section_ptr); } demand_empty_rest_of_line (); @@ -4840,6 +4908,10 @@ ppc_frob_label (sym) &symbol_rootP, &symbol_lastP); symbol_get_tc (ppc_current_csect)->within = sym; } + +#ifdef OBJ_ELF + dwarf2_emit_label (sym); +#endif } /* This variable is set by ppc_frob_symbol if any absolute symbols are @@ -5251,13 +5323,15 @@ md_number_to_chars (buf, val, n) /* Align a section (I don't know why this is machine dependent). */ valueT -md_section_align (seg, addr) - asection *seg; - valueT addr; +md_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr) { +#ifdef OBJ_ELF + return addr; +#else int align = bfd_get_section_alignment (stdoutput, seg); return ((addr + (1 << align) - 1) & (-1 << align)); +#endif } /* We don't have any form of relaxing. */ @@ -5505,6 +5579,47 @@ ppc_fix_adjustable (fix) } #endif +/* Implement HANDLE_ALIGN. This writes the NOP pattern into an + rs_align_code frag. */ + +void +ppc_handle_align (struct frag *fragP) +{ + valueT count = (fragP->fr_next->fr_address + - (fragP->fr_address + fragP->fr_fix)); + + if (count != 0 && (count & 3) == 0) + { + char *dest = fragP->fr_literal + fragP->fr_fix; + + fragP->fr_var = 4; + md_number_to_chars (dest, 0x60000000, 4); + + if ((ppc_cpu & PPC_OPCODE_POWER6) != 0) + { + /* For power6, we want the last nop to be a group terminating + one, "ori 1,1,0". Do this by inserting an rs_fill frag + immediately after this one, with its address set to the last + nop location. This will automatically reduce the number of + nops in the current frag by one. */ + if (count > 4) + { + struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4); + + memcpy (group_nop, fragP, SIZEOF_STRUCT_FRAG); + group_nop->fr_address = group_nop->fr_next->fr_address - 4; + group_nop->fr_fix = 0; + group_nop->fr_offset = 1; + group_nop->fr_type = rs_fill; + fragP->fr_next = group_nop; + dest = group_nop->fr_literal; + } + + md_number_to_chars (dest, 0x60210000, 4); + } + } +} + /* Apply a fixup to the object code. This is called for all the fixups we generated by the call to fix_new_exp, above. In the call above we used a reloc code which was the largest legal reloc code @@ -5575,7 +5690,7 @@ md_apply_fix (fixP, valP, seg) csect. Other usages, such as `.long sym', generate relocs. This is the documented behaviour of non-TOC symbols. */ if ((operand->flags & PPC_OPERAND_PARENS) != 0 - && operand->bits == 16 + && (operand->bitm & 0xfff0) == 0xfff0 && operand->shift == 0 && (operand->insert == NULL || ppc_obj64) && fixP->fx_addsy != NULL @@ -5613,11 +5728,11 @@ md_apply_fix (fixP, valP, seg) We are only prepared to turn a few of the operands into relocs. */ if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bits == 26 + && operand->bitm == 0x3fffffc && operand->shift == 0) fixP->fx_r_type = BFD_RELOC_PPC_B26; else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bits == 16 + && operand->bitm == 0xfffc && operand->shift == 0) { fixP->fx_r_type = BFD_RELOC_PPC_B16; @@ -5628,11 +5743,11 @@ md_apply_fix (fixP, valP, seg) #endif } else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bits == 26 + && operand->bitm == 0x3fffffc && operand->shift == 0) fixP->fx_r_type = BFD_RELOC_PPC_BA26; else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bits == 16 + && operand->bitm == 0xfffc && operand->shift == 0) { fixP->fx_r_type = BFD_RELOC_PPC_BA16; @@ -5644,7 +5759,7 @@ md_apply_fix (fixP, valP, seg) } #if defined (OBJ_XCOFF) || defined (OBJ_ELF) else if ((operand->flags & PPC_OPERAND_PARENS) != 0 - && operand->bits == 16 + && (operand->bitm & 0xfff0) == 0xfff0 && operand->shift == 0) { if (ppc_is_toc_sym (fixP->fx_addsy)) @@ -6073,7 +6188,7 @@ ppc_cfi_frame_initial_instructions () } int -tc_ppc_regname_to_dw2regnum (const char *regname) +tc_ppc_regname_to_dw2regnum (char *regname) { unsigned int regnum = -1; unsigned int i;