Skip to content

Commit

Permalink
Add ifunc support for Windows on AArch64. (#111962)
Browse files Browse the repository at this point in the history
On Windows there is no platform support for ifunc but we could lower
them to global function pointers.
This also enables FMV for Windows with Clang and Compiler-rt.

Depends on #111961
  • Loading branch information
DanielKristofKiss authored Nov 14, 2024
1 parent 9f06129 commit 3f40ad7
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 8 deletions.
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,9 @@ def TargetELF : TargetSpec {
def TargetELFOrMachO : TargetSpec {
let ObjectFormats = ["ELF", "MachO"];
}
def TargetIFuncSupport : TargetSpec {
let CustomCode = [{ Target.supportsIFunc() }];
}
def TargetWindowsArm64EC : TargetSpec {
let CustomCode = [{ Target.getTriple().isWindowsArm64EC() }];
}
Expand Down Expand Up @@ -1855,7 +1858,7 @@ def IBOutletCollection : InheritableAttr {
let Documentation = [Undocumented];
}

def IFunc : Attr, TargetSpecificAttr<TargetELFOrMachO> {
def IFunc : Attr, TargetSpecificAttr<TargetIFuncSupport> {
let Spellings = [GCC<"ifunc">];
let Args = [StringArgument<"Resolver">];
let Subjects = SubjectList<[Function]>;
Expand Down
19 changes: 13 additions & 6 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -6051,12 +6051,19 @@ declared entity. The entity must not have weak linkage; for example, in C++,
it cannot be applied to a declaration if a definition at that location would be
considered inline.

Not all targets support this attribute. ELF target support depends on both the
linker and runtime linker, and is available in at least lld 4.0 and later,
binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later.
Mach-O targets support it, but with slightly different semantics: the resolver
is run at first call, instead of at load time by the runtime linker. Targets
other than ELF and Mach-O currently do not support this attribute.
Not all targets support this attribute:

- ELF target support depends on both the linker and runtime linker, and is
available in at least lld 4.0 and later, binutils 2.20.1 and later, glibc
v2.11.1 and later, and FreeBSD 9.1 and later.
- Mach-O targets support it, but with slightly different semantics: the resolver
is run at first call, instead of at load time by the runtime linker.
- Windows target supports it on AArch64, but with different semantics: the
``ifunc`` is replaced with a global function pointer, and the call is replaced
with an indirect call. The function pointer is initialized by a constructor
that calls the resolver.
- Baremetal target supports it on AVR.
- Other targets currently do not support this attribute.
}];
}

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,10 @@ class TargetInfo : public TransferrableTargetInfo,
bool supportsIFunc() const {
if (getTriple().isOSBinFormatMachO())
return true;
if (getTriple().isOSWindows() && getTriple().isAArch64())
return true;
if (getTriple().getArch() == llvm::Triple::ArchType::avr)
return true;
return getTriple().isOSBinFormatELF() &&
((getTriple().isOSLinux() && !getTriple().isMusl()) ||
getTriple().isOSFreeBSD());
Expand Down
4 changes: 3 additions & 1 deletion clang/test/CodeGen/attr-ifunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// RUN: %clang_cc1 -triple x86_64-linux -verify -emit-llvm-only -DCHECK_ALIASES %s
// RUN: %clang_cc1 -triple x86_64-linux -verify -emit-llvm-only %s
// RUN: %clang_cc1 -triple x86_64-apple-macosx -verify -emit-llvm-only %s
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -verify -emit-llvm-only %s
// RUN: %clang_cc1 -triple aarch64-pc-windows-msvcu -verify -emit-llvm-only %s

#if defined(_WIN32)
#if defined(_WIN32) && !defined(__aarch64__)
void foo(void) {}
void bar(void) __attribute__((ifunc("foo")));
// expected-warning@-1 {{unknown attribute 'ifunc' ignored}}
Expand Down
65 changes: 65 additions & 0 deletions clang/test/CodeGen/ifunc-win.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -O2 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN

int foo(int) __attribute__ ((ifunc("foo_ifunc")));

static int f1(int i) {
return i + 1;
}

static int f2(int i) {
return i + 2;
}

typedef int (*foo_t)(int);

volatile int global;

static foo_t foo_ifunc(void) {
return global ? f1 : f2;
}

int bar(void) {
return foo(1);
}

extern void goo(void);

void bar2(void) {
goo();
}

extern void goo(void) __attribute__ ((ifunc("goo_ifunc")));

void* goo_ifunc(void) {
return 0;
}

/// The ifunc is emitted after its resolver.
void *hoo_ifunc(void) { return 0; }
extern void hoo(int) __attribute__ ((ifunc("hoo_ifunc")));

/// ifunc on Windows is lowered to global pointers and an indirect call.
// CHECK: @global = dso_local global i32 0, align 4
// CHECK: {{.*}} = internal{{.*}}global{{.*}}poison, align 8
/// Register the constructor for initialisation.
// CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 10, ptr @{{.*}}, ptr null }]

// CHECK-LABEL: @bar()
// CHECK %0 = load ptr, ptr @0, align 8
// CHECK %call = call i32 %0(i32 noundef 1)

// CHECK-LABEL: @bar2()
// CHECK %0 = load ptr, ptr getelementptr inbounds ([3 x ptr], ptr @0, i32 0, i32 1), align 8
// CHECK call void %0()

// CHECK: define internal void @{{.*}}()

// SAN: define {{(dso_local )?}}noalias {{(noundef )?}}ptr @goo_ifunc() {{(local_unnamed_addr )?}}

// SAN: define {{(dso_local )?}}noalias {{(noundef )?}}ptr @hoo_ifunc() {{(local_unnamed_addr )?}}

// SAN: define internal {{(fastcc )?}}{{(noundef )?}}nonnull ptr @foo_ifunc() {{(unnamed_addr )?}}

5 changes: 5 additions & 0 deletions clang/test/CodeGen/ifunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
// RUN: %clang_cc1 -triple arm64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
// RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm -o - %s | FileCheck %s --check-prefix=AVR
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -O2 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN


/// The ifunc is emitted before its resolver.
int foo(int) __attribute__ ((ifunc("foo_ifunc")));
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/CFGuard.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/LowerIFunc.h"
#include "llvm/Transforms/Vectorize/LoopIdiomVectorize.h"
#include <memory>
#include <optional>
Expand Down Expand Up @@ -570,6 +571,11 @@ void AArch64TargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
[=](LoopPassManager &LPM, OptimizationLevel Level) {
LPM.addPass(LoopIdiomVectorizePass());
});
if (getTargetTriple().isOSWindows())
PB.registerPipelineEarlySimplificationEPCallback(
[](ModulePassManager &PM, OptimizationLevel, ThinOrFullLTOPhase) {
PM.addPass(LowerIFuncPass());
});
}

TargetTransformInfo
Expand Down

0 comments on commit 3f40ad7

Please sign in to comment.