📄 mips-dis.c
字号:
}/* Disassemble mips16 instructions. */static intprint_insn_mips16 (memaddr, info) bfd_vma memaddr; struct disassemble_info *info;{ int status; bfd_byte buffer[2]; int length; int insn; boolean use_extend; int extend = 0; const struct mips_opcode *op, *opend; info->bytes_per_chunk = 2; info->display_endian = info->endian; info->insn_info_valid = 1; info->branch_delay_insns = 0; info->data_size = 0; info->insn_type = dis_nonbranch; info->target = 0; info->target2 = 0; status = (*info->read_memory_func) (memaddr, buffer, 2, info); if (status != 0) { (*info->memory_error_func) (status, memaddr, info); return -1; } length = 2; if (info->endian == BFD_ENDIAN_BIG) insn = bfd_getb16 (buffer); else insn = bfd_getl16 (buffer); /* Handle the extend opcode specially. */ use_extend = false; if ((insn & 0xf800) == 0xf000) { use_extend = true; extend = insn & 0x7ff; memaddr += 2; status = (*info->read_memory_func) (memaddr, buffer, 2, info); if (status != 0) { (*info->fprintf_func) (info->stream, "extend 0x%x", (unsigned int) extend); (*info->memory_error_func) (status, memaddr, info); return -1; } if (info->endian == BFD_ENDIAN_BIG) insn = bfd_getb16 (buffer); else insn = bfd_getl16 (buffer); /* Check for an extend opcode followed by an extend opcode. */ if ((insn & 0xf800) == 0xf000) { (*info->fprintf_func) (info->stream, "extend 0x%x", (unsigned int) extend); info->insn_type = dis_noninsn; return length; } length += 2; } /* FIXME: Should probably use a hash table on the major opcode here. */ opend = mips16_opcodes + bfd_mips16_num_opcodes; for (op = mips16_opcodes; op < opend; op++) { if (op->pinfo != INSN_MACRO && (insn & op->mask) == op->match) { const char *s; if (strchr (op->args, 'a') != NULL) { if (use_extend) { (*info->fprintf_func) (info->stream, "extend 0x%x", (unsigned int) extend); info->insn_type = dis_noninsn; return length - 2; } use_extend = false; memaddr += 2; status = (*info->read_memory_func) (memaddr, buffer, 2, info); if (status == 0) { use_extend = true; if (info->endian == BFD_ENDIAN_BIG) extend = bfd_getb16 (buffer); else extend = bfd_getl16 (buffer); length += 2; } } (*info->fprintf_func) (info->stream, "%s", op->name); if (op->args[0] != '\0') (*info->fprintf_func) (info->stream, "\t"); for (s = op->args; *s != '\0'; s++) { if (*s == ',' && s[1] == 'w' && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX) == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY))) { /* Skip the register and the comma. */ ++s; continue; } if (*s == ',' && s[1] == 'v' && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ) == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX))) { /* Skip the register and the comma. */ ++s; continue; } print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr, info); } if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) { info->branch_delay_insns = 1; if (info->insn_type != dis_jsr) info->insn_type = dis_branch; } return length; } } if (use_extend) (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000); (*info->fprintf_func) (info->stream, "0x%x", insn); info->insn_type = dis_noninsn; return length;}/* Disassemble an operand for a mips16 instruction. */static voidprint_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) char type; const struct mips_opcode *op; int l; boolean use_extend; int extend; bfd_vma memaddr; struct disassemble_info *info;{ switch (type) { case ',': case '(': case ')': (*info->fprintf_func) (info->stream, "%c", type); break; case 'y': case 'w': (*info->fprintf_func) (info->stream, "%s", mips16_reg_names[((l >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY)]); break; case 'x': case 'v': (*info->fprintf_func) (info->stream, "%s", mips16_reg_names[((l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)]); break; case 'z': (*info->fprintf_func) (info->stream, "%s", mips16_reg_names[((l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ)]); break; case 'Z': (*info->fprintf_func) (info->stream, "%s", mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z) & MIPS16OP_MASK_MOVE32Z)]); break; case '0': (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[0]); break; case 'S': (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[29]); break; case 'P': (*info->fprintf_func) (info->stream, "$pc"); break; case 'R': (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[31]); break; case 'X': (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[((l >> MIPS16OP_SH_REGR32) & MIPS16OP_MASK_REGR32)]); break; case 'Y': (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[MIPS16OP_EXTRACT_REG32R (l)]); break; case '<': case '>': case '[': case ']': case '4': case '5': case 'H': case 'W': case 'D': case 'j': case '6': case '8': case 'V': case 'C': case 'U': case 'k': case 'K': case 'p': case 'q': case 'A': case 'B': case 'E': { int immed, nbits, shift, signedp, extbits, pcrel, extu, branch; shift = 0; signedp = 0; extbits = 16; pcrel = 0; extu = 0; branch = 0; switch (type) { case '<': nbits = 3; immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; extbits = 5; extu = 1; break; case '>': nbits = 3; immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; extbits = 5; extu = 1; break; case '[': nbits = 3; immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; extbits = 6; extu = 1; break; case ']': nbits = 3; immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; extbits = 6; extu = 1; break; case '4': nbits = 4; immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4; signedp = 1; extbits = 15; break; case '5': nbits = 5; immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; info->insn_type = dis_dref; info->data_size = 1; break; case 'H': nbits = 5; shift = 1; immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; info->insn_type = dis_dref; info->data_size = 2; break; case 'W': nbits = 5; shift = 2; immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; if ((op->pinfo & MIPS16_INSN_READ_PC) == 0 && (op->pinfo & MIPS16_INSN_READ_SP) == 0) { info->insn_type = dis_dref; info->data_size = 4; } break; case 'D': nbits = 5; shift = 3; immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; info->insn_type = dis_dref; info->data_size = 8; break; case 'j': nbits = 5; immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; signedp = 1; break; case '6': nbits = 6; immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; break; case '8': nbits = 8; immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; break; case 'V': nbits = 8; shift = 2; immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; /* FIXME: This might be lw, or it might be addiu to $sp or $pc. We assume it's load. */ info->insn_type = dis_dref; info->data_size = 4; break; case 'C': nbits = 8; shift = 3; immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; info->insn_type = dis_dref; info->data_size = 8; break; case 'U': nbits = 8; immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; extu = 1; break; case 'k': nbits = 8; immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; signedp = 1; break; case 'K': nbits = 8; shift = 3; immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; signedp = 1; break; case 'p': nbits = 8; immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; signedp = 1; pcrel = 1; branch = 1; info->insn_type = dis_condbranch; break; case 'q': nbits = 11; immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11; signedp = 1; pcrel = 1; branch = 1; info->insn_type = dis_branch; break; case 'A': nbits = 8; shift = 2; immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; pcrel = 1; /* FIXME: This can be lw or la. We assume it is lw. */ info->insn_type = dis_dref; info->data_size = 4; break; case 'B': nbits = 5; shift = 3; immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; pcrel = 1; info->insn_type = dis_dref; info->data_size = 8; break; case 'E': nbits = 5; shift = 2; immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; pcrel = 1; break; default: abort (); } if (! use_extend) { if (signedp && immed >= (1 << (nbits - 1))) immed -= 1 << nbits; immed <<= shift; if ((type == '<' || type == '>' || type == '[' || type == ']') && immed == 0) immed = 8; } else { if (extbits == 16) immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0); else if (extbits == 15) immed |= ((extend & 0xf) << 11) | (extend & 0x7f0); else immed = ((extend >> 6) & 0x1f) | (extend & 0x20); immed &= (1 << extbits) - 1; if (! extu && immed >= (1 << (extbits - 1))) immed -= 1 << extbits; } if (! pcrel) (*info->fprintf_func) (info->stream, "%d", immed); else { bfd_vma baseaddr; bfd_vma val; if (branch) { immed *= 2; baseaddr = memaddr + 2; } else if (use_extend) baseaddr = memaddr - 2; else { int status; bfd_byte buffer[2]; baseaddr = memaddr; /* If this instruction is in the delay slot of a jr instruction, the base address is the address of the jr instruction. If it is in the delay slot of jalr instruction, the base address is the address of the jalr instruction. This test is unreliable: we have no way of knowing whether the previous word is instruction or data. */ status = (*info->read_memory_func) (memaddr - 4, buffer, 2, info); if (status == 0 && (((info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buffer) : bfd_getl16 (buffer)) & 0xf800) == 0x1800)) baseaddr = memaddr - 4; else { status = (*info->read_memory_func) (memaddr - 2, buffer, 2, info); if (status == 0 && (((info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buffer) : bfd_getl16 (buffer)) & 0xf81f) == 0xe800)) baseaddr = memaddr - 2; } } val = (baseaddr & ~ ((1 << shift) - 1)) + immed; (*info->print_address_func) (val, info); info->target = val; } } break; case 'a': if (! use_extend) extend = 0; l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); (*info->print_address_func) (((memaddr + 4) & 0xf0000000) | l, info); info->insn_type = dis_jsr; info->target = ((memaddr + 4) & 0xf0000000) | l; info->branch_delay_insns = 1; break; case 'l': case 'L': { int need_comma, amask, smask; need_comma = 0; l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; amask = (l >> 3) & 7; if (amask > 0 && amask < 5) { (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[4]); if (amask > 1) (*info->fprintf_func) (info->stream, "-%s", mips32_reg_names[amask + 3]); need_comma = 1; } smask = (l >> 1) & 3; if (smask == 3) { (*info->fprintf_func) (info->stream, "%s??", need_comma ? "," : ""); need_comma = 1; } else if (smask > 0) { (*info->fprintf_func) (info->stream, "%s%s", need_comma ? "," : "", mips32_reg_names[16]); if (smask > 1) (*info->fprintf_func) (info->stream, "-%s", mips32_reg_names[smask + 15]); need_comma = 1; } if (l & 1) { (*info->fprintf_func) (info->stream, "%s%s", need_comma ? "," : "", mips32_reg_names[31]); need_comma = 1; } if (amask == 5 || amask == 6) { (*info->fprintf_func) (info->stream, "%s$f0", need_comma ? "," : ""); if (amask == 6) (*info->fprintf_func) (info->stream, "-$f1"); } } break; default: /* xgettext:c-format */ (*info->fprintf_func) (info->stream, _("# internal disassembler error, unrecognised modifier (%c)"), type); abort (); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -