X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fcgen.c;h=b94802ebc8f8f2427c42e16862e72ef13b4fb32b;hb=c578f16ef18fde35d5887909d5faaf0bd0118e9d;hp=5b0694b03e222b8644c24d724737b1e7fa65f294;hpb=280d71bf40a544853567763c706e03334d6fd950;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/cgen.c b/gas/cgen.c index 5b0694b03e..b94802ebc8 100644 --- a/gas/cgen.c +++ b/gas/cgen.c @@ -1,25 +1,24 @@ /* GAS interface for targets using CGEN: Cpu tools GENerator. - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006 Free Software Foundation, Inc. + Copyright (C) 1996-2020 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. 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, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GAS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include #include "as.h" +#include #include "symcat.h" #include "cgen-desc.h" #include "subsegs.h" @@ -27,7 +26,6 @@ #include "dwarf2dbg.h" #include "symbols.h" -#include "struc-symbol.h" #ifdef OBJ_COMPLEX_RELC static expressionS * make_right_shifted_expr @@ -38,7 +36,7 @@ static unsigned long gas_cgen_encode_addend const unsigned long, const unsigned long, const unsigned long, \ const unsigned long); -static char * weak_operand_overflow_check +static const char * weak_operand_overflow_check (const expressionS *, const CGEN_OPERAND *); static void queue_fixup_recursively @@ -58,9 +56,7 @@ CGEN_CPU_DESC gas_cgen_cpu_desc; ??? Not currently used. */ void -cgen_asm_record_register (name, number) - char *name; - int number; +cgen_asm_record_register (char *name, int number) { /* Use symbol_create here instead of symbol_new so we don't try to output registers into the object file's symbol table. */ @@ -95,7 +91,7 @@ static int num_fixups; ??? May wish to make this static and delete calls in md_assemble. */ void -gas_cgen_init_parse () +gas_cgen_init_parse (void) { num_fixups = 0; } @@ -103,10 +99,7 @@ gas_cgen_init_parse () /* Queue a fixup. */ static void -queue_fixup (opindex, opinfo, expP) - int opindex; - int opinfo; - expressionS * expP; +queue_fixup (int opindex, int opinfo, expressionS *expP) { /* We need to generate a fixup for this expression. */ if (num_fixups >= GAS_CGEN_MAX_FIXUPS) @@ -160,7 +153,7 @@ struct saved_fixups static struct saved_fixups stored_fixups[MAX_SAVED_FIXUP_CHAINS]; void -gas_cgen_initialize_saved_fixups_array () +gas_cgen_initialize_saved_fixups_array (void) { int i = 0; @@ -169,8 +162,7 @@ gas_cgen_initialize_saved_fixups_array () } void -gas_cgen_save_fixups (i) - int i; +gas_cgen_save_fixups (int i) { if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS) { @@ -185,8 +177,7 @@ gas_cgen_save_fixups (i) } void -gas_cgen_restore_fixups (i) - int i; +gas_cgen_restore_fixups (int i) { if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS) { @@ -201,8 +192,7 @@ gas_cgen_restore_fixups (i) } void -gas_cgen_swap_fixups (i) - int i; +gas_cgen_swap_fixups (int i) { if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS) { @@ -248,15 +238,9 @@ gas_cgen_swap_fixups (i) operand type. We pick a BFD reloc type in md_apply_fix. */ fixS * -gas_cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset) - fragS * frag; - int where; - const CGEN_INSN * insn; - int length; - const CGEN_OPERAND * operand; - int opinfo; - symbolS * symbol; - offsetT offset; +gas_cgen_record_fixup (fragS *frag, int where, const CGEN_INSN *insn, + int length, const CGEN_OPERAND *operand, int opinfo, + symbolS *symbol, offsetT offset) { fixS *fixP; @@ -289,14 +273,9 @@ gas_cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offse operand type. We pick a BFD reloc type in md_apply_fix. */ fixS * -gas_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) - fragS * frag; - int where; - const CGEN_INSN * insn; - int length; - const CGEN_OPERAND * operand; - int opinfo; - expressionS * exp; +gas_cgen_record_fixup_exp (fragS *frag, int where, const CGEN_INSN *insn, + int length, const CGEN_OPERAND *operand, int opinfo, + expressionS *exp) { fixS *fixP; @@ -345,19 +324,11 @@ static int expr_jmp_buf_p; The resulting value is stored in VALUEP. */ const char * -gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) - -#ifdef OBJ_COMPLEX_RELC - CGEN_CPU_DESC cd; -#else - CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; -#endif - enum cgen_parse_operand_type want; - const char **strP; - int opindex; - int opinfo; - enum cgen_parse_operand_result *resultP; - bfd_vma *valueP; +gas_cgen_parse_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + enum cgen_parse_operand_type want, const char **strP, + int opindex, int opinfo, + enum cgen_parse_operand_result *resultP, + bfd_vma *valueP) { #ifdef __STDC__ /* These are volatile to survive the setjmp. */ @@ -410,7 +381,7 @@ gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) #ifdef TC_CGEN_PARSE_FIX_EXP opinfo_1 = TC_CGEN_PARSE_FIX_EXP (opinfo_1, & exp); -#endif +#endif /* FIXME: Need to check `want'. */ @@ -444,6 +415,8 @@ gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) if (! errmsg) { + asymbol *bsym; + /* Fragment the expression as necessary, and queue a reloc. */ memset (& dummy_fixup, 0, sizeof (fixS)); @@ -451,10 +424,12 @@ gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) if (exp.X_op == O_symbol && reloc_type == BFD_RELOC_RELC - && exp.X_add_symbol->sy_value.X_op == O_constant - && exp.X_add_symbol->bsym->section != expr_section - && exp.X_add_symbol->bsym->section != absolute_section - && exp.X_add_symbol->bsym->section != undefined_section) + && symbol_constant_p (exp.X_add_symbol) + && (!symbol_symbolS (exp.X_add_symbol) + || (bsym = symbol_get_bfdsym (exp.X_add_symbol)) == NULL + || (bsym->section != expr_section + && bsym->section != absolute_section + && bsym->section != undefined_section))) { /* Local labels will have been (eagerly) turned into constants by now, due to the inappropriately deep insight of the @@ -465,15 +440,15 @@ gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) stmp = symbol_create (FAKE_LABEL_NAME, expr_section, 0, & zero_address_frag); symbol_set_value_expression (stmp, & exp); - } - else + } + else stmp = make_expr_symbol (& exp); /* If this is a pc-relative RELC operand, we - need to subtract "." from the expression. */ + need to subtract "." from the expression. */ if (reloc_type == BFD_RELOC_RELC && CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR)) - stmp = expr_build_binary (O_subtract, stmp, expr_build_dot ()); + stmp = expr_build_binary (O_subtract, stmp, expr_build_dot ()); /* FIXME: this is not a perfect heuristic for figuring out whether an operand is signed: it only works when the operand @@ -481,24 +456,27 @@ gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) values will be signed relocs, but it's possible. */ if (operand && (operand->hw_type == HW_H_SINT)) signed_p = 1; - - if (stmp->bsym && (stmp->bsym->section == expr_section)) + + if (symbol_symbolS (stmp) + && (bsym = symbol_get_bfdsym (stmp)) != NULL + && bsym->section == expr_section + && ! S_IS_LOCAL (stmp)) { if (signed_p) - stmp->bsym->flags |= BSF_SRELC; + bsym->flags |= BSF_SRELC; else - stmp->bsym->flags |= BSF_RELC; + bsym->flags |= BSF_RELC; } - + /* Now package it all up for the fixup emitter. */ exp.X_op = O_symbol; exp.X_op_symbol = 0; exp.X_add_symbol = stmp; exp.X_add_number = 0; - + /* Re-init rightshift quantity, just in case. */ rightshift = operand->length; - queue_fixup_recursively (opindex, opinfo_1, & exp, + queue_fixup_recursively (opindex, opinfo_1, & exp, (reloc_type == BFD_RELOC_RELC) ? & (operand->index_fields) : 0, signed_p, -1); @@ -511,7 +489,7 @@ gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) queue_fixup (opindex, opinfo_1, &exp); *valueP = 0; *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED; -#endif +#endif break; } @@ -524,8 +502,7 @@ gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) ??? This could be done differently by adding code to `expression'. */ void -gas_cgen_md_operand (expressionP) - expressionS *expressionP ATTRIBUTE_UNUSED; +gas_cgen_md_operand (expressionS *expressionP ATTRIBUTE_UNUSED) { /* Don't longjmp if we're not called from within cgen_parse_operand(). */ if (expr_jmp_buf_p) @@ -540,12 +517,8 @@ gas_cgen_md_operand (expressionP) The "result" is stored in RESULT if non-NULL. */ void -gas_cgen_finish_insn (insn, buf, length, relax_p, result) - const CGEN_INSN *insn; - CGEN_INSN_BYTES_PTR buf; - unsigned int length; - int relax_p; - finished_insnS *result; +gas_cgen_finish_insn (const CGEN_INSN *insn, CGEN_INSN_BYTES_PTR buf, + unsigned int length, int relax_p, finished_insnS *result) { int i; int relax_operand; @@ -709,9 +682,9 @@ queue_fixup_recursively (const int opindex, if (field && field->count) { int i; - + for (i = 0; i < field->count; ++ i) - queue_fixup_recursively (opindex, opinfo, expP, + queue_fixup_recursively (opindex, opinfo, expP, & (field->val.multi[i]), signed_p, i); } else @@ -730,20 +703,20 @@ queue_fixup_recursively (const int opindex, /* Shift reloc value by number of bits remaining after this field. */ if (rightshift) - new_exp = make_right_shifted_expr (expP, rightshift, signed_p); + new_exp = make_right_shifted_expr (expP, rightshift, signed_p); } - + /* Truncate reloc values to length, *after* leftmost one. */ fixups[num_fixups].msb_field_p = (part_of_multi <= 0); fixups[num_fixups].field = (CGEN_MAYBE_MULTI_IFLD *) field; - + queue_fixup (opindex, opinfo, new_exp); } } /* Encode the self-describing RELC reloc format's addend. */ -static unsigned long +static unsigned long gas_cgen_encode_addend (const unsigned long start, /* in bits */ const unsigned long len, /* in bits */ const unsigned long oplen, /* in bits */ @@ -773,13 +746,13 @@ gas_cgen_encode_addend (const unsigned long start, /* in bits */ parse. when these %operators are translated to expressions by the macro expander, the ambiguity returns. we attempt to disambiguate by field size. - + Method: check to see if the expression's top node is an O_and operator, and the mask is larger than the operand length. This would be an overflow, so signal it by returning an error string. Any other case is ambiguous, so we assume it's OK and return NULL. */ -static char * +static const char * weak_operand_overflow_check (const expressionS * exp, const CGEN_OPERAND * operand) { @@ -793,23 +766,23 @@ weak_operand_overflow_check (const expressionS * exp, if (exp->X_op != O_bit_and) { /* Check for implicit overflow flag. */ - if (CGEN_OPERAND_ATTR_VALUE + if (CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_RELOC_IMPLIES_OVERFLOW)) return _("a reloc on this operand implies an overflow"); return NULL; } - + mask = exp->X_add_number; - if (exp->X_add_symbol && - exp->X_add_symbol->sy_value.X_op == O_constant) - mask |= exp->X_add_symbol->sy_value.X_add_number; + if (exp->X_add_symbol + && symbol_constant_p (exp->X_add_symbol)) + mask |= *symbol_X_add_number (exp->X_add_symbol); - if (exp->X_op_symbol && - exp->X_op_symbol->sy_value.X_op == O_constant) - mask |= exp->X_op_symbol->sy_value.X_add_number; + if (exp->X_op_symbol + && symbol_constant_p (exp->X_op_symbol)) + mask |= *symbol_X_add_number (exp->X_op_symbol); - /* Want to know if mask covers more bits than opmask. + /* Want to know if mask covers more bits than opmask. this is the same as asking if mask has any bits not in opmask, or whether (mask & ~opmask) is nonzero. */ if (mask && (mask & ~opmask)) @@ -821,10 +794,9 @@ weak_operand_overflow_check (const expressionS * exp, return _("operand mask overflow"); } - return NULL; + return NULL; } - static expressionS * make_right_shifted_expr (expressionS * exp, const int amount, @@ -832,27 +804,31 @@ make_right_shifted_expr (expressionS * exp, { symbolS * stmp = 0; expressionS * new_exp; + asymbol *bsym; - stmp = expr_build_binary (O_right_shift, + stmp = expr_build_binary (O_right_shift, make_expr_symbol (exp), expr_build_uconstant (amount)); - + bsym = symbol_get_bfdsym (stmp); + if (signed_p) - stmp->bsym->flags |= BSF_SRELC; + bsym->flags |= BSF_SRELC; else - stmp->bsym->flags |= BSF_RELC; - + bsym->flags |= BSF_RELC; + /* Then wrap that in a "symbol expr" for good measure. */ - new_exp = xmalloc (sizeof (expressionS)); + new_exp = XNEW (expressionS); memset (new_exp, 0, sizeof (expressionS)); new_exp->X_op = O_symbol; new_exp->X_op_symbol = 0; new_exp->X_add_symbol = stmp; new_exp->X_add_number = 0; - + return new_exp; } + #endif + /* 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 @@ -866,10 +842,7 @@ make_right_shifted_expr (expressionS * exp, should handle them all. */ void -gas_cgen_md_apply_fix (fixP, valP, seg) - fixS * fixP; - valueT * valP; - segT seg ATTRIBUTE_UNUSED; +gas_cgen_md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { char *where = fixP->fx_frag->fr_literal + fixP->fx_where; valueT value = * valP; @@ -889,14 +862,14 @@ gas_cgen_md_apply_fix (fixP, valP, seg) const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex); const char *errmsg; bfd_reloc_code_real_type reloc_type; - CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd)); const CGEN_INSN *insn = fixP->fx_cgen.insn; +#ifdef OBJ_COMPLEX_RELC int start; int length; int signed_p = 0; if (fixP->fx_cgen.field) - { + { /* Use the twisty little pointer path back to the ifield if it exists. */ start = fixP->fx_cgen.field->val.leaf->start; @@ -915,6 +888,7 @@ gas_cgen_md_apply_fix (fixP, valP, seg) values will be signed relocs, but it's possible. */ if (operand && (operand->hw_type == HW_H_SINT)) signed_p = 1; +#endif /* If the reloc has been fully resolved finish the operand here. */ /* FIXME: This duplicates the capabilities of code in BFD. */ @@ -923,6 +897,8 @@ gas_cgen_md_apply_fix (fixP, valP, seg) finish the job. Testing for pcrel is a temporary hack. */ || fixP->fx_pcrel) { + CGEN_FIELDS *fields = xmalloc (CGEN_CPU_SIZEOF_FIELDS (cd)); + CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn)); CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value); @@ -946,6 +922,8 @@ gas_cgen_md_apply_fix (fixP, valP, seg) #endif if (errmsg) as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg); + + free (fields); } if (fixP->fx_done) @@ -963,9 +941,9 @@ gas_cgen_md_apply_fix (fixP, valP, seg) /* Change addend to "self-describing" form, for BFD to handle in the linker. */ value = gas_cgen_encode_addend (start, operand->length, - length, fixP->fx_size, - cd->insn_chunk_bitsize / 8, - signed_p, + length, fixP->fx_size, + cd->insn_chunk_bitsize / 8, + signed_p, ! (fixP->fx_cgen.msb_field_p)); } #endif @@ -1014,19 +992,40 @@ gas_cgen_md_apply_fix (fixP, valP, seg) fixP->fx_addnumber = value; } +bfd_reloc_code_real_type +gas_cgen_pcrel_r_type (bfd_reloc_code_real_type r) +{ + switch (r) + { + case BFD_RELOC_8: r = BFD_RELOC_8_PCREL; break; + case BFD_RELOC_16: r = BFD_RELOC_16_PCREL; break; + case BFD_RELOC_24: r = BFD_RELOC_24_PCREL; break; + case BFD_RELOC_32: r = BFD_RELOC_32_PCREL; break; + case BFD_RELOC_64: r = BFD_RELOC_64_PCREL; break; + default: + break; + } + return r; +} + /* Translate internal representation of relocation info to BFD target format. FIXME: To what extent can we get all relevant targets to use this? */ arelent * -gas_cgen_tc_gen_reloc (section, fixP) - asection * section ATTRIBUTE_UNUSED; - fixS * fixP; +gas_cgen_tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) { + bfd_reloc_code_real_type r_type = fixP->fx_r_type; arelent *reloc; - reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); + reloc = XNEW (arelent); + +#ifdef GAS_CGEN_PCREL_R_TYPE + if (fixP->fx_pcrel) + r_type = GAS_CGEN_PCREL_R_TYPE (r_type); +#endif + reloc->howto = bfd_reloc_type_lookup (stdoutput, r_type); + if (reloc->howto == (reloc_howto_type *) NULL) { as_bad_where (fixP->fx_file, fixP->fx_line, @@ -1034,9 +1033,9 @@ gas_cgen_tc_gen_reloc (section, fixP) return NULL; } - assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); + gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc->sym_ptr_ptr = XNEW (asymbol *); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); /* Use fx_offset for these cases. */ @@ -1054,11 +1053,10 @@ gas_cgen_tc_gen_reloc (section, fixP) Called after gas_cgen_cpu_desc has been created. */ void -gas_cgen_begin () +gas_cgen_begin (void) { if (flag_signed_overflow_ok) cgen_set_signed_overflow_ok (gas_cgen_cpu_desc); else cgen_clear_signed_overflow_ok (gas_cgen_cpu_desc); } -