arm64jit: Don't sign-extend constant addresses with the top bit set

The ARM64 IR JIT crashed on any load/store to a constant address with the
top bit set and an offset too large for an immediate - the kernel RAM mirror
at 0x88000000, for instance.

PrepareSrc1Address is careful about this: a constant address like 0x89100010
arrives sign-extended as a negative int64_t, and the (imm & 0xC0000000) ==
0x80000000 check turns it back into the positive value it should be. But when
the offset doesn't fit an immediate we fall back to loading it into a register
and using the register-offset addressing mode, which only takes the W half of
that register plus an extend - and we asked for SXTW, undoing the fix and
pointing the access ~2GB below the memory view.

Sign extension is still right when the offset is genuinely negative, which
happens when the base is a pointerified register and the displacement is a
negative one from the MIPS instruction. So extend based on the sign of imm.

Found by the Jit unit test, which stores to 0x89100000 and segfaults in the
JIT_IR phase - only reproducible on an actual ARM64 CPU, which is why it never
showed up on CI. The RISC-V and LoongArch backends get this case right already.
This commit is contained in:
Henrik Rydgård committed 2026-09-02 17:53:12 +02:00
1 parent c34f5000ab
commit 3ef6ad6285
1 file changed
+6 -1
+6 -1
View File
@@ -153,7 +153,12 @@ Arm64JitBackend::LoadStoreArg Arm64JitBackend::PrepareSrc1Address(IRInst inst) {
MOVI2R(SCRATCH1, imm);
addrArg.regOffset = SCRATCH1;
addrArg.useRegisterOffset = true;
addrArg.signExtendRegOffset = true;
// Careful: the register offset is only the W half, extended into the 64-bit base.
// A negative imm here is a real displacement from a pointerified register, so it
// has to be sign extended. A positive one may be a full 32-bit address off
// MEMBASEREG with the top bit set, which we un-sign-extended above - SXTW would
// just make it negative again and point us ~2GB below the memory view.
addrArg.signExtendRegOffset = imm < 0;
}
}