https://github.com/kovdan01 created 
https://github.com/llvm/llvm-project/pull/211013

Compiler-synthesized functions such as `__llvm_gcov_writeout`, 
`__llvm_gcov_reset` and `__llvm_gcov_init` were previously never receiving the 
AArch64 hardening function attributes (ptrauth-returns, ptrauth-auth-traps, 
ptrauth-indirect-gotos and aarch64-jump-table-hardening) since the attributes 
were only emitted by Clang and gated by `PointerAuthOptions` structure's 
corresponding fields. See `setPointerAuthFnAttributes` and 
`initPointerAuthFnAttributes` member functions of `TargetCodeGenInfo`.

This patch resolves this in the same manner as #83153 does for several other 
attributes. Particularly, Clang now emits corresponding 4 module flags 
(conditionally on whether the related feature is enabled) with Max behavior, 
and LLVM's `Function::createWithDefaultAttr` derives the matching function 
attributes from them. Max behavior with conditional emission is safe because 
none of these features affect ABI, so promoting an absent flag on module merge 
cannot break compatibility.

>From 34e6a709f07ca0f7bce8fb8896da0a2585db36d3 Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <[email protected]>
Date: Tue, 21 Jul 2026 17:16:28 +0300
Subject: [PATCH] [clang][AArch64] Set hardening fn attrs on synthetic
 functions

Compiler-synthesized functions such as `__llvm_gcov_writeout`,
`__llvm_gcov_reset` and `__llvm_gcov_init` were previously never receiving the
AArch64 hardening function attributes (ptrauth-returns, ptrauth-auth-traps,
ptrauth-indirect-gotos and aarch64-jump-table-hardening) since the
attributes were only emitted by Clang and gated by `PointerAuthOptions`
structure's corresponding fields. See `setPointerAuthFnAttributes` and
`initPointerAuthFnAttributes` member functions of `TargetCodeGenInfo`.

This patch resolves this in the same manner as #83153 does for several
other attributes. Particularly, Clang now emits corresponding 4 module
flags (conditionally on whether the related feature is enabled) with Max
behavior, and LLVM's `Function::createWithDefaultAttr` derives the matching
function attributes from them. Max behavior with conditional emission is
safe because none of these features affect ABI, so promoting an absent
flag on module merge cannot break compatibility.
---
 clang/lib/CodeGen/CodeGenModule.cpp           | 21 ++++++++++
 .../ptrauth-function-attributes-synthetic.c   | 41 +++++++++++++++++++
 llvm/lib/IR/Function.cpp                      |  4 ++
 .../ptrauth-module-flags-aarch64.ll           | 14 +++++++
 4 files changed, 80 insertions(+)
 create mode 100644 
clang/test/CodeGen/AArch64/ptrauth-function-attributes-synthetic.c
 create mode 100644 
llvm/test/Instrumentation/AddressSanitizer/ptrauth-module-flags-aarch64.ll

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 5f5fc4401bb4e..52b110ccbac68 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1540,6 +1540,27 @@ void CodeGenModule::Release() {
                                 "sign-return-address-with-bkey", 2);
   }
   if (T.isAArch64()) {
+    // Emit the following 4 module flags so LLVM can derive corresponding
+    // function attributes for synthetically generated functions (e.g.
+    // __llvm_gcov_writeout). It is safe to only emit the flags conditionally
+    // and set the Max behavior because of two reasons:
+    // 1) all 4 hardening features gated behind the attributes do not break ABI
+    //    compatibility, so we do not need to error on flag mismatch (thus,
+    //    conditional emission);
+    // 2) promoting an absent flag to a present flag enables the corresponding
+    //    hardening feature for newly emitted functions which does not affect
+    //    correctness and is guaranteed to have sufficient target features for
+    //    it, since the module we are merging with already has the flag set.
+    if (LangOpts.PointerAuthReturns)
+      getModule().addModuleFlag(llvm::Module::Max, "ptrauth-returns", 1);
+    if (LangOpts.PointerAuthAuthTraps)
+      getModule().addModuleFlag(llvm::Module::Max, "ptrauth-auth-traps", 1);
+    if (LangOpts.PointerAuthIndirectGotos)
+      getModule().addModuleFlag(llvm::Module::Max, "ptrauth-indirect-gotos", 
1);
+    if (LangOpts.AArch64JumpTableHardening)
+      getModule().addModuleFlag(llvm::Module::Max,
+                                "aarch64-jump-table-hardening", 1);
+
     if (getTriple().isOSBinFormatELF()) {
       getModule().addModuleFlag(llvm::Module::Error, "ptrauth-elf-got",
                                 LangOpts.PointerAuthELFGOT);
diff --git a/clang/test/CodeGen/AArch64/ptrauth-function-attributes-synthetic.c 
b/clang/test/CodeGen/AArch64/ptrauth-function-attributes-synthetic.c
new file mode 100644
index 0000000000000..6e6d6542db0d6
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/ptrauth-function-attributes-synthetic.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios   -coverage-data-file=/dev/null     
                           -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,OFF
+// RUN: %clang_cc1 -triple arm64e-apple-ios  -coverage-data-file=/dev/null     
                           -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,OFF
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -coverage-data-file=/dev/null     
                           -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,OFF
+
+// RUN: %clang_cc1 -triple arm64-apple-ios   -coverage-data-file=/dev/null 
-fptrauth-returns              -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,RETS
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -coverage-data-file=/dev/null 
-fptrauth-returns              -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,RETS
+
+// RUN: %clang_cc1 -triple arm64-apple-ios   -coverage-data-file=/dev/null 
-fptrauth-auth-traps           -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,TRAPS
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -coverage-data-file=/dev/null 
-fptrauth-auth-traps           -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,TRAPS
+
+// RUN: %clang_cc1 -triple arm64-apple-ios   -coverage-data-file=/dev/null 
-fptrauth-indirect-gotos       -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,GOTOS
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -coverage-data-file=/dev/null 
-fptrauth-indirect-gotos       -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,GOTOS
+
+// RUN: %clang_cc1 -triple arm64e-apple-ios  -coverage-data-file=/dev/null 
-faarch64-jump-table-hardening -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,JMPTBL
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -coverage-data-file=/dev/null 
-faarch64-jump-table-hardening -emit-llvm %s -o - | FileCheck %s 
--check-prefixes=ALL,JMPTBL
+
+// ALL: define internal void @__llvm_gcov_writeout() unnamed_addr #[[#T:]] {
+// ALL: define internal void @__llvm_gcov_reset() unnamed_addr #[[#T]] {
+// ALL: define internal void @__llvm_gcov_init() unnamed_addr #[[#T]] {
+
+// RETS: attributes #[[#T]] = {{{.*}} "ptrauth-returns" {{.*}}}
+// RETS: !llvm.module.flags = !{{{.*}}!3{{.*}}}
+// RETS: !3 = !{i32 7, !"ptrauth-returns", i32 1}
+
+// TRAPS: attributes #[[#T]] = {{{.*}} "ptrauth-auth-traps" {{.*}}}
+// TRAPS: !llvm.module.flags = !{{{.*}}!3{{.*}}}
+// TRAPS: !3 = !{i32 7, !"ptrauth-auth-traps", i32 1}
+
+// GOTOS: attributes #[[#T]] = {{{.*}} "ptrauth-indirect-gotos" {{.*}}}
+// GOTOS: !llvm.module.flags = !{{{.*}}!3{{.*}}}
+// GOTOS: !3 = !{i32 7, !"ptrauth-indirect-gotos", i32 1}
+
+// JMPTBL: attributes #[[#T]] = {{{.*}} "aarch64-jump-table-hardening" {{.*}}}
+// JMPTBL: !llvm.module.flags = !{{{.*}}!3{{.*}}}
+// JMPTBL: !3 = !{i32 7, !"aarch64-jump-table-hardening", i32 1}
+
+// OFF-NOT: attributes {{.*}} "ptrauth-
+// OFF-NOT: !"ptrauth-returns"
+// OFF-NOT: !"ptrauth-auth-traps"
+// OFF-NOT: !"ptrauth-indirect-gotos"
+// OFF-NOT: !"aarch64-jump-table-hardening"
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 03e91bc8e2aa4..7c2a151dbefda 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -432,6 +432,10 @@ Function *Function::createWithDefaultAttr(FunctionType *Ty,
   AddAttributeIfSet("branch-target-enforcement");
   AddAttributeIfSet("branch-protection-pauth-lr");
   AddAttributeIfSet("guarded-control-stack");
+  AddAttributeIfSet("ptrauth-returns");
+  AddAttributeIfSet("ptrauth-auth-traps");
+  AddAttributeIfSet("ptrauth-indirect-gotos");
+  AddAttributeIfSet("aarch64-jump-table-hardening");
 
   F->addFnAttrs(B);
   return F;
diff --git 
a/llvm/test/Instrumentation/AddressSanitizer/ptrauth-module-flags-aarch64.ll 
b/llvm/test/Instrumentation/AddressSanitizer/ptrauth-module-flags-aarch64.ll
new file mode 100644
index 0000000000000..0e63ebd978d62
--- /dev/null
+++ b/llvm/test/Instrumentation/AddressSanitizer/ptrauth-module-flags-aarch64.ll
@@ -0,0 +1,14 @@
+; RUN: opt < %s -passes=asan -S | FileCheck %s
+; REQUIRES: aarch64-registered-target
+
+target triple = "aarch64-unknown-linux-gnu"
+
+!llvm.module.flags = !{!0, !1, !2, !3}
+
+!0 = !{i32 7, !"ptrauth-returns", i32 1}
+!1 = !{i32 7, !"ptrauth-auth-traps", i32 1}
+!2 = !{i32 7, !"ptrauth-indirect-gotos", i32 1}
+!3 = !{i32 7, !"aarch64-jump-table-hardening", i32 1}
+
+; CHECK: define internal void @asan.module_ctor() #[[#ATTR:]]
+; CHECK: attributes #[[#ATTR]] = { nounwind "aarch64-jump-table-hardening" 
"ptrauth-auth-traps" "ptrauth-indirect-gotos" "ptrauth-returns" }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to