diff options
author | Alex Lorenz <arphaman@gmail.com> | 2017-03-23 11:14:27 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2017-03-23 11:14:27 +0000 |
commit | a8fbef44fe2347942e2eb76e5b9144d74b5bdc7e (patch) | |
tree | 9bcd3977f509cd765829e2709c130b00fc8994fb /clang/lib/CodeGen/CGObjC.cpp | |
parent | 5ffe4e14f1e3476776663840af9b551caf6466c3 (diff) | |
download | bcm5719-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/CGObjC.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 33 |
1 files changed, 33 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() {} |