fixS * 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; /* It may seem strange to use operand->attrs and not insn->attrs here, but it is the operand that has a pc relative relocation. */ fixP = fix_new_exp (frag, where, length / 8, exp, CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR), (bfd_reloc_code_real_type) ((int) BFD_RELOC_UNUSED + (int) operand->type)); fixP->fx_cgen.insn = insn; fixP->fx_cgen.opinfo = opinfo; fixP->fx_cgen.field = NULL; fixP->fx_cgen.msb_field_p = 0; return fixP; }
static void build_operand_table (CGEN_CPU_TABLE *cd) { int i; int machs = cd->machs; const CGEN_OPERAND *init = & xstormy16_cgen_operand_table[0]; /* MAX_OPERANDS is only an upper bound on the number of selected entries. However each entry is indexed by it's enum so there can be holes in the table. */ const CGEN_OPERAND **selected = xmalloc (MAX_OPERANDS * sizeof (* selected)); cd->operand_table.init_entries = init; cd->operand_table.entry_size = sizeof (CGEN_OPERAND); memset (selected, 0, MAX_OPERANDS * sizeof (CGEN_OPERAND *)); /* ??? For now we just use mach to determine which ones we want. */ for (i = 0; init[i].name != NULL; ++i) if (CGEN_OPERAND_ATTR_VALUE (&init[i], CGEN_OPERAND_MACH) & machs) selected[init[i].type] = &init[i]; cd->operand_table.entries = selected; cd->operand_table.num_entries = MAX_OPERANDS; }
const char * 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. */ char * volatile hold; enum cgen_parse_operand_result * volatile resultP_1; volatile int opinfo_1; #else static char *hold; static enum cgen_parse_operand_result *resultP_1; int opinfo_1; #endif const char *errmsg; expressionS exp; #ifdef OBJ_COMPLEX_RELC volatile int signed_p = 0; symbolS * stmp = NULL; bfd_reloc_code_real_type reloc_type; const CGEN_OPERAND * operand; fixS dummy_fixup; #endif if (want == CGEN_PARSE_OPERAND_INIT) { gas_cgen_init_parse (); return NULL; } resultP_1 = resultP; hold = input_line_pointer; input_line_pointer = (char *) *strP; opinfo_1 = opinfo; /* We rely on md_operand to longjmp back to us. This is done via gas_cgen_md_operand. */ if (setjmp (expr_jmp_buf) != 0) { expr_jmp_buf_p = 0; input_line_pointer = (char *) hold; *resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR; return _("illegal operand"); } expr_jmp_buf_p = 1; expression (&exp); expr_jmp_buf_p = 0; errmsg = NULL; *strP = input_line_pointer; input_line_pointer = hold; #ifdef TC_CGEN_PARSE_FIX_EXP opinfo_1 = TC_CGEN_PARSE_FIX_EXP (opinfo_1, & exp); #endif /* FIXME: Need to check `want'. */ switch (exp.X_op) { case O_illegal: errmsg = _("illegal operand"); *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; break; case O_absent: errmsg = _("missing operand"); *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; break; case O_constant: if (want == CGEN_PARSE_OPERAND_SYMBOLIC) goto de_fault; *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; break; de_fault: default: #ifdef OBJ_COMPLEX_RELC /* Look up operand, check to see if there's an obvious overflow (this helps disambiguate some insn parses). */ operand = cgen_operand_lookup_by_num (cd, opindex); errmsg = weak_operand_overflow_check (& exp, operand); if (! errmsg) { /* Fragment the expression as necessary, and queue a reloc. */ memset (& dummy_fixup, 0, sizeof (fixS)); reloc_type = md_cgen_lookup_reloc (0, operand, & dummy_fixup); 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 || (exp.X_add_symbol->bsym->section != expr_section && exp.X_add_symbol->bsym->section != absolute_section && exp.X_add_symbol->bsym->section != undefined_section))) { /* Local labels will have been (eagerly) turned into constants by now, due to the inappropriately deep insight of the expression parser. Unfortunately make_expr_symbol prematurely dives into the symbol evaluator, and in this case it gets a bad answer, so we manually create the expression symbol we want here. */ stmp = symbol_create (FAKE_LABEL_NAME, expr_section, 0, & zero_address_frag); symbol_set_value_expression (stmp, & exp); } else stmp = make_expr_symbol (& exp); /* If this is a pc-relative RELC operand, we 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 ()); /* FIXME: this is not a perfect heuristic for figuring out whether an operand is signed: it only works when the operand is an immediate. it's not terribly likely that any other 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) && ! S_IS_LOCAL (stmp)) { if (signed_p) stmp->bsym->flags |= BSF_SRELC; else stmp->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, (reloc_type == BFD_RELOC_RELC) ? & (operand->index_fields) : 0, signed_p, -1); } * resultP = errmsg ? CGEN_PARSE_OPERAND_RESULT_ERROR : CGEN_PARSE_OPERAND_RESULT_QUEUED; *valueP = 0; #else queue_fixup (opindex, opinfo_1, &exp); *valueP = 0; *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED; #endif break; } return errmsg; }