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
