From 5265adc73721963d3bf605a7ad5eab6a7e0850b8 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Tue, 24 Jan 2023 11:51:22 +0100 Subject: [SanitizerBinaryMetadata] Declare callbacks extern weak Declare callbacks extern weak (if no existing declaration exists), and only call if the function address is non-null. This allows to attach semantic metadata to binaries where no user of that metadata exists, avoiding to have to link empty stub callbacks. Once the binary is linked (statically or dynamically) against a tool runtime that implements the callbacks, the respective callbacks will be called. This vastly simplifies gradual deployment of tools using the metadata, esp. avoiding having to recompile large codebases with different compiler flags (which negatively impacts compiler caches). Reviewed By: dvyukov, vitalybuka Differential Revision: https://reviews.llvm.org/D142408 --- llvm/lib/Transforms/Utils/ModuleUtils.cpp | 53 +++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 13 deletions(-) (limited to 'llvm/lib/Transforms/Utils/ModuleUtils.cpp') diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp index 5148df5..6d17a466 100644 --- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp +++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp @@ -170,14 +170,17 @@ void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) { } } -FunctionCallee -llvm::declareSanitizerInitFunction(Module &M, StringRef InitName, - ArrayRef InitArgTypes) { +FunctionCallee llvm::declareSanitizerInitFunction(Module &M, StringRef InitName, + ArrayRef InitArgTypes, + bool Weak) { assert(!InitName.empty() && "Expected init function name"); - return M.getOrInsertFunction( - InitName, - FunctionType::get(Type::getVoidTy(M.getContext()), InitArgTypes, false), - AttributeList()); + auto *VoidTy = Type::getVoidTy(M.getContext()); + auto *FnTy = FunctionType::get(VoidTy, InitArgTypes, false); + auto FnCallee = M.getOrInsertFunction(InitName, FnTy); + auto *Fn = cast(FnCallee.getCallee()); + if (Weak && Fn->isDeclaration()) + Fn->setLinkage(Function::ExternalWeakLinkage); + return FnCallee; } Function *llvm::createSanitizerCtor(Module &M, StringRef CtorName) { @@ -197,14 +200,33 @@ Function *llvm::createSanitizerCtor(Module &M, StringRef CtorName) { std::pair llvm::createSanitizerCtorAndInitFunctions( Module &M, StringRef CtorName, StringRef InitName, ArrayRef InitArgTypes, ArrayRef InitArgs, - StringRef VersionCheckName) { + StringRef VersionCheckName, bool Weak) { assert(!InitName.empty() && "Expected init function name"); assert(InitArgs.size() == InitArgTypes.size() && "Sanitizer's init function expects different number of arguments"); FunctionCallee InitFunction = - declareSanitizerInitFunction(M, InitName, InitArgTypes); + declareSanitizerInitFunction(M, InitName, InitArgTypes, Weak); Function *Ctor = createSanitizerCtor(M, CtorName); - IRBuilder<> IRB(Ctor->getEntryBlock().getTerminator()); + IRBuilder<> IRB(M.getContext()); + + BasicBlock *RetBB = &Ctor->getEntryBlock(); + if (Weak) { + RetBB->setName("ret"); + auto *EntryBB = BasicBlock::Create(M.getContext(), "entry", Ctor, RetBB); + auto *CallInitBB = + BasicBlock::Create(M.getContext(), "callfunc", Ctor, RetBB); + auto *InitFn = cast(InitFunction.getCallee()); + auto *InitFnPtr = + PointerType::get(InitFn->getType(), InitFn->getAddressSpace()); + IRB.SetInsertPoint(EntryBB); + Value *InitNotNull = + IRB.CreateICmpNE(InitFn, ConstantPointerNull::get(InitFnPtr)); + IRB.CreateCondBr(InitNotNull, CallInitBB, RetBB); + IRB.SetInsertPoint(CallInitBB); + } else { + IRB.SetInsertPoint(RetBB->getTerminator()); + } + IRB.CreateCall(InitFunction, InitArgs); if (!VersionCheckName.empty()) { FunctionCallee VersionCheckFunction = M.getOrInsertFunction( @@ -212,6 +234,10 @@ std::pair llvm::createSanitizerCtorAndInitFunctions( AttributeList()); IRB.CreateCall(VersionCheckFunction, {}); } + + if (Weak) + IRB.CreateBr(RetBB); + return std::make_pair(Ctor, InitFunction); } @@ -220,7 +246,7 @@ llvm::getOrCreateSanitizerCtorAndInitFunctions( Module &M, StringRef CtorName, StringRef InitName, ArrayRef InitArgTypes, ArrayRef InitArgs, function_ref FunctionsCreatedCallback, - StringRef VersionCheckName) { + StringRef VersionCheckName, bool Weak) { assert(!CtorName.empty() && "Expected ctor function name"); if (Function *Ctor = M.getFunction(CtorName)) @@ -228,12 +254,13 @@ llvm::getOrCreateSanitizerCtorAndInitFunctions( // globals. This will make moving to a concurrent model much easier. if (Ctor->arg_empty() || Ctor->getReturnType() == Type::getVoidTy(M.getContext())) - return {Ctor, declareSanitizerInitFunction(M, InitName, InitArgTypes)}; + return {Ctor, + declareSanitizerInitFunction(M, InitName, InitArgTypes, Weak)}; Function *Ctor; FunctionCallee InitFunction; std::tie(Ctor, InitFunction) = llvm::createSanitizerCtorAndInitFunctions( - M, CtorName, InitName, InitArgTypes, InitArgs, VersionCheckName); + M, CtorName, InitName, InitArgTypes, InitArgs, VersionCheckName, Weak); FunctionsCreatedCallback(Ctor, InitFunction); return std::make_pair(Ctor, InitFunction); } -- cgit v1.1