r298588 - [CodeGen] Emit a CoreFoundation link guard when @available is used
Alex Lorenz via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 23 04:14:28 PDT 2017
Author: arphaman
Date: Thu Mar 23 06:14:27 2017
New Revision: 298588
URL: http://llvm.org/viewvc/llvm-project?rev=298588&view=rev
Log:
[CodeGen] Emit a CoreFoundation link guard when @available is used
After r297760, __isOSVersionAtLeast in compiler-rt loads the CoreFoundation
symbols at runtime. This means that `@available` will always fail when used in a
binary without a linked CoreFoundation.
This commit forces Clang to emit a reference to a CoreFoundation symbol when
`@available` is used to ensure that linking will fail when CoreFoundation isn't
linked with the build product.
rdar://31039592
Differential Revision: https://reviews.llvm.org/D30977
Added:
cfe/trunk/test/CodeGenObjC/availability-cf-link-guard.m
Modified:
cfe/trunk/lib/CodeGen/CGObjC.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.h
Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=298588&r1=298587&r2=298588&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Thu Mar 23 06:14:27 2017
@@ -3416,4 +3416,37 @@ CodeGenFunction::EmitBuiltinAvailable(Ar
return Builder.CreateICmpNE(CallRes, llvm::Constant::getNullValue(Int32Ty));
}
+void CodeGenModule::emitAtAvailableLinkGuard() {
+ if (!IsOSVersionAtLeastFn)
+ return;
+ // @available requires CoreFoundation only on Darwin.
+ if (!Target.getTriple().isOSDarwin())
+ return;
+ // Add -framework CoreFoundation to the linker commands. We still want to
+ // emit the core foundation reference down below because otherwise if
+ // CoreFoundation is not used in the code, the linker won't link the
+ // framework.
+ auto &Context = getLLVMContext();
+ llvm::Metadata *Args[2] = {llvm::MDString::get(Context, "-framework"),
+ llvm::MDString::get(Context, "CoreFoundation")};
+ LinkerOptionsMetadata.push_back(llvm::MDNode::get(Context, Args));
+ // Emit a reference to a symbol from CoreFoundation to ensure that
+ // CoreFoundation is linked into the final binary.
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(Int32Ty, {VoidPtrTy}, false);
+ llvm::Constant *CFFunc =
+ CreateRuntimeFunction(FTy, "CFBundleGetVersionNumber");
+
+ llvm::FunctionType *CheckFTy = llvm::FunctionType::get(VoidTy, {}, false);
+ llvm::Function *CFLinkCheckFunc = cast<llvm::Function>(CreateBuiltinFunction(
+ CheckFTy, "__clang_at_available_requires_core_foundation_framework"));
+ CFLinkCheckFunc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+ CFLinkCheckFunc->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ CodeGenFunction CGF(*this);
+ CGF.Builder.SetInsertPoint(CGF.createBasicBlock("", CFLinkCheckFunc));
+ CGF.EmitNounwindRuntimeCall(CFFunc, llvm::Constant::getNullValue(VoidPtrTy));
+ CGF.Builder.CreateUnreachable();
+ addCompilerUsedGlobal(CFLinkCheckFunc);
+}
+
CGObjCRuntime::~CGObjCRuntime() {}
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=298588&r1=298587&r2=298588&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Thu Mar 23 06:14:27 2017
@@ -414,6 +414,7 @@ void CodeGenModule::Release() {
CoverageMapping->emit();
if (CodeGenOpts.SanitizeCfiCrossDso)
CodeGenFunction(*this).EmitCfiCheckFail();
+ emitAtAvailableLinkGuard();
emitLLVMUsed();
if (SanStats)
SanStats->finish();
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=298588&r1=298587&r2=298588&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Thu Mar 23 06:14:27 2017
@@ -1286,6 +1286,10 @@ private:
/// Emit any vtables which we deferred and still have a use for.
void EmitDeferredVTables();
+ /// Emit a dummy function that reference a CoreFoundation symbol when
+ /// @available is used on Darwin.
+ void emitAtAvailableLinkGuard();
+
/// Emit the llvm.used and llvm.compiler.used metadata.
void emitLLVMUsed();
Added: cfe/trunk/test/CodeGenObjC/availability-cf-link-guard.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/availability-cf-link-guard.m?rev=298588&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/availability-cf-link-guard.m (added)
+++ cfe/trunk/test/CodeGenObjC/availability-cf-link-guard.m Thu Mar 23 06:14:27 2017
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,CHECK_LINK_OPT %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - -D USE_BUILTIN %s | FileCheck --check-prefixes=CHECK,CHECK_LINK_OPT %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - -D DEF_CF %s | FileCheck --check-prefixes=CHECK_CF,CHECK_LINK_OPT %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK_NO_GUARD %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -emit-llvm -o - %s | FileCheck --check-prefix=CHECK_NO_GUARD %s
+
+#ifdef DEF_CF
+struct CFBundle;
+typedef struct CFBundle *CFBundleRef;
+unsigned CFBundleGetVersionNumber(CFBundleRef bundle);
+// CHECK_CF: declare i32 @CFBundleGetVersionNumber(%struct.CFBundle*)
+// CHECK_CF: @__clang_at_available_requires_core_foundation_framework
+// CHECK_CF-NEXT: call {{.*}}@CFBundleGetVersionNumber
+#endif
+
+void use_at_available() {
+#ifdef DEF_CF
+ CFBundleGetVersionNumber(0);
+#endif
+#ifdef USE_BUILTIN
+ if (__builtin_available(macos 10.12, *))
+ ;
+#else
+ if (@available(macos 10.12, *))
+ ;
+#endif
+}
+
+// CHECK: @llvm.compiler.used{{.*}}@__clang_at_available_requires_core_foundation_framework
+
+// CHECK: declare i32 @CFBundleGetVersionNumber(i8*)
+
+// CHECK-LABEL: linkonce hidden void @__clang_at_available_requires_core_foundation_framework
+// CHECK: call i32 @CFBundleGetVersionNumber(i8* null)
+// CHECK-NEXT: unreachable
+
+// CHECK_NO_GUARD-NOT: __clang_at_available_requires_core_foundation_framework
+// CHECK_NO_GUARD-NOT: CFBundleGetVersionNumber
+
+// CHECK_LINK_OPT: !"Linker Options", ![[OPTS:[0-9]+]]
+// CHECK_LINK_OPT: ![[OPTS]] = !{![[FRAMEWORK:[0-9]+]]
+// CHECK_LINK_OPT: ![[FRAMEWORK]] = !{!"-framework", !"CoreFoundation"}
+
+// CHECK_NO_GUARD-NOT: "Linker Options"
+// CHECK_NO_GUARD-NOT: CoreFoundation
More information about the cfe-commits
mailing list