📄 dsmlib.c
字号:
reg(bits(12,15), ','); reg(bits(16,19), ','); reg(bits(0,3), ','); reg(bits(8,11), 0); break; } /* **** Drop through */ case 1: case 2: case 3: if (bit(4) && bit (7)) { if (!bit(5) && !bit(6)) { if (bits(22, 27) == 0) { opcode(instr, (bit(21) ? "MLA" : "MUL"), (bit(20) ? 'S' : 0)); reg(bits(16,19), ','); reg(bits(0,3), ','); reg(bits(8,11), 0); if (bit(21)) { outc(','); reg(bits(12,15), 0); } break; } if (bits(23,27) == 2 && bits (8, 11) == 0) { /* Swap */ opcode(instr, "SWP", (bit(22) ? 'B' : 0)); reg(bits(12,15), ','); reg(bits(0,3), ','); outc('['); reg(bits(16,19), ']'); break; } } else { if (!bit(25) && (bit(20) || !bit(6))) { int l; l = outs(bit(20) ? "LDR" : "STR"); l += cond(instr); if (bit(6)) { outc('S'); outc(bit(5) ? 'H' : 'B'); l += 2; } else { outc('H'); l++; } spacetocol9(l); reg(bits(12,15), ','); outc('['); reg(bits(16,19), 0); if (bit(24)) outc(','); else { outc(']'); outc(','); } if (bit(22)) { outh(bits(0, 3) + (bits(8,11)<<4), bit(23)); } else { if (!bit(23)) outc('-'); reg(bits(0,3),0); } if (bit(24)) { outc(']'); if (bit(21)) outc('!'); } break; } } } if (bits(4, 27) == 0x12fff1) { opcode(instr, "BX", 0); reg(bits(0, 3), 0); break; } if (instr == 0xe1a00000L) { opcode(instr, "NOP", 0); break; } { /* data processing */ int op = (int)bits(21,24); const char *opnames = "AND\0EOR\0SUB\0RSB\0ADD\0ADC\0SBC\0RSC\0" "TST\0TEQ\0CMP\0CMN\0ORR\0MOV\0BIC\0MVN"; if (op >= 8 && op < 12 && !bit(20)) { if ((op & 1) == 0) { opcode(instr, "MRS", 0); reg(bits(12,15), ','); if (op == 8) outs("cpsr"); else outs("spsr"); oddity = (bits(0, 11) != 0 || bits(16, 19) != 15); break; } else { char *rname = op == 9 ? "cpsr" : "spsr"; int rn = (int)bits(16, 19); char *part = rn == 1 ? "ctl" : rn == 8 ? "flg" : rn == 9 ? "all" : "?"; opcode(instr, "MSR", 0); outs(rname); outf("_%s,", part); oddity = bits(12,15) != 15; } } else { int ch = (!bit(20)) ? 0 : (op>=8 && op<12) ? (bits(12,15)==15 ? 'P' : 0) : 'S'; opcode(instr, opnames+4*op, ch); if (!(op >= 8 && op < 12)) { /* not TST TEQ CMP CMN */ /* print the dest reg */ reg(bits(12,15), ','); } if (op != 13 && op != 15) { /* not MOV MVN */ reg(bits(16,19), ','); } } if (bit(25)) { /* rhs is immediate */ int shift = 2 * (int)bits(8,11); INT32 operand = ror(bits(0,7), shift); outh(operand, 1); } else { /* rhs is a register */ shiftedreg(instr); } } break; case 0xA: case 0xB: opcode(instr, (bit(24) ? "BL" : "B"), 0); { INT32 offset = (((INT32)bits(0,23))<<8)>>6; /* sign extend and * 4 */ address += offset + 8; prtAddress(address); } break; case 6: case 7: /* * Cope with the case where register shift register is specified * as this is an undefined instruction rather than an LDR or STR */ if (bit(4)) { outs("Undefined Instruction"); break; } /* ***** Drop through to always LDR / STR case */ case 4: case 5: { int l; l = outs(bit(20) ? "LDR" : "STR"); l += cond(instr); if (bit(22)) { outc('B'); l++; } if (!bit(24) && bit(21)) /* post, writeback */ { outc('T'); l++; } spacetocol9(l); reg(bits(12,15), ','); outAddress(instr, address, bits(0,11), prtAddress); break; } case 8: case 9: { int l; l = outs(bit(20) ? "LDM" : "STM"); l += cond(instr); l += outs("DA\0\0IA\0\0DB\0\0IB" + 4*(int)bits(23,24)); spacetocol9(l); reg(bits(16,19), 0); if (bit(21)) outc('!'); outc(','); outregset(instr); if (bit(22)) outc('^'); break; } case 0xF: opcode(instr, "SWI", 0); { INT32 swino = bits(0,23); outx(swino); } break; case 0xE: if (bit(4)==0) { /* CP data processing */ switch(bits(8,11)) { case 1: fp_cpdo(instr, &oddity); break; default: generic_cpdo(instr); break; } } else { /* CP reg to/from ARM reg */ switch (bits(8,11)) { case 1: fp_cprt(instr); break; default: generic_cprt(instr); break; } } break; case 0xC: case 0xD: switch (bits(8,11)) { case 1: fp_cpdt(instr, address, prtAddress); break; case 2: fm_cpdt(instr, address, prtAddress); break; default: generic_cpdt(instr, address, prtAddress); break; } break; default: outs("EQUD "); outx(instr); errnoSet (S_dsmLib_UNKNOWN_INSTRUCTION); break; } /* endswitch */ if (oddity) outs(" ; (?)"); outc('\n'); return 4; } /* disass_32() */#endif /* INCLUDE_ARM_DISASM */#ifdef INCLUDE_THUMB_DISASM/********************************************************************************* t_opcode - display the opcode of a Thumb instruction** RETURNS: N/A** NOMANUAL**/LOCAL void t_opcode ( const char * op /* the opcode as a string */ ) { int l; /* display the opcode */ l = outs(op); /* pad with spaces to column 9 */ spacetocol9(l); return; } /* t_opcode() *//********************************************************************************* disass_16 - disassemble a Thumb (16-bit) instruction** RETURNS: size of instruction, in bytes** NOMANUAL**/UINT32 disass_16 ( UINT32 instr, /* the value of the instruction */ UINT32 instr2, /* the value of the next instruction */ UINT32 address, /* the address to print before instruction */ VOIDFUNCPTR prtAddress /* routine to print addresses as symbols */ ) { INT32 Rd, Rm, Rn, Ro; INT32 imm5, imm8, imm11; INT32 L, B; Rd = bits(0, 2); Rm = bits(3, 5); Rn = bits(6, 8); Ro = bits(8, 10);#define imm3 Rn imm11 = bits(0, 10); imm8 = bits(0, 7); imm5 = bits(6, 10); L = bit(11);#define SP L#define H L B = bit(10);#define S B#define I B switch (bits(11, 15)) { case 3: if (bit(9) == 0 && I && imm3 == 0) { t_opcode("MOV"); reg(Rd, ','); reg(Rm, 0); break; } t_opcode(bit(9) ? "SUB" : "ADD"); reg(Rd, ','); if (Rd != Rm) reg(Rm, ','); I ? outh(imm3, 1) : reg(Rn, 0 ); break; case 10: case 11: t_opcode("STR\0*STRH\0STRB\0LDSB\0LDR\0*LDRH\0LDRB\0LDSH" + bits(9, 11) * 5); reg(Rd, ','); outc('['); reg(Rm, ','); reg(Rn, ']'); break; case 12: case 13: imm5 <<= 1; case 16: case 17: imm5 <<= 1; case 14: case 15: t_opcode("STR\0*LDR\0*STRB\0LDRB\0STRH\0LDRH\0" + (bits(11, 15) - 12) * 5); reg(Rd, ','); outc('['); reg(Rm, ','); outh(imm5, 1); outc(']'); break; case 0: case 1: case 2: t_opcode("LSL\0LSR\0ASR" + bits(11, 12) * 4); reg(Rd, ','); if (Rd != Rm) reg(Rm, ','); outh(imm5, 1); break; case 8: { INT32 op; op = bits(6, 10); if (op < 16) { t_opcode("AND\0EOR\0LSL\0LSR\0ASR\0ADC\0SBC\0ROR\0" "TST\0NEG\0CMP\0CMN\0ORR\0MUL\0BIC\0MVN" + op * 4); } else { if (op & 2) Rd += 8; if (op & 1) Rm += 8; switch(op) { case 17: case 18: case 19: t_opcode("ADD"); break; case 21: case 22: case 23: t_opcode("CMP"); break; case 25: case 26: case 27: t_opcode("MOV"); break; case 16: case 20: case 24: case 30: case 31: t_opcode("Undefined"); outc('\n'); return 2; case 28: case 29: t_opcode("BX"); reg(Rm, 0); outc('\n'); return 2; } /* end switch(op) */ } /* endelse (op >= 16) */ reg(Rd, ','); reg(Rm, 0); break; } /* endcase 8 */ case 4: case 5: case 6: case 7: /* ADD/SUB/MOV/CMP (large) immediate */ t_opcode("MOV\0CMP\0ADD\0SUB" + bits(11, 12) * 4); reg(Ro, ','); outh(imm8, 1); break; case 18: case 19: /* * LDR/STR SP-relative. ARM disassembler code would try to look * this up, but there seems little point in this. Display as * LDR Ro, [SP, #imm] */ t_opcode("STR\0LDR" + L * 4); reg(Ro, ','); imm8 <<= 2; outc('['); reg(13, ','); outh(imm8, 1); outc(']'); break; case 28: /* unconditional branch */ t_opcode("B"); imm11 = (imm11 << 21) / (1 << 20); prtAddress(address + imm11 + 4); break; case 22: case 23: if (!bit(10)) { if (bits(8, 11) != 0) { t_opcode("Undefined"); } else { imm8 = (imm8 & 0x7f) << 2; t_opcode(bit(7) ? "SUB" : "ADD"); reg(13, ','); outh(imm8, 1); } } else { if (bit(9)) { t_opcode("Undefined"); } else { instr &= 0x1ff; if (instr & 0x100) { instr &= ~0x100; if (L) instr |= 0x8000; else instr |= 0x4000; } t_opcode("PUSH\0POP" + L * 5); outregset(instr); } } break; case 9: t_opcode("LDR"); reg(Ro, ','); imm8 <<= 2; address = (address + 4) & ~3; prtAddress(address + imm8); break; case 24: case 25: instr &= 0xFF; t_opcode("STMIA\0LDMIA" + L * 6); reg(Ro, '!'); outc(','); outregset(instr); break; case 20: case 21: t_opcode("ADR\0ADD" + SP * 4); reg(Ro, ','); imm8 <<= 2; if (!SP) { address = (address + 4) & ~3; prtAddress(address + imm8); } else { reg(13, ','); outh(imm8, 1); } break; case 26: case 27: { /* Either SWI or conditional branch */ INT32 op; op = bits(8, 11); if (op == 15) { /* SWI */ t_opcode("SWI"); outx(imm8); } else { /* conditional branch: make up ARM instruction to display B?? */ opcode(op << 28, "B", 0); imm8 = (imm8 << 24) / (1 << 23); prtAddress(address + imm8 + 4); } break; } case 30: { /* * BL prefix: the BL Thumb instruction is actually TWO 16-bit * instructions, the BL prefix and the BL itself. */ INT32 offset; if ((instr2 & 0xf800) == 0xf800) { /* if next instruction is the BL itself */ t_opcode("BL"); offset = instr2 & 0x7ff; offset = (((imm11 << 11) | offset) << 10) / (1 << 9); prtAddress(address + offset + 4); outc('\n'); return 4; /* Note two 16-bit instructions */ } else { /* BL prefix, not followed by BL: not defined */ t_opcode("first half of BL instruction"); } break; } case 31: /* * BL suffix, but we should already have dealt with it, if * preceded by a BL prefix. */ t_opcode("second half of BL instruction"); break; default: t_opcode("Undefined"); break; } /* endswitch */ outc('\n'); return 2; } /* disass_16() */#undef imm3#undef SP#undef S#undef H#undef H1#undef H2#endif/********************************************************************************* nPrtAddress - print addresses as numbers** RETURNS: N/A** NOMANUAL**/LOCAL void nPrtAddress ( int address ) { printf ("0x%x", address); }/********************************************************************************* dsmInst - disassemble and print a single instruction** This routine disassembles and prints a single instruction on standard* output. The function passed as parameter <prtAddress> is used to print any* operands that might be construed as addresses. The function could be a* subroutine that prints a number or looks up the address in a symbol table.* The disassembled instruction will be prepended with the address passed as* a parameter.** ADDRESS-PRINTING ROUTINE* Many assembly language operands are addresses. In order to print these* addresses symbolically, dsmInst() calls a user-supplied routine, passed as a* parameter, to do the actual printing. The routine should be declared as:* .CS* void prtAddress (address)* int address; /@ address to print @/* .CE** When called, the routine prints the address on standard output in either* numeric or symbolic form. For example, the address-printing routine used* by l() looks up the address in the system symbol table and prints the* symbol associated with it, if there is one. If not, the routine prints the* address as a hex number.** If the <prtAddress> argument to dsmInst() is NULL, a default print routine is* used, which prints the address as a hexadecimal number.** The directive EQUD (declare word) is printed for unrecognized instructions.** RETURNS : The size of the instruction in units of sizeof(INSTR).*/int dsmInst ( FAST INSTR * binInst, /* Pointer to the instruction */ int address, /* Address prepended to instruction */ VOIDFUNCPTR prtAddress /* Address printing function */ ) {#ifdef INCLUDE_THUMB_DISASM UINT16 instr2 = 0;#endif /* If no address printing function has been supplied, use default */ if (prtAddress == NULL) prtAddress = nPrtAddress; /* Print the address first, then the instruction in hex */#ifdef INCLUDE_ARM_DISASM printf("%08x %08x ", address, (UINT32)*binInst); return disass_32((UINT32)*binInst, (UINT32)address, prtAddress) / sizeof(INSTR);#endif#ifdef INCLUDE_THUMB_DISASM if (INSTR_IS((*(UINT16 *)binInst), T_BL0)) { instr2 = *(((UINT16 *)binInst) + 1); if (INSTR_IS(instr2, T_BL1)) { /* * Instruction is a BL: i.e. this instruction is a BL * prefix and the next instruction is the BL itself. So, this * instruction is effectively 32-bits long. Get the next 16-bit * half of the instruction and display all of it as a 32-bit int. */ printf("%08x %04x%04x ", address, instr2, *(UINT16 *)binInst); } else /* BL prefix not followed by BL suffix */ printf("%08x %04x ", address, *(UINT16 *)binInst); } else /* Normal (16-bit) Thumb instruction */ printf("%08x %04x ", address, *(UINT16 *)binInst); return disass_16((UINT32)(*(UINT16 *)binInst), (UINT32)instr2, (UINT32)address, prtAddress) / sizeof(INSTR);#endif } /* dsmInst() *//********************************************************************************* dsmNbytes - determine the size of an instruction** This routine reports the size, in bytes, of an instruction.** RETURNS:* The size of the instruction, or* 0 if the instruction is unrecognized.**/int dsmNbytes ( FAST INSTR * binInst /* Pointer to the instruction */ ) {#if (ARM_THUMB) return INSTR_IS (*binInst, T_BL0) ? 2 * sizeof(INSTR) : sizeof(INSTR);#else return sizeof (INSTR);#endif } /* dsmNbytes() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -