diff options
author | Oxore <oxore@protonmail.com> | 2023-05-20 17:36:32 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-05-20 17:36:32 +0300 |
commit | 1a9089d41233b3b7b207e9a7e8553dc5b14e92ae (patch) | |
tree | c52b12343f1699b4350b4231c887a7a74b0bff0f | |
parent | 429d978d108dfb77665f0c03a7190e2754c8fa1f (diff) |
Fix MOVEM with PC relative argument when -frel-marks set
-rw-r--r-- | common.h | 8 | ||||
-rw-r--r-- | disasm.cpp | 22 | ||||
-rw-r--r-- | main.cpp | 3 | ||||
-rw-r--r-- | test_marks_referencing.bash | 5 |
4 files changed, 27 insertions, 11 deletions
@@ -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 @@ -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); @@ -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" |