Index: clang/lib/CodeGen/CGDeclCXX.cpp =================================================================== --- clang/lib/CodeGen/CGDeclCXX.cpp +++ clang/lib/CodeGen/CGDeclCXX.cpp @@ -421,22 +421,6 @@ !isInSanitizerBlacklist(SanitizerKind::ShadowCallStack, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::ShadowCallStack); - auto RASignKind = getLangOpts().getSignReturnAddressScope(); - if (RASignKind != LangOptions::SignReturnAddressScopeKind::None) { - Fn->addFnAttr("sign-return-address", - RASignKind == LangOptions::SignReturnAddressScopeKind::All - ? "all" - : "non-leaf"); - auto RASignKey = getLangOpts().getSignReturnAddressKey(); - Fn->addFnAttr("sign-return-address-key", - RASignKey == LangOptions::SignReturnAddressKeyKind::AKey - ? "a_key" - : "b_key"); - } - - if (getLangOpts().BranchTargetEnforcement) - Fn->addFnAttr("branch-target-enforcement"); - return Fn; } Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -590,6 +590,21 @@ 1); } + if (LangOpts.BranchTargetEnforcement) { + getModule().addModuleFlag(llvm::Module::Override, + "branch-target-enforcement", 1); + } + + if (LangOpts.hasSignReturnAddress()) { + getModule().addModuleFlag(llvm::Module::Override, "sign-return-address", 1); + if (LangOpts.isSignReturnAddressScopeAll()) + getModule().addModuleFlag(llvm::Module::Override, + "sign-return-address-all", 1); + if (!LangOpts.isSignReturnAddressWithAKey()) + getModule().addModuleFlag(llvm::Module::Override, + "sign-return-address-with-bkey", 1); + } + if (LangOpts.CUDAIsDevice && getTriple().isNVPTX()) { // Indicate whether __nvvm_reflect should be configured to flush denormal // floating point values to 0. (This corresponds to its "__CUDA_FTZ" Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -5521,40 +5521,33 @@ if (!FD) return; - LangOptions::SignReturnAddressScopeKind Scope = - CGM.getLangOpts().getSignReturnAddressScope(); - LangOptions::SignReturnAddressKeyKind Key = - CGM.getLangOpts().getSignReturnAddressKey(); - bool BranchTargetEnforcement = CGM.getLangOpts().BranchTargetEnforcement; - if (const auto *TA = FD->getAttr()) { - ParsedTargetAttr Attr = TA->parse(); - if (!Attr.BranchProtection.empty()) { - TargetInfo::BranchProtectionInfo BPI; - StringRef Error; - (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, - BPI, Error); - assert(Error.empty()); - Scope = BPI.SignReturnAddr; - Key = BPI.SignKey; - BranchTargetEnforcement = BPI.BranchTargetEnforcement; - } - } + const auto *TA = FD->getAttr(); + if (TA == nullptr) + return; + + ParsedTargetAttr Attr = TA->parse(); + if (Attr.BranchProtection.empty()) + return; + + TargetInfo::BranchProtectionInfo BPI; + StringRef Error; + (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, + BPI, Error); + assert(Error.empty()); auto *Fn = cast(GV); - if (Scope != LangOptions::SignReturnAddressScopeKind::None) { - Fn->addFnAttr("sign-return-address", - Scope == LangOptions::SignReturnAddressScopeKind::All - ? "all" - : "non-leaf"); + static const char *SignReturnAddrStr[] = {"none", "non-leaf", "all"}; + Fn->addFnAttr("sign-return-address", SignReturnAddrStr[static_cast(BPI.SignReturnAddr)]); + if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { Fn->addFnAttr("sign-return-address-key", - Key == LangOptions::SignReturnAddressKeyKind::AKey + BPI.SignKey == LangOptions::SignReturnAddressKeyKind::AKey ? "a_key" : "b_key"); } - if (BranchTargetEnforcement) - Fn->addFnAttr("branch-target-enforcement"); + Fn->addFnAttr("branch-target-enforcement", + BPI.BranchTargetEnforcement ? "true" : "false"); } }; Index: clang/test/CodeGen/aarch64-branch-protection-attr.c =================================================================== --- clang/test/CodeGen/aarch64-branch-protection-attr.c +++ clang/test/CodeGen/aarch64-branch-protection-attr.c @@ -1,81 +1,63 @@ // REQUIRES: aarch64-registered-target // RUN: %clang_cc1 -triple aarch64-unknown-unknown-eabi -emit-llvm -target-cpu generic -target-feature +v8.5a %s -o - \ -// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=NO-OVERRIDE -// RUN: %clang_cc1 -triple aarch64-unknown-unknown-eabi -emit-llvm -target-cpu generic -target-feature +v8.5a %s -o - \ -// RUN: -msign-return-address=non-leaf -msign-return-address-key=a_key -mbranch-target-enforce \ -// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=OVERRIDE - -void missing() {} -// NO-OVERRIDE: define void @missing() #[[#NONE:]] -// OVERRIDE: define void @missing() #[[#STD:]] +// RUN: | FileCheck %s --check-prefix=CHECK __attribute__ ((target("branch-protection=none"))) void none() {} -// NO-OVERRIDE: define void @none() #[[#NONE]] -// OVERRIDE: define void @none() #[[#NONE:]] +// CHECK: define void @none() #[[#NONE:]] __attribute__ ((target("branch-protection=standard"))) void std() {} -// NO-OVERRIDE: define void @std() #[[#STD:]] -// OVERRIDE: define void @std() #[[#STD]] +// CHECK: define void @std() #[[#STD:]] __attribute__ ((target("branch-protection=bti"))) void btionly() {} -// NO-OVERRIDE: define void @btionly() #[[#BTI:]] -// OVERRIDE: define void @btionly() #[[#BTI:]] +// CHECK: define void @btionly() #[[#BTI:]] __attribute__ ((target("branch-protection=pac-ret"))) void paconly() {} -// NO-OVERRIDE: define void @paconly() #[[#PAC:]] -// OVERRIDE: define void @paconly() #[[#PAC:]] +// CHECK: define void @paconly() #[[#PAC:]] __attribute__ ((target("branch-protection=pac-ret+bti"))) void pacbti0() {} -// NO-OVERRIDE: define void @pacbti0() #[[#PACBTI:]] -// OVERRIDE: define void @pacbti0() #[[#PACBTI:]] +// CHECK: define void @pacbti0() #[[#PACBTI:]] __attribute__ ((target("branch-protection=bti+pac-ret"))) void pacbti1() {} -// NO-OVERRIDE: define void @pacbti1() #[[#PACBTI]] -// OVERRIDE: define void @pacbti1() #[[#PACBTI]] +// CHECK: define void @pacbti1() #[[#PACBTI]] __attribute__ ((target("branch-protection=pac-ret+leaf"))) void leaf() {} -// NO-OVERRIDE: define void @leaf() #[[#PACLEAF:]] -// OVERRIDE: define void @leaf() #[[#PACLEAF:]] +// CHECK: define void @leaf() #[[#PACLEAF:]] __attribute__ ((target("branch-protection=pac-ret+b-key"))) void bkey() {} -// NO-OVERRIDE: define void @bkey() #[[#PACBKEY:]] -// OVERRIDE: define void @bkey() #[[#PACBKEY:]] +// CHECK: define void @bkey() #[[#PACBKEY:]] __attribute__ ((target("branch-protection=pac-ret+b-key+leaf"))) void bkeyleaf0() {} -// NO-OVERRIDE: define void @bkeyleaf0() #[[#PACBKEYLEAF:]] -// OVERRIDE: define void @bkeyleaf0() #[[#PACBKEYLEAF:]] +// CHECK: define void @bkeyleaf0() #[[#PACBKEYLEAF:]] __attribute__ ((target("branch-protection=pac-ret+leaf+b-key"))) void bkeyleaf1() {} -// NO-OVERRIDE: define void @bkeyleaf1() #[[#PACBKEYLEAF]] -// OVERRIDE: define void @bkeyleaf1() #[[#PACBKEYLEAF]] +// CHECK: define void @bkeyleaf1() #[[#PACBKEYLEAF]] __attribute__ ((target("branch-protection=pac-ret+leaf+bti"))) void btileaf() {} -// NO-OVERRIDE: define void @btileaf() #[[#BTIPACLEAF:]] -// OVERRIDE: define void @btileaf() #[[#BTIPACLEAF:]] +// CHECK: define void @btileaf() #[[#BTIPACLEAF:]] -// CHECK-DAG: attributes #[[#NONE]] +// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="none" -// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" +// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" -// CHECK-DAG: attributes #[[#BTI]] = { {{.*}}"branch-target-enforcement" +// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="none" -// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" +// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" -// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key" +// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "branch-target-enforcement"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key" -// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key" +// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}}"branch-target-enforcement"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key" -// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="b_key" +// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "branch-target-enforcement"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="b_key" -// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key" +// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement"="true" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key" Index: clang/test/CodeGen/aarch64-sign-return-address.c =================================================================== --- clang/test/CodeGen/aarch64-sign-return-address.c +++ clang/test/CodeGen/aarch64-sign-return-address.c @@ -4,24 +4,34 @@ // RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -msign-return-address=non-leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=PARTIAL --check-prefix=A-KEY // RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -msign-return-address=all %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL --check-prefix=A-KEY // RUN: %clang -target aarch64-arm-none-eabi -march=armv8.4-a -S -emit-llvm -o - -msign-return-address=all %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL --check-prefix=A-KEY +// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -mbranch-protection=none %s | FileCheck %s --check-prefix=CHECK --check-prefix=NONE // RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK --check-prefix=PARTIAL --check-prefix=B-KEY // RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key+leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL --check-prefix=B-KEY // RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -mbranch-protection=bti %s | FileCheck %s --check-prefix=CHECK --check-prefix=BTE // REQUIRES: aarch64-registered-target -// CHECK: @foo() #[[ATTR:[0-9]*]] -// -// NONE-NOT: "sign-return-address"={{.*}} +// Check there are no branch protection function attributes -// PARTIAL: "sign-return-address"="non-leaf" +// CHECK-LABEL: @foo() #[[#ATTR:]] -// ALL: "sign-return-address"="all" +// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address" +// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key" +// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement" -// BTE: "branch-target-enforcement" +// Check module attributes -// A-KEY: "sign-return-address-key"="a_key" +// NONE-NOT: !{i32 4, !"sign-return-address", i32 1} +// NONE-NOT: !{i32 4, !"branch-target-enforcement", i32 1} -// B-KEY: "sign-return-address-key"="b_key" +// ALL: !{i32 4, !"sign-return-address", i32 1} +// ALL: !{i32 4, !"sign-return-address-all", i32 1} + +// PARTIAL: !{i32 4, !"sign-return-address", i32 1} +// PARTIAL-NOT: !{i32 4, !"sign-return-address-all", i32 1} + +// BTE: !{i32 4, !"branch-target-enforcement", i32 1} + +// B-KEY: !{i32 4, !"sign-return-address-with-bkey", i32 1} void foo() {} Index: clang/test/CodeGenCXX/aarch64-sign-return-address-static-ctor.cpp =================================================================== --- clang/test/CodeGenCXX/aarch64-sign-return-address-static-ctor.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=none %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NONE -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=non-leaf %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-PARTIAL --check-prefix=CHECK-A-KEY -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=all %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ALL --check-prefix=CHECK-A-KEY - -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=none %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NONE -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=standard %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-PARTIAL --check-prefix=CHECK-A-KEY --check-prefix=CHECK-BTE -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-PARTIAL --check-prefix=CHECK-A-KEY -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+leaf %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ALL --check-prefix=CHECK-A-KEY -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-PARTIAL --check-prefix=CHECK-B-KEY -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key+leaf %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ALL --check-prefix=CHECK-B-KEY -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=bti %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BTE -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key+leaf+bti %s | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ALL --check-prefix=CHECK-B-KEY --check-prefix=BTE - -struct Foo { - Foo() {} - ~Foo() {} -}; - -Foo f; - -// CHECK: @llvm.global_ctors {{.*}}i32 65535, void ()* @[[CTOR_FN:.*]], i8* null - -// CHECK: @[[CTOR_FN]]() #[[ATTR:[0-9]*]] - -// CHECK-NONE-NOT: "sign-return-address"={{.*}} -// CHECK-PARTIAL: "sign-return-address"="non-leaf" -// CHECK-ALL: "sign-return-address"="all" -// CHECK-A-KEY: "sign-return-address-key"="a_key" -// CHECK-B-KEY: "sign-return-address-key"="b_key" -// CHECK-BTE: "branch-target-enforcement" Index: llvm/lib/Target/AArch64/AArch64BranchTargets.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64BranchTargets.cpp +++ llvm/lib/Target/AArch64/AArch64BranchTargets.cpp @@ -16,6 +16,7 @@ // //===----------------------------------------------------------------------===// +#include "AArch64MachineFunctionInfo.h" #include "AArch64Subtarget.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -57,13 +58,13 @@ } bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) { - const Function &F = MF.getFunction(); - if (!F.hasFnAttribute("branch-target-enforcement")) + if (!MF.getInfo()->branchTargetEnforcement()) return false; LLVM_DEBUG( dbgs() << "********** AArch64 Branch Targets **********\n" << "********** Function: " << MF.getName() << '\n'); + const Function &F = MF.getFunction(); // LLVM does not consider basic blocks which are the targets of jump tables // to be address-taken (the address can't escape anywhere else), but they are Index: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -375,31 +375,6 @@ return MBB.erase(I); } -static bool ShouldSignReturnAddress(MachineFunction &MF) { - // The function should be signed in the following situations: - // - sign-return-address=all - // - sign-return-address=non-leaf and the functions spills the LR - - const Function &F = MF.getFunction(); - if (!F.hasFnAttribute("sign-return-address")) - return false; - - StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString(); - if (Scope.equals("none")) - return false; - - if (Scope.equals("all")) - return true; - - assert(Scope.equals("non-leaf") && "Expected all, none or non-leaf"); - - for (const auto &Info : MF.getFrameInfo().getCalleeSavedInfo()) - if (Info.getReg() == AArch64::LR) - return true; - - return false; -} - // Convenience function to create a DWARF expression for // Expr + NumBytes + NumVGScaledBytes * AArch64::VG static void appendVGScaledOffsetExpr(SmallVectorImpl &Expr, @@ -1007,17 +982,6 @@ // } -static bool ShouldSignWithAKey(MachineFunction &MF) { - const Function &F = MF.getFunction(); - if (!F.hasFnAttribute("sign-return-address-key")) - return true; - - const StringRef Key = - F.getFnAttribute("sign-return-address-key").getValueAsString(); - assert(Key.equals_lower("a_key") || Key.equals_lower("b_key")); - return Key.equals_lower("a_key"); -} - static bool needsWinCFI(const MachineFunction &MF) { const Function &F = MF.getFunction(); return MF.getTarget().getMCAsmInfo()->usesWindowsCFI() && @@ -1070,15 +1034,16 @@ // to determine the end of the prologue. DebugLoc DL; - if (ShouldSignReturnAddress(MF)) { - if (ShouldSignWithAKey(MF)) - BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP)) - .setMIFlag(MachineInstr::FrameSetup); - else { + const auto &MFnI = *MF.getInfo(); + if (MFnI.shouldSignReturnAddress()) { + if (MFnI.shouldSignWithBKey()) { BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY)) .setMIFlag(MachineInstr::FrameSetup); BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIBSP)) .setMIFlag(MachineInstr::FrameSetup); + } else { + BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP)) + .setMIFlag(MachineInstr::FrameSetup); } unsigned CFIIndex = @@ -1510,7 +1475,8 @@ static void InsertReturnAddressAuth(MachineFunction &MF, MachineBasicBlock &MBB) { - if (!ShouldSignReturnAddress(MF)) + const auto &MFI = *MF.getInfo(); + if (!MFI.shouldSignReturnAddress()) return; const AArch64Subtarget &Subtarget = MF.getSubtarget(); const TargetInstrInfo *TII = Subtarget.getInstrInfo(); @@ -1527,13 +1493,13 @@ if (Subtarget.hasV8_3aOps() && MBBI != MBB.end() && MBBI->getOpcode() == AArch64::RET_ReallyLR) { BuildMI(MBB, MBBI, DL, - TII->get(ShouldSignWithAKey(MF) ? AArch64::RETAA : AArch64::RETAB)) + TII->get(MFI.shouldSignWithBKey() ? AArch64::RETAB : AArch64::RETAA)) .copyImplicitOps(*MBBI); MBB.erase(MBBI); } else { BuildMI( MBB, MBBI, DL, - TII->get(ShouldSignWithAKey(MF) ? AArch64::AUTIASP : AArch64::AUTIBSP)) + TII->get(MFI.shouldSignWithBKey() ? AArch64::AUTIBSP : AArch64::AUTIASP)) .setMIFlag(MachineInstr::FrameDestroy); } } Index: llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "AArch64MachineFunctionInfo.h" #include "AArch64TargetMachine.h" #include "MCTargetDesc/AArch64AddressingModes.h" #include "llvm/ADT/APSInt.h" Index: llvm/lib/Target/AArch64/AArch64InstrInfo.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -5760,84 +5760,20 @@ static bool outliningCandidatesSigningScopeConsensus(const outliner::Candidate &a, const outliner::Candidate &b) { - const Function &Fa = a.getMF()->getFunction(); - const Function &Fb = b.getMF()->getFunction(); + const auto &MFIa = a.getMF()->getInfo(); + const auto &MFIb = b.getMF()->getInfo(); - // If none of the functions have the "sign-return-address" attribute their - // signing behaviour is equal - if (!Fa.hasFnAttribute("sign-return-address") && - !Fb.hasFnAttribute("sign-return-address")) { - return true; - } - - // If both functions have the "sign-return-address" attribute their signing - // behaviour is equal, if the values of the attributes are equal - if (Fa.hasFnAttribute("sign-return-address") && - Fb.hasFnAttribute("sign-return-address")) { - StringRef ScopeA = - Fa.getFnAttribute("sign-return-address").getValueAsString(); - StringRef ScopeB = - Fb.getFnAttribute("sign-return-address").getValueAsString(); - return ScopeA.equals(ScopeB); - } - - // If function B doesn't have the "sign-return-address" attribute but A does, - // the functions' signing behaviour is equal if A's value for - // "sign-return-address" is "none" and vice versa. - if (Fa.hasFnAttribute("sign-return-address")) { - StringRef ScopeA = - Fa.getFnAttribute("sign-return-address").getValueAsString(); - return ScopeA.equals("none"); - } - - if (Fb.hasFnAttribute("sign-return-address")) { - StringRef ScopeB = - Fb.getFnAttribute("sign-return-address").getValueAsString(); - return ScopeB.equals("none"); - } - - llvm_unreachable("Unkown combination of sign-return-address attributes"); + return MFIa->shouldSignReturnAddress(false) == MFIb->shouldSignReturnAddress(false) && + MFIa->shouldSignReturnAddress(true) == MFIb->shouldSignReturnAddress(true); } static bool outliningCandidatesSigningKeyConsensus(const outliner::Candidate &a, const outliner::Candidate &b) { - const Function &Fa = a.getMF()->getFunction(); - const Function &Fb = b.getMF()->getFunction(); - - // If none of the functions have the "sign-return-address-key" attribute - // their keys are equal - if (!Fa.hasFnAttribute("sign-return-address-key") && - !Fb.hasFnAttribute("sign-return-address-key")) { - return true; - } - - // If both functions have the "sign-return-address-key" attribute their - // keys are equal if the values of "sign-return-address-key" are equal - if (Fa.hasFnAttribute("sign-return-address-key") && - Fb.hasFnAttribute("sign-return-address-key")) { - StringRef KeyA = - Fa.getFnAttribute("sign-return-address-key").getValueAsString(); - StringRef KeyB = - Fb.getFnAttribute("sign-return-address-key").getValueAsString(); - return KeyA.equals(KeyB); - } - - // If B doesn't have the "sign-return-address-key" attribute, both keys are - // equal, if function a has the default key (a_key) - if (Fa.hasFnAttribute("sign-return-address-key")) { - StringRef KeyA = - Fa.getFnAttribute("sign-return-address-key").getValueAsString(); - return KeyA.equals_lower("a_key"); - } - - if (Fb.hasFnAttribute("sign-return-address-key")) { - StringRef KeyB = - Fb.getFnAttribute("sign-return-address-key").getValueAsString(); - return KeyB.equals_lower("a_key"); - } + const auto &MFIa = a.getMF()->getInfo(); + const auto &MFIb = b.getMF()->getInfo(); - llvm_unreachable("Unkown combination of sign-return-address-key attributes"); + return MFIa->shouldSignWithBKey() == MFIb->shouldSignWithBKey(); } static bool outliningCandidatesV8_3OpsConsensus(const outliner::Candidate &a, @@ -5893,9 +5829,10 @@ // v8.3a RET can be replaced by RETAA/RETAB and no AUT instruction is // necessary. However, at this point we don't know if the outlined function // will have a RET instruction so we assume the worst. - const Function &FCF = FirstCand.getMF()->getFunction(); const TargetRegisterInfo &TRI = getRegisterInfo(); - if (FCF.hasFnAttribute("sign-return-address")) { + if (FirstCand.getMF() + ->getInfo() + ->shouldSignReturnAddress(true)) { // One PAC and one AUT instructions NumBytesToCreateFrame += 8; @@ -6024,7 +5961,7 @@ NumBytesToCreateFrame += 4; bool HasBTI = any_of(RepeatedSequenceLocs, [](outliner::Candidate &C) { - return C.getMF()->getFunction().hasFnAttribute("branch-target-enforcement"); + return C.getMF()->getInfo()->branchTargetEnforcement(); }); // We check to see if CFI Instructions are present, and if they are @@ -6729,27 +6666,11 @@ // If a bunch of candidates reach this point they must agree on their return // address signing. It is therefore enough to just consider the signing // behaviour of one of them - const Function &CF = OF.Candidates.front().getMF()->getFunction(); - bool ShouldSignReturnAddr = false; - if (CF.hasFnAttribute("sign-return-address")) { - StringRef Scope = - CF.getFnAttribute("sign-return-address").getValueAsString(); - if (Scope.equals("all")) - ShouldSignReturnAddr = true; - else if (Scope.equals("non-leaf") && !IsLeafFunction) - ShouldSignReturnAddr = true; - } + const auto &MFI = *OF.Candidates.front().getMF()->getInfo(); + bool ShouldSignReturnAddr = MFI.shouldSignReturnAddress(!IsLeafFunction); // a_key is the default - bool ShouldSignReturnAddrWithAKey = true; - if (CF.hasFnAttribute("sign-return-address-key")) { - const StringRef Key = - CF.getFnAttribute("sign-return-address-key").getValueAsString(); - // Key can either be a_key or b_key - assert((Key.equals_lower("a_key") || Key.equals_lower("b_key")) && - "Return address signing key must be either a_key or b_key"); - ShouldSignReturnAddrWithAKey = Key.equals_lower("a_key"); - } + bool ShouldSignReturnAddrWithAKey = !MFI.shouldSignWithBKey(); // If this is a tail call outlined function, then there's already a return. if (OF.FrameConstructionID == MachineOutlinerTailCall || Index: llvm/lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -593,8 +593,8 @@ // Avoid generating STRQro if it is slow, unless we're optimizing for code size. def UseSTRQro : Predicate<"!Subtarget->isSTRQroSlow() || shouldOptForSize(MF)">; - def UseBTI : Predicate<[{ MF->getFunction().hasFnAttribute("branch-target-enforcement") }]>; - def NotUseBTI : Predicate<[{ !MF->getFunction().hasFnAttribute("branch-target-enforcement") }]>; + def UseBTI : Predicate<[{ MF->getInfo()->branchTargetEnforcement() }]>; + def NotUseBTI : Predicate<[{ !MF->getInfo()->branchTargetEnforcement() }]>; def SLSBLRMitigation : Predicate<[{ MF->getSubtarget().hardenSlsBlr() }]>; def NoSLSBLRMitigation : Predicate<[{ !MF->getSubtarget().hardenSlsBlr() }]>; Index: llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h =================================================================== --- llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h +++ llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h @@ -36,6 +36,9 @@ /// AArch64FunctionInfo - This class is derived from MachineFunctionInfo and /// contains private AArch64-specific information for each MachineFunction. class AArch64FunctionInfo final : public MachineFunctionInfo { + /// Backreference to the machine function. + MachineFunction &MF; + /// Number of bytes of arguments this function has on the stack. If the callee /// is expected to restore the argument stack this should be a multiple of 16, /// all usable during a tail call. @@ -139,17 +142,24 @@ // CalleeSavedStackSize) to the address of the frame record. int CalleeSaveBaseToFrameRecordOffset = 0; -public: - AArch64FunctionInfo() = default; + /// SignReturnAddress is true if PAC-RET is enabled for the function with + /// defaults being sign non-leaf functions only, with the B key. + bool SignReturnAddress; - explicit AArch64FunctionInfo(MachineFunction &MF) { - (void)MF; + /// SignReturnAddressAll modifies the default PAC-RET mode to signing leaf + /// functions as well. + bool SignReturnAddressAll; + + /// SignWithBKey modifies the default PAC-RET mode to signing with the B key. + bool SignWithBKey; + + /// BranchTargetEnforcement enables placing BTI instructions at potential + /// indirect branch destinations. + bool BranchTargetEnforcement; + +public: + explicit AArch64FunctionInfo(MachineFunction &MF); - // If we already know that the function doesn't have a redzone, set - // HasRedZone here. - if (MF.getFunction().hasFnAttribute(Attribute::NoRedZone)) - HasRedZone = false; - } void initializeBaseYamlFields(const yaml::AArch64FunctionInfo &YamlMFI); unsigned getBytesInStackArgArea() const { return BytesInStackArgArea; } @@ -349,6 +359,13 @@ CalleeSaveBaseToFrameRecordOffset = Offset; } + bool shouldSignReturnAddress() const; + bool shouldSignReturnAddress(bool SpillsLR) const; + + bool shouldSignWithBKey() const { return SignWithBKey; } + + bool branchTargetEnforcement() const { return BranchTargetEnforcement; } + private: // Hold the lists of LOHs. MILOHContainer LOHContainerSet; Index: llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp +++ llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp @@ -14,6 +14,8 @@ //===----------------------------------------------------------------------===// #include "AArch64MachineFunctionInfo.h" +#include "AArch64InstrInfo.h" +#include using namespace llvm; @@ -30,3 +32,73 @@ if (YamlMFI.HasRedZone.hasValue()) HasRedZone = YamlMFI.HasRedZone; } + +static std::pair GetSignReturnAddress(const Function &F) { + // The function should be signed in the following situations: + // - sign-return-address=all + // - sign-return-address=non-leaf and the functions spills the LR + if (!F.hasFnAttribute("sign-return-address")) { + const Module &M = *F.getParent(); + if (!M.getModuleFlag("sign-return-address")) + return {false, false}; + if (M.getModuleFlag("sign-return-address-all")) + return {true, true}; + return {true, false}; + } + + StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString(); + if (Scope.equals("none")) + return {false, false}; + + if (Scope.equals("all")) + return {true, true}; + + assert(Scope.equals("non-leaf")); + return {true, false}; +} + +static bool ShouldSignWithBKey(const Function &F) { + if (!F.hasFnAttribute("sign-return-address-key")) + return F.getParent()->getModuleFlag("sign-return-address-with-bkey") != + nullptr; + + const StringRef Key = + F.getFnAttribute("sign-return-address-key").getValueAsString(); + assert(Key.equals_lower("a_key") || Key.equals_lower("b_key")); + return Key.equals_lower("b_key"); +} + +AArch64FunctionInfo::AArch64FunctionInfo(MachineFunction &MF) : MF(MF) { + // If we already know that the function doesn't have a redzone, set + // HasRedZone here. + if (MF.getFunction().hasFnAttribute(Attribute::NoRedZone)) + HasRedZone = false; + + const Function &F = MF.getFunction(); + std::tie(SignReturnAddress, SignReturnAddressAll) = GetSignReturnAddress(F); + SignWithBKey = ShouldSignWithBKey(F); + + if (!F.hasFnAttribute("branch-target-enforcement")) { + BranchTargetEnforcement = + F.getParent()->getModuleFlag("branch-target-enforcement") != nullptr; + return; + } + + const StringRef BTIEnable = F.getFnAttribute("branch-target-enforcement").getValueAsString(); + assert(BTIEnable.equals_lower("true") || BTIEnable.equals_lower("false")); + BranchTargetEnforcement = BTIEnable.equals_lower("true"); +} + +bool AArch64FunctionInfo::shouldSignReturnAddress(bool SpillsLR) const { + if (!SignReturnAddress) + return false; + if (SignReturnAddressAll) + return true; + return SpillsLR; +} + +bool AArch64FunctionInfo::shouldSignReturnAddress() const { + return shouldSignReturnAddress(llvm::any_of( + MF.getFrameInfo().getCalleeSavedInfo(), + [](const auto &Info) { return Info.getReg() == AArch64::LR; })); +} Index: llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp +++ llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp @@ -789,7 +789,7 @@ // When BTI is enabled, we need to use TCRETURNriBTI to make sure that we use // x16 or x17. - if (CallerF.getFunction().hasFnAttribute("branch-target-enforcement")) + if (CallerF.getInfo()->branchTargetEnforcement()) return AArch64::TCRETURNriBTI; return AArch64::TCRETURNri; @@ -809,7 +809,7 @@ // TODO: Right now, regbankselect doesn't know how to handle the rtcGPR64 // register class. Until we can do that, we should fall back here. - if (F.hasFnAttribute("branch-target-enforcement")) { + if (MF.getInfo()->branchTargetEnforcement()) { LLVM_DEBUG( dbgs() << "Cannot lower indirect tail calls with BTI enabled yet.\n"); return false; Index: llvm/test/CodeGen/AArch64/branch-target-enforcement-indirect-calls.ll =================================================================== --- llvm/test/CodeGen/AArch64/branch-target-enforcement-indirect-calls.ll +++ llvm/test/CodeGen/AArch64/branch-target-enforcement-indirect-calls.ll @@ -20,7 +20,7 @@ ret void } -define void @bti_enabled(void ()* %p) "branch-target-enforcement" { +define void @bti_enabled(void ()* %p) "branch-target-enforcement"="true" { entry: tail call void %p() ; CHECK: br {{x16|x17}} Index: llvm/test/CodeGen/AArch64/branch-target-enforcement.mir =================================================================== --- llvm/test/CodeGen/AArch64/branch-target-enforcement.mir +++ llvm/test/CodeGen/AArch64/branch-target-enforcement.mir @@ -3,29 +3,29 @@ target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64-arm-none-eabi" - define hidden i32 @simple_external() "branch-target-enforcement" { + define hidden i32 @simple_external() "branch-target-enforcement"="true" { entry: ret i32 0 } - define internal i32 @simple_internal() "branch-target-enforcement" { + define internal i32 @simple_internal() "branch-target-enforcement"="true" { entry: ret i32 0 } - define hidden i32 @ptr_auth() "branch-target-enforcement" { + define hidden i32 @ptr_auth() "branch-target-enforcement"="true" { entry: tail call void asm sideeffect "", "~{lr}"() ret i32 0 } - define hidden i32 @ptr_auth_b() "branch-target-enforcement" { + define hidden i32 @ptr_auth_b() "branch-target-enforcement"="true" { entry: tail call void asm sideeffect "", "~{lr}"() ret i32 0 } - define hidden i32 @jump_table(i32 %a) "branch-target-enforcement" { + define hidden i32 @jump_table(i32 %a) "branch-target-enforcement"="true" { entry: switch i32 %a, label %sw.epilog [ i32 1, label %sw.bb @@ -61,7 +61,7 @@ @label_address.addr = internal unnamed_addr global i8* blockaddress(@label_address, %return), align 8 - define hidden i32 @label_address() "branch-target-enforcement" { + define hidden i32 @label_address() "branch-target-enforcement"="true" { entry: %0 = load i8*, i8** @label_address.addr, align 8 indirectbr i8* %0, [label %return, label %lab2] @@ -79,7 +79,7 @@ ret i32 %merge2 } - define hidden i32 @label_address_entry() "branch-target-enforcement" { + define hidden i32 @label_address_entry() "branch-target-enforcement"="true" { entry: %0 = load i8*, i8** @label_address.addr, align 8 indirectbr i8* %0, [label %return, label %lab2] @@ -97,7 +97,7 @@ ret i32 %merge2 } - define hidden i32 @debug_ptr_auth() "branch-target-enforcement" { + define hidden i32 @debug_ptr_auth() "branch-target-enforcement"="true" { entry: tail call void asm sideeffect "", "~{lr}"() ret i32 0 Index: llvm/test/CodeGen/AArch64/bti-branch-relaxation.ll =================================================================== --- llvm/test/CodeGen/AArch64/bti-branch-relaxation.ll +++ llvm/test/CodeGen/AArch64/bti-branch-relaxation.ll @@ -61,4 +61,4 @@ declare dso_local i64 @llvm.aarch64.space(i32, i64) local_unnamed_addr #0 -attributes #0 = { nounwind "branch-target-enforcement" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon,+v8.5a" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #0 = { nounwind "branch-target-enforcement"="true" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon,+v8.5a" "unsafe-fp-math"="false" "use-soft-float"="false" } Index: llvm/test/CodeGen/AArch64/machine-outliner-2fixup-blr-terminator.mir =================================================================== --- llvm/test/CodeGen/AArch64/machine-outliner-2fixup-blr-terminator.mir +++ llvm/test/CodeGen/AArch64/machine-outliner-2fixup-blr-terminator.mir @@ -8,7 +8,7 @@ define void @f2() #0 { ret void } define void @f3() #0 { ret void } define void @f4() #0 { ret void } - attributes #0 = { minsize noredzone "branch-target-enforcement" } + attributes #0 = { minsize noredzone "branch-target-enforcement"="true" } ... --- name: f1 Index: llvm/test/CodeGen/AArch64/machine-outliner-bti.mir =================================================================== --- llvm/test/CodeGen/AArch64/machine-outliner-bti.mir +++ llvm/test/CodeGen/AArch64/machine-outliner-bti.mir @@ -15,7 +15,7 @@ --- | @g = hidden local_unnamed_addr global i32 0, align 4 - define hidden void @bar(void ()* nocapture %f) "branch-target-enforcement" { + define hidden void @bar(void ()* nocapture %f) "branch-target-enforcement"="true" { entry: ret void } Index: llvm/test/CodeGen/AArch64/machine-outliner-outline-bti.ll =================================================================== --- llvm/test/CodeGen/AArch64/machine-outliner-outline-bti.ll +++ llvm/test/CodeGen/AArch64/machine-outliner-outline-bti.ll @@ -5,7 +5,7 @@ @g = hidden global i32 0, align 4 -define hidden void @foo() minsize "branch-target-enforcement" { +define hidden void @foo() minsize "branch-target-enforcement"="true" { entry: ; CHECK: hint #34 ; CHECK: b OUTLINED_FUNCTION_0 @@ -13,7 +13,7 @@ ret void } -define hidden void @bar() minsize "branch-target-enforcement" { +define hidden void @bar() minsize "branch-target-enforcement"="true" { entry: ; CHECK: hint #34 ; CHECK: b OUTLINED_FUNCTION_0 Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll @@ -4,7 +4,7 @@ ; RUN: llvm-readelf --notes - | FileCheck %s --check-prefix=OBJ @x = common dso_local global i32 0, align 4 -attributes #0 = { "branch-target-enforcement" } +attributes #0 = { "branch-target-enforcement"="true" } ; Both attributes present in a file with no functions. ; ASM: .word 3221225472 Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll @@ -8,7 +8,7 @@ ret i32 0 } -attributes #0 = { "branch-target-enforcement" } +attributes #0 = { "branch-target-enforcement"="true" } ; BTI attribute present ; ASM: .word 3221225472 Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll @@ -8,7 +8,7 @@ ret i32 0 } -attributes #0 = { "branch-target-enforcement" "sign-return-address"="non-leaf" } +attributes #0 = { "branch-target-enforcement"="true" "sign-return-address"="non-leaf" } ; Both attribute present ; ASM: .word 3221225472 Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll @@ -13,9 +13,9 @@ ret i32 0 } -attributes #0 = { "branch-target-enforcement" "sign-return-address"="non-leaf" } +attributes #0 = { "branch-target-enforcement"="true" "sign-return-address"="non-leaf" } -attributes #1 = { "branch-target-enforcement" } +attributes #1 = { "branch-target-enforcement"="true" } ; Only the common atttribute (BTI) ; ASM: .word 3221225472 Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-5.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-5.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-5.ll @@ -13,7 +13,7 @@ ret i32 0 } -attributes #0 = { "branch-target-enforcement" "sign-return-address"="non-leaf" } +attributes #0 = { "branch-target-enforcement"="true" "sign-return-address"="non-leaf" } attributes #1 = { "sign-return-address"="all" } Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-7.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-7.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-7.ll @@ -15,7 +15,7 @@ attributes #0 = { "sign-return-address"="non-leaf" } -attributes #1 = { "branch-target-enforcement" } +attributes #1 = { "branch-target-enforcement"="true" } ; No common attribute, no note section ; ASM: warning: not setting BTI in feature flags Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-8.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-8.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-8.ll @@ -11,7 +11,7 @@ declare dso_local i32 @g() -attributes #0 = { "branch-target-enforcement" } +attributes #0 = { "branch-target-enforcement"="true" } ; Declarations don't prevent setting BTI ; ASM: .word 3221225472 Index: llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-1.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-1.ll @@ -0,0 +1,30 @@ +;; RUN: llc %s -o -| FileCheck %s +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-linux" + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 1, void ()* @asan.module_ctor, i8* null }] + +define dso_local i32 @f() #0 { +entry: + ret i32 0 +} +;; CHECK-LABEL: f: +;; CHECK: hint #34 + +declare void @__asan_init() +declare void @__asan_version_mismatch_check_v8() + +define internal void @asan.module_ctor() { + call void @__asan_init() + call void @__asan_version_mismatch_check_v8() + ret void +} +;; CHECK-LABEL: asan.module_ctor: +;; CHECK: hint #34 + +attributes #0 = { noinline nounwind optnone sanitize_address uwtable "branch-target-enforcement"="true" } + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 4, !"branch-target-enforcement", i32 1} \ No newline at end of file Index: llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll @@ -0,0 +1,70 @@ +;; RUN: llc --mattr=+v8.3a %s -o - | FileCheck %s +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-linux" + +@__llvm_gcov_ctr = internal global [1 x i64] zeroinitializer +@0 = private unnamed_addr constant [7 x i8] c"m.gcda\00", align 1 +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__llvm_gcov_init, i8* null }] + +define dso_local i32 @f() local_unnamed_addr #0 { +entry: + ret i32 0 +} +;; CHECK-LABEL: f: +;; CHECK: pacibsp + +declare void @llvm_gcda_start_file(i8*, i32, i32) local_unnamed_addr + +declare void @llvm_gcda_emit_function(i32, i32, i32) local_unnamed_addr + +declare void @llvm_gcda_emit_arcs(i32, i64*) local_unnamed_addr + +declare void @llvm_gcda_summary_info() local_unnamed_addr + +declare void @llvm_gcda_end_file() local_unnamed_addr + +define internal void @__llvm_gcov_writeout() unnamed_addr #1 { +entry: + tail call void @llvm_gcda_start_file(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i64 0, i64 0), i32 875575338, i32 0) + tail call void @llvm_gcda_emit_function(i32 0, i32 0, i32 0) + tail call void @llvm_gcda_emit_arcs(i32 1, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_gcov_ctr, i64 0, i64 0)) + tail call void @llvm_gcda_summary_info() + tail call void @llvm_gcda_end_file() + ret void +} +;; CHECK-LABEL: __llvm_gcov_writeout: +;; CHECK: .cfi_b_key_frame +;; CHECK-NEXT: pacibsp +;; CHECK-NEXT: .cfi_negate_ra_state + +define internal void @__llvm_gcov_reset() unnamed_addr #2 { +entry: + store i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_gcov_ctr, i64 0, i64 0), align 8 + ret void +} +;; CHECK-LABEL: __llvm_gcov_reset: +;; CHECK: pacibsp + +declare void @llvm_gcov_init(void ()*, void ()*) local_unnamed_addr + +define internal void @__llvm_gcov_init() unnamed_addr #1 { +entry: + tail call void @llvm_gcov_init(void ()* nonnull @__llvm_gcov_writeout, void ()* nonnull @__llvm_gcov_reset) + ret void +} +;; CHECK-LABEL: __llvm_gcov_init: +;; CHECK: .cfi_b_key_frame +;; CHECK-NEXT: pacibsp +;; CHECK-NEXT: .cfi_negate_ra_state + +attributes #0 = { norecurse nounwind readnone "sign-return-address"="all" "sign-return-address-key"="b_key" } +attributes #1 = { noinline } +attributes #2 = { nofree noinline norecurse nounwind writeonly } + +!llvm.module.flags = !{!0, !1, !2, !3, !4} + +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = !{i32 1, !"wchar_size", i32 4} +!2 = !{i32 4, !"sign-return-address", i32 1} +!3 = !{i32 4, !"sign-return-address-all", i32 1} +!4 = !{i32 4, !"sign-return-address-with-bkey", i32 1} Index: llvm/test/CodeGen/AArch64/pacbti-module-attrs.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/pacbti-module-attrs.ll @@ -0,0 +1,75 @@ +;; RUN: llc -mtriple=aarch64-eabi -mattr=+v8.5a %s -o - | FileCheck %s + +declare i32 @g(i32) #5 + +define i32 @f0(i32 %x) #0 { +entry: + %call = tail call i32 @g(i32 %x) #5 + %add = add nsw i32 %call, 1 + ret i32 %add +} +;; CHECK-LABEL: f0: +;; CHECK-NOT: bti +;; CHECK-NOT: pacia +;; CHECK-NOT: reta + +define i32 @f1(i32 %x) #1 { +entry: + %call = tail call i32 @g(i32 %x) #5 + %add = add nsw i32 %call, 1 + ret i32 %add +} +;; CHECK-LABEL: f1: +;; CHECK: bti c +;; CHECK-NOT: reta + +define i32 @f2(i32 %x) #2 { +entry: + %call = tail call i32 @g(i32 %x) #5 + %add = add nsw i32 %call, 1 + ret i32 %add +} +;; CHECK-LABEL: f2: +;; CHECK: paciasp +;; CHECK: retaa + +define i32 @f3(i32 %x) #3 { +entry: + %call = tail call i32 @g(i32 %x) #5 + %add = add nsw i32 %call, 1 + ret i32 %add +} +;; CHECK-LABEL: f3: +;; CHECK: pacibsp +;; CHECK: retab + +define i32 @f4(i32 %x) #4 { +entry: + ret i32 1 +} +;; CHECK-LABEL: f4: +;; CHECK: paciasp +;; CHECK: retaa + +define i32 @f5(i32 %x) #5 { +entry: + %call = tail call i32 @g(i32 %x) #5 + %add = add nsw i32 %call, 1 + ret i32 %add +} +;; CHECK-LABEL: f5: +;; CHECK: paciasp +;; CHECK: retaa + +attributes #0 = { nounwind "branch-target-enforcement"="false" "sign-return-address"="none" } +attributes #1 = { nounwind "branch-target-enforcement"="true" "sign-return-address"="none" } +attributes #2 = { nounwind "branch-target-enforcement"="false" "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" } +attributes #3 = { nounwind "branch-target-enforcement"="false" "sign-return-address"="non-leaf" "sign-return-address-key"="b_key" } +attributes #4 = { nounwind "branch-target-enforcement"="false" "sign-return-address"="all" "sign-return-address-key"="a_key" } +attributes #5 = { nounwind } + +!llvm.module.flags = !{!0, !1, !2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 4, !"branch-target-enforcement", i32 1} +!2 = !{i32 4, !"sign-return-address", i32 1} Index: llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll =================================================================== --- llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll +++ llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll @@ -1,6 +1,6 @@ ; RUN: llc -mtriple=aarch64 %s -o - | FileCheck %s -define void @f0() "patchable-function-entry"="0" "branch-target-enforcement" { +define void @f0() "patchable-function-entry"="0" "branch-target-enforcement"="true" { ; CHECK-LABEL: f0: ; CHECK-NEXT: .Lfunc_begin0: ; CHECK: // %bb.0: @@ -12,7 +12,7 @@ ;; -fpatchable-function-entry=1 -mbranch-protection=bti ;; For M=0, place the label .Lpatch0 after the initial BTI. -define void @f1() "patchable-function-entry"="1" "branch-target-enforcement" { +define void @f1() "patchable-function-entry"="1" "branch-target-enforcement"="true" { ; CHECK-LABEL: f1: ; CHECK-NEXT: .Lfunc_begin1: ; CHECK-NEXT: .cfi_startproc @@ -28,7 +28,7 @@ } ;; -fpatchable-function-entry=2,1 -mbranch-protection=bti -define void @f2_1() "patchable-function-entry"="1" "patchable-function-prefix"="1" "branch-target-enforcement" { +define void @f2_1() "patchable-function-entry"="1" "patchable-function-prefix"="1" "branch-target-enforcement"="true" { ; CHECK-LABEL: .type f2_1,@function ; CHECK-NEXT: .Ltmp0: ; CHECK-NEXT: nop @@ -50,7 +50,7 @@ ;; -fpatchable-function-entry=1 -mbranch-protection=bti ;; For M=0, don't create .Lpatch0 if the initial instruction is not BTI, ;; even if other basic blocks may have BTI. -define internal void @f1i(i64 %v) "patchable-function-entry"="1" "branch-target-enforcement" { +define internal void @f1i(i64 %v) "patchable-function-entry"="1" "branch-target-enforcement"="true" { ; CHECK-LABEL: f1i: ; CHECK-NEXT: .Lfunc_begin3: ; CHECK: // %bb.0: