From: Martin Storsjö <martin@martin.st> When unwinding through a "pac_sign_lr" opcode, we need to strip out pointer authentication bits from the address in the LR register. Previously this was done with the "autib1716" instruction, which does validate that the address in x17 is properly signed with the B key, given the reference address in x16 (SP). However - Clang has a bug [1] since Clang 19, that has caused it to generate incorrect prologues (if building with "-mbranch-protection=standard"), doing return address signing using the A key, while the unwind info says that the address should be signed using the B key. (The unwind info has no way of signaling which key to use, but the normative form uses the B key.) It also turns out that Windows doesn't do any validation of the signing of the return address when unwinding; Windows can correctly execute and do unwinding in binaries built with the buggy Clang - which might explain why the bug has passed unnoticed for so long. Therefore, doing the same and reducing the strictness here in Wine seems reasonable (in addition to doing it to work around the Clang bug). By using "xpaclri" instead of "autib1716", we strip out the authentication bits without validating them. Both instructions can be encoded as plain hint instructions, that are treated as nop instructions for older CPUs. In addition to failing on unwinding in user binaries built return address signing (e.g. "-mbranch-protection=standard") with a buggy Clang, this issue also hits cases if Wine itself has been built with "-mbranch-protection=standard" in CROSSCFLAGS, with a buggy version of Clang. This is the case on e.g. Ubuntu 26.04, making those builds of Wine fail (either directly on startup, or failing only if attempting to do unwinding in user code), if running on a CPU that supports pointer authentication. [1] https://github.com/llvm/llvm-project/issues/203852 --- dlls/ntdll/unwind.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/ntdll/unwind.c b/dlls/ntdll/unwind.c index 5b79e48ad85..f0707346a35 100644 --- a/dlls/ntdll/unwind.c +++ b/dlls/ntdll/unwind.c @@ -380,16 +380,16 @@ static void restore_any_reg( int reg, int count, int type, int pos, ARM64_NT_CON static void do_pac_auth( ARM64_NT_CONTEXT *context ) { - register DWORD64 x17 __asm__( "x17" ) = context->Lr; - register DWORD64 x16 __asm__( "x16" ) = context->Sp; + register DWORD64 x30 __asm__( "x30" ) = context->Lr; - /* This is the autib1716 instruction. The hint instruction is used here - * as gcc does not assemble autib1716 for pre armv8.3a targets. For - * pre-armv8.3a targets, this is just treated as a hint instruction, which - * is ignored. */ - __asm__( "hint 0xe" : "+r"(x17) : "r"(x16) ); + /* This is the xpaclri instruction. Assemble it through the hint + * instruction to make sure it builds with any toolchain, even if it + * doesn't support pointer authentication instructions, or if it might not + * know to emit them as hint instructions when targeting older versions + * than armv8.3. */ + __asm__( "hint 0x7" : "+r"(x30) ); - context->Lr = x17; + context->Lr = x30; } static void process_unwind_codes( BYTE *ptr, BYTE *end, ARM64_NT_CONTEXT *context, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11155