Index: clang/include/clang/AST/Attr.h =================================================================== --- clang/include/clang/AST/Attr.h +++ clang/include/clang/AST/Attr.h @@ -20,6 +20,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/Sanitizers.h" Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -2114,7 +2114,12 @@ struct ParsedTargetAttr { std::vector Features; StringRef Architecture; + int BranchProtectionAttr = 0; + CodeGenOptions::SignReturnAddressScope SignReturnAddress = CodeGenOptions::SignReturnAddressScope::None; + CodeGenOptions::SignReturnAddressKeyValue SignReturnAddressKey = CodeGenOptions::SignReturnAddressKeyValue::AKey; + bool BranchTargetEnforcement = false; bool DuplicateArchitecture = false; + bool operator ==(const ParsedTargetAttr &Other) const { return DuplicateArchitecture == Other.DuplicateArchitecture && Architecture == Other.Architecture && Features == Other.Features; @@ -2186,6 +2191,49 @@ if (Feature.startswith("fpmath=") || Feature.startswith("tune=")) continue; + if (Feature.startswith("branch-protection=")) { + Ret.BranchProtectionAttr = 1; + StringRef Value = Feature.split('=').second.trim(); + if (Value == "none") { + // Defaults are OK; + } else if (Value == "standard") { + Ret.SignReturnAddress = CodeGenOptions::SignReturnAddressScope::NonLeaf; + Ret.BranchTargetEnforcement = true; + } else { + SmallVector ProtOpts; + Value.split(ProtOpts,"+"); + for (auto &Opt : ProtOpts) { + if (Opt.trim() == "bti") { + Ret.BranchTargetEnforcement = true; + continue; + } + if (Opt.trim() == "pac-ret") { + Ret.SignReturnAddress = CodeGenOptions::SignReturnAddressScope::NonLeaf; + continue; + } + if (Opt.trim() == "leaf") { + if (Ret.SignReturnAddress == CodeGenOptions::SignReturnAddressScope::None) { + Ret.BranchProtectionAttr = -1; + break; + } + Ret.SignReturnAddress = CodeGenOptions::SignReturnAddressScope::All; + continue; + } + if (Opt.trim() == "b-key") { + if (Ret.SignReturnAddress == CodeGenOptions::SignReturnAddressScope::None) { + Ret.BranchProtectionAttr = -1; + break; + } + Ret.SignReturnAddressKey = CodeGenOptions::SignReturnAddressKeyValue::BKey; + continue; + } + Ret.BranchProtectionAttr = -1; + break; + } + } + continue; + } + // While we're here iterating check for a different target cpu. if (Feature.startswith("arch=")) { if (!Ret.Architecture.empty()) Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -109,13 +109,13 @@ Embed_Marker // Embed a marker as a placeholder for bitcode. }; - enum SignReturnAddressScope { + enum class SignReturnAddressScope { None, // No signing for any function NonLeaf, // Sign the return address of functions that spill LR All // Sign the return address of all functions }; - enum SignReturnAddressKeyValue { AKey, BKey }; + enum class SignReturnAddressKeyValue { AKey, BKey }; enum class FramePointerKind { None, // Omit all frame pointers. Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -360,8 +360,8 @@ /// Whether to emit an address-significance table into the object file. CODEGENOPT(Addrsig, 1, 0) -ENUM_CODEGENOPT(SignReturnAddress, SignReturnAddressScope, 2, None) -ENUM_CODEGENOPT(SignReturnAddressKey, SignReturnAddressKeyValue, 1, AKey) +ENUM_CODEGENOPT(SignReturnAddress, SignReturnAddressScope, 2, SignReturnAddressScope::None) +ENUM_CODEGENOPT(SignReturnAddressKey, SignReturnAddressKeyValue, 1, SignReturnAddressKeyValue::AKey) CODEGENOPT(BranchTargetEnforcement, 1, 0) /// Whether to emit unused static constants. Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2591,6 +2591,8 @@ "integral compile time constant expression">; def err_attribute_requires_opencl_version : Error< "%0 attribute requires OpenCL version %1%select{| or above}2">; +def err_invalid_branch_protection_spec : Error< + "Invalid branch protection specification">; def warn_unsupported_target_attribute : Warning<"%select{unsupported|duplicate}0%select{| architecture}1 '%2' in" " the 'target' attribute string; 'target' attribute ignored">, Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -5055,23 +5055,33 @@ const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; - llvm::Function *Fn = cast(GV); - auto Kind = CGM.getCodeGenOpts().getSignReturnAddress(); - if (Kind != CodeGenOptions::SignReturnAddressScope::None) { + CodeGenOptions::SignReturnAddressScope Scope = CGM.getCodeGenOpts().getSignReturnAddress(); + CodeGenOptions::SignReturnAddressKeyValue Key = CGM.getCodeGenOpts().getSignReturnAddressKey(); + bool BranchTargetEnforcement = CGM.getCodeGenOpts().BranchTargetEnforcement; + if (FD->hasAttr()) { + TargetAttr::ParsedTargetAttr Attr = FD->getAttr()->parse(); + if (Attr.BranchProtectionAttr) { + Scope = Attr.SignReturnAddress; + Key = Attr.SignReturnAddressKey; + BranchTargetEnforcement = Attr.BranchTargetEnforcement; + } + } + + llvm::Function *Fn = cast(GV); + if (Scope != CodeGenOptions::SignReturnAddressScope::None) { Fn->addFnAttr("sign-return-address", - Kind == CodeGenOptions::SignReturnAddressScope::All + Scope == CodeGenOptions::SignReturnAddressScope::All ? "all" : "non-leaf"); - auto Key = CGM.getCodeGenOpts().getSignReturnAddressKey(); Fn->addFnAttr("sign-return-address-key", Key == CodeGenOptions::SignReturnAddressKeyValue::AKey ? "a_key" : "b_key"); } - if (CGM.getCodeGenOpts().BranchTargetEnforcement) + if (BranchTargetEnforcement) Fn->addFnAttr("branch-target-enforcement"); } }; Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -2990,6 +2990,9 @@ << Unsupported << None << CurFeature; } + if (ParsedAttrs.BranchProtectionAttr < 0) + return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec); + return false; } Index: clang/test/CodeGen/aarch64-branch-protection-attr.c =================================================================== --- /dev/null +++ clang/test/CodeGen/aarch64-branch-protection-attr.c @@ -0,0 +1,81 @@ +// 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:]] + +__attribute__ ((target("branch-protection=none"))) +void none() {} +// NO-OVERRIDE: define void @none() #[[#NONE]] +// OVERRIDE: define void @none() #[[#NONE:]] + + __attribute__ ((target("branch-protection=standard"))) +void std() {} +// NO-OVERRIDE: define void @std() #[[#STD:]] +// OVERRIDE: define void @std() #[[#STD]] + +__attribute__ ((target("branch-protection=bti"))) +void btionly() {} +// NO-OVERRIDE: define void @btionly() #[[#BTI:]] +// OVERRIDE: define void @btionly() #[[#BTI:]] + +__attribute__ ((target("branch-protection=pac-ret"))) +void paconly() {} +// NO-OVERRIDE: define void @paconly() #[[#PAC:]] +// OVERRIDE: define void @paconly() #[[#PAC:]] + +__attribute__ ((target("branch-protection=pac-ret+bti"))) +void pacbti0() {} +// NO-OVERRIDE: define void @pacbti0() #[[#PACBTI:]] +// OVERRIDE: define void @pacbti0() #[[#PACBTI:]] + +__attribute__ ((target("branch-protection=bti+pac-ret"))) +void pacbti1() {} +// NO-OVERRIDE: define void @pacbti1() #[[#PACBTI]] +// OVERRIDE: define void @pacbti1() #[[#PACBTI]] + +__attribute__ ((target("branch-protection=pac-ret+leaf"))) +void leaf() {} +// NO-OVERRIDE: define void @leaf() #[[#PACLEAF:]] +// OVERRIDE: 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:]] + +__attribute__ ((target("branch-protection=pac-ret+b-key+leaf"))) +void bkeyleaf0() {} +// NO-OVERRIDE: define void @bkeyleaf0() #[[#PACBKEYLEAF:]] +// OVERRIDE: 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]] + +__attribute__ ((target("branch-protection=pac-ret+bti+leaf"))) +void btileaf() {} +// NO-OVERRIDE: define void @btileaf() #[[#BTIPACLEAF:]] +// OVERRIDE: define void @btileaf() #[[#BTIPACLEAF:]] + +// CHECK-DAG: attributes #[[#NONE]] + +// 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 #[[#PAC]] = { {{.*}} "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 #[[#PACBKEY]] = { {{.*}} "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 #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key" Index: clang/test/Sema/branch-protection-attr-err.c =================================================================== --- /dev/null +++ clang/test/Sema/branch-protection-attr-err.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +__attribute__((target("branch_protection=foo"))) // expected-warning {{unsupported 'branch_protection=foo' in the 'target' attribute string}} +void missing() {} + +__attribute__((target("branch-protection=foo"))) // expected-error {{Invalid branch protection specification}} +void badvalue0() {} + +__attribute__((target("branch-protection=+bti"))) // expected-error {{Invalid branch protection specification}} +void badvalue1() {} + +__attribute__((target("branch-protection=bti+"))) // expected-error {{Invalid branch protection specification}} +void badvalue2() {} + +__attribute__((target("branch-protection=bti+leaf"))) // expected-error {{Invalid branch protection specification}} +void badoption0() {} + +__attribute__((target("branch-protection=bti+leaf+pac-ret"))) // expected-error {{Invalid branch protection specification}} +void badorder() {}