diff options
author | Oxore <oxore@protonmail.com> | 2023-05-15 22:33:42 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-05-16 01:09:03 +0300 |
commit | 1c983286a91bc224ac792174b6e2fb7e124613c7 (patch) | |
tree | 9bc0bab2698db9eb4dabc766f249a37998dd9457 | |
parent | c9d192b63f4866b55623388f3ed53bb68eb2b05c (diff) |
Impl relocation marks support
-rw-r--r-- | disasm.cpp | 79 | ||||
-rw-r--r-- | disasm.h | 14 | ||||
-rw-r--r-- | main.cpp | 107 |
3 files changed, 154 insertions, 46 deletions
@@ -182,7 +182,6 @@ static size_t disasm_jsr_jmp( break; case AddrMode::kWord: // 4eb8 / 4ef8 { - // FIXME support s.abs_marks option for this instruction const uint32_t branch_addr = static_cast<uint32_t>(a.lword); node.branch_addr = branch_addr; node.has_branch_addr = true; @@ -190,7 +189,6 @@ static size_t disasm_jsr_jmp( break; case AddrMode::kLong: // 4eb9 / 4ef9 { - // FIXME support s.abs_marks option for this instruction const uint32_t branch_addr = static_cast<uint32_t>(a.lword); node.branch_addr = branch_addr; node.has_branch_addr = true; @@ -198,8 +196,8 @@ static size_t disasm_jsr_jmp( break; case AddrMode::kD16PCAddr: // 4eba / 4efa { - // FIXME support s.abs_marks option for this instruction - const uint32_t branch_addr = static_cast<uint32_t>(a.lword) + kInstructionSizeStepBytes; + const uint32_t branch_addr = node.offset + kInstructionSizeStepBytes + + static_cast<uint32_t>(a.d16_pc.d16); node.branch_addr = branch_addr; node.has_branch_addr = true; } @@ -379,7 +377,6 @@ static size_t disasm_bra_bsr_bcc( node.branch_addr = branch_addr; node.has_branch_addr = true; node.op = Op{OpCode::kBcc, opsize, condition, Arg::Displacement(dispmt)}; - // FIXME support s.rel_marks option for this instruction return node.size; } @@ -1008,7 +1005,6 @@ static size_t disasm_dbcc(DisasmNode &node, const uint16_t instr, const DataBuff Arg::AddrModeXn(ArgType::kDn, (instr & 7)), Arg::Displacement(dispmt), }; - // FIXME support s.rel_marks option for this instruction return node.size = kInstructionSizeStepBytes * 2; } @@ -1506,10 +1502,26 @@ size_t DisasmNode::Disasm(const DataBuffer &code) if (this->op.opcode != OpCode::kNone) { return this->size; } + size = kInstructionSizeStepBytes; + has_branch_addr = false; + branch_addr = 0; + is_call = false; const uint16_t instr = GetU16BE(code.buffer + this->offset); return m68k_disasm(*this, instr, code); } +size_t DisasmNode::DisasmAsRaw(const DataBuffer &code) +{ + // We assume that machine have no MMU and ROM data always starts with 0 + assert(this->offset < code.occupied_size); + size = kInstructionSizeStepBytes; + has_branch_addr = false; + branch_addr = 0; + is_call = false; + const uint16_t instr = GetU16BE(code.buffer + this->offset); + return disasm_verbatim(*this, instr); +} + static const char *ToString(const OpCode opcode, const Condition condition) { switch (opcode) { @@ -1724,7 +1736,12 @@ static size_t snprint_reg_mask( return written; } -int Arg::SNPrint(char *const buf, const size_t bufsz, const Settings &) const +int Arg::SNPrint( + char *const buf, + const size_t bufsz, + const bool has_relocation, + const uint32_t self_addr, + const uint32_t reloc_addr) const { switch (type) { case ArgType::kNone: @@ -1753,11 +1770,32 @@ int Arg::SNPrint(char *const buf, const size_t bufsz, const Settings &) const RegNum(d8_an_xi.xi), SizeSpecChar(d8_an_xi.xi)); case ArgType::kWord: - return snprintf(buf, bufsz, "0x%x:w", lword); case ArgType::kLong: - return snprintf(buf, bufsz, "0x%x:l", lword); + { + const char c = type == ArgType::kLong ? 'l' : 'w'; + if (has_relocation) { + if (static_cast<uint32_t>(lword) == reloc_addr) { + return snprintf(buf, bufsz, ".L%08x:%c", reloc_addr, c); + } else { + // It has to be AFTER the mark we are gonna reference here + assert(static_cast<uint32_t>(lword) > reloc_addr); + return snprintf(buf, bufsz, ".L%08x+%d:%c", reloc_addr, lword - reloc_addr, c); + } + } else { + return snprintf(buf, bufsz, "0x%x:%c", lword, c); + } + } case ArgType::kD16PCAddr: - return snprintf(buf, bufsz, "%%pc@(%d:w)", d16_pc.d16); + if (has_relocation) { + if (static_cast<uint32_t>(self_addr + d16_pc.d16 + kInstructionSizeStepBytes) == reloc_addr) { + return snprintf(buf, bufsz, "%%pc@(.L%08x:w)", reloc_addr); + } else { + assert(static_cast<uint32_t>(self_addr + d16_pc.d16 + kInstructionSizeStepBytes) > reloc_addr); + return snprintf(buf, bufsz, "%%pc@(.L%08x+%d:w)", reloc_addr, static_cast<uint32_t>(self_addr + d16_pc.d16 + kInstructionSizeStepBytes) - reloc_addr); + } + } else { + return snprintf(buf, bufsz, "%%pc@(%d:w)", d16_pc.d16); + } case ArgType::kD8PCXiAddr: return snprintf( buf, bufsz, "%%pc@(%d,%%%c%u:%c)", @@ -1771,7 +1809,16 @@ int Arg::SNPrint(char *const buf, const size_t bufsz, const Settings &) const case ArgType::kRegMaskPredecrement: return snprint_reg_mask(buf, bufsz, uword, type); case ArgType::kDisplacement: - return snprintf(buf, bufsz, ".%s%d", lword >= 0 ? "+" : "", lword); + if (has_relocation) { + if (static_cast<uint32_t>(self_addr + lword) == reloc_addr) { + return snprintf(buf, bufsz, ".L%08x", reloc_addr); + } else { + assert(static_cast<uint32_t>(self_addr + lword) > reloc_addr); + return snprintf(buf, bufsz, ".L%08x+%d", reloc_addr, (self_addr + lword) - reloc_addr); + } + } else { + return snprintf(buf, bufsz, ".%s%d", lword >= 0 ? "+" : "", lword); + } case ArgType::kCCR: return snprintf(buf, bufsz, "%%ccr"); case ArgType::kSR: @@ -1783,17 +1830,21 @@ int Arg::SNPrint(char *const buf, const size_t bufsz, const Settings &) const return -1; } -int Op::FPrint(FILE* const stream, const Settings &settings) const +int Op::FPrint( + FILE *const stream, + const bool has_relocation, + const uint32_t self_addr, + const uint32_t reloc_addr) const { assert(opcode != OpCode::kNone); char mnemonic_str[kMnemonicBufferSize]{}; OpcodeSNPrintf(mnemonic_str, kMnemonicBufferSize, opcode, condition, size_spec); if (arg1.type != ArgType::kNone) { char arg1_str[kArgsBufferSize]{}; - arg1.SNPrint(arg1_str, kArgsBufferSize, settings); + arg1.SNPrint(arg1_str, kArgsBufferSize, has_relocation, self_addr, reloc_addr); if (arg2.type != ArgType::kNone) { char arg2_str[kArgsBufferSize]{}; - arg2.SNPrint(arg2_str, kArgsBufferSize, settings); + arg2.SNPrint(arg2_str, kArgsBufferSize, has_relocation, self_addr, reloc_addr); return fprintf(stream, " %s %s,%s", mnemonic_str, arg1_str, arg2_str); } else { return fprintf(stream, " %s %s", mnemonic_str, arg1_str); @@ -294,7 +294,12 @@ struct Arg { a.uword = instr; return a; } - int SNPrint(char *buf, size_t bufsz, const Settings&) const; + int SNPrint( + char *buf, + size_t bufsz, + bool has_relocation = false, + uint32_t self_addr = 0, + uint32_t reloc_addr = 0) const; }; enum class TracedNodeType { @@ -343,7 +348,11 @@ struct Op { { return Op::Typical(OpCode::kRaw, OpSize::kNone, Arg::Raw(instr)); } - int FPrint(FILE*, const Settings&) const; + int FPrint( + FILE *, + bool has_relocation = false, + uint32_t self_addr = 0, + uint32_t reloc_addr = 0) const; }; struct DisasmNode { @@ -367,6 +376,7 @@ struct DisasmNode { * returns size of whole instruction with arguments in bytes */ size_t Disasm(const DataBuffer &code); + size_t DisasmAsRaw(const DataBuffer &code); void AddReferencedBy(uint32_t offset, ReferenceType); ~DisasmNode(); }; @@ -28,6 +28,7 @@ class DisasmMap { DisasmNode *_map[kDisasmMapSizeElements]{}; DisasmNode *findNodeByOffset(uint32_t offset) const; DisasmNode *insertTracedNode(uint32_t offset, TracedNodeType); + bool canBeAllocated(const DisasmNode& node) const; public: const DisasmNode *FindNodeByOffset(uint32_t offset) const { @@ -40,10 +41,7 @@ public: assert(_type == DisasmMapType::kTraced); return nullptr != insertTracedNode(offset, type); } - // This function disassembles everything that has been traced - void DisasmTraced(const DataBuffer &code, const Settings &); - // This function disassembles just everything from the beginning - void DisasmAll(const DataBuffer &code, const Settings &); + void Disasm(const DataBuffer &code, const Settings &); DisasmMap(DisasmMapType type): _type(type) {} ~DisasmMap(); }; @@ -55,43 +53,76 @@ DisasmNode *DisasmMap::findNodeByOffset(uint32_t offset) const return nullptr; } +static uint32_t AlignInstructionAddress(const uint32_t offset) +{ + return offset & ~1UL; +} + DisasmNode *DisasmMap::insertTracedNode(uint32_t offset, TracedNodeType type) { auto *node = findNodeByOffset(offset); if (node) { return node; } - node = new DisasmNode(DisasmNode{type, offset}); + node = new DisasmNode(DisasmNode{type, AlignInstructionAddress(offset)}); assert(node); _map[offset / kInstructionSizeStepBytes] = node; return node; } -void DisasmMap::DisasmTraced(const DataBuffer &code, const Settings &) +bool DisasmMap::canBeAllocated(const DisasmNode& node) const { - assert(_type == DisasmMapType::kTraced); - for (size_t i = 0; i < kDisasmMapSizeElements; i++) { - auto *node = _map[i]; - if (!node) { - continue; + const auto size = node.size / kInstructionSizeStepBytes; + const auto *const node_real = findNodeByOffset(node.offset); + for (size_t i = 1; i < size; i++) { + const auto *const ptr = _map[node.offset / kInstructionSizeStepBytes + i]; + if (ptr != nullptr && ptr != node_real) { + return false; + } + } + return true; +} + +void DisasmMap::Disasm(const DataBuffer &code, const Settings &) +{ + DisasmNode *node; + for (size_t i = 0; i < Min(kRomSizeBytes, code.occupied_size);) { + if (_type == DisasmMapType::kTraced) { + node = _map[i / kInstructionSizeStepBytes]; + if (!node) { + i += kInstructionSizeStepBytes; + continue; + } + } else { + node = insertTracedNode(i, TracedNodeType::kInstruction); + } + const auto size = node->Disasm(code); + assert(size >= kInstructionSizeStepBytes); + if (canBeAllocated(*node)) { + // Spread across the size + for (size_t o = kInstructionSizeStepBytes; o < size; o++) { + _map[(node->offset + o) / kInstructionSizeStepBytes] = node; + } + } else { + node->DisasmAsRaw(code); } - node->Disasm(code); + // FIXME implement deep graph walk for DisasmMapType::kTraced case if (node->has_branch_addr && node->branch_addr < code.occupied_size) { - auto *ref_node = insertTracedNode( + auto *const ref_node = insertTracedNode( node->branch_addr, TracedNodeType::kInstruction); - ref_node->Disasm(code); + const auto size = ref_node->Disasm(code); + assert(size >= kInstructionSizeStepBytes); + if (canBeAllocated(*ref_node)) { + // Spread across the size + for (size_t o = kInstructionSizeStepBytes; o < size; o++) { + _map[(ref_node->offset + o) / kInstructionSizeStepBytes] = ref_node; + } + } else { + ref_node->DisasmAsRaw(code); + } ref_node->AddReferencedBy( node->offset, node->is_call ? ReferenceType::kCall : ReferenceType::kBranch); } - } -} - -void DisasmMap::DisasmAll(const DataBuffer &code, const Settings &) -{ - assert(_type == DisasmMapType::kRaw); - for (size_t i = 0; i < Min(kDisasmMapSizeElements, code.occupied_size);) { - auto node = insertTracedNode(i, TracedNodeType::kInstruction); - node->Disasm(code); i += node->size; } } @@ -99,8 +130,17 @@ void DisasmMap::DisasmAll(const DataBuffer &code, const Settings &) DisasmMap::~DisasmMap() { for (size_t i = 0; i < kDisasmMapSizeElements; i++) { - delete _map[i]; - _map[i] = nullptr; + auto *const node = _map[i]; + if (!node) { + continue; + } + const auto size = node->size / kInstructionSizeStepBytes; + for (size_t o = 0; o < size; o++) { + assert(_map[i + o] == node); + _map[i + o] = nullptr; + } + delete node; + i += size - 1; } } @@ -175,17 +215,24 @@ static void RenderDisassembly( assert(node->op.opcode != OpCode::kNone); if (ShouldPrintAsRaw(node->op)) { auto raw = Op::Raw(GetU16BE(code.buffer + node->offset)); - raw.FPrint(output, s); + raw.FPrint(output); uint32_t i = kInstructionSizeStepBytes; for (; i < node->size; i += kInstructionSizeStepBytes) { char arg_str[kArgsBufferSize]{}; const auto arg = Arg::Raw(GetU16BE(code.buffer + node->offset + i)); - arg.SNPrint(arg_str, kArgsBufferSize, s); + arg.SNPrint(arg_str, kArgsBufferSize); fprintf(output, ", %s", arg_str); } fprintf(output, "\n"); } else { - node->op.FPrint(output, s); + // FIXME Split rel_marks and abs_marks support + if (node->has_branch_addr && s.marks && (s.abs_marks || s.rel_marks) && node->branch_addr < kRomSizeBytes) { + const auto *referenced = disasm_map.FindNodeByOffset(node->branch_addr); + const uint32_t ref_addr = referenced ? referenced->offset : 0; + node->op.FPrint(output, referenced, node->offset, ref_addr); + } else { + node->op.FPrint(output); + } } if (node->has_branch_addr && s.xrefs_to) { char branch_addr[12]{}; @@ -296,7 +343,7 @@ static int M68kDisasmByTrace(FILE *input_stream, FILE *output_stream, FILE *trac assert(disasm_map); ParseTraceData(*disasm_map, trace_data); // Disasm into output map - disasm_map->DisasmTraced(code, s); + disasm_map->Disasm(code, s); // Print output into output_stream RenderDisassembly(output_stream, *disasm_map, code, s); delete disasm_map; @@ -322,7 +369,7 @@ static int M68kDisasmAll(FILE *input_stream, FILE *output_stream, const Settings DisasmMap *disasm_map = new DisasmMap{DisasmMapType::kRaw}; assert(disasm_map); // Disasm into output map - disasm_map->DisasmAll(code, s); + disasm_map->Disasm(code, s); // Print output into output_stream RenderDisassembly(output_stream, *disasm_map, code, s); delete disasm_map; |