From 6738cfe0a40af2754000346ff090ebb2115ce15f Mon Sep 17 00:00:00 2001 From: Victor Campos Date: Fri, 25 Apr 2025 11:04:34 +0100 Subject: [PATCH] Mark CXX module initializer with PACBTI attributes (#133716) The CXX module initializer function, which is called at program startup, needs to be tagged with Pointer Authentication and Branch Target Identification marks whenever relevant. Before this patch, in CPUs set up for PACBTI execution, the function wasn't protected with return address signing and no BTI instruction was inserted at the start of it, thus leading to an execution fault. This patch fixes the issue by marking the function with the function attributes related to PAC and BTI if relevant. --- clang/lib/CodeGen/CGDeclCXX.cpp | 5 +++++ clang/lib/CodeGen/Targets/AArch64.cpp | 9 +++++---- clang/lib/CodeGen/Targets/ARM.cpp | 15 +++++++-------- .../cxx20-module-initializer-pacbti.cpp | 17 +++++++++++++++++ 4 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 clang/test/CodeGenCXX/cxx20-module-initializer-pacbti.cpp diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 303d21e6152f..8a214da6bf62 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -448,6 +448,11 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction( if (Linkage == llvm::GlobalVariable::InternalLinkage) SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); + else { + SetLLVMFunctionAttributes(GlobalDecl(), FI, Fn, false); + SetLLVMFunctionAttributesForDefinition(nullptr, Fn); + getTargetCodeGenInfo().setTargetAttributes(nullptr, Fn, *this); + } Fn->setCallingConv(getRuntimeCC()); diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index 77e225d19734..f098f09ebf58 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -136,13 +136,15 @@ public: void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { - const FunctionDecl *FD = dyn_cast_or_null(D); - if (!FD) + auto *Fn = dyn_cast(GV); + if (!Fn) return; + const auto *FD = dyn_cast_or_null(D); TargetInfo::BranchProtectionInfo BPI(CGM.getLangOpts()); - if (const auto *TA = FD->getAttr()) { + if (FD && FD->hasAttr()) { + const auto *TA = FD->getAttr(); ParsedTargetAttr Attr = CGM.getTarget().parseTargetAttr(TA->getFeaturesStr()); if (!Attr.BranchProtection.empty()) { @@ -152,7 +154,6 @@ public: assert(Error.empty()); } } - auto *Fn = cast(GV); setBranchProtectionFnAttributes(BPI, *Fn); } diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp index dddf51a82715..68f9e0185648 100644 --- a/clang/lib/CodeGen/Targets/ARM.cpp +++ b/clang/lib/CodeGen/Targets/ARM.cpp @@ -134,14 +134,13 @@ public: void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { - if (GV->isDeclaration()) + auto *Fn = dyn_cast(GV); + if (!Fn) return; - const FunctionDecl *FD = dyn_cast_or_null(D); - if (!FD) - return; - auto *Fn = cast(GV); + const auto *FD = dyn_cast_or_null(D); - if (const auto *TA = FD->getAttr()) { + if (FD && FD->hasAttr()) { + const auto *TA = FD->getAttr(); ParsedTargetAttr Attr = CGM.getTarget().parseTargetAttr(TA->getFeaturesStr()); if (!Attr.BranchProtection.empty()) { @@ -174,10 +173,10 @@ public: setBranchProtectionFnAttributes(BPI, (*Fn)); } - const ARMInterruptAttr *Attr = FD->getAttr(); - if (!Attr) + if (!FD || !FD->hasAttr()) return; + const ARMInterruptAttr *Attr = FD->getAttr(); const char *Kind; switch (Attr->getInterrupt()) { case ARMInterruptAttr::Generic: Kind = ""; break; diff --git a/clang/test/CodeGenCXX/cxx20-module-initializer-pacbti.cpp b/clang/test/CodeGenCXX/cxx20-module-initializer-pacbti.cpp new file mode 100644 index 000000000000..dc66b0090e56 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-initializer-pacbti.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple thumbv8.1m.main-unknown-none-eabi -emit-module-interface -target-feature +pacbti -msign-return-address=all -mbranch-target-enforce -std=c++20 %s -o %t.pcm +// RUN: %clang_cc1 -triple thumbv8.1m.main-unknown-none-eabi -std=c++20 %t.pcm -emit-llvm -o - | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK-PAC-ARM %s + +// RUN: %clang_cc1 -triple aarch64-unknown-none-elf -emit-module-interface -target-feature +pacbti -msign-return-address=all -msign-return-address-key=b_key -mbranch-target-enforce -std=c++20 %s -o %t.pcm +// RUN: %clang_cc1 -triple aarch64-unknown-none-elf -std=c++20 %t.pcm -emit-llvm -o - | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK-PAC-AARCH64 %s + +// CHECK: define void @_ZGIW3foo() #0 +// CHECK-PAC-ARM: attributes #0 = { noinline nounwind "branch-target-enforcement" "no-trapping-math"="true" "sign-return-address"="all" "sign-return-address-key"="a_key" "stack-protector-buffer-size"="8" "target-features"="+armv8.1-m.main,+pacbti,+thumb-mode" } +// CHECK-PAC-AARCH64: attributes #0 = { noinline nounwind "branch-target-enforcement" "no-trapping-math"="true" "sign-return-address"="all" "sign-return-address-key"="b_key" "stack-protector-buffer-size"="8" "target-features"="+pacbti" } + +module; + +export module foo; + +export void func();