Skip to content

Commit acf9aa3

Browse files
authored
[clang] 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: #73687
1 parent 640c1d3 commit acf9aa3

File tree

8 files changed

+65
-2
lines changed

8 files changed

+65
-2
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,9 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch6
455455
def TargetELF : TargetSpec {
456456
let ObjectFormats = ["ELF"];
457457
}
458+
def TargetELFOrMachO : TargetSpec {
459+
let ObjectFormats = ["ELF", "MachO"];
460+
}
458461

459462
def TargetSupportsInitPriority : TargetSpec {
460463
let CustomCode = [{ !Target.getTriple().isOSzOS() }];
@@ -1665,7 +1668,7 @@ def IBOutletCollection : InheritableAttr {
16651668
let Documentation = [Undocumented];
16661669
}
16671670

1668-
def IFunc : Attr, TargetSpecificAttr<TargetELF> {
1671+
def IFunc : Attr, TargetSpecificAttr<TargetELFOrMachO> {
16691672
let Spellings = [GCC<"ifunc">];
16701673
let Args = [StringArgument<"Resolver">];
16711674
let Subjects = SubjectList<[Function]>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5535,7 +5535,9 @@ considered inline.
55355535
Not all targets support this attribute. ELF target support depends on both the
55365536
linker and runtime linker, and is available in at least lld 4.0 and later,
55375537
binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later.
5538-
Non-ELF targets currently do not support this attribute.
5538+
Mach-O targets support it, but with slightly different semantics: the resolver
5539+
is run at first call, instead of at load time by the runtime linker. Targets
5540+
other than ELF and Mach-O currently do not support this attribute.
55395541
}];
55405542
}
55415543

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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
44
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
55
// 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
614

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

@@ -44,9 +52,13 @@ void* goo_ifunc(void) {
4452
// CHECK: call void @goo()
4553

4654
// SAN: define internal nonnull ptr @foo_ifunc() #[[#FOO_IFUNC:]] {
55+
// MACSAN: define internal nonnull ptr @foo_ifunc() #[[#FOO_IFUNC:]] {
4756

4857
// SAN: define dso_local noalias ptr @goo_ifunc() #[[#GOO_IFUNC:]] {
58+
// MACSAN: define noalias ptr @goo_ifunc() #[[#GOO_IFUNC:]] {
4959

5060
// SAN-DAG: attributes #[[#FOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}}
61+
// MACSAN-DAG: attributes #[[#FOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}}
5162

5263
// SAN-DAG: attributes #[[#GOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}}
64+
// MACSAN-DAG: attributes #[[#GOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}}

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)