Skip to content

Commit 890571f

Browse files
committed
Support __attribute__((ifunc(...))) on Darwin platforms
Unlike ELF targets, MachO does not support the same kind of dynamic symbol resolution at load time. Instead, the corresponding MachO feature resolves symbols lazily on first call. Reviewers: JDevlieghere, dmpolukhin, ahmedbougacha, tahonermann, echristo, MaskRay, erichkeane Reviewed By: MaskRay, echristo, ahmedbougacha Pull Request: llvm#73687
1 parent 4f55f45 commit 890571f

File tree

8 files changed

+70
-2
lines changed

8 files changed

+70
-2
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch6
450450
def TargetELF : TargetSpec {
451451
let ObjectFormats = ["ELF"];
452452
}
453+
def TargetELFOrMachO : TargetSpec {
454+
let ObjectFormats = ["ELF", "MachO"];
455+
}
453456

454457
def TargetSupportsInitPriority : TargetSpec {
455458
let CustomCode = [{ !Target.getTriple().isOSzOS() }];
@@ -1613,7 +1616,7 @@ def IBOutletCollection : InheritableAttr {
16131616
let Documentation = [Undocumented];
16141617
}
16151618

1616-
def IFunc : Attr, TargetSpecificAttr<TargetELF> {
1619+
def IFunc : Attr, TargetSpecificAttr<TargetELFOrMachO> {
16171620
let Spellings = [GCC<"ifunc">];
16181621
let Args = [StringArgument<"Resolver">];
16191622
let Subjects = SubjectList<[Function]>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5563,7 +5563,9 @@ considered inline.
55635563
Not all targets support this attribute. ELF target support depends on both the
55645564
linker and runtime linker, and is available in at least lld 4.0 and later,
55655565
binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later.
5566-
Non-ELF targets currently do not support this attribute.
5566+
Mach-O targets support it, but with slightly different semantics: the resolver
5567+
is run at first call, instead of at load time by the runtime linker. Targets
5568+
other than ELF and Mach-O currently do not support this attribute.
55675569
}];
55685570
}
55695571

clang/test/CodeGen/attr-ifunc.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %clang_cc1 -triple x86_64-windows -fsyntax-only -verify %s
22
// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only -DCHECK_ALIASES %s
33
// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s
4+
// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s
45

56
#if defined(_WIN32)
67
void foo(void) {}
@@ -36,6 +37,25 @@ void *f6_resolver(void) __attribute__((ifunc("f6_resolver_resolver")));
3637
void f6(void) __attribute__((ifunc("f6_resolver")));
3738
// expected-error@-1 {{ifunc must point to a defined function}}
3839

40+
#elif defined(__APPLE__)
41+
42+
// NOTE: aliases are not supported on Darwin, so the above tests are not relevant.
43+
44+
#define STR2(X) #X
45+
#define STR(X) STR2(X)
46+
#define PREFIX STR(__USER_LABEL_PREFIX__)
47+
48+
void f1a(void) __asm("f1");
49+
void f1a(void) {}
50+
// expected-note@-1 {{previous definition is here}}
51+
void f1(void) __attribute__((ifunc(PREFIX "f1_ifunc"))) __asm("f1");
52+
// expected-error@-1 {{definition with same mangled name '<U+0001>f1' as another definition}}
53+
void *f1_ifunc(void) { return 0; }
54+
55+
void *f6_ifunc(int i);
56+
void __attribute__((ifunc(PREFIX "f6_ifunc"))) f6(void) {}
57+
// expected-error@-1 {{definition 'f6' cannot also be an ifunc}}
58+
3959
#else
4060
void f1a(void) __asm("f1");
4161
void f1a(void) {}

clang/test/CodeGen/attr-ifunc.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s
2+
// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s
3+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s
24
// RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
5+
// RUN: not %clang_cc1 -triple x86_64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
6+
// RUN: not %clang_cc1 -triple arm64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
37

48
void *f1_ifunc(void) { return nullptr; }
59
void f1(void) __attribute__((ifunc("f1_ifunc")));

clang/test/CodeGen/ifunc.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
22
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -O2 -emit-llvm -o - %s | FileCheck %s
3+
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
4+
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
5+
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=memory -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
6+
// RUN: %clang_cc1 -triple arm64-apple-macosx -emit-llvm -o - %s | FileCheck %s
7+
// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s
8+
// RUN: %clang_cc1 -triple arm64-apple-macosx -O2 -emit-llvm -o - %s | FileCheck %s
9+
// RUN: %clang_cc1 -triple x86_64-apple-macosx -O2 -emit-llvm -o - %s | FileCheck %s
10+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN
11+
// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN
12+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN
13+
// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN
314

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

@@ -39,3 +50,9 @@ void* goo_ifunc(void) {
3950

4051
// CHECK: call i32 @foo(i32
4152
// CHECK: call void @goo()
53+
54+
// SAN: define internal nonnull ptr @foo_ifunc() #[[#FOO_IFUNC:]] {
55+
// MACSAN: define internal nonnull ptr @foo_ifunc() #[[#FOO_IFUNC:]] {
56+
57+
// SAN: define dso_local noalias ptr @goo_ifunc() #[[#GOO_IFUNC:]] {
58+
// MACSAN: define noalias ptr @goo_ifunc() #[[#GOO_IFUNC:]] {

clang/test/CodeGenCXX/externc-ifunc-resolver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s
3+
// RUN: %clang_cc1 -triple arm64-apple-macosx -emit-llvm -o - %s | FileCheck %s
24

35
extern "C" {
46
__attribute__((used)) static void *resolve_foo() { return 0; }

clang/test/SemaCXX/externc-ifunc-resolver.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-linux-gnu -verify %s
2+
// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-apple-macosx -verify %s
3+
// RUN: %clang_cc1 -emit-llvm-only -triple arm64-apple-macosx -verify %s
24
// RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
5+
// RUN: not %clang_cc1 -triple x86_64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
6+
// RUN: not %clang_cc1 -triple arm64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
37

48
extern "C" {
59
__attribute__((used)) static void *resolve_foo() { return 0; }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-linux-gnu -verify %s -DSUPPORTED=1
2+
// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-apple-macosx -verify %s -DSUPPORTED=1
3+
// RUN: %clang_cc1 -emit-llvm-only -triple arm64-apple-macosx -verify %s -DSUPPORTED=1
4+
// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-pc-win32 -verify %s -DNOT_SUPPORTED=1
5+
6+
// expected-no-diagnostics
7+
8+
#if __has_attribute(ifunc)
9+
# if NOT_SUPPORTED
10+
# error "ifunc appears to be supported on this platform, but shouldn't be"
11+
# endif
12+
#else
13+
# if SUPPORTED
14+
# error "ifunc should be supported on this platform, but isn't"
15+
# endif
16+
#endif

0 commit comments

Comments
 (0)