1 //===--- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer tests ---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "OrcTestCommon.h" 10 #include "llvm/ExecutionEngine/ExecutionEngine.h" 11 #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 12 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 13 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" 14 #include "llvm/ExecutionEngine/Orc/Legacy.h" 15 #include "llvm/ExecutionEngine/Orc/NullResolver.h" 16 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 17 #include "llvm/ExecutionEngine/SectionMemoryManager.h" 18 #include "llvm/IR/Constants.h" 19 #include "llvm/IR/LLVMContext.h" 20 #include "gtest/gtest.h" 21 22 using namespace llvm; 23 using namespace llvm::orc; 24 25 namespace { 26 27 class RTDyldObjectLinkingLayerExecutionTest : public testing::Test, 28 public OrcExecutionTest {}; 29 30 // Adds an object with a debug section to RuntimeDyld and then returns whether 31 // the debug section was passed to the memory manager. 32 static bool testSetProcessAllSections(std::unique_ptr<MemoryBuffer> Obj, 33 bool ProcessAllSections) { 34 class MemoryManagerWrapper : public SectionMemoryManager { 35 public: 36 MemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {} 37 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 38 unsigned SectionID, StringRef SectionName, 39 bool IsReadOnly) override { 40 if (SectionName == ".debug_str") 41 DebugSeen = true; 42 return SectionMemoryManager::allocateDataSection( 43 Size, Alignment, SectionID, SectionName, IsReadOnly); 44 } 45 46 private: 47 bool &DebugSeen; 48 }; 49 50 bool DebugSectionSeen = false; 51 52 ExecutionSession ES; 53 auto &JD = ES.createJITDylib("main"); 54 auto Foo = ES.intern("foo"); 55 56 RTDyldObjectLinkingLayer ObjLayer(ES, [&DebugSectionSeen]() { 57 return llvm::make_unique<MemoryManagerWrapper>(DebugSectionSeen); 58 }); 59 60 auto OnResolveDoNothing = [](Expected<SymbolMap> R) { 61 cantFail(std::move(R)); 62 }; 63 64 auto OnReadyDoNothing = [](Error Err) { cantFail(std::move(Err)); }; 65 66 ObjLayer.setProcessAllSections(ProcessAllSections); 67 cantFail(ObjLayer.add(JD, std::move(Obj), ES.allocateVModule())); 68 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, OnResolveDoNothing, 69 OnReadyDoNothing, NoDependenciesToRegister); 70 return DebugSectionSeen; 71 } 72 73 TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { 74 LLVMContext Context; 75 auto M = llvm::make_unique<Module>("", Context); 76 M->setTargetTriple("x86_64-unknown-linux-gnu"); 77 Type *Int32Ty = IntegerType::get(Context, 32); 78 GlobalVariable *GV = 79 new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage, 80 ConstantInt::get(Int32Ty, 42), "foo"); 81 82 GV->setSection(".debug_str"); 83 84 // Initialize the native target in case this is the first unit test 85 // to try to build a TM. 86 OrcNativeTarget::initialize(); 87 std::unique_ptr<TargetMachine> TM(EngineBuilder().selectTarget( 88 Triple(M->getTargetTriple()), "", "", SmallVector<std::string, 1>())); 89 if (!TM) 90 return; 91 92 auto Obj = SimpleCompiler(*TM)(*M); 93 94 EXPECT_FALSE(testSetProcessAllSections( 95 MemoryBuffer::getMemBufferCopy(Obj->getBuffer()), false)) 96 << "Debug section seen despite ProcessAllSections being false"; 97 EXPECT_TRUE(testSetProcessAllSections(std::move(Obj), true)) 98 << "Expected to see debug section when ProcessAllSections is true"; 99 } 100 101 TEST(RTDyldObjectLinkingLayerTest, TestOverrideObjectFlags) { 102 103 OrcNativeTarget::initialize(); 104 105 std::unique_ptr<TargetMachine> TM( 106 EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "", 107 SmallVector<std::string, 1>())); 108 109 if (!TM) 110 return; 111 112 // Our compiler is going to modify symbol visibility settings without telling 113 // ORC. This will test our ability to override the flags later. 114 class FunkySimpleCompiler : public SimpleCompiler { 115 public: 116 FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {} 117 118 CompileResult operator()(Module &M) { 119 auto *Foo = M.getFunction("foo"); 120 assert(Foo && "Expected function Foo not found"); 121 Foo->setVisibility(GlobalValue::HiddenVisibility); 122 return SimpleCompiler::operator()(M); 123 } 124 }; 125 126 // Create a module with two void() functions: foo and bar. 127 ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>()); 128 ThreadSafeModule M; 129 { 130 ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy"); 131 MB.getModule()->setDataLayout(TM->createDataLayout()); 132 133 Function *FooImpl = MB.createFunctionDecl( 134 FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false), 135 "foo"); 136 BasicBlock *FooEntry = 137 BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl); 138 IRBuilder<> B1(FooEntry); 139 B1.CreateRetVoid(); 140 141 Function *BarImpl = MB.createFunctionDecl( 142 FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false), 143 "bar"); 144 BasicBlock *BarEntry = 145 BasicBlock::Create(*TSCtx.getContext(), "entry", BarImpl); 146 IRBuilder<> B2(BarEntry); 147 B2.CreateRetVoid(); 148 149 M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx)); 150 } 151 152 // Create a simple stack and set the override flags option. 153 ExecutionSession ES; 154 auto &JD = ES.createJITDylib("main"); 155 auto Foo = ES.intern("foo"); 156 RTDyldObjectLinkingLayer ObjLayer( 157 ES, []() { return llvm::make_unique<SectionMemoryManager>(); }); 158 IRCompileLayer CompileLayer(ES, ObjLayer, FunkySimpleCompiler(*TM)); 159 160 ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true); 161 162 cantFail(CompileLayer.add(JD, std::move(M), ES.allocateVModule())); 163 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, 164 [](Expected<SymbolMap> R) { cantFail(std::move(R)); }, 165 [](Error Err) { cantFail(std::move(Err)); }, 166 NoDependenciesToRegister); 167 } 168 169 TEST(RTDyldObjectLinkingLayerTest, TestAutoClaimResponsibilityForSymbols) { 170 171 OrcNativeTarget::initialize(); 172 173 std::unique_ptr<TargetMachine> TM( 174 EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "", 175 SmallVector<std::string, 1>())); 176 177 if (!TM) 178 return; 179 180 // Our compiler is going to add a new symbol without telling ORC. 181 // This will test our ability to auto-claim responsibility later. 182 class FunkySimpleCompiler : public SimpleCompiler { 183 public: 184 FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {} 185 186 CompileResult operator()(Module &M) { 187 Function *BarImpl = Function::Create( 188 FunctionType::get(Type::getVoidTy(M.getContext()), {}, false), 189 GlobalValue::ExternalLinkage, "bar", &M); 190 BasicBlock *BarEntry = 191 BasicBlock::Create(M.getContext(), "entry", BarImpl); 192 IRBuilder<> B(BarEntry); 193 B.CreateRetVoid(); 194 195 return SimpleCompiler::operator()(M); 196 } 197 }; 198 199 // Create a module with two void() functions: foo and bar. 200 ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>()); 201 ThreadSafeModule M; 202 { 203 ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy"); 204 MB.getModule()->setDataLayout(TM->createDataLayout()); 205 206 Function *FooImpl = MB.createFunctionDecl( 207 FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false), 208 "foo"); 209 BasicBlock *FooEntry = 210 BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl); 211 IRBuilder<> B(FooEntry); 212 B.CreateRetVoid(); 213 214 M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx)); 215 } 216 217 // Create a simple stack and set the override flags option. 218 ExecutionSession ES; 219 auto &JD = ES.createJITDylib("main"); 220 auto Foo = ES.intern("foo"); 221 RTDyldObjectLinkingLayer ObjLayer( 222 ES, []() { return llvm::make_unique<SectionMemoryManager>(); }); 223 IRCompileLayer CompileLayer(ES, ObjLayer, FunkySimpleCompiler(*TM)); 224 225 ObjLayer.setAutoClaimResponsibilityForObjectSymbols(true); 226 227 cantFail(CompileLayer.add(JD, std::move(M), ES.allocateVModule())); 228 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, 229 [](Expected<SymbolMap> R) { cantFail(std::move(R)); }, 230 [](Error Err) { cantFail(std::move(Err)); }, 231 NoDependenciesToRegister); 232 } 233 234 } // end anonymous namespace 235