summaryrefslogtreecommitdiff
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
parent429d978d108dfb77665f0c03a7190e2754c8fa1f (diff)
Fix MOVEM with PC relative argument when -frel-marks set
-rw-r--r--common.h8
-rw-r--r--disasm.cpp22
-rw-r--r--main.cpp3
-rw-r--r--test_marks_referencing.bash5
4 files changed, 27 insertions, 11 deletions
diff --git a/common.h b/common.h
index 7ee965b..074823a 100644
--- a/common.h
+++ b/common.h
@@ -25,10 +25,14 @@ constexpr RefKindMask kRef2WriteMask = (1 << 7); // For second argument
/// Indicates whether instruction is a call or just a branch, for any argument.
/// Calls are BSR and JSR, branches are DBcc, Bcc and JMP.
constexpr RefKindMask kRefCallMask = (1 << 8);
+/// Hack flag for MOVEM with PC relative value when -frel-marks is set
+constexpr RefKindMask kRefPcRelFix2Bytes = (1 << 9);
+/// Everything for first argument
+constexpr RefKindMask kRef1Mask = kRef1RelMask | kRef1AbsMask | kRef1ReadMask | kRef1WriteMask;
+/// Everything for Second argument
+constexpr RefKindMask kRef2Mask = kRef2RelMask | kRef2AbsMask | kRef2ReadMask | kRef2WriteMask;
constexpr RefKindMask kRefRelMask = kRef1RelMask | kRef2RelMask;
constexpr RefKindMask kRefAbsMask = kRef1AbsMask | kRef2AbsMask;
-constexpr RefKindMask kRef1Mask = kRef1RelMask | kRef1AbsMask; // For first argument
-constexpr RefKindMask kRef2Mask = kRef2RelMask | kRef2AbsMask; // For second argument
constexpr RefKindMask kRef1DataMask = kRef1ReadMask | kRef1WriteMask; // For first argument
constexpr RefKindMask kRef2DataMask = kRef2ReadMask | kRef2WriteMask; // For second argument
constexpr RefKindMask kRefReadMask = kRef1ReadMask | kRef2ReadMask; // For any argument
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);
diff --git a/main.cpp b/main.cpp
index 4f10d03..ce40cc4 100644
--- a/main.cpp
+++ b/main.cpp
@@ -300,7 +300,8 @@ static void RenderDisassembly(
(s.rel_marks
? ((ref1 ? (node->ref_kinds & kRef1RelMask) : 0) |
(ref2 ? (node->ref_kinds & kRef2RelMask) : 0))
- : 0);
+ : 0) |
+ (node->ref_kinds & (kRefDataMask | kRefPcRelFix2Bytes));
node->op.FPrint(output, ref_kinds, node->offset, ref1_addr, ref2_addr);
if (s.xrefs_to && ref1) {
char ref_addr_str[12]{};
diff --git a/test_marks_referencing.bash b/test_marks_referencing.bash
index 237db1e..db5691d 100644
--- a/test_marks_referencing.bash
+++ b/test_marks_referencing.bash
@@ -62,7 +62,7 @@ run_check_rdisp() {
}
run_check_r() {
- if grep -e "[^0-9a-zA-Z_][0-9]\+" ${file_asm} >/dev/null 2>&1; then
+ if grep -e "[^0-9a-zA-Z_(+][0-9]\+" ${file_asm} >/dev/null 2>&1; then
echo -e "${CRED}FAIL${CRST}: raw number or displacement emitted"
cat ${file_asm}
exit
@@ -92,4 +92,7 @@ run_test_rdisp "braw .+2" "\x4e\x71\x60\x00\x00\x00"
run_test_rword "moveml 0x0:w,%d0" "\x4c\xf8\x00\x01\x00\x00"
run_test_rword "moveml 0x6:w,%a0" "\x4c\xf8\x01\x00\x00\x06\x4e\x71\x4e\x71"
run_test_rword "movemw 0x0:l,%a0" "\x4e\x71\x4e\x71\x4c\xb9\x01\x00\x00\x00\x00\x02"
+run_test_rpcrel "lea (0,PC)" "\x47\xfa\x00\x00"
+run_test_rpcrel "jmp (0,PC)" "\x4e\xfa\x00\x00"
+run_test_rpcrel "movemw (0,PC),%a0" "\x4e\x71\x4e\x71\x4c\xba\x01\x00\x00\x00"
run_test_rword "movew 0x0:w,0x2:w" "\x4e\x75\x4e\x76\x31\xf8\x00\x00\x00\x02"