https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/141573
>From 3e625155a44a88ec8f276f8c25379bec1a153e38 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Mon, 26 May 2025 22:28:55 +0300 Subject: [PATCH 1/6] [AArch64][FMV] Enable PAuth and BTI hardening of resolver functions --- clang/lib/CodeGen/CodeGenModule.cpp | 9 +++++++ .../CodeGen/ptrauth-resolver-attributes.c | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 clang/test/CodeGen/ptrauth-resolver-attributes.c diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c8866f15745c2..e3ca1761cf85a 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4757,6 +4757,13 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion()) AddDeferredMultiVersionResolverToEmit(GD); + auto SetResolverAttrs = [&](llvm::Function &Resolver) { + TargetInfo::BranchProtectionInfo BPI(getLangOpts()); + TargetCodeGenInfo::setBranchProtectionFnAttributes(BPI, Resolver); + TargetCodeGenInfo::setPointerAuthFnAttributes(CodeGenOpts.PointerAuth, + Resolver); + }; + // For cpu_specific, don't create an ifunc yet because we don't know if the // cpu_dispatch will be emitted in this translation unit. if (ShouldReturnIFunc) { @@ -4771,6 +4778,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { "", Resolver, &getModule()); GIF->setName(ResolverName); SetCommonAttributes(FD, GIF); + SetResolverAttrs(cast<llvm::Function>(*Resolver)); if (ResolverGV) replaceDeclarationWith(ResolverGV, GIF); return GIF; @@ -4781,6 +4789,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV && "Resolver should be created for the first time"); SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver)); + SetResolverAttrs(cast<llvm::Function>(*Resolver)); return Resolver; } diff --git a/clang/test/CodeGen/ptrauth-resolver-attributes.c b/clang/test/CodeGen/ptrauth-resolver-attributes.c new file mode 100644 index 0000000000000..8bdedd2c549be --- /dev/null +++ b/clang/test/CodeGen/ptrauth-resolver-attributes.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s +// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s + +// Check that resolver functions generated by clang have the correct attributes. + +int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; } + +int __attribute__((target_version("crc"))) fmv(void) { return 0; } +int __attribute__((target_version("default"))) fmv(void) { return 0; } + +// CHECK: define{{.*}} i32 @ftc._Mcrc() #0 +// CHECK: define{{.*}} ptr @ftc.resolver() #1 +// CHECK: define{{.*}} i32 @fmv._Mcrc() #0 +// CHECK: define{{.*}} i32 @fmv.default() #2 +// CHECK: define{{.*}} i32 @ftc.default() #2 +// CHECK: define{{.*}} ptr @fmv.resolver() #1 + +// BTI-SIGNRA: attributes #0 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// BTI-SIGNRA: attributes #1 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// BTI-SIGNRA: attributes #2 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// PAUTHTEST: attributes #0 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } +// PAUTHTEST: attributes #1 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } +// PAUTHTEST: attributes #2 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } >From 6d63e7e1a9b5399d4c6478acc3cad03b0e0ff583 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Wed, 4 Jun 2025 16:34:47 +0300 Subject: [PATCH 2/6] Use setTargetAttributes function --- clang/lib/CodeGen/CodeGenModule.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index e3ca1761cf85a..51f9f85c7f561 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4757,11 +4757,11 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion()) AddDeferredMultiVersionResolverToEmit(GD); - auto SetResolverAttrs = [&](llvm::Function &Resolver) { - TargetInfo::BranchProtectionInfo BPI(getLangOpts()); - TargetCodeGenInfo::setBranchProtectionFnAttributes(BPI, Resolver); - TargetCodeGenInfo::setPointerAuthFnAttributes(CodeGenOpts.PointerAuth, - Resolver); + auto SetResolverAttrs = [&](llvm::Function *Resolver) { + // Set the default target-specific attributes, such as PAC and BTI ones on + // AArch64. Not passing Decl to prevent setting unrelated attributes, + // as Resolver can be shared by multiple declarations. + getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this); }; // For cpu_specific, don't create an ifunc yet because we don't know if the @@ -4778,7 +4778,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { "", Resolver, &getModule()); GIF->setName(ResolverName); SetCommonAttributes(FD, GIF); - SetResolverAttrs(cast<llvm::Function>(*Resolver)); + SetResolverAttrs(cast<llvm::Function>(Resolver)); if (ResolverGV) replaceDeclarationWith(ResolverGV, GIF); return GIF; @@ -4789,7 +4789,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV && "Resolver should be created for the first time"); SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver)); - SetResolverAttrs(cast<llvm::Function>(*Resolver)); + SetResolverAttrs(cast<llvm::Function>(Resolver)); return Resolver; } >From 2d74565fa5b0313a603447823d851b13ef324f6c Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Wed, 4 Jun 2025 17:36:20 +0300 Subject: [PATCH 3/6] test: accept functions and attribute groups in any order --- .../CodeGen/ptrauth-resolver-attributes.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/clang/test/CodeGen/ptrauth-resolver-attributes.c b/clang/test/CodeGen/ptrauth-resolver-attributes.c index 8bdedd2c549be..a1239604226a0 100644 --- a/clang/test/CodeGen/ptrauth-resolver-attributes.c +++ b/clang/test/CodeGen/ptrauth-resolver-attributes.c @@ -10,16 +10,16 @@ int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; } int __attribute__((target_version("crc"))) fmv(void) { return 0; } int __attribute__((target_version("default"))) fmv(void) { return 0; } -// CHECK: define{{.*}} i32 @ftc._Mcrc() #0 -// CHECK: define{{.*}} ptr @ftc.resolver() #1 -// CHECK: define{{.*}} i32 @fmv._Mcrc() #0 -// CHECK: define{{.*}} i32 @fmv.default() #2 -// CHECK: define{{.*}} i32 @ftc.default() #2 -// CHECK: define{{.*}} ptr @fmv.resolver() #1 +// CHECK-DAG: define{{.*}} i32 @ftc._Mcrc() #[[ATTR_CRC:[0-9]+]] +// CHECK-DAG: define{{.*}} i32 @ftc.default() #[[ATTR_DEFAULT:[0-9]+]] +// CHECK-DAG: define{{.*}} ptr @ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]] +// CHECK-DAG: define{{.*}} i32 @fmv._Mcrc() #[[ATTR_CRC]] +// CHECK-DAG: define{{.*}} i32 @fmv.default() #[[ATTR_DEFAULT]] +// CHECK-DAG: define{{.*}} ptr @fmv.resolver() #[[ATTR_RESOLVER]] -// BTI-SIGNRA: attributes #0 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } -// BTI-SIGNRA: attributes #1 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } -// BTI-SIGNRA: attributes #2 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } -// PAUTHTEST: attributes #0 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } -// PAUTHTEST: attributes #1 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } -// PAUTHTEST: attributes #2 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } +// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// BTI-SIGNRA-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// PAUTHTEST-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } +// PAUTHTEST-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } +// PAUTHTEST-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } >From 23a5407776bb7aa27b4fd07f5221c265fb080b1e Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Mon, 14 Jul 2025 21:33:40 +0300 Subject: [PATCH 4/6] Move new test file to AArch64/ subdirectory --- clang/test/CodeGen/{ => AArch64}/ptrauth-resolver-attributes.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename clang/test/CodeGen/{ => AArch64}/ptrauth-resolver-attributes.c (100%) diff --git a/clang/test/CodeGen/ptrauth-resolver-attributes.c b/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c similarity index 100% rename from clang/test/CodeGen/ptrauth-resolver-attributes.c rename to clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c >From 33a92e00d7acf0041a7d1579cf7a7d3bc64386d4 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Fri, 5 Sep 2025 00:11:23 +0300 Subject: [PATCH 5/6] [WIP] Set common attributes on the resolver functions --- clang/lib/CodeGen/CodeGenModule.cpp | 5 +++ .../AArch64/ptrauth-resolver-attributes.c | 36 +++++++++++++------ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 51f9f85c7f561..29b9ae3069b9b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4537,6 +4537,8 @@ void CodeGenModule::emitMultiVersionFunctions() { llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant); ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); + setGlobalVisibility(ResolverFunc, /*D=*/nullptr); + setDSOLocal(ResolverFunc); if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT()) ResolverFunc->setComdat( @@ -4601,6 +4603,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction( ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false)); ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); + setGlobalVisibility(ResolverFunc, /*D=*/nullptr); + setDSOLocal(ResolverFunc); + if (supportsCOMDAT()) ResolverFunc->setComdat( getModule().getOrInsertComdat(ResolverFunc->getName())); diff --git a/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c b/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c index a1239604226a0..edb30cf491fda 100644 --- a/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c +++ b/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s -// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s -// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s -// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck -DLINKVIS="dso_local " --check-prefixes=CHECK,BTI-SIGNRA %s +// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck -DLINKVIS="" --check-prefixes=CHECK,BTI-SIGNRA %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck -DLINKVIS="dso_local " --check-prefixes=CHECK,PAUTHTEST %s +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck -DLINKVIS="" --check-prefixes=CHECK,PAUTHTEST %s // Check that resolver functions generated by clang have the correct attributes. @@ -10,12 +10,28 @@ int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; } int __attribute__((target_version("crc"))) fmv(void) { return 0; } int __attribute__((target_version("default"))) fmv(void) { return 0; } -// CHECK-DAG: define{{.*}} i32 @ftc._Mcrc() #[[ATTR_CRC:[0-9]+]] -// CHECK-DAG: define{{.*}} i32 @ftc.default() #[[ATTR_DEFAULT:[0-9]+]] -// CHECK-DAG: define{{.*}} ptr @ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]] -// CHECK-DAG: define{{.*}} i32 @fmv._Mcrc() #[[ATTR_CRC]] -// CHECK-DAG: define{{.*}} i32 @fmv.default() #[[ATTR_DEFAULT]] -// CHECK-DAG: define{{.*}} ptr @fmv.resolver() #[[ATTR_RESOLVER]] +static int __attribute__((target_clones("crc", "default"))) static_ftc(void) { return 0; } + +static int __attribute__((target_version("crc"))) static_fmv(void) { return 0; } +static int __attribute__((target_version("default"))) static_fmv(void) { return 0; } + +// Force emission of static_* functions. +void *get_ptr1(void) { return static_ftc; } +void *get_ptr2(void) { return static_fmv; } + +// CHECK-DAG: define [[LINKVIS]]i32 @ftc._Mcrc() #[[ATTR_CRC:[0-9]+]] +// CHECK-DAG: define [[LINKVIS]]i32 @ftc.default() #[[ATTR_DEFAULT:[0-9]+]] +// CHECK-DAG: define weak_odr ptr @ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]] +// CHECK-DAG: define [[LINKVIS]]i32 @fmv._Mcrc() #[[ATTR_CRC]] +// CHECK-DAG: define [[LINKVIS]]i32 @fmv.default() #[[ATTR_DEFAULT]] +// CHECK-DAG: define weak_odr ptr @fmv.resolver() #[[ATTR_RESOLVER]] + +// CHECK-DAG: define internal i32 @static_ftc._Mcrc() #[[ATTR_CRC:[0-9]+]] +// CHECK-DAG: define internal i32 @static_ftc.default() #[[ATTR_DEFAULT:[0-9]+]] +// CHECK-DAG: define internal ptr @static_ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]] +// CHECK-DAG: define internal i32 @static_fmv._Mcrc() #[[ATTR_CRC]] +// CHECK-DAG: define internal i32 @static_fmv.default() #[[ATTR_DEFAULT]] +// CHECK-DAG: define internal ptr @static_fmv.resolver() #[[ATTR_RESOLVER]] // BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } // BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } >From 01b56904e1ddad3cf0eeb59fce3351db04a34f98 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Fri, 5 Sep 2025 20:05:30 +0300 Subject: [PATCH 6/6] Introduce setMultiVersionResolverAttributes function --- clang/lib/CodeGen/CodeGenModule.cpp | 38 +++++++----- clang/lib/CodeGen/CodeGenModule.h | 9 +++ .../CodeGen/AArch64/fmv-resolver-emission.c | 2 +- clang/test/CodeGen/AArch64/ptrauth-fmv.c | 42 +++++++++++++ .../AArch64/ptrauth-resolver-attributes.c | 41 ------------ .../CodeGen/AArch64/resolver-attributes.c | 62 +++++++++++++++++++ clang/test/CodeGen/attr-target-clones.c | 4 +- clang/test/CodeGen/attr-target-mv.c | 6 +- 8 files changed, 141 insertions(+), 63 deletions(-) create mode 100644 clang/test/CodeGen/AArch64/ptrauth-fmv.c delete mode 100644 clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c create mode 100644 clang/test/CodeGen/AArch64/resolver-attributes.c diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 29b9ae3069b9b..ee61ede97dfbb 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4536,10 +4536,6 @@ void CodeGenModule::emitMultiVersionFunctions() { } llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant); - ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); - setGlobalVisibility(ResolverFunc, /*D=*/nullptr); - setDSOLocal(ResolverFunc); - if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT()) ResolverFunc->setComdat( getModule().getOrInsertComdat(ResolverFunc->getName())); @@ -4552,6 +4548,7 @@ void CodeGenModule::emitMultiVersionFunctions() { }); CodeGenFunction CGF(*this); CGF.EmitMultiVersionResolver(ResolverFunc, Options); + setMultiVersionResolverAttributes(ResolverFunc, GD); } // Ensure that any additions to the deferred decls list caused by emitting a @@ -4602,9 +4599,6 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction( ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false)); - ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); - setGlobalVisibility(ResolverFunc, /*D=*/nullptr); - setDSOLocal(ResolverFunc); if (supportsCOMDAT()) ResolverFunc->setComdat( @@ -4671,6 +4665,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { CodeGenFunction CGF(*this); CGF.EmitMultiVersionResolver(ResolverFunc, Options); + setMultiVersionResolverAttributes(ResolverFunc, GD); if (getTarget().supportsIFunc()) { llvm::GlobalValue::LinkageTypes Linkage = getMultiversionLinkage(*this, GD); @@ -4762,13 +4757,6 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion()) AddDeferredMultiVersionResolverToEmit(GD); - auto SetResolverAttrs = [&](llvm::Function *Resolver) { - // Set the default target-specific attributes, such as PAC and BTI ones on - // AArch64. Not passing Decl to prevent setting unrelated attributes, - // as Resolver can be shared by multiple declarations. - getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this); - }; - // For cpu_specific, don't create an ifunc yet because we don't know if the // cpu_dispatch will be emitted in this translation unit. if (ShouldReturnIFunc) { @@ -4783,7 +4771,6 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { "", Resolver, &getModule()); GIF->setName(ResolverName); SetCommonAttributes(FD, GIF); - SetResolverAttrs(cast<llvm::Function>(Resolver)); if (ResolverGV) replaceDeclarationWith(ResolverGV, GIF); return GIF; @@ -4794,10 +4781,29 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV && "Resolver should be created for the first time"); SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver)); - SetResolverAttrs(cast<llvm::Function>(Resolver)); return Resolver; } +void CodeGenModule::setMultiVersionResolverAttributes(llvm::Function *Resolver, + GlobalDecl GD) { + const NamedDecl *D = dyn_cast_or_null<NamedDecl>(GD.getDecl()); + Resolver->setLinkage(getMultiversionLinkage(*this, GD)); + + // Function body has to be emitted before calling setGlobalVisibility + // for Resolver to be considered as definition. + setGlobalVisibility(Resolver, D); + + setDSOLocal(Resolver); + + // Set the default target-specific attributes, such as PAC and BTI ones on + // AArch64. Not passing Decl to prevent setting unrelated attributes, + // as Resolver can be shared by multiple declarations. + // FIXME Some targets may require a non-null D to set some attributes + // (such as "stackrealign" on X86, even when it is requested via + // "-mstackrealign" command line option). + getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this); +} + bool CodeGenModule::shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const { auto SC = GV->getDLLStorageClass(); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index cb013feb769fc..94b14dfddd754 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1843,6 +1843,15 @@ class CodeGenModule : public CodeGenTypeCache { // that feature and for a regular function (llvm::GlobalValue) otherwise. llvm::Constant *GetOrCreateMultiVersionResolver(GlobalDecl GD); + // Set attributes to a resolver function generated by Clang. + // GD is either the cpu_dispatch declaration or an arbitrarily chosen + // function declaration that triggered the implicit generation of this + // resolver function. + // + /// NOTE: This should only be called for definitions. + void setMultiVersionResolverAttributes(llvm::Function *Resolver, + GlobalDecl GD); + // In scenarios where a function is not known to be a multiversion function // until a later declaration, it is sometimes necessary to change the // previously created mangled name to align with requirements of whatever diff --git a/clang/test/CodeGen/AArch64/fmv-resolver-emission.c b/clang/test/CodeGen/AArch64/fmv-resolver-emission.c index 591625d4d0da1..193ee9556cab0 100644 --- a/clang/test/CodeGen/AArch64/fmv-resolver-emission.c +++ b/clang/test/CodeGen/AArch64/fmv-resolver-emission.c @@ -328,7 +328,7 @@ __attribute__((target_clones("aes"))) void clones_without_default(void) {} // CHECK-NEXT: ret void // // -// CHECK-LABEL: define {{[^@]+}}@internal_func.resolver() { +// CHECK-LABEL: define {{[^@]+}}@internal_func.resolver() comdat { // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 diff --git a/clang/test/CodeGen/AArch64/ptrauth-fmv.c b/clang/test/CodeGen/AArch64/ptrauth-fmv.c new file mode 100644 index 0000000000000..3b60ea7412f1b --- /dev/null +++ b/clang/test/CodeGen/AArch64/ptrauth-fmv.c @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s +// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s + +// Check that both multi-versioned functions themselves and corresponding +// resolvers generated by Clang have the correct PAC/BTI attributes. + +int __attribute__((target_clones("crc", "default"))) global_target_clones(void) { return 0; } + +int __attribute__((target_version("crc"))) global_target_version(void) { return 0; } +int __attribute__((target_version("default"))) global_target_version(void) { return 0; } + +static int __attribute__((target_clones("crc", "default"))) static_target_clones(void) { return 0; } + +static int __attribute__((target_version("crc"))) static_target_version(void) { return 0; } +static int __attribute__((target_version("default"))) static_target_version(void) { return 0; } + +// Force emission of static_* functions. +void *get_ptr1(void) { return static_target_clones; } +void *get_ptr2(void) { return static_target_version; } + +// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_clones._Mcrc() #[[ATTR_CRC:[0-9]+]] +// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_clones.default() #[[ATTR_DEFAULT:[0-9]+]] +// CHECK-DAG: define weak_odr ptr @global_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]] +// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_version._Mcrc() #[[ATTR_CRC]] +// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_version.default() #[[ATTR_DEFAULT]] +// CHECK-DAG: define weak_odr ptr @global_target_version.resolver() #[[ATTR_RESOLVER]] + +// CHECK-DAG: define internal i32 @static_target_clones._Mcrc() #[[ATTR_CRC:[0-9]+]] +// CHECK-DAG: define internal i32 @static_target_clones.default() #[[ATTR_DEFAULT:[0-9]+]] +// CHECK-DAG: define internal ptr @static_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]] +// CHECK-DAG: define internal i32 @static_target_version._Mcrc() #[[ATTR_CRC]] +// CHECK-DAG: define internal i32 @static_target_version.default() #[[ATTR_DEFAULT]] +// CHECK-DAG: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]] + +// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// BTI-SIGNRA-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } +// PAUTHTEST-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } +// PAUTHTEST-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } +// PAUTHTEST-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } diff --git a/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c b/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c deleted file mode 100644 index edb30cf491fda..0000000000000 --- a/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c +++ /dev/null @@ -1,41 +0,0 @@ -// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck -DLINKVIS="dso_local " --check-prefixes=CHECK,BTI-SIGNRA %s -// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck -DLINKVIS="" --check-prefixes=CHECK,BTI-SIGNRA %s -// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck -DLINKVIS="dso_local " --check-prefixes=CHECK,PAUTHTEST %s -// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck -DLINKVIS="" --check-prefixes=CHECK,PAUTHTEST %s - -// Check that resolver functions generated by clang have the correct attributes. - -int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; } - -int __attribute__((target_version("crc"))) fmv(void) { return 0; } -int __attribute__((target_version("default"))) fmv(void) { return 0; } - -static int __attribute__((target_clones("crc", "default"))) static_ftc(void) { return 0; } - -static int __attribute__((target_version("crc"))) static_fmv(void) { return 0; } -static int __attribute__((target_version("default"))) static_fmv(void) { return 0; } - -// Force emission of static_* functions. -void *get_ptr1(void) { return static_ftc; } -void *get_ptr2(void) { return static_fmv; } - -// CHECK-DAG: define [[LINKVIS]]i32 @ftc._Mcrc() #[[ATTR_CRC:[0-9]+]] -// CHECK-DAG: define [[LINKVIS]]i32 @ftc.default() #[[ATTR_DEFAULT:[0-9]+]] -// CHECK-DAG: define weak_odr ptr @ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]] -// CHECK-DAG: define [[LINKVIS]]i32 @fmv._Mcrc() #[[ATTR_CRC]] -// CHECK-DAG: define [[LINKVIS]]i32 @fmv.default() #[[ATTR_DEFAULT]] -// CHECK-DAG: define weak_odr ptr @fmv.resolver() #[[ATTR_RESOLVER]] - -// CHECK-DAG: define internal i32 @static_ftc._Mcrc() #[[ATTR_CRC:[0-9]+]] -// CHECK-DAG: define internal i32 @static_ftc.default() #[[ATTR_DEFAULT:[0-9]+]] -// CHECK-DAG: define internal ptr @static_ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]] -// CHECK-DAG: define internal i32 @static_fmv._Mcrc() #[[ATTR_CRC]] -// CHECK-DAG: define internal i32 @static_fmv.default() #[[ATTR_DEFAULT]] -// CHECK-DAG: define internal ptr @static_fmv.resolver() #[[ATTR_RESOLVER]] - -// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } -// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } -// BTI-SIGNRA-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} } -// PAUTHTEST-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } -// PAUTHTEST-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } -// PAUTHTEST-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} } diff --git a/clang/test/CodeGen/AArch64/resolver-attributes.c b/clang/test/CodeGen/AArch64/resolver-attributes.c new file mode 100644 index 0000000000000..a1263ded46565 --- /dev/null +++ b/clang/test/CodeGen/AArch64/resolver-attributes.c @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -emit-llvm %s -o - | FileCheck --check-prefixes=BTI,ELF %s +// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -emit-llvm %s -o - | FileCheck --check-prefixes=BTI %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefixes=NOBTI,ELF %s +// RUN: %clang_cc1 -triple arm64-apple-ios -emit-llvm %s -o - | FileCheck --check-prefixes=NOBTI %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fvisibility=hidden -emit-llvm %s -o - | FileCheck --check-prefixes=HIDDEN,ELF %s +// RUN: %clang_cc1 -triple arm64-apple-ios -fvisibility=hidden -emit-llvm %s -o - | FileCheck --check-prefixes=HIDDEN %s + +// Check that the resolver functions generated by Clang have the correct attributes. +// In these test cases, branch-target-enforcement is used as an example of +// target-specific attribute that has to be set on every function by default. + +// FIXME: `cpu_specific`/`cpu_dispatch` and `target` attributes cannot be +// tested on AArch64. + +__attribute__((target_clones("crc", "default"))) +int global_target_clones(void) { return 0; } + +__attribute__((target_version("crc"))) int global_target_version(void) { return 0; } +__attribute__((target_version("default"))) int global_target_version(void) { return 0; } + +__attribute__((target_clones("crc", "default"))) +static int static_target_clones(void) { return 0; } + +__attribute__((target_version("crc"))) static int static_target_version(void) { return 0; } +__attribute__((target_version("default"))) static int static_target_version(void) { return 0; } + +// Force emission of static_* functions. +void *get_ptr1(void) { return static_target_clones; } +void *get_ptr2(void) { return static_target_version; } + +#ifdef __ELF__ +// Make sure target-specific attributes can be overriden as needed for +// non-autogenerated resolver functions. +// Note that since there is only a single definition of ifunc_resolver, it +// is not itself a multi-versioned function, even though it has target(...) +// attribute. +int ifunc_func(void) { return 0; } +__attribute__((target("branch-protection=bti"))) void *ifunc_resolver(void) { return ifunc_func; } +__attribute__((ifunc("ifunc_resolver"))) int ifunc(void); +#endif + +// ELF: define{{.*}} ptr @ifunc_resolver() #[[ATTR_IFUNC_RESOLVER:[0-9]+]] + +// BTI: define weak_odr ptr @global_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]] +// BTI: define weak_odr ptr @global_target_version.resolver() #[[ATTR_RESOLVER]] +// BTI: define internal ptr @static_target_clones.resolver() #[[ATTR_RESOLVER]] +// BTI: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]] + +// In NOBTI case, no attribute groups are assigned to the resolver functions: +// NOBTI: define weak_odr ptr @global_target_clones.resolver(){{[^#]*}} { +// NOBTI: define weak_odr ptr @global_target_version.resolver(){{[^#]*}} { +// NOBTI: define internal ptr @static_target_clones.resolver(){{[^#]*}} { +// NOBTI: define internal ptr @static_target_version.resolver(){{[^#]*}} { + +// HIDDEN: define weak_odr hidden ptr @global_target_clones.resolver(){{[^#]*}} +// HIDDEN: define weak_odr hidden ptr @global_target_version.resolver(){{[^#]*}} +// HIDDEN: define internal ptr @static_target_clones.resolver(){{[^#]*}} +// HIDDEN: define internal ptr @static_target_version.resolver(){{[^#]*}} + +// ELF: attributes #[[ATTR_IFUNC_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} } + +// BTI: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} } diff --git a/clang/test/CodeGen/attr-target-clones.c b/clang/test/CodeGen/attr-target-clones.c index 3256db061f9a2..e11daa67192dc 100644 --- a/clang/test/CodeGen/attr-target-clones.c +++ b/clang/test/CodeGen/attr-target-clones.c @@ -44,9 +44,9 @@ static int __attribute__((target_clones("sse4.2, default"))) internal(void) { return 0; } int use(void) { return internal(); } /// Internal linkage resolvers do not use comdat. -// LINUX: define internal ptr @internal.resolver() { +// LINUX: define internal ptr @internal.resolver() comdat { // DARWIN: define internal ptr @internal.resolver() { -// WINDOWS: define internal i32 @internal() { +// WINDOWS: define internal i32 @internal() comdat { int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; } // LINUX: define {{.*}}i32 @foo.sse4.2.0() diff --git a/clang/test/CodeGen/attr-target-mv.c b/clang/test/CodeGen/attr-target-mv.c index 07f47d93cd29c..6699326ef834f 100644 --- a/clang/test/CodeGen/attr-target-mv.c +++ b/clang/test/CodeGen/attr-target-mv.c @@ -283,9 +283,9 @@ void calls_pr50025c(void) { pr50025c(); } // WINDOWS: call i32 @foo /// Internal linkage resolvers do not use comdat. -// ITANIUM: define internal ptr @foo_internal.resolver() { - -// WINDOWS: define internal i32 @foo_internal.resolver() { +// LINUX: define internal ptr @foo_internal.resolver() comdat { +// DARWIN: define internal ptr @foo_internal.resolver() { +// WINDOWS: define internal i32 @foo_internal.resolver() comdat { // ITANIUM: define{{.*}} i32 @bar2() // ITANIUM: call i32 @foo_inline.ifunc() _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
