diff --git a/src/coreclr/tools/superpmi/superpmi/jitinstance.h b/src/coreclr/tools/superpmi/superpmi/jitinstance.h index b264894d368499..cbc6e5f5043ad5 100644 --- a/src/coreclr/tools/superpmi/superpmi/jitinstance.h +++ b/src/coreclr/tools/superpmi/superpmi/jitinstance.h @@ -52,6 +52,10 @@ class JitInstance ULONGLONG times[2]; ICorJitCompiler* pJitInstance; + // The loaded JIT module handle. Used to detect when the baseline and diff + // JITs resolve to the same loaded module (which shares global state). + HMODULE getModule() const { return hLib; } + // Allocate and initialize the jit provided static JitInstance* InitJit(char* nameOfJit, bool breakOnAssert, diff --git a/src/coreclr/tools/superpmi/superpmi/neardiffer.cpp b/src/coreclr/tools/superpmi/superpmi/neardiffer.cpp index 9bb7f913393056..e60b9d64454a81 100644 --- a/src/coreclr/tools/superpmi/superpmi/neardiffer.cpp +++ b/src/coreclr/tools/superpmi/superpmi/neardiffer.cpp @@ -562,6 +562,28 @@ bool NearDiffer::compareOffsets( return compareOffsetsWasm(payload, blockOffset, instrLen, offset1, offset2); } + // On arm32 a direct BL is fixed up with an ARM32_THUMB_BRANCH24 reloc. When the + // two code blocks are allocated more than +-16MB apart, applyRelocs substitutes a + // placeholder target for the out-of-range side, so the immediates differ even + // though both BLs target the same recorded address. Treat the sites as equal when + // both recorded the same reloc kind and target. + if (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_ARM) + { + const DiffData* data = (const DiffData*)payload; + + const Agnostic_RecordRelocation* reloc1 = + data->cr1->findRelocationInRange(data->originalBlock1, blockOffset, instrLen); + const Agnostic_RecordRelocation* reloc2 = + data->cr2->findRelocationInRange(data->originalBlock2, blockOffset, instrLen); + + if ((reloc1 != nullptr) && (reloc2 != nullptr) && (reloc1->fRelocType == reloc2->fRelocType) && + ((uint64_t)reloc1->target + (int32_t)reloc1->addlDelta == + (uint64_t)reloc2->target + (int32_t)reloc2->addlDelta)) + { + return true; + } + } + const DiffData* data = (const DiffData*)payload; size_t ip1 = data->originalBlock1 + blockOffset; size_t ip2 = data->originalBlock2 + blockOffset; diff --git a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp index c509589330c9c9..b906f243703612 100644 --- a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp +++ b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp @@ -447,6 +447,18 @@ int __cdecl main(int argc, char* argv[]) // InitJit already printed a failure message return (int)SpmiResult::JitFailedToInit; } + + if (jit2->getModule() == jit->getModule()) + { + // The baseline and diff JITs resolved to the same loaded module. Because the JIT keeps + // global state (e.g. g_jitHost, JitConfig), sharing a single module between the two + // JitInstances corrupts that state and produces spurious diffs and intermittent crashes. + // Require the two JITs to be distinct files (copy one to a different path if needed). + LogError("The baseline JIT ('%s') and diff JIT ('%s') resolve to the same loaded module. " + "They must be distinct files; copy one JIT to a different path.", + o.nameOfJit, o.nameOfJit2); + return (int)SpmiResult::JitFailedToInit; + } } }