Skip to content

Commit

Permalink
Emit attributes for functions always.
Browse files Browse the repository at this point in the history
Branch protection, sign return address, guarded control stack flags are
only emitted as module flags if not specified per function.

The inliner might inline functions with different set of flags as it
doesn't see the flags.

In case of LTO build the module flags get merged with the `min` rule which means
if one of the modules is not build with PAC/BTI then the features will be turned
off on all functions due to the functions takes the branch-protection and
sign-return-address features from the module flags. The sign-return-address is
function level option therefore it is expected functions from files that are
compiled with -mbranch-protection=pac-ret to be protected but in LTO case this
might not happen. This patch adds the flags to functions in case of an LTO build
therefore they don't need to rely on the module flag.
  • Loading branch information
DanielKristofKiss committed Mar 1, 2024
1 parent dfec4ef commit 9e844b9
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 61 deletions.
44 changes: 41 additions & 3 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Frontend/OpenMP/OMPGridValues.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/VersionTuple.h"
Expand Down Expand Up @@ -1368,15 +1370,15 @@ class TargetInfo : public TransferrableTargetInfo,
return StringRef();
}

struct BranchProtectionInfo {
class BranchProtectionInfo {
public:
LangOptions::SignReturnAddressScopeKind SignReturnAddr;
LangOptions::SignReturnAddressKeyKind SignKey;
bool BranchTargetEnforcement;
bool BranchProtectionPAuthLR;
bool GuardedControlStack;

BranchProtectionInfo() = default;

protected:
const char *getSignReturnAddrStr() const {
switch (SignReturnAddr) {
case LangOptions::SignReturnAddressScopeKind::None:
Expand All @@ -1398,6 +1400,42 @@ class TargetInfo : public TransferrableTargetInfo,
}
llvm_unreachable("Unexpected SignReturnAddressKeyKind");
}

public:
BranchProtectionInfo() = default;
BranchProtectionInfo(const LangOptions &LangOpts) {
SignReturnAddr =
LangOpts.hasSignReturnAddress()
? (LangOpts.isSignReturnAddressScopeAll()
? LangOptions::SignReturnAddressScopeKind::All
: LangOptions::SignReturnAddressScopeKind::NonLeaf)
: LangOptions::SignReturnAddressScopeKind::None;
SignKey = LangOpts.isSignReturnAddressWithAKey()
? LangOptions::SignReturnAddressKeyKind::AKey
: LangOptions::SignReturnAddressKeyKind::BKey;
BranchTargetEnforcement = LangOpts.BranchTargetEnforcement;
BranchProtectionPAuthLR = LangOpts.BranchProtectionPAuthLR;
GuardedControlStack = LangOpts.GuardedControlStack;
}

void setFnAttributes(llvm::Function &F) {
llvm::AttrBuilder FuncAttrs(F.getContext());
setFnAttributes(FuncAttrs);
F.addFnAttrs(FuncAttrs);
}

void setFnAttributes(llvm::AttrBuilder &FuncAttrs) {
if (SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
FuncAttrs.addAttribute("sign-return-address", getSignReturnAddrStr());
FuncAttrs.addAttribute("sign-return-address-key", getSignKeyStr());
}
if (BranchTargetEnforcement)
FuncAttrs.addAttribute("branch-target-enforcement", "true");
if (BranchProtectionPAuthLR)
FuncAttrs.addAttribute("branch-protection-pauth-lr", "true");
if (GuardedControlStack)
FuncAttrs.addAttribute("guarded-control-stack", "true");
}
};

/// Determine if the Architecture in this TargetInfo supports branch
Expand Down
45 changes: 15 additions & 30 deletions clang/lib/CodeGen/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,37 +116,22 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
if (!FD)
return;

const auto *TA = FD->getAttr<TargetAttr>();
if (TA == nullptr)
return;

ParsedTargetAttr Attr =
CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
if (Attr.BranchProtection.empty())
return;

TargetInfo::BranchProtectionInfo BPI;
StringRef Error;
(void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
Attr.CPU, BPI, Error);
assert(Error.empty());

auto *Fn = cast<llvm::Function>(GV);
Fn->addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());

if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
Fn->addFnAttr("sign-return-address-key",
BPI.SignKey == LangOptions::SignReturnAddressKeyKind::AKey
? "a_key"
: "b_key");
TargetInfo::BranchProtectionInfo BPI(CGM.getLangOpts());

if (const auto *TA = FD->getAttr<TargetAttr>()) {
ParsedTargetAttr Attr =
CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
if (!Attr.BranchProtection.empty()) {
StringRef Error;
(void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
Attr.CPU, BPI, Error);
#ifndef NDEBUG
assert(Error.empty());
#endif
}
}

Fn->addFnAttr("branch-target-enforcement",
BPI.BranchTargetEnforcement ? "true" : "false");
Fn->addFnAttr("branch-protection-pauth-lr",
BPI.BranchProtectionPAuthLR ? "true" : "false");
Fn->addFnAttr("guarded-control-stack",
BPI.GuardedControlStack ? "true" : "false");
auto *Fn = cast<llvm::Function>(GV);
BPI.setFnAttributes(*Fn);
}

bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/CodeGen/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
diag::warn_target_unsupported_branch_protection_attribute)
<< Arch;
} else {
Fn->addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());
Fn->addFnAttr("branch-target-enforcement",
BPI.BranchTargetEnforcement ? "true" : "false");
BPI.setFnAttributes(*Fn);
}
} else if (CGM.getLangOpts().BranchTargetEnforcement ||
CGM.getLangOpts().hasSignReturnAddress()) {
Expand All @@ -167,6 +165,10 @@ class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
diag::warn_target_unsupported_branch_protection_attribute)
<< Attr.CPU;
}
} else if (CGM.getTarget().isBranchProtectionSupportedArch(
CGM.getTarget().getTargetOpts().CPU)) {
TargetInfo::BranchProtectionInfo BPI(CGM.getLangOpts());
BPI.setFnAttributes(*Fn);
}

const ARMInterruptAttr *Attr = FD->getAttr<ARMInterruptAttr>();
Expand Down
24 changes: 12 additions & 12 deletions clang/test/CodeGen/aarch64-branch-protection-attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,29 +67,29 @@ __attribute__ ((target("branch-protection=gcs")))
void gcs() {}
// CHECK: define{{.*}} void @gcs() #[[#GCS:]]

// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#NONE]] = { {{.*}}

// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" "guarded-control-stack"="true" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true" "guarded-control-stack"="false" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true"

// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key"

// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "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"="true" "guarded-control-stack"="false" {{.*}} "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"


// CHECK-DAG: attributes #[[#PAUTHLR]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR]] = { {{.*}} "branch-protection-pauth-lr"="true" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PAUTHLR_BKEY]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
// CHECK-DAG: attributes #[[#PAUTHLR_BKEY]] = { {{.*}} "branch-protection-pauth-lr"="true" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="b_key"

// CHECK-DAG: attributes #[[#PAUTHLR_LEAF]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR_LEAF]] = { {{.*}} "branch-protection-pauth-lr"="true" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PAUTHLR_BTI]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="true" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR_BTI]] = { {{.*}} "branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="true" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#GCS]] = { {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="true" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#GCS]] = { {{.*}} "guarded-control-stack"="true"
14 changes: 10 additions & 4 deletions clang/test/CodeGen/aarch64-sign-return-address.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@

// CHECK-LABEL: @foo() #[[#ATTR:]]

// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"

// ALL: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// PART: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="a_key"
// B-KEY: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="b_key"
// BTE: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"


// Check module attributes

Expand Down Expand Up @@ -43,4 +49,4 @@
// BTE-NOT: !"sign-return-address-with-bkey"
// B-KEY: !{i32 8, !"sign-return-address-with-bkey", i32 1}

void foo() {}
void foo() {}
10 changes: 5 additions & 5 deletions clang/test/CodeGen/arm-branch-protection-attr-1.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ __attribute__((target("branch-protection=pac-ret+leaf"))) void leaf() {}
__attribute__((target("branch-protection=pac-ret+leaf+bti"))) void btileaf() {}
// CHECK: define{{.*}} void @btileaf() #[[#BTIPACLEAF:]]

// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#NONE]] = { {{.*}}

// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="non-leaf"

// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true"

// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="non-leaf"
// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf"

// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "branch-target-enforcement"="false" {{.*}}"sign-return-address"="all"
// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all"

// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement"="true" {{.*}} "sign-return-address"="all"
// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="all"
13 changes: 9 additions & 4 deletions clang/test/CodeGen/arm-branch-protection-attr-2.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK --check-prefix=PART
// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=bti %s | FileCheck %s --check-prefix=CHECK --check-prefix=BTE

// Check there are no branch protection function attributes
// Check there is branch protection function attributes

// CHECK-LABEL: @foo() #[[#ATTR:]]

// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"

// ALL: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"="all"
// PART: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"="non-leaf"
// BTE: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"


// Check module attributes

Expand Down
22 changes: 22 additions & 0 deletions clang/test/Frontend/arm-branch-protection-lto.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// REQUIRES: arm-registered-target

// RUN: %clang_cc1 -triple=thumbv7m-unknown-unknown-eabi -msign-return-address=non-leaf %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=SIGN
// RUN: %clang_cc1 -triple=thumbv7m-unknown-unknown-eabi -mbranch-target-enforce %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=BTE
// RUN: %clang_cc1 -triple=thumbv7m-unknown-unknown-eabi -mbranch-target-enforce -msign-return-address=all %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALL

// RUN: %clang_cc1 -flto -triple=thumbv7m-unknown-unknown-eabi -msign-return-address=non-leaf %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=SIGN
// RUN: %clang_cc1 -flto -triple=thumbv7m-unknown-unknown-eabi -mbranch-target-enforce %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=BTE
// RUN: %clang_cc1 -flto -triple=thumbv7m-unknown-unknown-eabi -mbranch-target-enforce -msign-return-address=all %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALL

// RUN: %clang_cc1 -flto=thin -triple=thumbv7m-unknown-unknown-eabi -msign-return-address=non-leaf %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=SIGN
// RUN: %clang_cc1 -flto=thin -triple=thumbv7m-unknown-unknown-eabi -mbranch-target-enforce %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=BTE
// RUN: %clang_cc1 -flto=thin -triple=thumbv7m-unknown-unknown-eabi -mbranch-target-enforce -msign-return-address=all %s -S -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALL

void foo() {}

// Check there are branch protection function attributes.
// CHECK-LABEL: @foo() #[[#ATTR:]]

// SIGN: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"="non-leaf"
// BTE: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"
// ALL: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"{{.*}} "sign-return-address"="all"

0 comments on commit 9e844b9

Please sign in to comment.