[clang] [Clang][ARM][AArch64] Alway emit protection attributes for functions. (PR #82819)

via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 1 14:29:01 PST 2024


https://github.com/DanielKristofKiss updated https://github.com/llvm/llvm-project/pull/82819

>From 9e844b9e61ad1c81983aafd7ac9b3fb9e1939787 Mon Sep 17 00:00:00 2001
From: Daniel Kiss <daniel.kiss at arm.com>
Date: Mon, 22 Jan 2024 11:33:15 +0100
Subject: [PATCH] Emit attributes for functions always.

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.
---
 clang/include/clang/Basic/TargetInfo.h        | 44 ++++++++++++++++--
 clang/lib/CodeGen/Targets/AArch64.cpp         | 45 +++++++------------
 clang/lib/CodeGen/Targets/ARM.cpp             |  8 ++--
 .../CodeGen/aarch64-branch-protection-attr.c  | 24 +++++-----
 .../CodeGen/aarch64-sign-return-address.c     | 14 ++++--
 .../CodeGen/arm-branch-protection-attr-1.c    | 10 ++---
 .../CodeGen/arm-branch-protection-attr-2.c    | 13 ++++--
 .../test/Frontend/arm-branch-protection-lto.c | 22 +++++++++
 8 files changed, 119 insertions(+), 61 deletions(-)
 create mode 100644 clang/test/Frontend/arm-branch-protection-lto.c

diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 7682f84e491c7b..bd8bdaefe4eb1b 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -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"
@@ -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:
@@ -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
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 725e8a70fddfe6..a62814ba34ef57 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -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,
diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp
index 5d42e6286e525b..6aa83240de9dbd 100644
--- a/clang/lib/CodeGen/Targets/ARM.cpp
+++ b/clang/lib/CodeGen/Targets/ARM.cpp
@@ -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()) {
@@ -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>();
diff --git a/clang/test/CodeGen/aarch64-branch-protection-attr.c b/clang/test/CodeGen/aarch64-branch-protection-attr.c
index f0e1dcccd1e827..93d4f7747c0cf3 100644
--- a/clang/test/CodeGen/aarch64-branch-protection-attr.c
+++ b/clang/test/CodeGen/aarch64-branch-protection-attr.c
@@ -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"
diff --git a/clang/test/CodeGen/aarch64-sign-return-address.c b/clang/test/CodeGen/aarch64-sign-return-address.c
index 8bc54b1a56c38c..0edacc5a78c247 100644
--- a/clang/test/CodeGen/aarch64-sign-return-address.c
+++ b/clang/test/CodeGen/aarch64-sign-return-address.c
@@ -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
 
@@ -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() {}
\ No newline at end of file
diff --git a/clang/test/CodeGen/arm-branch-protection-attr-1.c b/clang/test/CodeGen/arm-branch-protection-attr-1.c
index 2a9cc600742f36..36dfee9248e9e8 100644
--- a/clang/test/CodeGen/arm-branch-protection-attr-1.c
+++ b/clang/test/CodeGen/arm-branch-protection-attr-1.c
@@ -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"
diff --git a/clang/test/CodeGen/arm-branch-protection-attr-2.c b/clang/test/CodeGen/arm-branch-protection-attr-2.c
index 1f3c00873043e8..532e7fe9ccc2b4 100644
--- a/clang/test/CodeGen/arm-branch-protection-attr-2.c
+++ b/clang/test/CodeGen/arm-branch-protection-attr-2.c
@@ -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
 
diff --git a/clang/test/Frontend/arm-branch-protection-lto.c b/clang/test/Frontend/arm-branch-protection-lto.c
new file mode 100644
index 00000000000000..251645370e6c2c
--- /dev/null
+++ b/clang/test/Frontend/arm-branch-protection-lto.c
@@ -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"



More information about the cfe-commits mailing list