[compiler-rt] [llvm] Reapply "compiler-rt: Introduce runtime functions for emulated PAC." (PR #148094)

Anatoly Trosinenko via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 14 04:31:47 PDT 2025


================
@@ -0,0 +1,156 @@
+//===--- emupac.cpp - Emulated PAC implementation -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements Emulated PAC using SipHash_1_3 as the IMPDEF hashing
+//  scheme.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+#include "siphash/SipHash.h"
+
+// EmuPAC implements runtime emulation of PAC instructions. If the current
+// CPU supports PAC, EmuPAC uses real PAC instructions. Otherwise, it uses the
+// emulation, which is effectively an implementation of PAC with an IMPDEF
+// hashing scheme based on SipHash_1_3.
+//
+// The purpose of the emulation is to allow programs to be built to be portable
+// to machines without PAC support, with some performance loss and increased
+// probability of false positives (due to not being able to portably determine
+// the VA size), while being functionally almost equivalent to running on a
+// machine with PAC support. One example of a use case is if PAC is used in
+// production as a security mitigation, but the testing environment is
+// heterogeneous (i.e. some machines lack PAC support). In this case we would
+// like the testing machines to be able to detect issues resulting
+// from the use of PAC instructions that would affect production by running
+// tests. This can be achieved by building test binaries with EmuPAC and
+// production binaries with real PAC.
+//
+// EmuPAC should not be used in production and is only intended for testing use
+// cases. This is not only because of the performance costs, which will exist
+// even on PAC-supporting machines because of the function call overhead for
+// each sign/auth operation, but because it provides weaker security compared to
+// real PAC: the key is constant and public, which means that we do not mix a
+// global secret.
+//
+// The emulation assumes that the VA size is at most 48 bits. The architecture
+// as of ARMv8.2, which was the last architecture version in which PAC was not
+// mandatory, permitted VA size up to 52 bits via ARMv8.2-LVA, but we are
+// unaware of an ARMv8.2 CPU that implemented ARMv8.2-LVA.
+
+const uint64_t max_va_size = 48;
+const uint64_t pac_mask = ((1ULL << 55) - 1) & ~((1ULL << max_va_size) - 1);
+const uint64_t ttbr1_mask = 1ULL << 55;
+
+// Determine whether PAC is supported without accessing memory. This utilizes
+// the XPACLRI instruction which will copy bit 55 of x30 into at least bit 54 if
+// PAC is supported and acts as a NOP if PAC is not supported.
+static bool pac_supported() {
+  register uintptr_t x30 __asm__("x30") = 1ULL << 55;
+  __asm__ __volatile__("xpaclri" : "+r"(x30));
+  return x30 & (1ULL << 54);
+}
+
+// This asm snippet is used to force the creation of a frame record when
+// calling the EmuPAC functions. This is important because the EmuPAC functions
+// may crash if an auth failure is detected and may be unwound past using a
+// frame pointer based unwinder.
+#ifdef __GCC_HAVE_DWARF2_CFI_ASM
+#define CFI_INST(inst) inst
+#else
+#define CFI_INST(inst)
+#endif
+
+#ifdef __APPLE__
+#define ASM_SYMBOL(symbol) "_" #symbol
+#else
+#define ASM_SYMBOL(symbol) #symbol
+#endif
----------------
atrosinenko wrote:

For the sake of completeness, it seems there is another exception, [Arm64EC ABI](https://learn.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170#FormatC):
> For ARM64EC functions with C linkage (whether compiled as C or by using extern "C"), a # is prepended to the decorated name.

This seems to be something Clang already knows about: for a trivial `int f(void) { return 0; }` source compiled with `clang -target arm64ec-windows-msvc -S -o- /tmp/arm64ec-test.c` it produces
```
// ...
        .p2align        2
"#f":                                   // @"#f"
        .weak_anti_dep  f
f = "#f"
// %bb.0:                               // %entry
        mov     w0, wzr
        ret
// ...
```
Furthermore, some aliases are mentioned in [AArch64MCInstLower.cpp](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp#L58). Please feel free to ignore / postpone this as long as builders are not affected.

https://github.com/llvm/llvm-project/pull/148094


More information about the llvm-commits mailing list