Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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()));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 42 additions & 0 deletions clang/test/CodeGen/AArch64/ptrauth-fmv.c
Original file line number Diff line number Diff line change
@@ -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"{{.*}} }
62 changes: 62 additions & 0 deletions clang/test/CodeGen/AArch64/resolver-attributes.c
Original file line number Diff line number Diff line change
@@ -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"{{.*}} }
Loading