From effee09f856ecc81feb91290459a2cda49d20287 Mon Sep 17 00:00:00 2001 From: jdp Date: Sun, 6 Sep 1998 22:57:45 +0000 Subject: Import GNU binutils-2.9.1. This will break things for a few minutes until I've made the commits to resolve the conflicts. Submitted by: Doug Rabson --- contrib/binutils/gas/cgen.c | 291 +++++++++++++++++++++++++++++--------------- 1 file changed, 193 insertions(+), 98 deletions(-) (limited to 'contrib/binutils/gas/cgen.c') diff --git a/contrib/binutils/gas/cgen.c b/contrib/binutils/gas/cgen.c index e9024e4..2c541ef 100644 --- a/contrib/binutils/gas/cgen.c +++ b/contrib/binutils/gas/cgen.c @@ -1,5 +1,5 @@ /* GAS interface for targets using CGEN: Cpu tools GENerator. - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -17,8 +17,10 @@ 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include "ansidecl.h" #include "bfd.h" +#include "symcat.h" #include "cgen-opc.h" #include "as.h" #include "subsegs.h" @@ -29,13 +31,13 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ void cgen_asm_record_register (name, number) - char *name; - int number; + 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. */ symbol_table_insert (symbol_create (name, reg_section, - number, &zero_address_frag)); + number, & zero_address_frag)); } /* We need to keep a list of fixups. We can't simply generate them as @@ -51,15 +53,15 @@ cgen_asm_record_register (name, number) struct fixup { - int opindex; - int opinfo; + int opindex; + int opinfo; expressionS exp; }; #define MAX_FIXUPS 5 -static struct fixup fixups[MAX_FIXUPS]; -static int num_fixups; +static struct fixup fixups [MAX_FIXUPS]; +static int num_fixups; /* Prepare to parse an instruction. ??? May wish to make this static and delete calls in md_assemble. */ @@ -72,18 +74,74 @@ cgen_asm_init_parse () /* Queue a fixup. */ -void +static void cgen_queue_fixup (opindex, opinfo, expP) - int opindex; - expressionS *expP; + int opindex; + expressionS * expP; { /* We need to generate a fixup for this expression. */ if (num_fixups >= MAX_FIXUPS) as_fatal ("too many fixups"); - fixups[num_fixups].exp = *expP; + fixups[num_fixups].exp = * expP; fixups[num_fixups].opindex = opindex; - fixups[num_fixups].opinfo = opinfo; - ++num_fixups; + fixups[num_fixups].opinfo = opinfo; + ++ num_fixups; +} + +/* The following three functions allow a backup of the fixup chain to be made, + and to have this backup be swapped with the current chain. This allows + certain ports, eg the m32r, to swap two instructions and swap their fixups + at the same time. */ +static struct fixup saved_fixups [MAX_FIXUPS]; +static int saved_num_fixups; + +void +cgen_save_fixups () +{ + saved_num_fixups = num_fixups; + + memcpy (saved_fixups, fixups, sizeof (fixups[0]) * num_fixups); + + num_fixups = 0; +} + +void +cgen_restore_fixups () +{ + num_fixups = saved_num_fixups; + + memcpy (fixups, saved_fixups, sizeof (fixups[0]) * num_fixups); + + saved_num_fixups = 0; +} + +void +cgen_swap_fixups () +{ + int tmp; + struct fixup tmp_fixup; + + if (num_fixups == 0) + { + cgen_restore_fixups (); + } + else if (saved_num_fixups == 0) + { + cgen_save_fixups (); + } + else + { + tmp = saved_num_fixups; + saved_num_fixups = num_fixups; + num_fixups = tmp; + + for (tmp = MAX_FIXUPS; tmp--;) + { + tmp_fixup = saved_fixups [tmp]; + saved_fixups [tmp] = fixups [tmp]; + fixups [tmp] = tmp_fixup; + } + } } /* Default routine to record a fixup. @@ -101,16 +159,16 @@ cgen_queue_fixup (opindex, opinfo, expP) fixS * cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset) - fragS *frag; - int where; - const struct cgen_insn *insn; - int length; - const struct cgen_operand *operand; - int opinfo; - symbolS *symbol; - offsetT offset; + fragS * frag; + int where; + const CGEN_INSN * insn; + int length; + const CGEN_OPERAND * operand; + int opinfo; + symbolS * symbol; + offsetT offset; { - fixS *fixP; + fixS * fixP; /* It may seem strange to use operand->attrs and not insn->attrs here, but it is the operand that has a pc relative relocation. */ @@ -118,7 +176,7 @@ cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset) fixP = fix_new (frag, where, length / 8, symbol, offset, CGEN_OPERAND_ATTR (operand, CGEN_OPERAND_PCREL_ADDR) != 0, (bfd_reloc_code_real_type) ((int) BFD_RELOC_UNUSED + CGEN_OPERAND_INDEX (operand))); - fixP->tc_fix_data.insn = (PTR) insn; + fixP->tc_fix_data.insn = (PTR) insn; fixP->tc_fix_data.opinfo = opinfo; return fixP; @@ -139,15 +197,15 @@ cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset) fixS * cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) - fragS *frag; - int where; - const struct cgen_insn *insn; - int length; - const struct cgen_operand *operand; - int opinfo; - expressionS *exp; + fragS * frag; + int where; + const CGEN_INSN * insn; + int length; + const CGEN_OPERAND * operand; + int opinfo; + expressionS * exp; { - fixS *fixP; + fixS * fixP; /* It may seem strange to use operand->attrs and not insn->attrs here, but it is the operand that has a pc relative relocation. */ @@ -161,6 +219,9 @@ cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) return fixP; } +/* Used for communication between the next two procedures. */ +static jmp_buf expr_jmp_buf; + /* Callback for cgen interface. Parse the expression at *STRP. The result is an error message or NULL for success (in which case *STRP is advanced past the parsed text). @@ -174,16 +235,23 @@ cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) const char * cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP) - enum cgen_parse_operand_type want; - const char **strP; - int opindex; - int opinfo; - enum cgen_parse_operand_result *resultP; - bfd_vma *valueP; + enum cgen_parse_operand_type want; + const char ** strP; + int opindex; + int opinfo; + enum cgen_parse_operand_result * resultP; + bfd_vma * valueP; { - char *hold; - const char *errmsg = NULL; - expressionS exp; +#ifdef __STDC__ + /* These is volatile to survive the setjmp. */ + char * volatile hold; + enum cgen_parse_operand_result * volatile resultP_1; +#else + static char * hold; + static enum cgen_parse_operand_result * resultP_1; +#endif + const char * errmsg = NULL; + expressionS exp; if (want == CGEN_PARSE_OPERAND_INIT) { @@ -191,10 +259,22 @@ cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP) return NULL; } + resultP_1 = resultP; hold = input_line_pointer; - input_line_pointer = (char *) *strP; - expression (&exp); - *strP = input_line_pointer; + input_line_pointer = (char *) * strP; + + /* We rely on md_operand to longjmp back to us. + This is done via cgen_md_operand. */ + if (setjmp (expr_jmp_buf) != 0) + { + input_line_pointer = (char *) hold; + * resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR; + return "illegal operand"; + } + + expression (& exp); + + * strP = input_line_pointer; input_line_pointer = hold; /* FIXME: Need to check `want'. */ @@ -203,48 +283,63 @@ cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP) { case O_illegal : errmsg = "illegal operand"; - *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; + * resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; break; case O_absent : errmsg = "missing operand"; - *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; + * resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; break; case O_constant : - *valueP = exp.X_add_number; - *resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER; + * valueP = exp.X_add_number; + * resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER; break; case O_register : - *valueP = exp.X_add_number; - *resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER; + * valueP = exp.X_add_number; + * resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER; break; default : - cgen_queue_fixup (opindex, opinfo, &exp); - *valueP = 0; - *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED; + cgen_queue_fixup (opindex, opinfo, & exp); + * valueP = 0; + * resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED; break; } return errmsg; } +/* md_operand handler to catch unrecognized expressions and halt the + parsing process so the next entry can be tried. + + ??? This could be done differently by adding code to `expression'. */ + +void +cgen_md_operand (expressionP) + expressionS * expressionP; +{ + longjmp (expr_jmp_buf, 1); +} + /* Finish assembling instruction INSN. BUF contains what we've built up so far. - LENGTH is the size of the insn in bits. */ + LENGTH is the size of the insn in bits. + Returns the address of the buffer containing the assembled instruction, + in case the caller needs to modify it for some reason. */ -void +char * cgen_asm_finish_insn (insn, buf, length) - const struct cgen_insn *insn; - cgen_insn_t *buf; - unsigned int length; + const CGEN_INSN * insn; + cgen_insn_t * buf; + unsigned int length; { - int i, relax_operand; - char *f; + int i; + int relax_operand; + char * f; unsigned int byte_len = length / 8; /* ??? Target foo issues various warnings here, so one might want to provide a hook here. However, our caller is defined in tc-foo.c so there shouldn't be a need for a hook. */ - + /* Write out the instruction. It is important to fetch enough space in one call to `frag_more'. We use (f - frag_now->fr_literal) to compute where we are and we @@ -264,7 +359,7 @@ cgen_asm_finish_insn (insn, buf, length) /* Scan the fixups for the operand affected by relaxing (i.e. the branch address). */ - for (i = 0; i < num_fixups; ++i) + for (i = 0; i < num_fixups; ++ i) { if (CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex], CGEN_OPERAND_RELAX) != 0) @@ -277,8 +372,8 @@ cgen_asm_finish_insn (insn, buf, length) if (relax_operand != -1) { - int max_len; - fragS *old_frag; + int max_len; + fragS * old_frag; #ifdef TC_CGEN_MAX_RELAX max_len = TC_CGEN_MAX_RELAX (insn, byte_len); @@ -288,10 +383,13 @@ cgen_asm_finish_insn (insn, buf, length) /* Ensure variable part and fixed part are in same fragment. */ /* FIXME: Having to do this seems like a hack. */ frag_grow (max_len); + /* Allocate space for the fixed part. */ f = frag_more (byte_len); + /* Create a relaxable fragment for this instruction. */ old_frag = frag_now; + frag_var (rs_machine_dependent, max_len - byte_len /* max chars */, 0 /* variable part already allocated */, @@ -301,14 +399,12 @@ cgen_asm_finish_insn (insn, buf, length) fixups[relax_operand].exp.X_add_symbol, fixups[relax_operand].exp.X_add_number, f); + /* Record the operand number with the fragment so md_convert_frag can use cgen_md_record_fixup to record the appropriate reloc. */ - /* FIXME: fr_targ.cgen is used pending deciding whether to - allow a target to add members to fragS. For more info - see the comment above fr_targ in as.h. */ - old_frag->fr_targ.cgen.insn = insn; - old_frag->fr_targ.cgen.opindex = fixups[relax_operand].opindex; - old_frag->fr_targ.cgen.opinfo = fixups[relax_operand].opinfo; + old_frag->fr_cgen.insn = insn; + old_frag->fr_cgen.opindex = fixups[relax_operand].opindex; + old_frag->fr_cgen.opinfo = fixups[relax_operand].opinfo; } else f = frag_more (byte_len); @@ -320,15 +416,15 @@ cgen_asm_finish_insn (insn, buf, length) { case 16: if (cgen_big_endian_p) - bfd_putb16 ((bfd_vma) *buf, f); + bfd_putb16 ((bfd_vma) * buf, f); else - bfd_putl16 ((bfd_vma) *buf, f); + bfd_putl16 ((bfd_vma) * buf, f); break; case 32: if (cgen_big_endian_p) - bfd_putb32 ((bfd_vma) *buf, f); + bfd_putb32 ((bfd_vma) * buf, f); else - bfd_putl32 ((bfd_vma) *buf, f); + bfd_putl32 ((bfd_vma) * buf, f); break; default: abort (); @@ -356,8 +452,10 @@ cgen_asm_finish_insn (insn, buf, length) insn, length, & CGEN_SYM (operand_table) [fixups[i].opindex], fixups[i].opinfo, - &fixups[i].exp); + & fixups[i].exp); } + + return f; } /* Apply a fixup to the object code. This is called for all the @@ -374,11 +472,11 @@ cgen_asm_finish_insn (insn, buf, length) int cgen_md_apply_fix3 (fixP, valueP, seg) - fixS *fixP; - valueT *valueP; - segT seg; + fixS * fixP; + valueT * valueP; + segT seg; { - char *where = fixP->fx_frag->fr_literal + fixP->fx_where; + char * where = fixP->fx_frag->fr_literal + fixP->fx_where; valueT value; /* FIXME FIXME FIXME: The value we are passed in *valuep includes @@ -394,11 +492,11 @@ cgen_md_apply_fix3 (fixP, valueP, seg) if (fixP->fx_addsy == (symbolS *) NULL) { - value = *valueP; + value = * valueP; fixP->fx_done = 1; } else if (fixP->fx_pcrel) - value = *valueP; + value = * valueP; else { value = fixP->fx_offset; @@ -417,12 +515,12 @@ cgen_md_apply_fix3 (fixP, valueP, seg) if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) { - int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; - const struct cgen_operand *operand = & CGEN_SYM (operand_table) [opindex]; - const char *errmsg; + int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; + const CGEN_OPERAND * operand = & CGEN_SYM (operand_table) [opindex]; + const char * errmsg; bfd_reloc_code_real_type reloc_type; - struct cgen_fields fields; - const struct cgen_insn *insn = (struct cgen_insn *) fixP->tc_fix_data.insn; + CGEN_FIELDS fields; + const CGEN_INSN * insn = (CGEN_INSN *) fixP->tc_fix_data.insn; /* If the reloc has been fully resolved finish the operand here. */ /* FIXME: This duplicates the capabilities of code in BFD. */ @@ -431,14 +529,11 @@ cgen_md_apply_fix3 (fixP, valueP, seg) finish the job. Testing for pcrel is a temporary hack. */ || fixP->fx_pcrel) { - /* This may seem like overkill, and using bfd_install_relocation or - some such may be preferable, but this is simple. */ - CGEN_FIELDS_BITSIZE (&fields) = CGEN_INSN_BITSIZE (insn); - CGEN_SYM (set_operand) (opindex, &value, &fields); - errmsg = CGEN_SYM (validate_operand) (opindex, &fields); + CGEN_FIELDS_BITSIZE (& fields) = CGEN_INSN_BITSIZE (insn); + CGEN_SYM (set_operand) (opindex, & value, & fields); + errmsg = CGEN_SYM (insert_operand) (opindex, & fields, where); if (errmsg) as_warn_where (fixP->fx_file, fixP->fx_line, "%s\n", errmsg); - CGEN_SYM (insert_operand) (opindex, &fields, where); } if (fixP->fx_done) @@ -501,10 +596,10 @@ cgen_md_apply_fix3 (fixP, valueP, seg) arelent * cgen_tc_gen_reloc (section, fixP) - asection *section; - fixS *fixP; + asection * section; + fixS * fixP; { - arelent *reloc; + arelent * reloc; reloc = (arelent *) bfd_alloc (stdoutput, sizeof (arelent)); @@ -519,9 +614,9 @@ cgen_tc_gen_reloc (section, fixP) assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); - reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym; - reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; - reloc->addend = fixP->fx_addnumber; + reloc->sym_ptr_ptr = & fixP->fx_addsy->bsym; + reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; + reloc->addend = fixP->fx_addnumber; return reloc; } -- cgit v1.1