Author: Anatoly Trosinenko Date: 2025-09-17T20:23:09+03:00 New Revision: 6bbf734ecac35a5a1c3bcb680d20519dfd46da11
URL: https://github.com/llvm/llvm-project/commit/6bbf734ecac35a5a1c3bcb680d20519dfd46da11 DIFF: https://github.com/llvm/llvm-project/commit/6bbf734ecac35a5a1c3bcb680d20519dfd46da11.diff LOG: [FMV] Set default attributes on the resolver functions (#141573) There is a number of attributes that is expected to be set on functions by default. This patch implements setting more such attributes on the FMV resolver functions generated by Clang. On AArch64, this makes the resolver functions use the default PAC and BTI hardening settings. Added: clang/test/CodeGen/AArch64/ptrauth-fmv.c clang/test/CodeGen/AArch64/resolver-attributes.c Modified: clang/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/CodeGenModule.h Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0ebab141b187d..0b660e3daaf81 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4610,12 +4610,6 @@ void CodeGenModule::emitMultiVersionFunctions() { } llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant); - ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); - - if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT()) - ResolverFunc->setComdat( - getModule().getOrInsertComdat(ResolverFunc->getName())); - const TargetInfo &TI = getTarget(); llvm::stable_sort( Options, [&TI](const CodeGenFunction::FMVResolverOption &LHS, @@ -4624,6 +4618,11 @@ void CodeGenModule::emitMultiVersionFunctions() { }); CodeGenFunction CGF(*this); CGF.EmitMultiVersionResolver(ResolverFunc, Options); + + setMultiVersionResolverAttributes(ResolverFunc, GD); + if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT()) + ResolverFunc->setComdat( + getModule().getOrInsertComdat(ResolverFunc->getName())); } // Ensure that any additions to the deferred decls list caused by emitting a @@ -4674,7 +4673,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction( ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false)); - ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); + if (supportsCOMDAT()) ResolverFunc->setComdat( getModule().getOrInsertComdat(ResolverFunc->getName())); @@ -4740,6 +4739,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); @@ -4858,6 +4858,26 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { 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 8b1ac2d976c5e..3971b296b3f80 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1851,6 +1851,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/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/resolver-attributes.c b/clang/test/CodeGen/AArch64/resolver-attributes.c new file mode 100644 index 0000000000000..6e4497cdc8611 --- /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(){{( comdat)?}} { +// NOBTI: define weak_odr ptr @global_target_version.resolver(){{( comdat)?}} { +// 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(){{( comdat)?}} { +// HIDDEN: define weak_odr hidden ptr @global_target_version.resolver(){{( comdat)?}} { +// 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"{{.*}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
