Repository navigation
Conversation
The injected bootstrap inherits the hijacked thread's RSP alignment. pushAll only moves RSP by a multiple of 16, so a misaligned incoming stack propagates through LoadLibrary, GetProcAddress and the init function. Callees then fault on their first aligned SSE spill (movaps), which happens consistently when injecting into x64 processes under ARM64 emulation. Normalise RSP after pushAll and restore it from rbp on both exit paths.
|
On a side note, I added a small change to my branch to get the CI to run (otherwise PR runs in all forks will always fail), but I have removed that commit from this PR branch. Let me know if you want to keep it instead, possibly with some hardening so it doesn't silently ignore missing secrets when run in the main repo. |
d8e4209 to
dc7db6a
Compare
|
I've been working on getting MO2 running on the Steam Frame and hit this same issue, and this fix worked. For context, the Steam Frame has an ARM CPU and runs Windows applications through Proton and the FEX emulator. Using the |
|
@skjiisa thanks, that's really interesting because the bug and fix are now validated on an entirely different emulator as well now -- which confirms my hypothesis that this isn't an emulation bug, it was an issue in the code not adhering to the x64 ABI, which was running fine on real x64 hardware by coincidence, not by design. For anyone wanting to try this out, I have added links to the the usvfs patched DLLs and a complete MO2 2.5.2 package with the patch to the PR description. |
Programs started through MO2 2.5.2 die on ARM64 because USVFS's injection stub calls InitHooks with a misaligned stack. This downloads ndabas's v0.5.6.1-woa.1 backport of ModOrganizer2/usvfs#93, pinned by archive and per-file SHA-256, replaces only the four stock MO2 2.5.2 USVFS files, and keeps verified originals in <instance>/.modsync-usvfs/backup. Available from the dashboard, the Steam launch hub and `modsync mo2 usvfs status|apply|restore`; `doctor` reports it. Changes are refused while any process maps the instance's USVFS files. Validated on a Steam Frame: modded Skyrim through Play and MO2, the in-use check under Proton ARM64 through the Flatpak, hub Apply/Restore, and offline reapply. Fixes a doctor crash found there. Closes #62. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Hello! I've recently tried using your fixed version of MO2 ( https://github.com/ndabas/modorganizer/releases ) and while it seems to work smoothly, I've run into a problem with Pandora acting up when launched.
For whatever reason, it loads up as a transparent window (not including the visible purple outline). I've attempted this both on the current version of Pandora and an older version (4.1.2). Neither avenue seemed to work, and now I'm thinking the fact that I'm running this all on an ARM system (Surface Pro x) may have something to do with it. Do you have any insight on this sort of thing? That, or would you be willing to test Pandora on an ARM system with the version of MO2 you put together? Any and all help is appreciated! |
|
@flopku2026-ux unfortunately that appears to be a different issue from the one fixed in this PR. The one that I've fixed here prevents games from launching at all; if it's launching but then behaving oddly, it's a different problem somewhere. |


I was trying to use MO2 with Skyrim SE + SKSE on my Windows ARM64 laptop, which crashes silently.
Further testing and analyzing crash dumps has shown that usvfs currently fails on x64 targets on Windows ARM64. The DLL injects successfully, then crashes in
DllMainbefore it can write anything to the log. It looks like the cause is an assumption in the x64 injection stub which doesn't hold true under emulation.I have added RSP normalization to fix this issue, and have also added a
windows-11-armrunner to the test matrix so we can verify that it works.Root cause
addStub()emits a bootstrap that inherits the hijacked thread'sRSPand never normalises it:pushreturn address (8 bytes)pushAll(pushf+ 15 registers) (128 bytes)sub rsp, 32) (32 bytes)168 mod 16 == 8, and the x64 ABI requires0, so the stub is only correct when the thread is hijacked atRSP mod 16 = 8.MO2 creates targets with
CREATE_SUSPENDED, so on native x64 the thread is frozen atRtlUserThreadStartand that assumption holds. Under x64 emulation on ARM64 the initial context is synthesised by the emulator (as it's really an ARM64 thread not x64) and it seems with the opposite parity, consistently, so every frame below the stub is skewed by 8 bytes and the first function to spill an SSE register withMOVAPSfaults.Evidence
Crash is deterministic with the same fault offset across Skyrim reinstalls and MO2 versions.
At the fault:
rsp = 0xb60815f2f8, targetrsp+0x90 = 0xb60815f388,mod 16 == 8whereMOVAPSrequires0.RBPis likewise 8 short of its compile-time-known residue, confirming the whole frame is displaced rather than a single bad address.Environment: Windows 11 ARM64 build 28000,
xtajit64se.dllloaded, MO2 2.5.2, Skyrim SE via SKSE.Interestingly, the trampolines and inline hooks work fine under emulation, which I initially thought might be a problem, but apparently not!
CI
Failing run on my fork, without the change.
Passing run on my fork, with the change.
Test binaries
I have added a release to my fork of usvfs with compiled DLLs that can be dropped in to an existing MO2 2.5.2 install: https://github.com/ndabas/modorganizer/releases -- another build with the latest
masteris also there.A complete MO2 2.5.2 release with the patch is also available: https://github.com/ndabas/modorganizer/releases