summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2017-03-23 11:14:27 +0000
committerAlex Lorenz <arphaman@gmail.com>2017-03-23 11:14:27 +0000
commita8fbef44fe2347942e2eb76e5b9144d74b5bdc7e (patch)
tree9bcd3977f509cd765829e2709c130b00fc8994fb /clang/lib/CodeGen
parent5ffe4e14f1e3476776663840af9b551caf6466c3 (diff)
downloadbcm5719-llvm-a8fbef44fe2347942e2eb76e5b9144d74b5bdc7e.tar.gz
bcm5719-llvm-a8fbef44fe2347942e2eb76e5b9144d74b5bdc7e.zip
[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 llvm-svn: 298588
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp33
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp1
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h4
3 files changed, 38 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index 4954a0d1238..4af5af93248 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -3416,4 +3416,37 @@ CodeGenFunction::EmitBuiltinAvailable(ArrayRef<llvm::Value *> Args) {
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() {}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index ca1850e1043..89ee7fc74c3 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -414,6 +414,7 @@ void CodeGenModule::Release() {
CoverageMapping->emit();
if (CodeGenOpts.SanitizeCfiCrossDso)
CodeGenFunction(*this).EmitCfiCheckFail();
+ emitAtAvailableLinkGuard();
emitLLVMUsed();
if (SanStats)
SanStats->finish();
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 1d59230c2c2..5c9dd965e85 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -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();
OpenPOWER on IntegriCloud