📄 tc-m68hc11.c
字号:
if (i == 0 && (format & M6811_OP_BITMASK)) break; } if (mode & (M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16)) { if (format & (M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16)) continue; } if (mode & M6812_OP_REG) { if (i == 0 && (format & M6812_OP_REG) && (operands[i].reg2 == REG_NONE)) continue; if (i == 0 && (format & M6812_OP_REG) && (format & M6812_OP_REG_2) && (operands[i].reg2 != REG_NONE)) continue; if (i == 0 && (format & M6812_OP_IDX) && (operands[i].reg2 != REG_NONE)) continue; if (i == 0 && (format & M6812_OP_D_IDX)) continue; if (i == 0 && (format & M6812_OP_IDX) && (format & (M6812_OP_IND16_P2 | M6812_OP_IDX_P2))) continue; if (i == 1 && (format & M6812_OP_IDX_P2)) continue; break; } if (mode & M6812_OP_IDX) { if (format & M6811_OP_IX && operands[i].reg1 == REG_X) continue; if (format & M6811_OP_IY && operands[i].reg1 == REG_Y) continue; if (i == 0 && format & (M6812_OP_IDX | M6812_OP_IDX_1 | M6812_OP_IDX_2) && (operands[i].reg1 == REG_X || operands[i].reg1 == REG_Y || operands[i].reg1 == REG_SP || operands[i].reg1 == REG_PC)) continue; if (i == 1 && format & M6812_OP_IDX_P2) continue; } if (mode & M6812_AUTO_INC_DEC) { if (i == 0 && format & (M6812_OP_IDX | M6812_OP_IDX_1 | M6812_OP_IDX_2)) continue; if (i == 1 && format & M6812_OP_IDX_P2) continue; } break; } match = i == nb_operands; /* Operands are ok but an operand uses page 0 addressing mode while the insn supports abs-16 mode. Keep a reference to this insns in case there is no insn supporting page 0 addressing. */ if (match && poss_indirect) { op_indirect = opcode; match = 0; } if (match) break; } /* Page 0 addressing is used but not supported by any insn. If absolute addresses are supported, we use that insn. */ if (match == 0 && op_indirect) { opcode = op_indirect; match = 1; } if (!match) { return (0); } return opcode;}/* Find the real opcode and its associated operands. We use a progressive approach here. On entry, 'opc' points to the first opcode in the table that matches the opcode name in the source line. We try to isolate an operand, find a possible match in the opcode table. We isolate another operand if no match were found. The table 'operands' is filled while operands are recognized. Returns the opcode pointer that matches the opcode name in the source line and the associated operands. */static struct m68hc11_opcode *find_opcode (opc, operands, nb_operands) struct m68hc11_opcode_def *opc; operand operands[]; int *nb_operands;{ struct m68hc11_opcode *opcode; int i; if (opc->max_operands == 0) { *nb_operands = 0; return opc->opcode; } for (i = 0; i < opc->max_operands;) { int result; result = get_operand (&operands[i], i, opc->format); if (result <= 0) return 0; /* Special case where the bitmask of the bclr/brclr instructions is not introduced by #. Example: bclr 3,x $80. */ if (i == 1 && (opc->format & M6811_OP_BITMASK) && (operands[i].mode & M6811_OP_IND16)) { operands[i].mode = M6811_OP_IMM16; } i += result; *nb_operands = i; if (i >= opc->min_operands) { opcode = find (opc, operands, i); if (opcode) return opcode; } if (*input_line_pointer == ',') input_line_pointer++; } return 0;}#define M6812_XBCC_MARKER (M6812_OP_TBCC_MARKER \ | M6812_OP_DBCC_MARKER \ | M6812_OP_IBCC_MARKER)/* Gas line assembler entry point. *//* This is the main entry point for the machine-dependent assembler. str points to a machine-dependent instruction. This function is supposed to emit the frags/bytes it assembles to. */voidmd_assemble (str) char *str;{ struct m68hc11_opcode_def *opc; struct m68hc11_opcode *opcode; unsigned char *op_start, *save; unsigned char *op_end; char name[20]; int nlen = 0; operand operands[M6811_MAX_OPERANDS]; int nb_operands; int branch_optimize = 0; int alias_id = -1; /* Drop leading whitespace. */ while (*str == ' ') str++; /* Find the opcode end and get the opcode in 'name'. The opcode is forced lower case (the opcode table only has lower case op-codes). */ for (op_start = op_end = (unsigned char *) (str); *op_end && nlen < 20 && !is_end_of_line[*op_end] && *op_end != ' '; op_end++) { name[nlen] = tolower (op_start[nlen]); nlen++; } name[nlen] = 0; if (nlen == 0) { as_bad (_("No instruction or missing opcode.")); return; } /* Find the opcode definition given its name. */ opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, name); /* If it's not recognized, look for 'jbsr' and 'jbxx'. These are pseudo insns for relative branch. For these branchs, we always optimize them (turned into absolute branchs) even if --short-branchs is given. */ if (opc == NULL && name[0] == 'j' && name[1] == 'b') { opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, &name[1]); if (opc && (!(opc->format & M6811_OP_JUMP_REL) || (opc->format & M6811_OP_BITMASK))) opc = 0; if (opc) branch_optimize = 1; } /* The following test should probably be removed. This is not conform to Motorola assembler specs. */ if (opc == NULL && flag_mri) { if (*op_end == ' ' || *op_end == '\t') { while (*op_end == ' ' || *op_end == '\t') op_end++; if (nlen < 19 && (*op_end && (is_end_of_line[op_end[1]] || op_end[1] == ' ' || op_end[1] == '\t' || !isalnum (op_end[1]))) && (*op_end == 'a' || *op_end == 'b' || *op_end == 'A' || *op_end == 'B' || *op_end == 'd' || *op_end == 'D' || *op_end == 'x' || *op_end == 'X' || *op_end == 'y' || *op_end == 'Y')) { name[nlen++] = tolower (*op_end++); name[nlen] = 0; opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, name); } } } /* Identify a possible instruction alias. There are some on the 68HC12 to emulate a few 68HC11 instructions. */ if (opc == NULL && (current_architecture & cpu6812)) { int i; for (i = 0; i < m68hc12_num_alias; i++) if (strcmp (m68hc12_alias[i].name, name) == 0) { alias_id = i; break; } } if (opc == NULL && alias_id < 0) { as_bad (_("Opcode `%s' is not recognized."), name); return; } save = input_line_pointer; input_line_pointer = op_end; if (opc) { opc->used++; opcode = find_opcode (opc, operands, &nb_operands); } else opcode = 0; if ((opcode || alias_id >= 0) && !flag_mri) { char *p = input_line_pointer; while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; if (*p != '\n' && *p) as_bad (_("Garbage at end of instruction: `%s'."), p); } input_line_pointer = save; if (alias_id >= 0) { char *f = m68hc11_new_insn (m68hc12_alias[alias_id].size); number_to_chars_bigendian (f, m68hc12_alias[alias_id].code1, 1); if (m68hc12_alias[alias_id].size > 1) number_to_chars_bigendian (f + 1, m68hc12_alias[alias_id].code2, 1); return; } /* Opcode is known but does not have valid operands. Print out the syntax for this opcode. */ if (opcode == 0) { if (flag_print_insn_syntax) print_insn_format (name); as_bad (_("Invalid operand for `%s'"), name); return; } /* Treat dbeq/ibeq/tbeq instructions in a special way. The branch is relative and must be in the range -256..255 (9-bits). */ if ((opcode->format & M6812_XBCC_MARKER) && (opcode->format & M6811_OP_JUMP_REL)) build_dbranch_insn (opcode, operands, nb_operands); /* Relative jumps instructions are taken care of separately. We have to make sure that the relative branch is within the range -128..127. If it's out of range, the instructions are changed into absolute instructions. This is not supported for the brset and brclr instructions. */ else if ((opcode->format & (M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16)) && !(opcode->format & M6811_OP_BITMASK)) build_jump_insn (opcode, operands, nb_operands, branch_optimize); else build_insn (opcode, operands, nb_operands);}/* Relocation, relaxation and frag conversions. */longmd_pcrel_from_section (fixp, sec) fixS *fixp; segT sec;{ int adjust; if (fixp->fx_addsy != (symbolS *) NULL && (!S_IS_DEFINED (fixp->fx_addsy) || (S_GET_SEGMENT (fixp->fx_addsy) != sec))) return 0; adjust = fixp->fx_pcrel_adjust; return fixp->fx_frag->fr_address + fixp->fx_where + adjust;}/* If while processing a fixup, a reloc really needs to be created then it is done here. */arelent *tc_gen_reloc (section, fixp) asection *section; 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; if (fixp->fx_r_type == 0) reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16); else 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, _("Relocation %d is not supported by object file format."), (int) fixp->fx_r_type); return NULL; } if (!fixp->fx_pcrel) reloc->addend = fixp->fx_addnumber; else reloc->addend = (section->vma + (fixp->fx_pcrel_adjust == 64 ? -1 : fixp->fx_pcrel_adjust) + fixp->fx_addnumber + md_pcrel_from_section (fixp, section)); return reloc;}voidmd_convert_frag (abfd, sec, fragP) bfd *abfd ATTRIBUTE_UNUSED; asection *sec ATTRIBUTE_UNUSED; fragS *fragP;{ fixS *fixp; long value; long disp; char *buffer_address = fragP->fr_literal; /* Address in object code of the displacement. */ register int object_address = fragP->fr_fix + fragP->fr_address; buffer_address += fragP->fr_fix; /* The displacement of the address, from current location. */ value = fragP->fr_symbol ? S_GET_VALUE (fragP->fr_symbol) : 0; disp = (value + fragP->fr_offset) - object_address; disp += symbol_get_frag (fragP->fr_symbol)->fr_address; switch (fragP->fr_subtype) { case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE): fragP->fr_opcode[1] = disp; break; case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD): /* This relax is only for bsr and bra. */ assert (IS_OPCODE (fragP->fr_opcode[0], M6811_BSR) || IS_OPCODE (fragP->fr_opcode[0], M6811_BRA) || IS_OPCODE (fragP->fr_opcode[0], M6812_BSR)); fragP->fr_opcode[0] = convert_branch (fragP->fr_opcode[0]); fix_new (fragP, fragP->fr_fix - 1, 2, fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_16); fragP->fr_fix += 1; break; case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE): case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH_6812, STATE_BYTE): fragP->fr_opcode[1] = disp; break; case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD): /* Invert branch. */ fragP->fr_opcode[0] ^= 1; fragP->fr_opcode[1] = 3; /* Branch offset. */ buffer_address[0] = M6811_JMP; fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_16); fragP->fr_fix += 3; break; case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH_6812, STATE_WORD): /* Translate branch into a long branch. */ fragP->fr_opcode[1] = fragP->fr_opcode[0]; fragP->fr_opcode[0] = M6811_OPCODE_PAGE2; fixp = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 1, BFD_RELOC_16_PCREL); fixp->fx_pcrel_adjust = 2; fragP->fr_fix += 2; break; case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS5): fragP->fr_opcode[0] = fragP->fr_opcode[0] << 6; if ((fragP->fr_opcode[0] & 0x0ff) == 0x0c0) fragP->fr_opcode[0] |= disp & 0x1f; else fragP->fr_opcode[0] |= value & 0x1f; break; case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS9): fragP->fr_opcode[0] = (fragP->fr_opcode[0] << 3); fragP->fr_opcode[0] |= 0xE0; fix_new (fragP, fragP->fr_fix, 1, fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_8); fragP->fr_fix += 1; break; case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS16): fragP->fr_opcode[0] = (fragP->fr_opcode[0] << 3); fragP->fr_opcode[0] |= 0xe2; if ((fragP->fr_opcode[0] & 0x0ff) == 0x0fa) { fixp = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 1, BFD_RELOC_16_PCREL); fixp->fx_pcrel_adjust = 2; } else { fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_16); } fragP->fr_fix += 2; break; case ENCODE_RELAX (STATE_XBCC_BRANCH, STATE_BYTE): if (disp < 0) fragP->fr_opcode[0] |= 0x10; fragP->fr_opcode[1] = disp & 0x0FF; break; case ENCODE_RELAX (STATE_XBCC_BRANCH, STATE_WORD): /* Invert branch. */ fragP->fr_opcode[0] ^= 0x20; fragP->fr_opcode[1] = 3; /* Branch offset. */ buffer_address[0] = M6812_JMP; fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_16); fragP->fr_fix += 3; break; default: break; }}/* On an ELF system, we can't relax a weak symbol. The weak symbol can be overridden at final link time by a non weak symbol. We can relax externally visible symbol because there is no shared library and such symbol can't be overridden (unless they are weak). */static intrelaxable_symbol (symbol) symbolS *symbol;{ return ! S_IS_WEAK (symbol);}/* Force truly undefined symbols to their maximum size, and generally set up the frag list to be relaxed. */intmd_estim
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -