summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--disasm.cpp79
-rw-r--r--disasm.h14
-rw-r--r--main.cpp107
3 files changed, 154 insertions, 46 deletions
diff --git a/disasm.cpp b/disasm.cpp
index 6f19b94..7a186f8 100644
--- a/disasm.cpp
+++ b/disasm.cpp
@@ -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);
diff --git a/disasm.h b/disasm.h
index 6f90dad..4f0ef9f 100644
--- a/disasm.h
+++ b/disasm.h
@@ -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();
};
diff --git a/main.cpp b/main.cpp
index 122e556..1cb1212 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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;