📄 disassembler.c
字号:
}/* This Function calculates the target address from an indirect addressing * command using an 8 bit address relative to the program counter. * The return value is an absolute 16 bit address. */intdecodeRelAddr(struct MemoryMap *MemMap, int pass, unsigned char operand, int memPtr){ int addr; /* calculate address */ addr = memPtr + (signed char)operand; /* if in pass 1 check if this address has already been labelled */ if (pass == 1) addLabel(MemMap, addr, CODE); return addr;}voidprintHexList (struct MemoryMap *MemMap, struct MemChunk *Chunk, int addr, int len){ printf(" %04Xh %02X", addr-len, getByte(addr-len)); switch(len) { case 3: printf(" %02X", getByte(addr-2)); case 2: printf(" %02X", getByte(addr-1)); if(len == 2) printf(" "); break; default: printf(" "); } printf(" ");}/* dis_inst: Disassemble one instruction (pass 1) * Also increments memPtr to point to the next instruction address. * * Return -1 on error. Otherwise, return opcode byte. * * CAVEAT: Indirect jumps not handled completely (JMP @A+DPTR) */static intdis_inst1(struct MemoryMap *MemMap, struct MemChunk *Chunk, int memPtr){ unsigned char opcode, op1, op2; int newaddr = -1; MemMap->flags[memPtr] |= ADR_OPCODE; /* mark the beginning of a command */ opcode = getNextByte(1); switch(op_format[opcode]) { case 0: /* A5 is an illegal opcode */ fprintf(stderr, "Illegal opcode A5 at address %04X\n", memPtr-1); newaddr = -1; break; case 1: /* no operands */ newaddr = memPtr; if ((opcode & 0xef) == 0x22) /* RET or RETI ?*/ newaddr = -1; /* ->stop disassembling */ else if (opcode == 0x73) { /* JMP @A+DPTR ?*/ addCodeEntryRange(MemMap, DPTR, 256); newaddr = -1; } else if (opcode == 0x83) /* MOVC A,@A+PC */ addLabel(MemMap, memPtr, DATA); else if (opcode == 0x93) /* MOVC A,@A+DPTR */ addLabel(MemMap, DPTR, DATA); else if (opcode == 0xa3) /* INC DPTR ? */ DPTR++; /* ->track DPTR */ break; case 2: case 3: case 4: /* one operand */ getNextByte(1); newaddr = memPtr; break; case 5: /* one operand, relative address */ op1 = getNextByte(1); /* relative addr calculation */ newaddr = decodeRelAddr(MemMap, 1, op1, memPtr); /* if this is a branch, continue disassembly */ if (opcode != 0x80) pass1(MemMap, Chunk, memPtr); break; case 6: /* one operand, absolute address */ op1 = getNextByte(1); /* absolute addr calculation */ newaddr = decodeAbsAddr(MemMap, 1, opcode, op1, memPtr); /* if this is a call, continue disassembly */ if (opcode & 0x10) pass1(MemMap, Chunk, memPtr); break; case 7: case 8: case 9: /* two operands */ op1 = getNextByte(1); op2 = getNextByte(1); newaddr = memPtr; if (opcode == 0x90) /* MOV DPTR, #16 ? */ DPTR = ((((int)op1)<<8) | op2); /* ->track DPTR */ break; case 10: case 11: case 12: /* two operands, relative address */ getNextByte(1); op2 = getNextByte(1); /* relative addr calculation */ newaddr = decodeRelAddr(MemMap, 1, op2, memPtr); /* this is always a branch instruction */ pass1(MemMap, Chunk, memPtr); break; case 13: /* long address */ op1 = getNextByte(1); op2 = getNextByte(1); /* long addr calculation */ newaddr = decodeLongAddr(MemMap, 1, op1, op2); /* if this is a call, continue disassembly */ if (opcode == 0x12) pass1(MemMap, Chunk, memPtr); break; default: /* error in op_format table */ fprintf(stderr, "Invalid opcode format, error in format table\n"); newaddr = -1; break; } return newaddr;}/* dis_inst2: Disassemble one instruction to ofile * * Returns address immediately after instruction. */intdis_inst2(struct MemoryMap *MemMap, struct MemChunk *Chunk, int memPtr){ unsigned char opcode, op1 = 0, op2 = 0; char buffer[6]; int bytes = 1, addr; /* Fetch opcode */ opcode = getNextByte(2); /* Fetch second and third byte, if appropriate */ if (op_format[opcode] > 1) { op1 = getNextByte(2); bytes = 2; } if (op_format[opcode] > 6) { op2 = getNextByte(2); bytes = 3; } /* Output decoded instruction */ printHexList(MemMap, Chunk, memPtr, bytes); switch(op_format[opcode]) { case 0: /* A5 is an illegal opcode */ printf("DB 85h ; illegal opcode"); case 1: /* no operands */ printf(mnemonic[opcode]); break; case 2: /* one immediate operand */ printf(mnemonic[opcode], formatHexValue(op1)); break; case 3: /* one direct operand */ printf(mnemonic[opcode], decodeSFR(op1)); break; case 4: /* one bit-addressed operand */ printf(mnemonic[opcode], decodeSFBit(op1)); break; case 5: /* one operand, relative address */ addr = decodeRelAddr(MemMap, 2, op1, memPtr); printf(mnemonic[opcode], getLabelName(MemMap, addr, CODE)); break; case 6: /* one operand, absolute address */ addr = decodeAbsAddr(MemMap, 2, opcode, op1, memPtr); printf(mnemonic[opcode], getLabelName(MemMap, addr, CODE)); break; case 7: /* two-byte immediate operand */ /* MOV DPTR, #immediate16 */ addr = decodeLongAddr(MemMap, 2, op1, op2); printf(mnemonic[opcode], getLabelName(MemMap, addr, DATA)); break; case 8: /* two operands: direct, immediate */ strcpy(buffer, decodeSFR(op1)); printf(mnemonic[opcode], buffer, formatHexValue(op2)); break; case 9: /* two operands: direct, direct */ /* (operands in reverse order) */ strcpy(buffer, decodeSFR(op1)); printf(mnemonic[opcode], decodeSFR(op2), buffer); break; case 10: /* two operands: immediate, relative */ addr = decodeRelAddr(MemMap, 2, op2, memPtr); printf(mnemonic[opcode], formatHexValue(op1), getLabelName(MemMap, addr, CODE)); break; case 11: /* two operands: direct, relative */ addr = decodeRelAddr(MemMap, 2, op2, memPtr); printf(mnemonic[opcode], decodeSFR(op1), getLabelName(MemMap, addr, CODE)); break; case 12: /* two operands: bit, relative */ addr = decodeRelAddr(MemMap, 2, op2, memPtr); printf(mnemonic[opcode], decodeSFBit(op1), getLabelName(MemMap, addr, CODE)); break; case 13: /* long address */ addr = decodeLongAddr(MemMap, 2, op1, op2); printf(mnemonic[opcode], getLabelName(MemMap, addr, CODE)); break; default: /* error in op_format table */ printf("DB %02Xh ; error in op_format table", opcode); } printf("\n"); return memPtr;}/* This is a helper function for dissassembler pass1. It disassembles * one thread of instructions starting at given entry point. This * function will be called recursively. */voidpass1(struct MemoryMap *MemMap, struct MemChunk *Chunk, int addr){ while ((addr != -1) && ((MemMap->flags[addr] & ADR_USED) == 0)) /* no error, we haven't been here before, and non-empty */ /* disassemble next instruction */ addr = dis_inst1(MemMap, Chunk, addr);}/* pass1 of the disassember. Disassemble instructions starting with * the first marked code entry point found. */voiddisassembler_pass1(struct MemoryMap *MemMap, struct MemChunk *Chunk){ int addr; do { for (addr=0; addr < MemMap->mapsize; addr++) if ((MemMap->flags[addr] & ADR_ENTRY) && /* Entry point */ !(MemMap->flags[addr] & ADR_CODE)) { /* and not yet code ? */ pass1(MemMap, Chunk, addr); /* then track code */ MemMap->flags[addr] |= ADR_ENTRY; /* and mark real entry point */ break; } } while (addr < MemMap->mapsize);}/* pass2 of the disassember. Try to find out which addresses are unused * and save the results in the MemoryMap. */voiddisassembler_pass2(struct MemoryMap *MemMap, struct MemChunk *Chunk){ int n, cnt, ch, mode, addr; cnt = ch = mode = 0; /* for gcc stop complaining */ while (Chunk->header.length) { for (n=0; n < Chunk->header.length; n++) { addr = Chunk->header.address + n; /* substitution */ if (n == 0) ch = Chunk->data[0] + 1; /* ensure that ch != Chunk->data[0] */ if (Chunk->data[n] != ch) { ch = Chunk->data[n]; /* reset variables */ cnt = 0; mode = 0; } if (MemMap->flags[addr] == 0 && Chunk->data[n] == ch) { /* if the address is unused and filled with the same * * character as the address before count it and switch * * mode if a chain of more than 4 identical characters * * have been found. Mark the found chain and following * * characters of the same kind as free. */ if (mode == 0) { /* chain not found yet */ if (++cnt > 3 && (ch == 0x00 || ch == 0xFF)) { for (cnt--; cnt >= 0; cnt--) MemMap->flags[addr - cnt] |= ADR_FREE; mode = 1; } } else /* continue chain */ MemMap->flags[addr] |= ADR_FREE; } } Chunk = (struct MemChunk*) ((char*) Chunk + sizeof(struct MemChunkHeader) + Chunk->header.length); }}/* pass3 of the disassembler. Disassemble memory and print the results * to stdout. */voiddisassembler_pass3(struct MemoryMap *MemMap, struct MemChunk *Chunk){ int addr = 0; unsigned char empty = 1; /* 1 for no code/data, 0 for code or data */ while (addr < MemMap->mapsize) { /* Step 1: check if memory is empty */ if (!(MemMap->flags[addr] & ADR_FREE) && (empty)) /* We've changed from empty to non-empty, * so start a new segment. */ printf("CSEG AT %04Xh\n", addr); else if (MemMap->flags[addr] & ADR_FREE) { /* no code or data here */ ++addr; empty = 1; continue; } empty = 0; /* Step 2: Output a label if one exists */ if (MemMap->flags[addr] & ADR_CLABEL) printf("%s: ", getLabelName(MemMap, addr, CODE)); else if (MemMap->flags[addr] & ADR_DLABEL) printf("%s: ", getLabelName(MemMap, addr, DATA)); else if (MemMap->flags[addr] & ADR_ENTRY) printf("E --> "); else printf(" "); /* Step 3: Output code or data as appropriate */ if (MemMap->flags[addr] & ADR_CODE) /* code here, so disassemble next instruction */ addr = dis_inst2(MemMap, Chunk, addr); else { /* data here */ printHexList(MemMap, Chunk, addr+1, 1); if(isprint(getByte(addr))) printf("DB %02Xh ; '%c'\n", getByte(addr), getByte(addr)); else printf("DB %02Xh \n", getByte(addr)); ++addr; } } printf("END\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -