Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -1823,6 +1823,17 @@ std::tie(Var, Value) = Attr.split('='); FuncAttrs.addAttribute(Var, Value); } + + if (getLangOpts().hasSignReturnAddress()) { + FuncAttrs.addAttribute( + "sign-return-address", + getLangOpts().isSignReturnAddressScopeAll() ? "all" : "non-leaf"); + FuncAttrs.addAttribute( + "sign-return-address-key", + getLangOpts().isSignReturnAddressWithAKey() ? "a_key" : "b_key"); + } + if (getLangOpts().BranchTargetEnforcement) + FuncAttrs.addAttribute("branch-target-enforcement"); } void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) { Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -588,6 +588,24 @@ 1); } + if (Context.getLangOpts().BranchTargetEnforcement) { + getModule().addModuleFlag(llvm::Module::Override, + "branch-target-enforcement", 1); + } + + if (Context.getLangOpts().hasSignReturnAddress()) { + getModule().addModuleFlag( + llvm::Module::Override, "sign-return-address", + Context.getLangOpts().isSignReturnAddressScopeAll() + ? llvm::MDString::get(VMContext, "all") + : llvm::MDString::get(VMContext, "non-leaf")); + getModule().addModuleFlag( + llvm::Module::Override, "sign-return-address-key", + Context.getLangOpts().isSignReturnAddressWithAKey() + ? llvm::MDString::get(VMContext, "a_key") + : llvm::MDString::get(VMContext, "b_key")); + } + 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 @@ -5107,40 +5107,52 @@ 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; + LangOptions::SignReturnAddressScopeKind Scope = + CGM.getLangOpts().getSignReturnAddressScope(); + LangOptions::SignReturnAddressKeyKind Key = + CGM.getLangOpts().getSignReturnAddressKey(); + (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, BPI, Error); assert(Error.empty()); - Scope = BPI.SignReturnAddr; - Key = BPI.SignKey; - BranchTargetEnforcement = BPI.BranchTargetEnforcement; - } - } - - auto *Fn = cast(GV); - if (Scope != LangOptions::SignReturnAddressScopeKind::None) { - Fn->addFnAttr("sign-return-address", - Scope == LangOptions::SignReturnAddressScopeKind::All - ? "all" - : "non-leaf"); + auto *Fn = cast(GV); + + // Update flags only when differ from the codegen flags. + if (Scope != BPI.SignReturnAddr || Key != BPI.SignKey) { + Scope = BPI.SignReturnAddr; + Key = BPI.SignKey; + if (Scope != LangOptions::SignReturnAddressScopeKind::None) { + Fn->addFnAttr("sign-return-address", + Scope == LangOptions::SignReturnAddressScopeKind::All + ? "all" + : "non-leaf"); + + Fn->addFnAttr("sign-return-address-key", + Key == LangOptions::SignReturnAddressKeyKind::AKey + ? "a_key" + : "b_key"); + } else { + Fn->removeAttribute(llvm::AttributeList::FunctionIndex, + "sign-return-address"); + Fn->removeAttribute(llvm::AttributeList::FunctionIndex, + "sign-return-address-key"); + } + } - Fn->addFnAttr("sign-return-address-key", - Key == LangOptions::SignReturnAddressKeyKind::AKey - ? "a_key" - : "b_key"); + if (!BPI.BranchTargetEnforcement) { + Fn->addFnAttr("ignore-branch-target-enforcement"); + Fn->removeAttribute(llvm::AttributeList::FunctionIndex, + "branch-target-enforcement"); + } else { + Fn->addFnAttr("branch-target-enforcement"); + } + } } - - if (BranchTargetEnforcement) - Fn->addFnAttr("branch-target-enforcement"); } llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override { 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 @@ -11,10 +11,10 @@ __attribute__ ((target("branch-protection=none"))) void none() {} -// NO-OVERRIDE: define void @none() #[[#NONE]] +// NO-OVERRIDE: define void @none() #[[#NONE:]] // OVERRIDE: define void @none() #[[#NONE:]] - __attribute__ ((target("branch-protection=standard"))) +__attribute__ ((target("branch-protection=standard"))) void std() {} // NO-OVERRIDE: define void @std() #[[#STD:]] // OVERRIDE: define void @std() #[[#STD]] @@ -36,8 +36,8 @@ __attribute__ ((target("branch-protection=bti+pac-ret"))) void pacbti1() {} -// NO-OVERRIDE: define void @pacbti1() #[[#PACBTI]] -// OVERRIDE: define void @pacbti1() #[[#PACBTI]] +// NO-OVERRIDE: define void @pacbti1() #[[#PACBTI:]] +// OVERRIDE: define void @pacbti1() #[[#PACBTI:]] __attribute__ ((target("branch-protection=pac-ret+leaf"))) void leaf() {} @@ -56,26 +56,31 @@ __attribute__ ((target("branch-protection=pac-ret+leaf+b-key"))) void bkeyleaf1() {} -// NO-OVERRIDE: define void @bkeyleaf1() #[[#PACBKEYLEAF]] -// OVERRIDE: define void @bkeyleaf1() #[[#PACBKEYLEAF]] +// NO-OVERRIDE: define void @bkeyleaf1() #[[#PACBKEYLEAF:]] +// OVERRIDE: 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-DAG: attributes #[[#NONE]] +// NO-OVERRIDE-DAG: attributes #[[#NONE]] = { {{.*}} +// OVERRIDE-DAG: attributes #[[#NONE]] = { {{.*}} "ignore-branch-target-enforcement" // CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement" {{.*}} "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" -// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" +// NO-OVERRIDE-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" +// OVERRIDE-DAG: attributes #[[#PAC]] = { {{.*}} "ignore-branch-target-enforcement" {{.*}} "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" +// NO-OVERRIDE-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key" +// OVERRIDE-DAG: attributes #[[#PACLEAF]] = { {{.*}} "ignore-branch-target-enforcement" {{.*}} "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" +// NO-OVERRIDE-DAG: attributes #[[#PACBKEY]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key" +// OVERRIDE: attributes #[[#PACBKEY]] = { {{.*}} "ignore-branch-target-enforcement" {{.*}} "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" +// NO-OVERRIDE-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="b_key" +// OVERRIDE-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "ignore-branch-target-enforcement" {{.*}} "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" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key" Index: clang/test/CodeGenCXX/aarch64-branch-target_clang_call_terminate.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/aarch64-branch-target_clang_call_terminate.cpp @@ -0,0 +1,34 @@ +// RUN: %clang -target aarch64-linux-android -mbranch-protection=none -c %s -o - | \ +// RUN: llvm-objdump -d --mattr=+bti - | FileCheck %s --check-prefix=CHECK-NONE +// RUN: %clang -target aarch64-linux-android -mbranch-protection=pac-ret -c %s -o - | \ +// RUN: llvm-objdump -d --mattr=+bti - | FileCheck %s --check-prefix=CHECK-NONE +// RUN: %clang -target aarch64-linux-android -mbranch-protection=pac-ret+leaf -c %s -o - | \ +// RUN: llvm-objdump -d --mattr=+bti - | FileCheck %s --check-prefix=CHECK-NONE +// RUN: %clang -target aarch64-linux-android -mbranch-protection=pac-ret+b-key -c %s -o - | \ +// RUN: llvm-objdump -d --mattr=+bti - | FileCheck %s --check-prefix=CHECK-NONE +// RUN: %clang -target aarch64-linux-android -mbranch-protection=pac-ret+b-key+leaf -c %s -o - | \ +// RUN: llvm-objdump -d --mattr=+bti - | FileCheck %s --check-prefix=CHECK-NONE +// RUN: %clang -target aarch64-linux-android -mbranch-protection=standard -c %s -o - | \ +// RUN: llvm-objdump -d --mattr=+bti - | FileCheck %s --check-prefix=CHECK-BTI +// RUN: %clang -target aarch64-linux-android -mbranch-protection=bti -c %s -o - | \ +// RUN: llvm-objdump -d --mattr=+bti - | FileCheck %s --check-prefix=CHECK-BTI +// RUN: %clang -target aarch64-linux-android -mbranch-protection=pac-ret+b-key+leaf+bti -c %s -o - | \ +// RUN: llvm-objdump -d --mattr=+bti - | FileCheck %s --check-prefix=CHECK-BTI + +void a(); +void d(); + +void c() { + try { + d(); + } catch (...) { + a(); + } +} + +// CHECK-BTI: 0000000000000000 <__clang_call_terminate>: +// CHECK-BTI-NEXT: bti c +// CHECK-BTI-NEXT: str x30, [sp, #-16]! + +// CHECK-NONE: 0000000000000000 <__clang_call_terminate>: +// CHECK-NONE-NEXT: str x30, [sp, #-16]! Index: llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -187,12 +187,19 @@ return; // Assemble feature flags that may require creation of a note section. - unsigned Flags = ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI | - ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC; + unsigned Flags = 0; + if (M.getModuleFlag("branch-target-enforcement")) + Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI; + if (M.getModuleFlag("sign-return-address")) + Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC; + + if (Flags == 0) + return; if (any_of(M, [](const Function &F) { - return !F.isDeclaration() && - !F.hasFnAttribute("branch-target-enforcement"); + if (F.isDeclaration()) + return false; + return F.hasFnAttribute("ignore-branch-target-enforcement"); })) { Flags &= ~ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI; } Index: llvm/lib/Target/AArch64/AArch64BranchTargets.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64BranchTargets.cpp +++ llvm/lib/Target/AArch64/AArch64BranchTargets.cpp @@ -58,7 +58,14 @@ bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) { const Function &F = MF.getFunction(); - if (!F.hasFnAttribute("branch-target-enforcement")) + + // Explicitly requested to not generate BTI. + if (F.hasFnAttribute("ignore-branch-target-enforcement")) + return false; + // Add BTI if function is compiled with it or in case of generated functions + // fallback to the module flag. + if (!F.hasFnAttribute("branch-target-enforcement") && + !MF.getMMI().getModule()->getModuleFlag("branch-target-enforcement")) return false; LLVM_DEBUG( 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 @@ -6,6 +6,11 @@ attributes #0 = { "branch-target-enforcement" } +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 4, !"branch-target-enforcement", i32 1} +!1 = !{i32 4, !"sign-return-address", !"all"} + ; Both attributes present in a file with no functions. ; ASM: .word 3221225472 ; ASM-NEXT: .word 4 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 @@ -10,6 +10,10 @@ attributes #0 = { "branch-target-enforcement" } +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"branch-target-enforcement", i32 1} + ; BTI attribute present ; ASM: .word 3221225472 ; ASM-NEXT: .word 4 Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-2.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-2.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-2.ll @@ -10,6 +10,10 @@ attributes #0 = { "sign-return-address"="all" } +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"sign-return-address", !"all"} + ; PAC attribute present ; ASM: .word 3221225472 ; ASM-NEXT: .word 4 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 @@ -10,6 +10,11 @@ attributes #0 = { "branch-target-enforcement" "sign-return-address"="non-leaf" } +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 4, !"branch-target-enforcement", i32 1} +!1 = !{i32 4, !"sign-return-address", !"non-leaf"} + ; Both attribute present ; ASM: .word 3221225472 ; ASM-NEXT: .word 4 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 @@ -17,6 +17,10 @@ attributes #1 = { "branch-target-enforcement" } +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"branch-target-enforcement", i32 1} + ; Only the common atttribute (BTI) ; ASM: .word 3221225472 ; ASM-NEXT: .word 4 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 @@ -15,7 +15,13 @@ attributes #0 = { "branch-target-enforcement" "sign-return-address"="non-leaf" } -attributes #1 = { "sign-return-address"="all" } +attributes #1 = { "ignore-branch-target-enforcement" "sign-return-address"="all" } + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 4, !"branch-target-enforcement", i32 1} +!1 = !{i32 4, !"sign-return-address", !"all"} + ; Only the common atttribute (PAC) ; ASM: warning: not setting BTI in feature flags Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-6.ll =================================================================== --- llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-6.ll +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-6.ll @@ -17,6 +17,11 @@ attributes #1 = { "sign-return-address"="none" } +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"sign-return-address", !"non-leaf"} + + ; No common attribute, no note section ; ASM-NOT: .note.gnu.property ; OBJ-NOT: .note.gnu.property 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 @@ -13,10 +13,14 @@ ret i32 0 } -attributes #0 = { "sign-return-address"="non-leaf" } +attributes #0 = { "ignore-branch-target-enforcement" "sign-return-address"="non-leaf" } attributes #1 = { "branch-target-enforcement" } +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"branch-target-enforcement", i32 1} + ; No common attribute, no note section ; ASM: warning: not setting BTI in feature flags ; ASM-NOT: .note.gnu.property 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 @@ -13,6 +13,10 @@ attributes #0 = { "branch-target-enforcement" } +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"branch-target-enforcement", i32 1} + ; Declarations don't prevent setting BTI ; ASM: .word 3221225472 ; ASM-NEXT: .word 4 Index: llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-9.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-9.ll @@ -0,0 +1,27 @@ +; RUN: llc -mtriple=aarch64-linux %s -o - | \ +; RUN: FileCheck %s --check-prefix=ASM +; RUN: llc -mtriple=aarch64-linux %s -filetype=obj -o - | \ +; RUN: llvm-readelf --notes | FileCheck %s --check-prefix=OBJ + +define dso_local i32 @f() #0 { +entry: + ret i32 0 +} + +define dso_local i32 @g() { +entry: + ret i32 0 +} + +attributes #0 = { "branch-target-enforcement" } + +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"branch-target-enforcement", i32 1} + +; Only the common atttribute (BTI) +; ASM: .word 3221225472 +; ASM-NEXT: .word 4 +; ASM-NEXT .word 1 + +; OBJ: Properties: aarch64 feature: BTI