Issue 203852
Summary [AArch64] [COFF] Unwind info for return address signing is broken since LLVM 19
Labels
Assignees DanielKristofKiss, efriedma-quic
Reporter mstorsjo
    Support for generating the correct unwind info for return address signing was implemented in bd3fa318878a5f709d4324fbf74e10314012368f for LLVM 16. However since LLVM 19, since commit e15d67cfc2e5775cc79281aa860f3ad3be628f39 it has been subtly broken.

The unwind opcodes for return address signing on Windows are hardwired to signing with the B key. However, this commit subtly changed the prologues so they use the A key, while the unwind info specifies it as being signed with the B key.

A small testcase:
```c
void other(char *buf);

void func1(void) {
    char buf[100];
 other(buf);
}
```
Before that change:
```console
$ bin/clang -target aarch64-windows -S -o - test.c -O2 -mbranch-protection=standard -march=armv8.3-a
func1:
.seh_proc func1
        pacibsp
 .seh_pac_sign_lr
        sub     sp, sp, #128
        .seh_stackalloc 128
 str     x30, [sp, #112]                 // 8-byte Folded Spill
 .seh_save_reg   x30, 112
        .seh_endprologue
        add     x0, sp, #12
        bl      other
        .seh_startepilogue
        ldr     x30, [sp, #112]                 // 8-byte Folded Reload
        .seh_save_reg x30, 112
        add     sp, sp, #128
        .seh_stackalloc 128
 autibsp
        .seh_pac_sign_lr
        .seh_endepilogue
        ret
 .seh_endfunclet
        .seh_endproc
$ bin/clang -target aarch64-windows -c -o test.o test.c -O2 -mbranch-protection=standard
$ bin/llvm-readelf -u test.o

UnwindInformation [
  RuntimeFunction {
 Function: func1 (0x0)
    ExceptionRecord: .xdata (0x0)
    ExceptionData {
      FunctionLength: 36
      Version: 0
      ExceptionData: No
 EpiloguePacked: Yes
      EpilogueOffset: 0
      ByteCodeLength: 8
 Prologue [
        0xd2ce              ; str x30, [sp, #112]
        0x08 ; sub sp, #128
        0xfc                ; pacibsp
 0xe4                ; end
      ]
    }
  }
]
```
(The `-march=armv8.3-a` argument on the compiler is only used for clarity - to make it print explicit `pacibsp` instructions instead of hint instructions.)

However, after this change, the output changes like this:
```console
$ bin/clang-old -target aarch64-windows -S -o out-old.s test.c -O2 -mbranch-protection=standard -march=armv8.3-a
$ bin/clang-new -target aarch64-windows -S -o out-new.s test.c -O2 -mbranch-protection=standard -march=armv8.3-a
$ diff -u out-old.s out-new.s
--- out-old.s   2026-06-15 12:04:22.097292494 +0300
+++ out-new.s 2026-06-15 12:04:30.477328445 +0300
@@ -15,7 +15,7 @@
 func1: // @func1
 .seh_proc func1
 // %bb.0: // %entry
-       pacibsp
+       paciasp
 .seh_pac_sign_lr
        sub     sp, sp, #128
        .seh_stackalloc 128
@@ -29,7 +29,7 @@
        .seh_save_reg   x30, 112
        add     sp, sp, #128
        .seh_stackalloc 128
-       autibsp
+       autiasp
 .seh_pac_sign_lr
        .seh_endepilogue
        ret
```
This, while the unwind info still specifies that the address is signed with the B key.

In practice, this doesn't seem to lead to any crashes on Windows right now. It seems like Windows, when unwinding a `pac_sign_lr` opcode, Windows just strips the pointer authentication code (with a `xpaci` instruction?), and doesn't validate that it is signed.

It also seems like signing with the A key, on Windows right now, doesn't actually do any signing - so `-mbranch-protection=standard` essentially doesn't add any protection on Windows.

However - this mismatch does have implications on Wine. When Wine unwinds, it uses the `autib1716` instruction for handling the `pac_sign_lr` opcode, see https://gitlab.winehq.org/wine/wine/-/commit/7f7f06fe615fbd662d469cd1c16fd933692e05de. This means that the mismatch in unwind info causes crashes when binaries built with LLVM >= 19 run on Wine.

This also has implications for Wine itself; Ubuntu distributed versions of Wine (e.g. on 25.10 and 26.04) are built with `-mbranch-protection=standard`, including the PE DLLs in Wine, which breaks unwinding them.


_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to