Dear Maintainer, When running Wine on arm64, on HW with pointer authentication (armv8.3 and newer), Wine fails to run. In some cases, it hangs directly on startup for any case (e.g. "wine wineboot" hangs), in some cases it seemingly runs successfully, but any case that requires unwinding in the user executables fail. (Exactly what makes it seemingly succeed in some cases and hang in others is unclear.) The issue can be consistently observed by running "WINEDEBUG=+seh wine wineboot" in a fresh install with no preexisting wine prefix (~/.wine). On older hardware, without support for pointer authentication, Wine starts up nicely (and there are a handful of debug printouts about unwinding one exception). On newer hardware, it results in repeated printouts about EXCEPTION_ILLEGAL_INSTRUCTION. The root cause of this issue is that Clang 19 and newer has regressed the code generation for return address signing on Windows on aarch64 - this issue has been filed upstream at [1]. Debian builds of Wine have pointer authentication enabled for the internal PE components of Wine (and those components are compiled with Clang), which causes Wine to trip over itself when unwinding through those components. However, the issue is made visible due to the fact that Wine's unwinding of pointer authentication was more strict than what really is necessary. A fix for this was merged in [2]. This fix avoids triggering illegal instructions and breaking on these cases. This fix will be in the upcoming development release Wine 11.12, but it also applies cleanly on e.g. Wine 10.0. Applying this patch in the Debian packaging will likely fix this issue. [1] https://github.com/llvm/llvm-project/issues/203852 [2] https://gitlab.winehq.org/wine/wine/-/commit/a83427f29e925d8b29cf58a55406d28bd95750a2
Hi Martin, [...] On systems with FEAT_FPAC support, indeed I could reproduce the behavior you mentioned: EXCEPTION_ILLEGAL_INSTRUCTION printed out repeatedly, immediate failure. On systems with pointer authentication but without FEAT_FPAC, the issue is more subtle: things seem to more or less work, but explorer.exe maxes out one CPU core. Also, running simple stuff like `wine cmd` does not really work. I built a local version of wine with your patch, and it does seem to fix the issue for systems without FEAT_FPAC. I don't see explorer.exe maxing out cores, and `wine cmd` works fine. However, on systems with FEAT_FPAC I still get illegal instructions. The general difference between the two is that with FEAT_FPAC, the autiasp (or equivalent) instruction fails with a SIGILL when failing to validate the value stored in LR. Without FEAT_FPAC, the autiasp instruction itself does not cause an exception, but instead it leaves a faulting value in LR. The crash then occurs when that corrupted value is next used. See https://wiki.debian.org/ToolChain/PACBTI#PAC-1. Here's the SIGILL with your patch: $ WINEDEBUG=+seh gdb /usr/lib/aarch64-linux-gnu/wine/wine [...] (gdb) run wineboot [...] wine_dbg_output: debugstr buffer overflow (contents: '002c:trace:seh:dispatch_exception code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D76230 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c000001d (EXCEPTION_ILLEGAL_INSTRUCTION) flags=0 addr=0000FFFFF7D763F0 code=c00000fd (EXCEPTION_STACK_OVERFLOW) flags=0 addr=00006FFFFFD567C4 ') 002c:err:virtual:virtual_setup_exception nested exception on signal stack addr 0xfffff7e7b5bc stack 0x7ffce130 Program received signal SIGILL, Illegal instruction. 0x0000fffff7d76230 in __wine_syscall_dispatcher () from /usr/lib/aarch64-linux-gnu/wine/aarch64-unix/ntdll.so For anyone who wants to follow along and build a patched wine, the version currently in sid (10.0~repack-12) does not build for several reasons. First you have to install a bunch of unicode-related packages from stable due to https://bugs.debian.org/1125336 # apt install unicode-data=15.1.0-1 unicode-idna=16.0.0-1 unicode-cldr-core=46-0.1 Then the make_vulkan bits fail due to the XML files shipped by libvulkan being too new. Again installing stuff from stable helps: # apt install libvulkan-dev=1.4.309.0-1 libvulkan1=1.4.309.0-1 The patch disable/duplicate-nls.patch does not seem to apply, I've commented it out in debian/patch/series. Then later the build fails due to NLS files not being installed anywhere. Out of time, I just added the following to debian/wine-common.install to carry on with the build: usr/* usr/share/wine/nls
Hi Emanuele, Thanks for testing and looking into this, I appreciate it a lot! This issue here can also be observed by trying to run a test app that does unwinding. E.g. https://martin.st/temp/hello-exception-aarch64.exe is a build of https://github.com/mstorsjo/llvm-mingw/blob/master/test/hello-exception.cpp, built with an llvm-mingw toolchain. This program fails when throwing a C++ exception, if Wine is built with CROSSCFLAGS="-mbranch-protection=standard", like it is in the Debian packages. But anyway, this part is fixed by the previously referenced patch. Thanks for these hints for how to fix rebuilding it! Yeah due to troubles with rebuilding the Debian package I didn't get to testing the final fix in the full context. With these hints, I was able to rebuild the package on Debian sid nicely, and reproduce the remaining problem. Actually, it turns out that this second issue isn't related to PAC or FPAC at all - but related to BTI. This issue is actually fixed in latest upstream Wine already, in [1]. Unfortunately, this fix doesn't apply cleanly on Wine 10.0, but it's easy enough to backport. I tested a backport of it, which I pushed at [2]. With these fixes, the packages now run fine on both a Cortex A720, and on Neoverse V2 (Graviton 4), where I previously hit the immediate EXCEPTION_ILLEGAL_INSTRUCTION. [1] https://gitlab.winehq.org/wine/wine/-/commit/da0b77340302d90b6b11ef030a8861fdfe728f48 [2] https://gitlab.winehq.org/mstorsjo/wine/-/commit/64c22e090351fd37c6b4f38ce5235d4c9c1bdaa2 // Martin
Hello Martin, systems with PAC support enabled: https://gitlab.winehq.org/wine/wine/-/commit/a83427f29e925d8b29cf58a55406d28bd95750a2 And the following addresses BTI: https://gitlab.winehq.org/mstorsjo/wine/-/commit/64c22e090351fd37c6b4f38ce5235d4c9c1bdaa2