Skip to content

Commit 6bbf734

Browse files
authored
[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.
1 parent 453e410 commit 6bbf734

File tree

4 files changed

+140
-7
lines changed

4 files changed

+140
-7
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4610,12 +4610,6 @@ void CodeGenModule::emitMultiVersionFunctions() {
46104610
}
46114611
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
46124612

4613-
ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
4614-
4615-
if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT())
4616-
ResolverFunc->setComdat(
4617-
getModule().getOrInsertComdat(ResolverFunc->getName()));
4618-
46194613
const TargetInfo &TI = getTarget();
46204614
llvm::stable_sort(
46214615
Options, [&TI](const CodeGenFunction::FMVResolverOption &LHS,
@@ -4624,6 +4618,11 @@ void CodeGenModule::emitMultiVersionFunctions() {
46244618
});
46254619
CodeGenFunction CGF(*this);
46264620
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
4621+
4622+
setMultiVersionResolverAttributes(ResolverFunc, GD);
4623+
if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT())
4624+
ResolverFunc->setComdat(
4625+
getModule().getOrInsertComdat(ResolverFunc->getName()));
46274626
}
46284627

46294628
// Ensure that any additions to the deferred decls list caused by emitting a
@@ -4674,7 +4673,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
46744673

46754674
auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction(
46764675
ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false));
4677-
ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
4676+
46784677
if (supportsCOMDAT())
46794678
ResolverFunc->setComdat(
46804679
getModule().getOrInsertComdat(ResolverFunc->getName()));
@@ -4740,6 +4739,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
47404739

47414740
CodeGenFunction CGF(*this);
47424741
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
4742+
setMultiVersionResolverAttributes(ResolverFunc, GD);
47434743

47444744
if (getTarget().supportsIFunc()) {
47454745
llvm::GlobalValue::LinkageTypes Linkage = getMultiversionLinkage(*this, GD);
@@ -4858,6 +4858,26 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
48584858
return Resolver;
48594859
}
48604860

4861+
void CodeGenModule::setMultiVersionResolverAttributes(llvm::Function *Resolver,
4862+
GlobalDecl GD) {
4863+
const NamedDecl *D = dyn_cast_or_null<NamedDecl>(GD.getDecl());
4864+
Resolver->setLinkage(getMultiversionLinkage(*this, GD));
4865+
4866+
// Function body has to be emitted before calling setGlobalVisibility
4867+
// for Resolver to be considered as definition.
4868+
setGlobalVisibility(Resolver, D);
4869+
4870+
setDSOLocal(Resolver);
4871+
4872+
// Set the default target-specific attributes, such as PAC and BTI ones on
4873+
// AArch64. Not passing Decl to prevent setting unrelated attributes,
4874+
// as Resolver can be shared by multiple declarations.
4875+
// FIXME Some targets may require a non-null D to set some attributes
4876+
// (such as "stackrealign" on X86, even when it is requested via
4877+
// "-mstackrealign" command line option).
4878+
getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this);
4879+
}
4880+
48614881
bool CodeGenModule::shouldDropDLLAttribute(const Decl *D,
48624882
const llvm::GlobalValue *GV) const {
48634883
auto SC = GV->getDLLStorageClass();

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,6 +1851,15 @@ class CodeGenModule : public CodeGenTypeCache {
18511851
// that feature and for a regular function (llvm::GlobalValue) otherwise.
18521852
llvm::Constant *GetOrCreateMultiVersionResolver(GlobalDecl GD);
18531853

1854+
// Set attributes to a resolver function generated by Clang.
1855+
// GD is either the cpu_dispatch declaration or an arbitrarily chosen
1856+
// function declaration that triggered the implicit generation of this
1857+
// resolver function.
1858+
//
1859+
/// NOTE: This should only be called for definitions.
1860+
void setMultiVersionResolverAttributes(llvm::Function *Resolver,
1861+
GlobalDecl GD);
1862+
18541863
// In scenarios where a function is not known to be a multiversion function
18551864
// until a later declaration, it is sometimes necessary to change the
18561865
// previously created mangled name to align with requirements of whatever
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// 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
2+
// 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
3+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
4+
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
5+
6+
// Check that both multi-versioned functions themselves and corresponding
7+
// resolvers generated by Clang have the correct PAC/BTI attributes.
8+
9+
int __attribute__((target_clones("crc", "default"))) global_target_clones(void) { return 0; }
10+
11+
int __attribute__((target_version("crc"))) global_target_version(void) { return 0; }
12+
int __attribute__((target_version("default"))) global_target_version(void) { return 0; }
13+
14+
static int __attribute__((target_clones("crc", "default"))) static_target_clones(void) { return 0; }
15+
16+
static int __attribute__((target_version("crc"))) static_target_version(void) { return 0; }
17+
static int __attribute__((target_version("default"))) static_target_version(void) { return 0; }
18+
19+
// Force emission of static_* functions.
20+
void *get_ptr1(void) { return static_target_clones; }
21+
void *get_ptr2(void) { return static_target_version; }
22+
23+
// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_clones._Mcrc() #[[ATTR_CRC:[0-9]+]]
24+
// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_clones.default() #[[ATTR_DEFAULT:[0-9]+]]
25+
// CHECK-DAG: define weak_odr ptr @global_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
26+
// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_version._Mcrc() #[[ATTR_CRC]]
27+
// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_version.default() #[[ATTR_DEFAULT]]
28+
// CHECK-DAG: define weak_odr ptr @global_target_version.resolver() #[[ATTR_RESOLVER]]
29+
30+
// CHECK-DAG: define internal i32 @static_target_clones._Mcrc() #[[ATTR_CRC:[0-9]+]]
31+
// CHECK-DAG: define internal i32 @static_target_clones.default() #[[ATTR_DEFAULT:[0-9]+]]
32+
// CHECK-DAG: define internal ptr @static_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
33+
// CHECK-DAG: define internal i32 @static_target_version._Mcrc() #[[ATTR_CRC]]
34+
// CHECK-DAG: define internal i32 @static_target_version.default() #[[ATTR_DEFAULT]]
35+
// CHECK-DAG: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]]
36+
37+
// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
38+
// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
39+
// BTI-SIGNRA-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
40+
// PAUTHTEST-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
41+
// PAUTHTEST-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
42+
// PAUTHTEST-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -emit-llvm %s -o - | FileCheck --check-prefixes=BTI,ELF %s
2+
// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -emit-llvm %s -o - | FileCheck --check-prefixes=BTI %s
3+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefixes=NOBTI,ELF %s
4+
// RUN: %clang_cc1 -triple arm64-apple-ios -emit-llvm %s -o - | FileCheck --check-prefixes=NOBTI %s
5+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fvisibility=hidden -emit-llvm %s -o - | FileCheck --check-prefixes=HIDDEN,ELF %s
6+
// RUN: %clang_cc1 -triple arm64-apple-ios -fvisibility=hidden -emit-llvm %s -o - | FileCheck --check-prefixes=HIDDEN %s
7+
8+
// Check that the resolver functions generated by Clang have the correct attributes.
9+
// In these test cases, branch-target-enforcement is used as an example of
10+
// target-specific attribute that has to be set on every function by default.
11+
12+
// FIXME: `cpu_specific`/`cpu_dispatch` and `target` attributes cannot be
13+
// tested on AArch64.
14+
15+
__attribute__((target_clones("crc", "default")))
16+
int global_target_clones(void) { return 0; }
17+
18+
__attribute__((target_version("crc"))) int global_target_version(void) { return 0; }
19+
__attribute__((target_version("default"))) int global_target_version(void) { return 0; }
20+
21+
__attribute__((target_clones("crc", "default")))
22+
static int static_target_clones(void) { return 0; }
23+
24+
__attribute__((target_version("crc"))) static int static_target_version(void) { return 0; }
25+
__attribute__((target_version("default"))) static int static_target_version(void) { return 0; }
26+
27+
// Force emission of static_* functions.
28+
void *get_ptr1(void) { return static_target_clones; }
29+
void *get_ptr2(void) { return static_target_version; }
30+
31+
#ifdef __ELF__
32+
// Make sure target-specific attributes can be overriden as needed for
33+
// non-autogenerated resolver functions.
34+
// Note that since there is only a single definition of ifunc_resolver, it
35+
// is not itself a multi-versioned function, even though it has target(...)
36+
// attribute.
37+
int ifunc_func(void) { return 0; }
38+
__attribute__((target("branch-protection=bti"))) void *ifunc_resolver(void) { return ifunc_func; }
39+
__attribute__((ifunc("ifunc_resolver"))) int ifunc(void);
40+
#endif
41+
42+
// ELF: define{{.*}} ptr @ifunc_resolver() #[[ATTR_IFUNC_RESOLVER:[0-9]+]]
43+
44+
// BTI: define weak_odr ptr @global_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
45+
// BTI: define weak_odr ptr @global_target_version.resolver() #[[ATTR_RESOLVER]]
46+
// BTI: define internal ptr @static_target_clones.resolver() #[[ATTR_RESOLVER]]
47+
// BTI: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]]
48+
49+
// In NOBTI case, no attribute groups are assigned to the resolver functions:
50+
// NOBTI: define weak_odr ptr @global_target_clones.resolver(){{( comdat)?}} {
51+
// NOBTI: define weak_odr ptr @global_target_version.resolver(){{( comdat)?}} {
52+
// NOBTI: define internal ptr @static_target_clones.resolver() {
53+
// NOBTI: define internal ptr @static_target_version.resolver() {
54+
55+
// HIDDEN: define weak_odr hidden ptr @global_target_clones.resolver(){{( comdat)?}} {
56+
// HIDDEN: define weak_odr hidden ptr @global_target_version.resolver(){{( comdat)?}} {
57+
// HIDDEN: define internal ptr @static_target_clones.resolver() {
58+
// HIDDEN: define internal ptr @static_target_version.resolver() {
59+
60+
// ELF: attributes #[[ATTR_IFUNC_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} }
61+
62+
// BTI: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} }

0 commit comments

Comments
 (0)