https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/193087
>From c38613012477f54f25f7b542f016f68948b01935 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Fri, 17 Apr 2026 20:55:13 +0300 Subject: [PATCH 1/4] [AArch64][PAC] Handle signing of init/fini pointers in AsmPrinter Move signing of the contents of `@llvm.global_(ctors|dtors)` from Clang frontend to the end of the backend pipeline, to AsmPrinter. Signing of the pointers to init/fini functions in the backend fixes registration of the constructors and destructors performed by the optimizer or the backend. This commit introduces two new module flags, `ptrauth-init-fini` and `ptrauth-init-fini-address-discrimination`, mirroring corresponding Clang options. The flags are semantically boolean, and the module is allowed to have either none of these flags, only the first one, or both. The particular constant discriminator to use is not configurable via module flags and is hardcoded to the value 0xD9D4 in the `llvm/lib/Target/AArch64/AArch64PointerAuth.h` file. --- .../include/clang/Basic/PointerAuthOptions.h | 7 - clang/lib/CodeGen/CodeGenModule.cpp | 27 +--- clang/lib/Frontend/CompilerInvocation.cpp | 6 - clang/test/CodeGen/ptrauth-init-fini.c | 30 ++-- llvm/lib/IR/AutoUpgrade.cpp | 101 ++++++++++++- llvm/lib/IR/Verifier.cpp | 58 +++++-- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 44 ++++-- llvm/lib/Target/AArch64/AArch64PointerAuth.h | 10 +- .../AArch64/ptrauth-init-fini-autoupgrade.ll | 143 ++++++++++++++++++ .../test/CodeGen/AArch64/ptrauth-init-fini.ll | 87 +++++++++-- 10 files changed, 428 insertions(+), 85 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index 2b920250721fc..2aa8d70088dbc 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -27,10 +27,6 @@ namespace clang { /// is ptrauth_string_discriminator("block_descriptor") constexpr uint16_t BlockDescriptorConstantDiscriminator = 0xC0BB; -/// Constant discriminator to be used with function pointers in .init_array and -/// .fini_array. The value is ptrauth_string_discriminator("init_fini") -constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4; - /// Constant discriminator to be used with method list pointers. The value is /// ptrauth_string_discriminator("method_list_t") constexpr uint16_t MethodListPointerConstantDiscriminator = 0xC310; @@ -224,9 +220,6 @@ struct PointerAuthOptions { /// The ABI for C++ member function pointers. PointerAuthSchema CXXMemberFunctionPointers; - /// The ABI for function addresses in .init_array and .fini_array - PointerAuthSchema InitFiniPointers; - /// The ABI for block invocation function pointers. PointerAuthSchema BlockInvocationFunctionPointers; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 813cd67e4dd51..df5ada1a508db 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1484,6 +1484,12 @@ void CodeGenModule::Release() { if (LangOpts.PointerAuthELFGOT) getModule().addModuleFlag(llvm::Module::Error, "ptrauth-elf-got", 1); + if (LangOpts.PointerAuthCalls && LangOpts.PointerAuthInitFini) { + getModule().addModuleFlag(llvm::Module::Error, "ptrauth-init-fini", 1); + if (LangOpts.PointerAuthInitFiniAddressDiscrimination) + getModule().addModuleFlag( + llvm::Module::Error, "ptrauth-init-fini-address-discrimination", 1); + } if (getTriple().isOSLinux()) { if (LangOpts.PointerAuthCalls) @@ -2562,9 +2568,6 @@ void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority, void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) { if (Fns.empty()) return; - const PointerAuthSchema &InitFiniAuthSchema = - getCodeGenOpts().PointerAuth.InitFiniPointers; - // Ctor function type is ptr. llvm::PointerType *PtrTy = llvm::PointerType::get( getLLVMContext(), TheModule.getDataLayout().getProgramAddressSpace()); @@ -2578,23 +2581,7 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) { for (const auto &I : Fns) { auto Ctor = Ctors.beginStruct(CtorStructTy); Ctor.addInt(Int32Ty, I.Priority); - if (InitFiniAuthSchema) { - llvm::Constant *StorageAddress = - (InitFiniAuthSchema.isAddressDiscriminated() - ? llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get( - IntPtrTy, - llvm::ConstantPtrAuth::AddrDiscriminator_CtorsDtors), - PtrTy) - : nullptr); - llvm::Constant *SignedCtorPtr = getConstantSignedPointer( - I.Initializer, InitFiniAuthSchema.getKey(), StorageAddress, - llvm::ConstantInt::get( - SizeTy, InitFiniAuthSchema.getConstantDiscrimination())); - Ctor.add(SignedCtorPtr); - } else { - Ctor.add(I.Initializer); - } + Ctor.add(I.Initializer); if (I.AssociatedData) Ctor.add(I.AssociatedData); else diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 50a2359c0e986..632fd02a6d362 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1487,12 +1487,6 @@ void CompilerInvocation::setDefaultPointerAuthOptions( Opts.CXXMemberFunctionPointers = PointerAuthSchema(Key::ASIA, false, Discrimination::Type); - if (LangOpts.PointerAuthInitFini) { - Opts.InitFiniPointers = PointerAuthSchema( - Key::ASIA, LangOpts.PointerAuthInitFiniAddressDiscrimination, - Discrimination::Constant, InitFiniPointerConstantDiscriminator); - } - Opts.BlockInvocationFunctionPointers = PointerAuthSchema(Key::ASIA, true, Discrimination::None); Opts.BlockHelperFunctionPointers = diff --git a/clang/test/CodeGen/ptrauth-init-fini.c b/clang/test/CodeGen/ptrauth-init-fini.c index 1e8953961d64e..466d992299226 100644 --- a/clang/test/CodeGen/ptrauth-init-fini.c +++ b/clang/test/CodeGen/ptrauth-init-fini.c @@ -1,28 +1,36 @@ // REQUIRES: aarch64-registered-target // RUN: %clang_cc1 -triple aarch64-elf -target-feature +pauth -fptrauth-calls -fptrauth-init-fini \ -// RUN: -emit-llvm %s -o - | FileCheck --check-prefix=SIGNED %s +// RUN: -emit-llvm %s -o - | FileCheck --check-prefix=COMMON,SIGNED %s // RUN: %clang_cc1 -triple aarch64-elf -target-feature +pauth -fptrauth-calls -fptrauth-init-fini \ -// RUN: -fptrauth-init-fini-address-discrimination -emit-llvm %s -o - | FileCheck --check-prefix=ADDRDISC %s +// RUN: -fptrauth-init-fini-address-discrimination -emit-llvm %s -o - | FileCheck --check-prefix=COMMON,ADDRDISC %s // RUN: %clang_cc1 -triple aarch64-elf -target-feature +pauth -fptrauth-calls \ -// RUN: -emit-llvm %s -o - | FileCheck --check-prefix=UNSIGNED %s +// RUN: -emit-llvm %s -o - | FileCheck --check-prefix=COMMON,UNSIGNED %s // RUN: %clang_cc1 -triple aarch64-elf -target-feature +pauth -fptrauth-calls -fptrauth-init-fini-address-discrimination \ -// RUN: -emit-llvm %s -o - | FileCheck --check-prefix=UNSIGNED %s +// RUN: -emit-llvm %s -o - | FileCheck --check-prefix=COMMON,UNSIGNED %s // RUN: %clang_cc1 -triple aarch64-elf -target-feature +pauth -fptrauth-init-fini \ -// RUN: -emit-llvm %s -o - | FileCheck --check-prefix=UNSIGNED %s +// RUN: -emit-llvm %s -o - | FileCheck --check-prefix=COMMON,UNSIGNED %s -// SIGNED: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }] -// SIGNED: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764), ptr null }] +// COMMON: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] +// COMMON: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] -// ADDRDISC: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] -// ADDRDISC: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] +// The below checks assume no other module flags happens to be set. -// UNSIGNED: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] -// UNSIGNED: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] +// UNSIGNED-NOT: !llvm.module.flags +// UNSIGNED-NOT: !"ptrauth-init-fini" +// UNSIGNED-NOT: !"ptrauth-init-fini-address-discrimination" + +// SIGNED: !llvm.module.flags = !{!0} +// SIGNED: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} +// SIGNED-NOT: !"ptrauth-init-fini-address-discrimination" + +// ADDRDISC: !llvm.module.flags = !{!0, !1} +// ADDRDISC: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} +// ADDRDISC: !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} volatile int x = 0; diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index 229c7757db3dc..a465e0ebec9be 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -6372,12 +6372,109 @@ void llvm::UpgradeARCRuntime(Module &M) { UpgradeToIntrinsic(I.first, I.second); } +// Upgrade from wrapping each pointer stored in the @llvm.global_(ctors|dtors) +// with ptrauth constant expression to storing plain pointers in these arrays +// and requesting the particular signing schema globally via module flags. +// +// Only perform the upgrade if all elements of *both* arrays agree on a common +// signing schema. The processing of the array is *not* stopped on the first +// null function pointer. +static bool upgradePtrauthInitFiniArrays(Module &M) { + // Either "not decided yet" or whether we should request address diversity + // in addition to the basic constant diversity. + // There is no value representing "decided not to sign", as this results + // in immediate return from upgradePtrauthInitFiniArrays. + std::optional<bool> UseAddressDisc; + + // Do not attempt upgrading if the new module flags already exist. + if (const NamedMDNode *ModFlags = M.getModuleFlagsMetadata()) { + for (const MDNode *Flag : ModFlags->operands()) { + if (Flag->getNumOperands() != 3) + continue; + const MDString *ID = dyn_cast_or_null<MDString>(Flag->getOperand(1)); + if (ID && (ID->getString() == "ptrauth-init-fini" || + ID->getString() == "ptrauth-init-fini-address-discriminator")) + return false; + } + } + + auto UpgradeSinglePointer = [&UseAddressDisc](Constant *CV) -> Constant * { + const unsigned ExpectedConstDisc = 0xD9D4; + const unsigned ExpectedAddressMarker = 1; + + auto *CPA = dyn_cast<ConstantPtrAuth>(CV); + if (!CPA || !CPA->getDiscriminator()->equalsInt(ExpectedConstDisc)) + return nullptr; // Nothing to upgrade or unknown pattern found. + + bool HasAddressDisc; + if (!CPA->hasAddressDiscriminator()) + HasAddressDisc = false; + else if (CPA->hasSpecialAddressDiscriminator(ExpectedAddressMarker)) + HasAddressDisc = true; + else + return nullptr; // Unknown pattern. + + if (UseAddressDisc && *UseAddressDisc != HasAddressDisc) + return nullptr; // Disagreement with the decided mode. + + UseAddressDisc = HasAddressDisc; + return CPA->getPointer(); + }; + + SmallVector<std::pair<GlobalVariable *, Constant *>> PendingUpgrades; + for (const char *Name : {"llvm.global_ctors", "llvm.global_dtors"}) { + auto *GV = dyn_cast_if_present<GlobalVariable>(M.getNamedValue(Name)); + if (!GV || !GV->hasInitializer()) + continue; // Skip, but it is okay to upgrade the other variable. + + auto *Init = dyn_cast<ConstantArray>(GV->getInitializer()); + if (!Init) + return false; + + std::vector<Constant *> NewStructors; + NewStructors.reserve(Init->getNumOperands()); + for (Use &U : Init->operands()) { + auto *Structor = dyn_cast<ConstantStruct>(U.get()); + if (!Structor || Structor->getNumOperands() != 3) + return false; + + Constant *Prio = Structor->getOperand(0); + Constant *Func = UpgradeSinglePointer(Structor->getOperand(1)); + Constant *Arg = Structor->getOperand(2); + if (!Func) + return false; + + NewStructors.push_back( + ConstantStruct::get(Structor->getType(), {Prio, Func, Arg})); + } + + Constant *NewInit = ConstantArray::get(Init->getType(), NewStructors); + PendingUpgrades.push_back({GV, NewInit}); + } + + if (PendingUpgrades.empty()) + return false; + assert(UseAddressDisc.has_value()); + + for (auto [GV, NewInit] : PendingUpgrades) + GV->setInitializer(NewInit); + M.addModuleFlag(Module::Error, "ptrauth-init-fini", 1); + if (UseAddressDisc.value()) + M.addModuleFlag(Module::Error, "ptrauth-init-fini-address-discriminator", + 1); + + return true; +} + bool llvm::UpgradeModuleFlags(Module &M) { + bool Changed = false; + Changed |= upgradePtrauthInitFiniArrays(M); + NamedMDNode *ModFlags = M.getModuleFlagsMetadata(); if (!ModFlags) - return false; + return Changed; - bool HasObjCFlag = false, HasClassProperties = false, Changed = false; + bool HasObjCFlag = false, HasClassProperties = false; bool HasSwiftVersionFlag = false; uint8_t SwiftMajorVersion, SwiftMinorVersion; uint32_t SwiftABIVersion; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 5f8b5e187bf14..4a79356c1a079 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -748,6 +748,19 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) { Check(ETy->isPointerTy(), "wrong type for intrinsic global variable", &GV); } + + auto *Init = GV.hasInitializer() + ? dyn_cast<ConstantArray>(GV.getInitializer()) + : nullptr; + if (Init) { + for (const Use &U : Init->operands()) { + auto *Structor = dyn_cast<ConstantStruct>(U); + if (!Structor || Structor->getNumOperands() != 3) + continue; + Check(!isa<ConstantPtrAuth>(Structor->getOperand(1)), + "signing of ctors/dtors should be requested via module flags"); + } + } } if (GV.hasName() && (GV.getName() == "llvm.used" || @@ -1816,26 +1829,49 @@ void Verifier::visitModuleFlags() { // Scan each flag, and track the flags and requirements. DenseMap<const MDString*, const MDNode*> SeenIDs; SmallVector<const MDNode*, 16> Requirements; - uint64_t PAuthABIPlatform = -1; - uint64_t PAuthABIVersion = -1; + std::optional<uint64_t> PAuthABIPlatform; + std::optional<uint64_t> PAuthABIVersion; + std::optional<uint64_t> HasPtrauthInitFini; + std::optional<uint64_t> HasPtrauthInitFiniAddr; + for (const MDNode *MDN : Flags->operands()) { visitModuleFlag(MDN, SeenIDs, Requirements); if (MDN->getNumOperands() != 3) continue; + if (const auto *FlagName = dyn_cast_or_null<MDString>(MDN->getOperand(1))) { - if (FlagName->getString() == "aarch64-elf-pauthabi-platform") { - if (const auto *PAP = + auto GetFlagNamed = [&](StringRef Name) -> std::optional<uint64_t> { + if (FlagName->getString() != Name) + return std::nullopt; + if (const auto *FlagValue = mdconst::dyn_extract_or_null<ConstantInt>(MDN->getOperand(2))) - PAuthABIPlatform = PAP->getZExtValue(); - } else if (FlagName->getString() == "aarch64-elf-pauthabi-version") { - if (const auto *PAV = - mdconst::dyn_extract_or_null<ConstantInt>(MDN->getOperand(2))) - PAuthABIVersion = PAV->getZExtValue(); - } + return FlagValue->getZExtValue(); + + CheckFailed(Name + ": module flag expects integer value"); + return std::nullopt; + }; + + if (auto Value = GetFlagNamed("aarch64-elf-pauthabi-platform")) + PAuthABIPlatform = *Value; + else if (auto Value = GetFlagNamed("aarch64-elf-pauthabi-version")) + PAuthABIVersion = *Value; + else if (auto Value = GetFlagNamed("ptrauth-init-fini")) + HasPtrauthInitFini = *Value; + else if (auto Value = + GetFlagNamed("ptrauth-init-fini-address-discrimination")) + HasPtrauthInitFiniAddr = *Value; } } - if ((PAuthABIPlatform == uint64_t(-1)) != (PAuthABIVersion == uint64_t(-1))) + Check(!HasPtrauthInitFini || HasPtrauthInitFini.value() == 1, + "ptrauth-init-fini must be set to 1 or unset"); + Check(!HasPtrauthInitFiniAddr || HasPtrauthInitFiniAddr.value() == 1, + "ptrauth-init-fini-address-discrimination must be set to 1 or unset"); + if (HasPtrauthInitFiniAddr) + Check(HasPtrauthInitFini, "ptrauth-init-fini-address-discrimination module " + "flag requires ptrauth-init-fini"); + + if (PAuthABIPlatform.has_value() != PAuthABIVersion.has_value()) CheckFailed("either both or no 'aarch64-elf-pauthabi-platform' and " "'aarch64-elf-pauthabi-version' module flags must be present"); diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index b239890d3ccb4..f2011c58f85ce 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -98,6 +98,8 @@ class AArch64AsmPrinter : public AsmPrinter { FaultMaps FM; const AArch64Subtarget *STI; bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = false; + bool PtrauthInitFini = false; + bool PtrauthInitFiniAddressDisc = false; #ifndef NDEBUG unsigned InstsEmitted; #endif @@ -405,6 +407,11 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) { EnableImportCallOptimization = true; } + if (M.getModuleFlag("ptrauth-init-fini")) + PtrauthInitFini = true; + if (M.getModuleFlag("ptrauth-init-fini-address-discrimination")) + PtrauthInitFiniAddressDisc = true; + if (!TT.isOSBinFormatELF()) return; @@ -1461,18 +1468,31 @@ void AArch64AsmPrinter::emitFunctionEntryLabel() { void AArch64AsmPrinter::emitXXStructor(const DataLayout &DL, const Constant *CV) { - if (const auto *CPA = dyn_cast<ConstantPtrAuth>(CV)) - if (CPA->hasAddressDiscriminator() && - !CPA->hasSpecialAddressDiscriminator( - ConstantPtrAuth::AddrDiscriminator_CtorsDtors)) - report_fatal_error( - "unexpected address discrimination value for ctors/dtors entry, only " - "'ptr inttoptr (i64 1 to ptr)' is allowed"); - // If we have signed pointers in xxstructors list, they'll be lowered to @AUTH - // MCExpr's via AArch64AsmPrinter::lowerConstantPtrAuth. It does not look at - // actual address discrimination value and only checks - // hasAddressDiscriminator(), so it's OK to leave special address - // discrimination value here. + LLVMContext &C = CV->getContext(); + assert(!isa<ConstantPtrAuth>(CV) && + "ctors/dtors are to be signed by asm printer"); + + if (PtrauthInitFini) { + IntegerType *Int32Ty = IntegerType::get(C, 32); + IntegerType *Int64Ty = IntegerType::get(C, 64); + PointerType *PtrTy = PointerType::get(C, 0); + + ConstantInt *Key = ConstantInt::get(Int32Ty, AArch64PAuth::InitFiniKey); + ConstantInt *IntDisc = ConstantInt::get( + Int64Ty, AArch64PAuth::InitFiniPointerConstantDiscriminator); + Constant *Null = ConstantPointerNull::get(PtrTy); + Constant *AddressDisc = Null; + if (PtrauthInitFiniAddressDisc) { + uint64_t Marker = ConstantPtrAuth::AddrDiscriminator_CtorsDtors; + AddressDisc = + ConstantExpr::getIntToPtr(ConstantInt::get(Int64Ty, Marker), PtrTy); + } + + CV = ConstantPtrAuth::get(const_cast<Constant *>(CV), Key, IntDisc, + AddressDisc, /*DeactivationSymbol=*/Null); + } + + // Signed pointers will be lowered by AArch64AsmPrinter::lowerConstantPtrAuth. AsmPrinter::emitXXStructor(DL, CV); } diff --git a/llvm/lib/Target/AArch64/AArch64PointerAuth.h b/llvm/lib/Target/AArch64/AArch64PointerAuth.h index d6947f0d22aac..1e69558e996d1 100644 --- a/llvm/lib/Target/AArch64/AArch64PointerAuth.h +++ b/llvm/lib/Target/AArch64/AArch64PointerAuth.h @@ -9,12 +9,18 @@ #ifndef LLVM_LIB_TARGET_AARCH64_AARCH64POINTERAUTH_H #define LLVM_LIB_TARGET_AARCH64_AARCH64POINTERAUTH_H -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/CodeGen/Register.h" +#include "Utils/AArch64BaseInfo.h" namespace llvm { namespace AArch64PAuth { +/// PAuth key to be used with function pointers in .init_array and .fini_array. +constexpr AArch64PACKey::ID InitFiniKey = AArch64PACKey::IA; + +/// Constant discriminator to be used with function pointers in .init_array and +/// .fini_array. The value is ptrauth_string_discriminator("init_fini") +constexpr unsigned InitFiniPointerConstantDiscriminator = 0xD9D4; + /// Variants of check performed on an authenticated pointer. /// /// In cases such as authenticating the LR value when performing a tail call diff --git a/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll b/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll new file mode 100644 index 0000000000000..68efd9c2a8b7e --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll @@ -0,0 +1,143 @@ +; RUN: rm -rf %t && split-file %s %t && cd %t + +;--- nodisc.ll + +; RUN: opt -S < nodisc.ll | FileCheck %s --check-prefix=NODISC + [email protected]_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo1, i32 0, i64 55764), ptr null }, { i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo2, i32 0, i64 55764), ptr null }] [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764), ptr null }] + +define void @foo1() { + ret void +} + +define void @foo2() { + ret void +} + +define void @bar() { + ret void +} + +; NODISC: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @foo2, ptr null }] +; NODISC: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] +; NODISC: !llvm.module.flags = !{!0} +; NODISC: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} + +;--- disc.ll + +; RUN: opt -S < disc.ll | FileCheck %s --check-prefix=DISC + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] [email protected]_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar1, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }, { i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar2, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] + +define void @foo() { + ret void +} + +define void @bar1() { + ret void +} + +define void @bar2() { + ret void +} + +; DISC: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] +; DISC: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @bar2, ptr null }] +; DISC: !llvm.module.flags = !{!0, !1} +; DISC: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} +; DISC: !1 = !{i32 1, !"ptrauth-init-fini-address-discriminator", i32 1} + +;--- err1.ll + +; RUN: not opt -S < err1.ll 2>&1 | FileCheck %s --check-prefix=ERR1 + +; ERR1: signing of ctors/dtors should be requested via module flags + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr inttoptr (i64 2 to ptr)), ptr null }] + +define void @foo() { + ret void +} + +;--- err2.ll + +; RUN: not opt -S < err2.ll 2>&1 | FileCheck %s --check-prefix=ERR2 + +; ERR2: signing of ctors/dtors should be requested via module flags + +@g = external global ptr [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764, ptr @g), ptr null }] + +define void @bar() { + ret void +} + +;--- disagreement1.ll + +; RUN: not opt -S < disagreement1.ll 2>&1 | FileCheck %s --check-prefix=DISAGREEMENT1 + +; DISAGREEMENT1: signing of ctors/dtors should be requested via module flags + [email protected]_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }, { i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] + +define void @foo() { + ret void +} + +define void @bar() { + ret void +} + +;--- disagreement2.ll + +; RUN: not opt -S < disagreement2.ll 2>&1 | FileCheck %s --check-prefix=DISAGREEMENT2 + +; DISAGREEMENT2: signing of ctors/dtors should be requested via module flags + [email protected]_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }, { i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] + +define void @foo() { + ret void +} + +define void @bar() { + ret void +} + +;--- disagreement3.ll + +; RUN: not opt -S < disagreement3.ll 2>&1 | FileCheck %s --check-prefix=DISAGREEMENT3 + +; DISAGREEMENT3: signing of ctors/dtors should be requested via module flags + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }] [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] + +define void @foo() { + ret void +} + +define void @bar() { + ret void +} + +;--- existing-flags.ll + +; RUN: not opt -S < existing-flags.ll 2>&1 | FileCheck %s --check-prefix=EXISTING-FLAGS + +; EXISTING-FLAGS: signing of ctors/dtors should be requested via module flags + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }] + +define void @foo() { + ret void +} + +define void @bar() { + ret void +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"ptrauth-init-fini", i32 1} diff --git a/llvm/test/CodeGen/AArch64/ptrauth-init-fini.ll b/llvm/test/CodeGen/AArch64/ptrauth-init-fini.ll index 186a31c63ba10..e3b1f3835f553 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-init-fini.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-init-fini.ll @@ -27,8 +27,8 @@ ;; ^^^^ 0xD9D4: constant discriminator = 55764 ;; ^^ 0x80: bits 61..60 key = IA; bit 63 addr disc = false [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }] [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764), ptr null }] [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] define void @foo() { ret void @@ -38,6 +38,9 @@ define void @bar() { ret void } +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"ptrauth-init-fini", i32 1} + ;--- disc.ll ; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=asm -o - disc.ll | \ @@ -65,8 +68,8 @@ define void @bar() { ;; ^^^^ 0xD9D4: constant discriminator = 55764 ;; ^^ 0x80: bits 61..60 key = IA; bit 63 addr disc = true [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] define void @foo() { ret void @@ -76,29 +79,85 @@ define void @bar() { ret void } +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"ptrauth-init-fini", i32 1} +!1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} + ;--- err1.ll -; RUN: not --crash llc -mtriple aarch64-elf -mattr=+pauth -filetype=asm -o - err1.ll 2>&1 | \ -; RUN: FileCheck %s --check-prefix=ERR1 +; RUN: not opt -S < err1.ll 2>&1 | FileCheck %s --check-prefix=ERR1 -; ERR1: LLVM ERROR: unexpected address discrimination value for ctors/dtors entry, only 'ptr inttoptr (i64 1 to ptr)' is allowed +; ERR1: ptrauth-init-fini must be set to 1 or unset [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr inttoptr (i64 2 to ptr)), ptr null }] [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] define void @foo() { ret void } +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"ptrauth-init-fini", i32 0} +!1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} + ;--- err2.ll -; RUN: not --crash llc -mtriple aarch64-elf -mattr=+pauth -filetype=asm -o - err2.ll 2>&1 | \ -; RUN: FileCheck %s --check-prefix=ERR2 +; RUN: not opt -S < err2.ll 2>&1 | FileCheck %s --check-prefix=ERR2 -; ERR2: LLVM ERROR: unexpected address discrimination value for ctors/dtors entry, only 'ptr inttoptr (i64 1 to ptr)' is allowed +; ERR2: ptrauth-init-fini-address-discrimination must be set to 1 or unset -@g = external global ptr [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764, ptr @g), ptr null }] [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] -define void @bar() { +define void @foo() { ret void } + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"ptrauth-init-fini", i32 1} +!1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0} + +;--- err3.ll + +; RUN: not opt -S < err3.ll 2>&1 | FileCheck %s --check-prefix=ERR3 + +; ERR3: ptrauth-init-fini: module flag expects integer value + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] + +define void @foo() { + ret void +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"ptrauth-init-fini", !"1"} +!1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} + +;--- err4.ll + +; RUN: not opt -S < err4.ll 2>&1 | FileCheck %s --check-prefix=ERR4 + +; ERR4: ptrauth-init-fini-address-discrimination: module flag expects integer value + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] + +define void @foo() { + ret void +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"ptrauth-init-fini", i32 1} +!1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", !"1"} + +;--- err5.ll + +; RUN: not opt -S < err5.ll 2>&1 | FileCheck %s --check-prefix=ERR5 + +; ERR5: ptrauth-init-fini-address-discrimination module flag requires ptrauth-init-fini + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] + +define void @foo() { + ret void +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} >From 694de74d7681d44f0f18016cb95f27895773a097 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Fri, 12 Jun 2026 17:51:40 +0300 Subject: [PATCH 2/4] Improve readability --- llvm/lib/IR/AutoUpgrade.cpp | 60 +++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index a465e0ebec9be..e8fc873af0746 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -6039,6 +6039,14 @@ Constant *llvm::UpgradeBitCastExpr(unsigned Opc, Constant *C, Type *DestTy) { return nullptr; } +static std::optional<StringRef> getModuleFlagNameSafely(const MDNode &Flag) { + if (Flag.getNumOperands() < 3) + return std::nullopt; + if (MDString *Name = dyn_cast_or_null<MDString>(Flag.getOperand(1))) + return Name->getString(); + return std::nullopt; +} + /// Check the debug info version number, if it is out-dated, drop the debug /// info. Return true if module is modified. bool llvm::UpgradeDebugInfo(Module &M) { @@ -6052,10 +6060,8 @@ bool llvm::UpgradeDebugInfo(Module &M) { unsigned Version = 0; if (NamedMDNode *ModFlags = M.getModuleFlagsMetadata()) { auto OpIt = find_if(ModFlags->operands(), [](const MDNode *Flag) { - if (Flag->getNumOperands() < 3) - return false; - if (MDString *K = dyn_cast_or_null<MDString>(Flag->getOperand(1))) - return K->getString() == "Debug Info Version"; + if (auto Name = getModuleFlagNameSafely(*Flag)) + return *Name == "Debug Info Version"; return false; }); if (OpIt != ModFlags->op_end()) { @@ -6372,13 +6378,11 @@ void llvm::UpgradeARCRuntime(Module &M) { UpgradeToIntrinsic(I.first, I.second); } -// Upgrade from wrapping each pointer stored in the @llvm.global_(ctors|dtors) -// with ptrauth constant expression to storing plain pointers in these arrays -// and requesting the particular signing schema globally via module flags. +// Upgrade from storing `ptrauth` constants in `@llvm.global_(ctors|dtors)` +// arrays to configuring signing of pointers to *structors via module flags. // // Only perform the upgrade if all elements of *both* arrays agree on a common -// signing schema. The processing of the array is *not* stopped on the first -// null function pointer. +// signing schema. static bool upgradePtrauthInitFiniArrays(Module &M) { // Either "not decided yet" or whether we should request address diversity // in addition to the basic constant diversity. @@ -6389,11 +6393,9 @@ static bool upgradePtrauthInitFiniArrays(Module &M) { // Do not attempt upgrading if the new module flags already exist. if (const NamedMDNode *ModFlags = M.getModuleFlagsMetadata()) { for (const MDNode *Flag : ModFlags->operands()) { - if (Flag->getNumOperands() != 3) - continue; - const MDString *ID = dyn_cast_or_null<MDString>(Flag->getOperand(1)); - if (ID && (ID->getString() == "ptrauth-init-fini" || - ID->getString() == "ptrauth-init-fini-address-discriminator")) + std::optional<StringRef> Name = getModuleFlagNameSafely(*Flag); + if (Name && (*Name == "ptrauth-init-fini" || + *Name == "ptrauth-init-fini-address-discriminator")) return false; } } @@ -6421,26 +6423,32 @@ static bool upgradePtrauthInitFiniArrays(Module &M) { return CPA->getPointer(); }; - SmallVector<std::pair<GlobalVariable *, Constant *>> PendingUpgrades; + // Do not apply any changes until we know the upgrade is non-ambiguous. + using PendingUpgrade = std::pair<GlobalVariable *, Constant *>; + SmallVector<PendingUpgrade, 2> GlobalArraysToUpgrade; + for (const char *Name : {"llvm.global_ctors", "llvm.global_dtors"}) { auto *GV = dyn_cast_if_present<GlobalVariable>(M.getNamedValue(Name)); if (!GV || !GV->hasInitializer()) continue; // Skip, but it is okay to upgrade the other variable. - auto *Init = dyn_cast<ConstantArray>(GV->getInitializer()); - if (!Init) + auto *OldStructorsArray = dyn_cast<ConstantArray>(GV->getInitializer()); + if (!OldStructorsArray) return false; std::vector<Constant *> NewStructors; - NewStructors.reserve(Init->getNumOperands()); - for (Use &U : Init->operands()) { - auto *Structor = dyn_cast<ConstantStruct>(U.get()); + NewStructors.reserve(OldStructorsArray->getNumOperands()); + + for (Use &U : OldStructorsArray->operands()) { + ConstantStruct *Structor = dyn_cast<ConstantStruct>(U.get()); if (!Structor || Structor->getNumOperands() != 3) return false; Constant *Prio = Structor->getOperand(0); - Constant *Func = UpgradeSinglePointer(Structor->getOperand(1)); + Constant *Func = Structor->getOperand(1); Constant *Arg = Structor->getOperand(2); + + Func = UpgradeSinglePointer(Func); if (!Func) return false; @@ -6448,16 +6456,18 @@ static bool upgradePtrauthInitFiniArrays(Module &M) { ConstantStruct::get(Structor->getType(), {Prio, Func, Arg})); } - Constant *NewInit = ConstantArray::get(Init->getType(), NewStructors); - PendingUpgrades.push_back({GV, NewInit}); + Constant *NewInit = + ConstantArray::get(OldStructorsArray->getType(), NewStructors); + GlobalArraysToUpgrade.push_back({GV, NewInit}); } - if (PendingUpgrades.empty()) + if (GlobalArraysToUpgrade.empty()) return false; assert(UseAddressDisc.has_value()); - for (auto [GV, NewInit] : PendingUpgrades) + for (auto [GV, NewInit] : GlobalArraysToUpgrade) GV->setInitializer(NewInit); + M.addModuleFlag(Module::Error, "ptrauth-init-fini", 1); if (UseAddressDisc.value()) M.addModuleFlag(Module::Error, "ptrauth-init-fini-address-discriminator", >From ecc20fef0a7e94763c80ca78f9728ca73c2d326a Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Fri, 12 Jun 2026 17:52:12 +0300 Subject: [PATCH 3/4] Fix module flag name spelling in AutoUpgrade.cpp --- llvm/lib/IR/AutoUpgrade.cpp | 4 ++-- llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index e8fc873af0746..4d3fc6f2f07de 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -6395,7 +6395,7 @@ static bool upgradePtrauthInitFiniArrays(Module &M) { for (const MDNode *Flag : ModFlags->operands()) { std::optional<StringRef> Name = getModuleFlagNameSafely(*Flag); if (Name && (*Name == "ptrauth-init-fini" || - *Name == "ptrauth-init-fini-address-discriminator")) + *Name == "ptrauth-init-fini-address-discrimination")) return false; } } @@ -6470,7 +6470,7 @@ static bool upgradePtrauthInitFiniArrays(Module &M) { M.addModuleFlag(Module::Error, "ptrauth-init-fini", 1); if (UseAddressDisc.value()) - M.addModuleFlag(Module::Error, "ptrauth-init-fini-address-discriminator", + M.addModuleFlag(Module::Error, "ptrauth-init-fini-address-discrimination", 1); return true; diff --git a/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll b/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll index 68efd9c2a8b7e..c07ffd8c7e4c4 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll @@ -47,7 +47,7 @@ define void @bar2() { ; DISC: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @bar2, ptr null }] ; DISC: !llvm.module.flags = !{!0, !1} ; DISC: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} -; DISC: !1 = !{i32 1, !"ptrauth-init-fini-address-discriminator", i32 1} +; DISC: !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} ;--- err1.ll >From b553fccb117ff46872ced2b1d2a338ef1b2b9f59 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Fri, 3 Jul 2026 20:06:05 +0300 Subject: [PATCH 4/4] Switch to unconditionally-set module flags --- clang/lib/CodeGen/CodeGenModule.cpp | 14 +- clang/test/CodeGen/ptrauth-init-fini.c | 13 +- clang/test/CodeGen/ptrauth-module-flags.c | 7 +- clang/test/CodeGenCXX/pfp-memcpy.cpp | 4 +- llvm/lib/IR/AutoUpgrade.cpp | 32 ++-- llvm/lib/IR/Verifier.cpp | 15 +- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 18 ++- .../AArch64/ptrauth-init-fini-autoupgrade.ll | 52 +++++-- .../test/CodeGen/AArch64/ptrauth-init-fini.ll | 145 ++++++++++-------- 9 files changed, 179 insertions(+), 121 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index df5ada1a508db..8816e41f2cfb8 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1484,11 +1484,15 @@ void CodeGenModule::Release() { if (LangOpts.PointerAuthELFGOT) getModule().addModuleFlag(llvm::Module::Error, "ptrauth-elf-got", 1); - if (LangOpts.PointerAuthCalls && LangOpts.PointerAuthInitFini) { - getModule().addModuleFlag(llvm::Module::Error, "ptrauth-init-fini", 1); - if (LangOpts.PointerAuthInitFiniAddressDiscrimination) - getModule().addModuleFlag( - llvm::Module::Error, "ptrauth-init-fini-address-discrimination", 1); + + if (T.isAArch64()) { + getModule().addModuleFlag(llvm::Module::Error, "ptrauth-init-fini", + LangOpts.PointerAuthCalls && + LangOpts.PointerAuthInitFini); + getModule().addModuleFlag( + llvm::Module::Error, "ptrauth-init-fini-address-discrimination", + LangOpts.PointerAuthCalls && LangOpts.PointerAuthInitFini && + LangOpts.PointerAuthInitFiniAddressDiscrimination); } if (getTriple().isOSLinux()) { diff --git a/clang/test/CodeGen/ptrauth-init-fini.c b/clang/test/CodeGen/ptrauth-init-fini.c index 466d992299226..73ad1300c4d6f 100644 --- a/clang/test/CodeGen/ptrauth-init-fini.c +++ b/clang/test/CodeGen/ptrauth-init-fini.c @@ -20,15 +20,14 @@ // The below checks assume no other module flags happens to be set. -// UNSIGNED-NOT: !llvm.module.flags -// UNSIGNED-NOT: !"ptrauth-init-fini" -// UNSIGNED-NOT: !"ptrauth-init-fini-address-discrimination" +// COMMON: !llvm.module.flags = !{!0, !1} -// SIGNED: !llvm.module.flags = !{!0} -// SIGNED: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} -// SIGNED-NOT: !"ptrauth-init-fini-address-discrimination" +// UNSIGNED: !0 = !{i32 1, !"ptrauth-init-fini", i32 0} +// UNSIGNED: !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0} + +// SIGNED: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} +// SIGNED: !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0} -// ADDRDISC: !llvm.module.flags = !{!0, !1} // ADDRDISC: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} // ADDRDISC: !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} diff --git a/clang/test/CodeGen/ptrauth-module-flags.c b/clang/test/CodeGen/ptrauth-module-flags.c index 6c175c0aad781..75d9fdcf7b914 100644 --- a/clang/test/CodeGen/ptrauth-module-flags.c +++ b/clang/test/CodeGen/ptrauth-module-flags.c @@ -7,7 +7,10 @@ // ELFGOT: !0 = !{i32 1, !"ptrauth-elf-got", i32 1} // PERSONALITY: !llvm.module.flags = !{ -// PERSONALITY-SAME: !0 -// PERSONALITY: !0 = !{i32 1, !"ptrauth-sign-personality", i32 1} +// PERSONALITY-SAME: !2 +// PERSONALITY: !2 = !{i32 1, !"ptrauth-sign-personality", i32 1} // OFF-NOT: "ptrauth- +// OFF: !{i32 1, !"ptrauth-init-fini", i32 0} +// OFF: !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0} +// OFF-NOT: "ptrauth- diff --git a/clang/test/CodeGenCXX/pfp-memcpy.cpp b/clang/test/CodeGenCXX/pfp-memcpy.cpp index be746fd8673a0..7f6fcc7af16c0 100644 --- a/clang/test/CodeGenCXX/pfp-memcpy.cpp +++ b/clang/test/CodeGenCXX/pfp-memcpy.cpp @@ -42,7 +42,7 @@ void trivial_copy(ClassWithTrivialCopy *s1) { // CHECK-NEXT: %a = getelementptr inbounds nuw %struct.ClassWithTrivialCopy, ptr %this1, i32 0, i32 0 // CHECK-NEXT: %1 = ptrtoint ptr %this1 to i64 // CHECK-NEXT: %2 = call ptr @llvm.protected.field.ptr.p0(ptr %a, i64 %1, i1 true) [ "deactivation-symbol"(ptr @__pfp_ds__ZTS20ClassWithTrivialCopy.a) ] -// CHECK-NEXT: %3 = load ptr, ptr %.addr, align 8, !nonnull !1, !align !2 +// CHECK-NEXT: %3 = load ptr, ptr %.addr, align 8, !nonnull !3, !align !4 // CHECK-NEXT: %a2 = getelementptr inbounds nuw %struct.ClassWithTrivialCopy, ptr %3, i32 0, i32 0 // CHECK-NEXT: %4 = ptrtoint ptr %3 to i64 // CHECK-NEXT: %5 = call ptr @llvm.protected.field.ptr.p0(ptr %a2, i64 %4, i1 true) [ "deactivation-symbol"(ptr @__pfp_ds__ZTS20ClassWithTrivialCopy.a) ] @@ -51,7 +51,7 @@ void trivial_copy(ClassWithTrivialCopy *s1) { // CHECK-NEXT: %c = getelementptr inbounds nuw %struct.ClassWithTrivialCopy, ptr %this1, i32 0, i32 1 // CHECK-NEXT: %7 = ptrtoint ptr %this1 to i64 // CHECK-NEXT: %8 = call ptr @llvm.protected.field.ptr.p0(ptr %c, i64 %7, i1 true) [ "deactivation-symbol"(ptr @__pfp_ds__ZTS20ClassWithTrivialCopy.c) ] -// CHECK-NEXT: %9 = load ptr, ptr %.addr, align 8, !nonnull !1, !align !2 +// CHECK-NEXT: %9 = load ptr, ptr %.addr, align 8, !nonnull !3, !align !4 // CHECK-NEXT: %c3 = getelementptr inbounds nuw %struct.ClassWithTrivialCopy, ptr %9, i32 0, i32 1 // CHECK-NEXT: %10 = ptrtoint ptr %9 to i64 // CHECK-NEXT: %11 = call ptr @llvm.protected.field.ptr.p0(ptr %c3, i64 %10, i1 true) [ "deactivation-symbol"(ptr @__pfp_ds__ZTS20ClassWithTrivialCopy.c) ] diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index 4d3fc6f2f07de..47b2bff958579 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -6378,16 +6378,27 @@ void llvm::UpgradeARCRuntime(Module &M) { UpgradeToIntrinsic(I.first, I.second); } -// Upgrade from storing `ptrauth` constants in `@llvm.global_(ctors|dtors)` -// arrays to configuring signing of pointers to *structors via module flags. +// Upgrade the way signing of pointers to init/fini functions is described. // -// Only perform the upgrade if all elements of *both* arrays agree on a common -// signing schema. +// Originally, the `@llvm.global_(ctors|dtors)` arrays contained `ptrauth` +// constants, if signing was requested. After the upgrade, these arrays contain +// plain function pointers and the desired signing schema is described via a +// pair of module flags. +// +// Note that the upgrade is only performed if all elements of *both* arrays +// agree on a common signing schema. static bool upgradePtrauthInitFiniArrays(Module &M) { - // Either "not decided yet" or whether we should request address diversity - // in addition to the basic constant diversity. - // There is no value representing "decided not to sign", as this results - // in immediate return from upgradePtrauthInitFiniArrays. + // As we cannot always decide whether the particular module should have + // ptrauth-init-fini flags, we have to treat absent flags as having zero + // values for compatibility reasons. Thus, upgradePtrauthInitFiniArrays + // returns as soon as it spots any non-signed init/fini pointer: either we + // should request non-signed pointers (safe to omit both flags) or there is + // no common schema (and thus we do not modify anything). + // + // UseAddressDisc's value either represents "not decided yet" state (nullopt) + // or whether we should request address diversity in addition to the basic + // constant diversity. There is no value representing "decided not to sign" + // for the reasons explained above. std::optional<bool> UseAddressDisc; // Do not attempt upgrading if the new module flags already exist. @@ -6469,9 +6480,8 @@ static bool upgradePtrauthInitFiniArrays(Module &M) { GV->setInitializer(NewInit); M.addModuleFlag(Module::Error, "ptrauth-init-fini", 1); - if (UseAddressDisc.value()) - M.addModuleFlag(Module::Error, "ptrauth-init-fini-address-discrimination", - 1); + M.addModuleFlag(Module::Error, "ptrauth-init-fini-address-discrimination", + *UseAddressDisc); return true; } diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 4a79356c1a079..16649823dd1de 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1829,10 +1829,13 @@ void Verifier::visitModuleFlags() { // Scan each flag, and track the flags and requirements. DenseMap<const MDString*, const MDNode*> SeenIDs; SmallVector<const MDNode*, 16> Requirements; + + // Either both aarch64-elf-pauthabi-* flags should be set or none at all. std::optional<uint64_t> PAuthABIPlatform; std::optional<uint64_t> PAuthABIVersion; - std::optional<uint64_t> HasPtrauthInitFini; - std::optional<uint64_t> HasPtrauthInitFiniAddr; + // Signing of init/fini pointers: address diversity implies basic signing. + uint64_t HasPtrauthInitFini = 0; + uint64_t HasPtrauthInitFiniAddr = 0; for (const MDNode *MDN : Flags->operands()) { visitModuleFlag(MDN, SeenIDs, Requirements); @@ -1863,10 +1866,10 @@ void Verifier::visitModuleFlags() { } } - Check(!HasPtrauthInitFini || HasPtrauthInitFini.value() == 1, - "ptrauth-init-fini must be set to 1 or unset"); - Check(!HasPtrauthInitFiniAddr || HasPtrauthInitFiniAddr.value() == 1, - "ptrauth-init-fini-address-discrimination must be set to 1 or unset"); + Check(llvm::is_contained({0u, 1u}, HasPtrauthInitFini), + "ptrauth-init-fini must be 0 or 1"); + Check(llvm::is_contained({0u, 1u}, HasPtrauthInitFiniAddr), + "ptrauth-init-fini-address-discrimination must be 0 or 1, if set"); if (HasPtrauthInitFiniAddr) Check(HasPtrauthInitFini, "ptrauth-init-fini-address-discrimination module " "flag requires ptrauth-init-fini"); diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index f2011c58f85ce..6ebc8797c8d4b 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -396,6 +396,17 @@ class AArch64AsmPrinter : public AsmPrinter { } // end anonymous namespace +// Get boolean module flag (0 or 1), treating absent flag as having value 0. +static bool getOptionalBooleanModuleFlag(Module &M, StringRef Name) { + Metadata *Flag = M.getModuleFlag(Name); + if (!Flag) + return false; + + uint64_t Value = mdconst::extract<ConstantInt>(Flag)->getZExtValue(); + assert((Value == 0 || Value == 1) && "Boolean flag is expected, if present"); + return Value; +} + void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) { const Triple &TT = TM.getTargetTriple(); @@ -407,10 +418,9 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) { EnableImportCallOptimization = true; } - if (M.getModuleFlag("ptrauth-init-fini")) - PtrauthInitFini = true; - if (M.getModuleFlag("ptrauth-init-fini-address-discrimination")) - PtrauthInitFiniAddressDisc = true; + PtrauthInitFini = getOptionalBooleanModuleFlag(M, "ptrauth-init-fini"); + PtrauthInitFiniAddressDisc = getOptionalBooleanModuleFlag( + M, "ptrauth-init-fini-address-discrimination"); if (!TT.isOSBinFormatELF()) return; diff --git a/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll b/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll index c07ffd8c7e4c4..78284fd64d3a7 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-init-fini-autoupgrade.ll @@ -1,8 +1,8 @@ ; RUN: rm -rf %t && split-file %s %t && cd %t -;--- nodisc.ll +;--- const.ll -; RUN: opt -S < nodisc.ll | FileCheck %s --check-prefix=NODISC +; RUN: opt -S < const.ll | FileCheck %s --check-prefix=CONST @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo1, i32 0, i64 55764), ptr null }, { i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo2, i32 0, i64 55764), ptr null }] @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764), ptr null }] @@ -19,14 +19,15 @@ define void @bar() { ret void } -; NODISC: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @foo2, ptr null }] -; NODISC: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] -; NODISC: !llvm.module.flags = !{!0} -; NODISC: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} +; CONST: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @foo2, ptr null }] +; CONST: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] +; CONST: !llvm.module.flags = !{!0, !1} +; CONST: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} +; CONST: !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0} -;--- disc.ll +;--- blended.ll -; RUN: opt -S < disc.ll | FileCheck %s --check-prefix=DISC +; RUN: opt -S < blended.ll | FileCheck %s --check-prefix=BLENDED @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar1, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }, { i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar2, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }] @@ -43,11 +44,11 @@ define void @bar2() { ret void } -; DISC: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] -; DISC: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @bar2, ptr null }] -; DISC: !llvm.module.flags = !{!0, !1} -; DISC: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} -; DISC: !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} +; BLENDED: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] +; BLENDED: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @bar2, ptr null }] +; BLENDED: !llvm.module.flags = !{!0, !1} +; BLENDED: !0 = !{i32 1, !"ptrauth-init-fini", i32 1} +; BLENDED: !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} ;--- err1.ll @@ -123,11 +124,11 @@ define void @bar() { ret void } -;--- existing-flags.ll +;--- existing-flags-1.ll -; RUN: not opt -S < existing-flags.ll 2>&1 | FileCheck %s --check-prefix=EXISTING-FLAGS +; RUN: not opt -S < existing-flags-1.ll 2>&1 | FileCheck %s --check-prefix=EXISTING-FLAGS-1 -; EXISTING-FLAGS: signing of ctors/dtors should be requested via module flags +; EXISTING-FLAGS-1: signing of ctors/dtors should be requested via module flags @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }] @@ -141,3 +142,22 @@ define void @bar() { !llvm.module.flags = !{!0} !0 = !{i32 1, !"ptrauth-init-fini", i32 1} + +;--- existing-flags-2.ll + +; RUN: not opt -S < existing-flags-2.ll 2>&1 | FileCheck %s --check-prefix=EXISTING-FLAGS-2 + +; EXISTING-FLAGS-2: signing of ctors/dtors should be requested via module flags + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }] + +define void @foo() { + ret void +} + +define void @bar() { + ret void +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0} diff --git a/llvm/test/CodeGen/AArch64/ptrauth-init-fini.ll b/llvm/test/CodeGen/AArch64/ptrauth-init-fini.ll index e3b1f3835f553..7527d7e437fdb 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-init-fini.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-init-fini.ll @@ -1,29 +1,29 @@ ; RUN: rm -rf %t && split-file %s %t && cd %t -;--- nodisc.ll - -; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=asm -o - nodisc.ll | \ -; RUN: FileCheck %s --check-prefix=ASM -; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=obj -o - nodisc.ll | \ -; RUN: llvm-readelf -r -x .init_array -x .fini_array - | FileCheck %s --check-prefix=OBJ - -; ASM: .section .init_array,"aw",@init_array -; ASM-NEXT: .p2align 3, 0x0 -; ASM-NEXT: .xword foo@AUTH(ia,55764) -; ASM-NEXT: .section .fini_array,"aw",@fini_array -; ASM-NEXT: .p2align 3, 0x0 -; ASM-NEXT: .xword bar@AUTH(ia,55764) - -; OBJ: Relocation section '.rela.init_array' at offset 0x[[#]] contains 1 entries: -; OBJ-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend -; OBJ-NEXT: 0000000000000000 0000000700000244 R_AARCH64_AUTH_ABS64 0000000000000000 foo + 0 -; OBJ: Relocation section '.rela.fini_array' at offset 0x[[#]] contains 1 entries: -; OBJ-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend -; OBJ-NEXT: 0000000000000000 0000000800000244 R_AARCH64_AUTH_ABS64 0000000000000004 bar + 0 -; OBJ: Hex dump of section '.init_array': -; OBJ-NEXT: 0x00000000 00000000 d4d90000 -; OBJ: Hex dump of section '.fini_array': -; OBJ-NEXT: 0x00000000 00000000 d4d90000 +;--- const-1.ll + +; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=asm -o - const-1.ll | \ +; RUN: FileCheck %s --check-prefix=ASM-CONST +; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=obj -o - const-1.ll | \ +; RUN: llvm-readelf -r -x .init_array -x .fini_array - | FileCheck %s --check-prefix=OBJ-CONST + +; ASM-CONST: .section .init_array,"aw",@init_array +; ASM-CONST-NEXT: .p2align 3, 0x0 +; ASM-CONST-NEXT: .xword foo@AUTH(ia,55764) +; ASM-CONST-NEXT: .section .fini_array,"aw",@fini_array +; ASM-CONST-NEXT: .p2align 3, 0x0 +; ASM-CONST-NEXT: .xword bar@AUTH(ia,55764) + +; OBJ-CONST: Relocation section '.rela.init_array' at offset 0x[[#]] contains 1 entries: +; OBJ-CONST-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +; OBJ-CONST-NEXT: 0000000000000000 0000000700000244 R_AARCH64_AUTH_ABS64 0000000000000000 foo + 0 +; OBJ-CONST: Relocation section '.rela.fini_array' at offset 0x[[#]] contains 1 entries: +; OBJ-CONST-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +; OBJ-CONST-NEXT: 0000000000000000 0000000800000244 R_AARCH64_AUTH_ABS64 0000000000000004 bar + 0 +; OBJ-CONST: Hex dump of section '.init_array': +; OBJ-CONST-NEXT: 0x00000000 00000000 d4d90000 +; OBJ-CONST: Hex dump of section '.fini_array': +; OBJ-CONST-NEXT: 0x00000000 00000000 d4d90000 ;; ^^^^ 0xD9D4: constant discriminator = 55764 ;; ^^ 0x80: bits 61..60 key = IA; bit 63 addr disc = false @@ -38,33 +38,58 @@ define void @bar() { ret void } +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"ptrauth-init-fini", i32 1} +!1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0} + +;--- const-2.ll + +; Use the same set of check lines as in const-1.ll, but check that absent flag +; is treated as having zero value. + +; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=asm -o - const-2.ll | \ +; RUN: FileCheck %s --check-prefix=ASM-CONST +; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=obj -o - const-2.ll | \ +; RUN: llvm-readelf -r -x .init_array -x .fini_array - | FileCheck %s --check-prefix=OBJ-CONST + [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] [email protected]_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }] + +define void @foo() { + ret void +} + +define void @bar() { + ret void +} + !llvm.module.flags = !{!0} !0 = !{i32 1, !"ptrauth-init-fini", i32 1} -;--- disc.ll - -; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=asm -o - disc.ll | \ -; RUN: FileCheck %s --check-prefix=ASM-DISC -; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=obj -o - disc.ll | \ -; RUN: llvm-readelf -r -x .init_array -x .fini_array - | FileCheck %s --check-prefix=OBJ-DISC - -; ASM-DISC: .section .init_array,"aw",@init_array -; ASM-DISC-NEXT: .p2align 3, 0x0 -; ASM-DISC-NEXT: .xword foo@AUTH(ia,55764,addr) -; ASM-DISC-NEXT: .section .fini_array,"aw",@fini_array -; ASM-DISC-NEXT: .p2align 3, 0x0 -; ASM-DISC-NEXT: .xword bar@AUTH(ia,55764,addr) - -; OBJ-DISC: Relocation section '.rela.init_array' at offset 0x[[#]] contains 1 entries: -; OBJ-DISC-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend -; OBJ-DISC-NEXT: 0000000000000000 0000000700000244 R_AARCH64_AUTH_ABS64 0000000000000000 foo + 0 -; OBJ-DISC: Relocation section '.rela.fini_array' at offset 0x[[#]] contains 1 entries: -; OBJ-DISC-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend -; OBJ-DISC-NEXT: 0000000000000000 0000000800000244 R_AARCH64_AUTH_ABS64 0000000000000004 bar + 0 -; OBJ-DISC: Hex dump of section '.init_array': -; OBJ-DISC-NEXT: 0x00000000 00000000 d4d90080 -; OBJ-DISC: Hex dump of section '.fini_array': -; OBJ-DISC-NEXT: 0x00000000 00000000 d4d90080 +;--- blended.ll + +; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=asm -o - blended.ll | \ +; RUN: FileCheck %s --check-prefix=ASM-BLENDED +; RUN: llc -mtriple aarch64-elf -mattr=+pauth -filetype=obj -o - blended.ll | \ +; RUN: llvm-readelf -r -x .init_array -x .fini_array - | FileCheck %s --check-prefix=OBJ-BLENDED + +; ASM-BLENDED: .section .init_array,"aw",@init_array +; ASM-BLENDED-NEXT: .p2align 3, 0x0 +; ASM-BLENDED-NEXT: .xword foo@AUTH(ia,55764,addr) +; ASM-BLENDED-NEXT: .section .fini_array,"aw",@fini_array +; ASM-BLENDED-NEXT: .p2align 3, 0x0 +; ASM-BLENDED-NEXT: .xword bar@AUTH(ia,55764,addr) + +; OBJ-BLENDED: Relocation section '.rela.init_array' at offset 0x[[#]] contains 1 entries: +; OBJ-BLENDED-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +; OBJ-BLENDED-NEXT: 0000000000000000 0000000700000244 R_AARCH64_AUTH_ABS64 0000000000000000 foo + 0 +; OBJ-BLENDED: Relocation section '.rela.fini_array' at offset 0x[[#]] contains 1 entries: +; OBJ-BLENDED-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +; OBJ-BLENDED-NEXT: 0000000000000000 0000000800000244 R_AARCH64_AUTH_ABS64 0000000000000004 bar + 0 +; OBJ-BLENDED: Hex dump of section '.init_array': +; OBJ-BLENDED-NEXT: 0x00000000 00000000 d4d90080 +; OBJ-BLENDED: Hex dump of section '.fini_array': +; OBJ-BLENDED-NEXT: 0x00000000 00000000 d4d90080 ;; ^^^^ 0xD9D4: constant discriminator = 55764 ;; ^^ 0x80: bits 61..60 key = IA; bit 63 addr disc = true @@ -87,7 +112,7 @@ define void @bar() { ; RUN: not opt -S < err1.ll 2>&1 | FileCheck %s --check-prefix=ERR1 -; ERR1: ptrauth-init-fini must be set to 1 or unset +; ERR1: ptrauth-init-fini-address-discrimination module flag requires ptrauth-init-fini @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] @@ -103,7 +128,7 @@ define void @foo() { ; RUN: not opt -S < err2.ll 2>&1 | FileCheck %s --check-prefix=ERR2 -; ERR2: ptrauth-init-fini-address-discrimination must be set to 1 or unset +; ERR2: ptrauth-init-fini-address-discrimination module flag requires ptrauth-init-fini @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] @@ -111,9 +136,8 @@ define void @foo() { ret void } -!llvm.module.flags = !{!0, !1} -!0 = !{i32 1, !"ptrauth-init-fini", i32 1} -!1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 0} +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} ;--- err3.ll @@ -146,18 +170,3 @@ define void @foo() { !llvm.module.flags = !{!0, !1} !0 = !{i32 1, !"ptrauth-init-fini", i32 1} !1 = !{i32 1, !"ptrauth-init-fini-address-discrimination", !"1"} - -;--- err5.ll - -; RUN: not opt -S < err5.ll 2>&1 | FileCheck %s --check-prefix=ERR5 - -; ERR5: ptrauth-init-fini-address-discrimination module flag requires ptrauth-init-fini - [email protected]_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }] - -define void @foo() { - ret void -} - -!llvm.module.flags = !{!0} -!0 = !{i32 1, !"ptrauth-init-fini-address-discrimination", i32 1} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
