summaryrefslogtreecommitdiff
path: root/disasm.cpp
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2023-05-20 17:36:32 +0300
committerOxore <oxore@protonmail.com>2023-05-20 17:36:32 +0300
commit1a9089d41233b3b7b207e9a7e8553dc5b14e92ae (patch)
treec52b12343f1699b4350b4231c887a7a74b0bff0f /disasm.cpp
parent429d978d108dfb77665f0c03a7190e2754c8fa1f (diff)
Fix MOVEM with PC relative argument when -frel-marks set
Diffstat (limited to 'disasm.cpp')
-rw-r--r--disasm.cpp22
1 files changed, 15 insertions, 7 deletions
diff --git a/disasm.cpp b/disasm.cpp
index a95b0a2..4d965fd 100644
--- a/disasm.cpp
+++ b/disasm.cpp
@@ -273,9 +273,13 @@ static size_t disasm_ext_movem(
if (dir == MoveDirection::kRegisterToMemory) {
return disasm_verbatim(node, instr);
} else if (a.mode == AddrMode::kD16PCAddr) {
- node.ref1_addr = node.offset + kInstructionSizeStepBytes +
+ // XXX: kRefPcRelFix2Bytes flag is a hack that needed to correctly
+ // print PC relative mark referenced value for MOVEM. Alongside with
+ // *NOT* adding kInstructionSizeStepBytes to ref1_addr. Still
+ // figuring that out.
+ node.ref1_addr = node.offset + kInstructionSizeStepBytes * 2 +
static_cast<uint32_t>(a.d16_pc.d16);
- node.ref_kinds = kRef1RelMask | kRef1ReadMask;
+ node.ref_kinds = kRef1RelMask | kRef1ReadMask | kRefPcRelFix2Bytes;
}
break;
case AddrMode::kImmediate: // 4ebc / 4efc
@@ -1833,11 +1837,15 @@ int Arg::SNPrint(
}
case ArgType::kD16PCAddr:
if (ref_kinds & kRefRelMask) {
- if (static_cast<uint32_t>(self_addr + d16_pc.d16 + kInstructionSizeStepBytes) == ref_addr) {
+ // XXX: Most of instructions with PC relative values have 2 bytes
+ // added to the offset, some does not. Still figuring that out.
+ const bool has_fix = ref_kinds & kRefPcRelFix2Bytes;
+ const uint32_t arg_addr = self_addr + d16_pc.d16 + kInstructionSizeStepBytes + (has_fix ? kInstructionSizeStepBytes : 0);
+ if (arg_addr == ref_addr) {
return snprintf(buf, bufsz, "%%pc@(.L%08x:w)", ref_addr);
} else {
- assert(static_cast<uint32_t>(self_addr + d16_pc.d16 + kInstructionSizeStepBytes) > ref_addr);
- return snprintf(buf, bufsz, "%%pc@(.L%08x+%d:w)", ref_addr, static_cast<uint32_t>(self_addr + d16_pc.d16 + kInstructionSizeStepBytes) - ref_addr);
+ assert(arg_addr > ref_addr);
+ return snprintf(buf, bufsz, "%%pc@(.L%08x+%d:w)", ref_addr, arg_addr - ref_addr);
}
} else {
return snprintf(buf, bufsz, "%%pc@(%d:w)", d16_pc.d16);
@@ -1888,10 +1896,10 @@ int Op::FPrint(
OpcodeSNPrintf(mnemonic_str, kMnemonicBufferSize, opcode, condition, size_spec);
if (arg1.type != ArgType::kNone) {
char arg1_str[kArgsBufferSize]{};
- arg1.SNPrint(arg1_str, kArgsBufferSize, ref_kinds & kRef1Mask, self_addr, ref1_addr);
+ arg1.SNPrint(arg1_str, kArgsBufferSize, ref_kinds & (kRef1Mask | kRefPcRelFix2Bytes), self_addr, ref1_addr);
if (arg2.type != ArgType::kNone) {
char arg2_str[kArgsBufferSize]{};
- arg2.SNPrint(arg2_str, kArgsBufferSize, ref_kinds & kRef2Mask, self_addr, ref2_addr);
+ arg2.SNPrint(arg2_str, kArgsBufferSize, ref_kinds & (kRef2Mask | kRefPcRelFix2Bytes), self_addr, ref2_addr);
return fprintf(stream, " %s %s,%s", mnemonic_str, arg1_str, arg2_str);
} else {
return fprintf(stream, " %s %s", mnemonic_str, arg1_str);