================ @@ -1823,9 +1826,127 @@ extern "C" void *__libunwind_shstk_get_jump_target() { #endif class _LIBUNWIND_HIDDEN Registers_arm64 { + struct GPRs; + +private: + /// The program counter is used effectively as a return address + /// when the context is restored therefore protect it with PAC. + /// The base address of the context is used with the A key for + /// authentication and signing. Return address authentication is + /// still managed according to the unwind info. In some cases + /// the LR contains significant bits in the space for the PAC bits the + /// value of the PC is stored in 2 halfs and each signed. + inline uint64_t getDiscriminator() const { + return reinterpret_cast<uint64_t>(this); + } +#if defined(_LIBUNWIND_AARCH64_PC_PROTECTION) +#if defined(_LIBUNWIND_PTRAUTH_AVAILABLE) +/// Use Pointer Authentication Intrinsics when available. +#define __libunwind_ptrauth_auth_data(__value, __key, __discriminator) \ + ptrauth_auth_data(__value, __key, __discriminator) +#define __libunwind_ptrauth_auth_and_resign(pointer, oldKey, oldDiscriminator, \ + newKey, newDiscriminator) \ + ptrauth_auth_and_resign(pointer, oldKey, oldDiscriminator, newKey, \ + newDiscriminator) +#define __libunwind_ptrauth_sign_unauthenticated(__value, __key, __data) \ + ptrauth_sign_unauthenticated(__value, __key, __data) +#else // !_LIBUNWIND_PTRAUTH_AVAILABLE + typedef enum { + ptrauth_key_asia = 0, + } ptrauth_key; + /// Using only the NOP space compatible instructions. FPAC might not be + /// available on the target so a manual check is added. + inline void *__libunwind_ptrauth_strip(void *__value, + ptrauth_key __key) const { + assert(__key == ptrauth_key_asia && "Only A key is supported"); + void *__return = 0; + asm("mov x30, %[__value] \r\n" + "hint 0x7 \r\n" // xpaclri + "mov %[__return], x30 \r\n" + : [__return] "+r"(__return) + : [__value] "r"(__value) + : "x30"); + return __return; + } + + inline void *__libunwind_ptrauth_auth_data(void *__value, ptrauth_key __key, + uint64_t __discriminator) const { + assert(__key == ptrauth_key_asia && "Only A key is supported"); + register void *x17 __asm("x17") = __value; + register uintptr_t x16 __asm("x16") = __discriminator; + asm("hint 0xc" // autia1716 + : "+r"(x17) + : "r"(x16) + :); + if (x17 != __libunwind_ptrauth_strip(__value, __key)) + _LIBUNWIND_ABORT("ptrauth authentication failure"); + return x17; + } + + inline void * + __libunwind_ptrauth_sign_unauthenticated(void *__value, ptrauth_key __key, + uint64_t __discriminator) const { + assert(__key == ptrauth_key_asia && "Only A key is supported"); + register void *x17 __asm("x17") = __value; + register uint64_t x16 __asm("x16") = __discriminator; + asm("hint 0x8" : "+r"(x17) : "r"(x16)); + return x17; + } + + inline void *__libunwind_ptrauth_auth_and_resign( + void *pointer, ptrauth_key oldKey, uint64_t oldDiscriminator, + ptrauth_key newKey, uint64_t newDiscriminator) const { + return __libunwind_ptrauth_sign_unauthenticated( + __libunwind_ptrauth_auth_data(pointer, oldKey, oldDiscriminator), + newKey, newDiscriminator); + } +#endif + // Authenticate the currently stored PC and return it's raw value. + inline uint64_t authPC(const struct GPRs *gprs, + uint64_t discriminator) const { + uint64_t lower = (uint64_t)__libunwind_ptrauth_auth_data( + (void *)gprs->__pc, ptrauth_key_asia, discriminator); + uint64_t upper = (uint64_t)__libunwind_ptrauth_auth_data( + (void *)gprs->__pc2, ptrauth_key_asia, discriminator); + return (upper << 32) | lower; + } + + // Sign and store the new PC. + inline void updatePC(uint64_t value) { ---------------- DanielKristofKiss wrote:
This shouldn't manifest as a function as only internally used and should be always inlined, could be improved. ```suggestion __attribute__((always_inline)) inline void updatePC(uint64_t value) { ``` https://github.com/llvm/llvm-project/pull/113368 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits