📄 tc-v850.c
字号:
errmsg = _("register r0 cannot be used here"); /* Force an error message to be generated by skipping over any following potential matches for this opcode. */ opcode += 3; } } else if ((operand->flags & V850_OPERAND_SRG) != 0) { if (!system_register_name (&ex, true, false)) { errmsg = _("invalid system register name"); } } else if ((operand->flags & V850_OPERAND_EP) != 0) { char *start = input_line_pointer; char c = get_symbol_end (); if (strcmp (start, "ep") != 0 && strcmp (start, "r30") != 0) { /* Put things back the way we found them. */ *input_line_pointer = c; input_line_pointer = start; errmsg = _("expected EP register"); goto error; } *input_line_pointer = c; str = input_line_pointer; input_line_pointer = hold; while (*str == ' ' || *str == ',' || *str == '[' || *str == ']') ++str; continue; } else if ((operand->flags & V850_OPERAND_CC) != 0) { if (!cc_name (&ex)) { errmsg = _("invalid condition code name"); } } else if (operand->flags & V850E_PUSH_POP) { errmsg = parse_register_list (&insn, operand); /* The parse_register_list() function has already done everything, so fake a dummy expression. */ ex.X_op = O_constant; ex.X_add_number = 0; } else if (operand->flags & V850E_IMMEDIATE16) { expression (&ex); if (ex.X_op != O_constant) errmsg = _("constant expression expected"); else if (ex.X_add_number & 0xffff0000) { if (ex.X_add_number & 0xffff) errmsg = _("constant too big to fit into instruction"); else if ((insn & 0x001fffc0) == 0x00130780) ex.X_add_number >>= 16; else errmsg = _("constant too big to fit into instruction"); } extra_data_after_insn = true; extra_data_len = 2; extra_data = ex.X_add_number; ex.X_add_number = 0; } else if (operand->flags & V850E_IMMEDIATE32) { expression (&ex); if (ex.X_op != O_constant) errmsg = _("constant expression expected"); extra_data_after_insn = true; extra_data_len = 4; extra_data = ex.X_add_number; ex.X_add_number = 0; } else if (register_name (&ex) && (operand->flags & V850_OPERAND_REG) == 0) { char c; int exists = 0; /* It is possible that an alias has been defined that matches a register name. For example the code may include a ".set ZERO, 0" directive, which matches the register name "zero". Attempt to reparse the field as an expression, and only complain if we cannot generate a constant. */ input_line_pointer = str; c = get_symbol_end (); if (symbol_find (str) != NULL) exists = 1; *input_line_pointer = c; input_line_pointer = str; expression (&ex); if (ex.X_op != O_constant) { /* If this register is actually occuring too early on the parsing of the instruction, (because another field is missing) then report this. */ if (opindex_ptr[1] != 0 && (v850_operands[opindex_ptr[1]].flags & V850_OPERAND_REG)) errmsg = _("syntax error: value is missing before the register name"); else errmsg = _("syntax error: register not expected"); /* If we created a symbol in the process of this test then delete it now, so that it will not be output with the real symbols... */ if (exists == 0 && ex.X_op == O_symbol) symbol_remove (ex.X_add_symbol, &symbol_rootP, &symbol_lastP); } } else if (system_register_name (&ex, false, false) && (operand->flags & V850_OPERAND_SRG) == 0) { errmsg = _("syntax error: system register not expected"); } else if (cc_name (&ex) && (operand->flags & V850_OPERAND_CC) == 0) { errmsg = _("syntax error: condition code not expected"); } else { expression (&ex); /* Special case: If we are assembling a MOV instruction (or a CALLT.... :-) and the immediate value does not fit into the bits available then create a fake error so that the next MOV instruction will be selected. This one has a 32 bit immediate field. */ if (((insn & 0x07e0) == 0x0200) && ex.X_op == O_constant && (ex.X_add_number < (-(1 << (operand->bits - 1))) || ex.X_add_number > ((1 << operand->bits) - 1))) errmsg = _("immediate operand is too large"); } if (errmsg) goto error;#if 0 fprintf (stderr, " insn: %x, operand %d, op: %d, add_number: %d\n", insn, opindex_ptr - opcode->operands, ex.X_op, ex.X_add_number);#endif switch (ex.X_op) { case O_illegal: errmsg = _("illegal operand"); goto error; case O_absent: errmsg = _("missing operand"); goto error; case O_register: if ((operand->flags & (V850_OPERAND_REG | V850_OPERAND_SRG)) == 0) { errmsg = _("invalid operand"); goto error; } insn = v850_insert_operand (insn, operand, ex.X_add_number, (char *) NULL, 0, copy_of_instruction); break; case O_constant: insn = v850_insert_operand (insn, operand, ex.X_add_number, (char *) NULL, 0, copy_of_instruction); break; default: /* We need to generate a fixup for this expression. */ if (fc >= MAX_INSN_FIXUPS) as_fatal (_("too many fixups")); fixups[fc].exp = ex; fixups[fc].opindex = *opindex_ptr; fixups[fc].reloc = BFD_RELOC_UNUSED; ++fc; break; } } str = input_line_pointer; input_line_pointer = hold; while (*str == ' ' || *str == ',' || *str == '[' || *str == ']' || *str == ')') ++str; } match = 1; error: if (match == 0) { next_opcode = opcode + 1; if (next_opcode->name != NULL && strcmp (next_opcode->name, opcode->name) == 0) { opcode = next_opcode; /* Skip versions that are not supported by the target processor. */ if ((opcode->processors & processor_mask) == 0) goto error; continue; } as_bad ("%s: %s", copy_of_instruction, errmsg); if (*input_line_pointer == ']') ++input_line_pointer; ignore_rest_of_line (); input_line_pointer = saved_input_line_pointer; return; } break; } while (isspace (*str)) ++str; if (*str != '\0') /* xgettext:c-format */ as_bad (_("junk at end of line: `%s'"), str); input_line_pointer = str; /* Tie dwarf2 debug info to the address at the start of the insn. We can't do this after the insn has been output as the current frag may have been closed off. eg. by frag_var. */ dwarf2_emit_insn (0); /* Write out the instruction. */ if (relaxable && fc > 0) { insn_size = 2; fc = 0; if (!strcmp (opcode->name, "br")) { f = frag_var (rs_machine_dependent, 4, 2, 2, fixups[0].exp.X_add_symbol, fixups[0].exp.X_add_number, (char *) fixups[0].opindex); md_number_to_chars (f, insn, insn_size); md_number_to_chars (f + 2, 0, 2); } else { f = frag_var (rs_machine_dependent, 6, 4, 0, fixups[0].exp.X_add_symbol, fixups[0].exp.X_add_number, (char *) fixups[0].opindex); md_number_to_chars (f, insn, insn_size); md_number_to_chars (f + 2, 0, 4); } } else { /* Four byte insns have an opcode with the two high bits on. */ if ((insn & 0x0600) == 0x0600) insn_size = 4; else insn_size = 2; /* Special case: 32 bit MOV. */ if ((insn & 0xffe0) == 0x0620) insn_size = 2; f = frag_more (insn_size); md_number_to_chars (f, insn, insn_size); if (extra_data_after_insn) { f = frag_more (extra_data_len); md_number_to_chars (f, extra_data, extra_data_len); extra_data_after_insn = false; } } /* Create any fixups. At this point we do not use a bfd_reloc_code_real_type, but instead just use the BFD_RELOC_UNUSED plus the operand index. This lets us easily handle fixups for any operand type, although that is admittedly not a very exciting feature. We pick a BFD reloc type in md_apply_fix. */ for (i = 0; i < fc; i++) { const struct v850_operand *operand; bfd_reloc_code_real_type reloc; operand = &v850_operands[fixups[i].opindex]; reloc = fixups[i].reloc; if (reloc != BFD_RELOC_UNUSED) { reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc); int size; int address; fixS *fixP; if (!reloc_howto) abort (); size = bfd_get_reloc_size (reloc_howto); /* XXX This will abort on an R_V850_8 reloc - is this reloc actually used? */ if (size != 2 && size != 4) abort (); address = (f - frag_now->fr_literal) + insn_size - size; if (reloc == BFD_RELOC_32) address += 2; fixP = fix_new_exp (frag_now, address, size, &fixups[i].exp, reloc_howto->pc_relative, reloc); switch (reloc) { case BFD_RELOC_LO16: case BFD_RELOC_HI16: case BFD_RELOC_HI16_S: fixP->fx_no_overflow = 1; break; default: break; } } else { fix_new_exp (frag_now, f - frag_now->fr_literal, 4, & fixups[i].exp, 1 /* FIXME: V850_OPERAND_RELATIVE ??? */, (bfd_reloc_code_real_type) (fixups[i].opindex + (int) BFD_RELOC_UNUSED)); } } input_line_pointer = saved_input_line_pointer;}/* If while processing a fixup, a reloc really needs to be created then it is done here. */arelent *tc_gen_reloc (seg, fixp) asection *seg ATTRIBUTE_UNUSED; fixS *fixp;{ arelent *reloc; reloc = (arelent *) xmalloc (sizeof (arelent)); reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == (reloc_howto_type *) NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, /* xgettext:c-format */ _("reloc %d not supported by object file format"), (int) fixp->fx_r_type); xfree (reloc); return NULL; } if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY || fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT) reloc->addend = fixp->fx_offset; else reloc->addend = fixp->fx_addnumber; return reloc;}/* Return current size of variable part of frag. */intmd_estimate_size_before_relax (fragp, seg) fragS *fragp; asection *seg ATTRIBUTE_UNUSED;{ if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0])) abort (); return md_relax_table[fragp->fr_subtype].rlx_length;}longv850_pcrel_from_section (fixp, section) fixS *fixp; segT section;{ /* If the symbol is undefined, or in a section other than our own, or it is weak (in which case it may well be in another section, then let the linker figure it out. */ if (fixp->fx_addsy != (symbolS *) NULL && (! S_IS_DEFINED (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy) || (S_GET_SEGMENT (fixp->fx_addsy) != section))) return 0; return fixp->fx_frag->fr_address + fixp->fx_where;}intmd_apply_fix3 (fixp, valuep, seg) fixS *fixp; valueT *valuep; segT seg ATTRIBUTE_UNUSED;{ valueT value; char *where; if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) { fixp->fx_done = 0; return 1; } if (fixp->fx_addsy == (symbolS *) NULL) { value = *valuep; fixp->fx_done = 1; } else if (fixp->fx_pcrel) value = *valuep; else { value = fixp->fx_offset; if (fixp->fx_subsy != (symbolS *) NULL) { if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) value -= S_GET_VALUE (fixp->fx_subsy); else { /* We don't actually support subtracting a symbol. */ as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex")); } } } if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED) { int opindex; const struct v850_operand *operand; unsigned long insn; opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED; operand = &v850_operands[opindex]; /* Fetch the instruction, insert the fully resolved operand value, and stuff the instruction back again. Note the instruction has been stored in little endian format! */ where = fixp->fx_frag->fr_literal + fixp->fx_where; insn = bfd_getl32 ((unsigned char *) where); insn = v850_insert_operand (insn, operand, (offsetT) value, fixp->fx_file, fixp->fx_line, NULL); bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); if (fixp->fx_done) { /* Nothing else to do here. */ return 1; } /* Determine a BFD reloc value based on the operand information. We are only prepared to turn a few of the operands into relocs. */ if (operand->bits == 22) fixp->fx_r_type = BFD_RELOC_V850_22_PCREL; else if (operand->bits == 9) fixp->fx_r_type = BFD_RELOC_V850_9_PCREL; else {#if 0 fprintf (stderr, "bits: %d, insn: %x\n", operand->bits, insn);#endif as_bad_where (fixp->fx_file, fixp->fx_line, _("unresolved expression that must be resolved")); fixp->fx_done = 1; return 1; } } else if (fixp->fx_done) { /* We still have to insert the value into memory! */ where = fixp->fx_frag->fr_literal + fixp->fx_where; if (fixp->fx_size == 1) *where = value & 0xff; else if (fixp->fx_size == 2) bfd_putl16 (value & 0xffff, (unsigned char *) where); else if (fixp->fx_size == 4) bfd_putl32 (value, (unsigned char *) where); } fixp->fx_addnumber = value; return 1;}/* Parse a cons expression. We have to handle hi(), lo(), etc on the v850. */voidparse_cons_expression_v850 (exp) expressionS *exp;{ /* See if there's a reloc prefix like hi() we have to handle. */ hold_cons_reloc = v850_reloc_prefix (NULL); /* Do normal expression parsing. */ expression (exp);}/* Create a fixup for a cons expression. If parse_cons_expression_v850 found a reloc prefix, then we use that reloc, else we choose an appropriate one based on the size of the expression. */voidcons_fix_new_v850 (frag, where, size, exp) fragS *frag; int where; int size; expressionS *exp;{ if (hold_cons_reloc == BFD_RELOC_UNUSED) { if (size == 4) hold_cons_reloc = BFD_RELOC_32; if (size == 2) hold_cons_reloc = BFD_RELOC_16; if (size == 1) hold_cons_reloc = BFD_RELOC_8; } if (exp != NULL) fix_new_exp (frag, where, size, exp, 0, hold_cons_reloc); else fix_new (frag, where, size, NULL, 0, 0, hold_cons_reloc); hold_cons_reloc = BFD_RELOC_UNUSED;}booleanv850_fix_adjustable (fixP) fixS *fixP;{ if (fixP->fx_addsy == NULL) return 1; /* Prevent all adjustments to global symbols. */ if (S_IS_EXTERN (fixP->fx_addsy)) return 0; /* Similarly for weak symbols. */ if (S_IS_WEAK (fixP->fx_addsy)) return 0; /* Don't adjust function names. */ if (S_IS_FUNCTION (fixP->fx_addsy)) return 0; /* We need the symbol name for the VTABLE entries. */ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 0; return 1;}intv850_force_relocation (fixP) struct fix *fixP;{ if (fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)) return 1; if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 1; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -