📄 tc-mn10200.c
字号:
case O_illegal: errmsg = _("illegal operand"); goto error; case O_absent: errmsg = _("missing operand"); goto error; case O_register: if ((operand->flags & (MN10200_OPERAND_DREG | MN10200_OPERAND_AREG)) == 0) { input_line_pointer = hold; str = hold; goto error; } if (opcode->format == FMT_2 || opcode->format == FMT_5) extra_shift = 8; else if (opcode->format == FMT_3 || opcode->format == FMT_6 || opcode->format == FMT_7) extra_shift = 16; else extra_shift = 0; mn10200_insert_operand (&insn, &extension, operand, ex.X_add_number, (char *) NULL, 0, extra_shift); break; case O_constant: /* If this operand can be promoted, and it doesn't fit into the allocated bitfield for this insn, then promote it (ie this opcode does not match). */ if (operand->flags & (MN10200_OPERAND_PROMOTE | MN10200_OPERAND_RELAX) && !check_operand (insn, operand, ex.X_add_number)) { input_line_pointer = hold; str = hold; goto error; } mn10200_insert_operand (&insn, &extension, operand, ex.X_add_number, (char *) NULL, 0, 0); break; default: /* If this operand can be promoted, then this opcode didn't match since we can't know if it needed promotion! */ if (operand->flags & MN10200_OPERAND_PROMOTE) { input_line_pointer = hold; str = hold; goto error; } /* 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; }keep_going: str = input_line_pointer; input_line_pointer = hold; while (*str == ' ' || *str == ',') ++str; } /* Make sure we used all the operands! */ if (*str != ',') match = 1; error: if (match == 0) { next_opcode = opcode + 1; if (!strcmp (next_opcode->name, opcode->name)) { opcode = next_opcode; continue; } as_bad ("%s", errmsg); return; } break; } while (isspace (*str)) ++str; if (*str != '\0') as_bad (_("junk at end of line: `%s'"), str); input_line_pointer = str; if (opcode->format == FMT_1) size = 1; else if (opcode->format == FMT_2 || opcode->format == FMT_4) size = 2; else if (opcode->format == FMT_3 || opcode->format == FMT_5) size = 3; else if (opcode->format == FMT_6) size = 4; else if (opcode->format == FMT_7) size = 5; else abort (); /* Write out the instruction. */ if (relaxable && fc > 0) { int type; /* bCC */ if (size == 2 && opcode->opcode != 0xfc0000) { /* Handle bra specially. Basically treat it like jmp so that we automatically handle 8, 16 and 32 bit offsets correctly as well as jumps to an undefined address. It is also important to not treat it like other bCC instructions since the long forms of bra is different from other bCC instructions. */ if (opcode->opcode == 0xea00) type = 8; else type = 0; } /* jsr */ else if (size == 3 && opcode->opcode == 0xfd0000) type = 6; /* jmp */ else if (size == 3 && opcode->opcode == 0xfc0000) type = 8; /* bCCx */ else type = 3; f = frag_var (rs_machine_dependent, 8, 8 - size, type, fixups[0].exp.X_add_symbol, fixups[0].exp.X_add_number, (char *)fixups[0].opindex); number_to_chars_bigendian (f, insn, size); if (8 - size > 4) { number_to_chars_bigendian (f + size, 0, 4); number_to_chars_bigendian (f + size + 4, 0, 8 - size - 4); } else number_to_chars_bigendian (f + size, 0, 8 - size); } else { f = frag_more (size); /* Oh, what a mess. The instruction is in big endian format, but 16 and 24bit immediates are little endian! */ if (opcode->format == FMT_3) { number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1); number_to_chars_littleendian (f + 1, insn & 0xffff, 2); } else if (opcode->format == FMT_6) { number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2); number_to_chars_littleendian (f + 2, insn & 0xffff, 2); } else if (opcode->format == FMT_7) { number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2); number_to_chars_littleendian (f + 2, insn & 0xffff, 2); number_to_chars_littleendian (f + 4, extension & 0xff, 1); } else { number_to_chars_bigendian (f, insn, size > 4 ? 4 : size); } /* Create any fixups. */ for (i = 0; i < fc; i++) { const struct mn10200_operand *operand; operand = &mn10200_operands[fixups[i].opindex]; if (fixups[i].reloc != BFD_RELOC_UNUSED) { reloc_howto_type *reloc_howto; int size; int offset; fixS *fixP; reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); if (!reloc_howto) abort (); size = bfd_get_reloc_size (reloc_howto); if (size < 1 || size > 4) abort (); offset = 4 - size; fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size, &fixups[i].exp, reloc_howto->pc_relative, fixups[i].reloc); /* PC-relative offsets are from the first byte of the next instruction, not from the start of the current instruction. */ if (reloc_howto->pc_relative) fixP->fx_offset += size; } else { int reloc, pcrel, reloc_size, offset; fixS *fixP; reloc = BFD_RELOC_NONE; /* How big is the reloc? Remember SPLIT relocs are implicitly 32bits. */ reloc_size = operand->bits; offset = size - reloc_size / 8; /* Is the reloc pc-relative? */ pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0; /* Choose a proper BFD relocation type. */ if (pcrel) { if (reloc_size == 8) reloc = BFD_RELOC_8_PCREL; else if (reloc_size == 24) reloc = BFD_RELOC_24_PCREL; else abort (); } else { if (reloc_size == 32) reloc = BFD_RELOC_32; else if (reloc_size == 16) reloc = BFD_RELOC_16; else if (reloc_size == 8) reloc = BFD_RELOC_8; else if (reloc_size == 24) reloc = BFD_RELOC_24; else abort (); } /* Convert the size of the reloc into what fix_new_exp wants. */ reloc_size = reloc_size / 8; if (reloc_size == 8) reloc_size = 0; else if (reloc_size == 16) reloc_size = 1; else if (reloc_size == 32 || reloc_size == 24) reloc_size = 2; fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, reloc_size, &fixups[i].exp, pcrel, ((bfd_reloc_code_real_type) reloc)); /* PC-relative offsets are from the first byte of the next instruction, not from the start of the current instruction. */ if (pcrel) fixP->fx_offset += size; } } }}/* 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; fixS *fixp;{ arelent *reloc; reloc = (arelent *) xmalloc (sizeof (arelent)); 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, _("reloc %d not supported by object file format"), (int) fixp->fx_r_type); return NULL; } reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; if (fixp->fx_addsy && fixp->fx_subsy) { if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section) { as_bad_where (fixp->fx_file, fixp->fx_line, "Difference of symbols in different sections is not supported"); return NULL; } reloc->sym_ptr_ptr = &bfd_abs_symbol; reloc->addend = (S_GET_VALUE (fixp->fx_addsy) - S_GET_VALUE (fixp->fx_subsy) + fixp->fx_offset); } else { reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->addend = fixp->fx_offset; } return reloc;}intmd_estimate_size_before_relax (fragp, seg) fragS *fragp; asection *seg;{ if (fragp->fr_subtype == 6 && (!S_IS_DEFINED (fragp->fr_symbol) || seg != S_GET_SEGMENT (fragp->fr_symbol))) fragp->fr_subtype = 7; else if (fragp->fr_subtype == 8 && (!S_IS_DEFINED (fragp->fr_symbol) || seg != S_GET_SEGMENT (fragp->fr_symbol))) fragp->fr_subtype = 10; if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0])) abort (); return md_relax_table[fragp->fr_subtype].rlx_length;}longmd_pcrel_from (fixp) fixS *fixp;{ return fixp->fx_frag->fr_address;#if 0 if (fixp->fx_addsy != (symbolS *) NULL && !S_IS_DEFINED (fixp->fx_addsy)) { /* The symbol is undefined. Let the linker figure it out. */ return 0; } return fixp->fx_frag->fr_address + fixp->fx_where;#endif}intmd_apply_fix3 (fixp, valuep, seg) fixS *fixp; valueT *valuep; segT seg;{ /* We shouldn't ever get here because linkrelax is nonzero. */ abort (); fixp->fx_done = 1; return 0;}/* Insert an operand value into an instruction. */static voidmn10200_insert_operand (insnp, extensionp, operand, val, file, line, shift) unsigned long *insnp; unsigned long *extensionp; const struct mn10200_operand *operand; offsetT val; char *file; unsigned int line; unsigned int shift;{ /* No need to check 24 or 32bit operands for a bit. */ if (operand->bits < 24 && (operand->flags & MN10200_OPERAND_NOCHECK) == 0) { long min, max; offsetT test; if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) { max = (1 << (operand->bits - 1)) - 1; min = - (1 << (operand->bits - 1)); } else { max = (1 << operand->bits) - 1; min = 0; } test = val; if (test < (offsetT) min || test > (offsetT) max) { const char *err = _("operand out of range (%s not between %ld and %ld)"); char buf[100]; sprint_value (buf, test); if (file == (char *) NULL) as_warn (err, buf, min, max); else as_warn_where (file, line, err, buf, min, max); } } if ((operand->flags & MN10200_OPERAND_EXTENDED) == 0) { *insnp |= (((long) val & ((1 << operand->bits) - 1)) << (operand->shift + shift)); if ((operand->flags & MN10200_OPERAND_REPEATED) != 0) *insnp |= (((long) val & ((1 << operand->bits) - 1)) << (operand->shift + shift + 2)); } else { *extensionp |= (val >> 16) & 0xff; *insnp |= val & 0xffff; }}static unsigned longcheck_operand (insn, operand, val) unsigned long insn; const struct mn10200_operand *operand; offsetT val;{ /* No need to check 24bit or 32bit operands for a bit. */ if (operand->bits < 24 && (operand->flags & MN10200_OPERAND_NOCHECK) == 0) { long min, max; offsetT test; if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) { max = (1 << (operand->bits - 1)) - 1; min = - (1 << (operand->bits - 1)); } else { max = (1 << operand->bits) - 1; min = 0; } test = val; if (test < (offsetT) min || test > (offsetT) max) return 0; else return 1; } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -