1 //===- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer unit tests -===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 11 #include "OrcTestCommon.h" 12 #include "llvm/ExecutionEngine/ExecutionEngine.h" 13 #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 14 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" 15 #include "llvm/ExecutionEngine/Orc/Legacy.h" 16 #include "llvm/ExecutionEngine/Orc/NullResolver.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 }; 31 32 class SectionMemoryManagerWrapper : public SectionMemoryManager { 33 public: 34 int FinalizationCount = 0; 35 int NeedsToReserveAllocationSpaceCount = 0; 36 37 bool needsToReserveAllocationSpace() override { 38 ++NeedsToReserveAllocationSpaceCount; 39 return SectionMemoryManager::needsToReserveAllocationSpace(); 40 } 41 42 bool finalizeMemory(std::string *ErrMsg = nullptr) override { 43 ++FinalizationCount; 44 return SectionMemoryManager::finalizeMemory(ErrMsg); 45 } 46 }; 47 48 TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { 49 class MemoryManagerWrapper : public SectionMemoryManager { 50 public: 51 MemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {} 52 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 53 unsigned SectionID, 54 StringRef SectionName, 55 bool IsReadOnly) override { 56 if (SectionName == ".debug_str") 57 DebugSeen = true; 58 return SectionMemoryManager::allocateDataSection(Size, Alignment, 59 SectionID, 60 SectionName, 61 IsReadOnly); 62 } 63 private: 64 bool &DebugSeen; 65 }; 66 67 bool DebugSectionSeen = false; 68 auto MM = std::make_shared<MemoryManagerWrapper>(DebugSectionSeen); 69 70 SymbolStringPool SSP; 71 ExecutionSession ES(SSP); 72 73 RTDyldObjectLinkingLayer ObjLayer(ES, [&MM](VModuleKey) { 74 return RTDyldObjectLinkingLayer::Resources{ 75 MM, std::make_shared<NullResolver>()}; 76 }); 77 78 LLVMContext Context; 79 auto M = llvm::make_unique<Module>("", Context); 80 M->setTargetTriple("x86_64-unknown-linux-gnu"); 81 Type *Int32Ty = IntegerType::get(Context, 32); 82 GlobalVariable *GV = 83 new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage, 84 ConstantInt::get(Int32Ty, 42), "foo"); 85 86 GV->setSection(".debug_str"); 87 88 89 // Initialize the native target in case this is the first unit test 90 // to try to build a TM. 91 OrcNativeTarget::initialize(); 92 std::unique_ptr<TargetMachine> TM( 93 EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "", 94 SmallVector<std::string, 1>())); 95 if (!TM) 96 return; 97 98 auto Obj = SimpleCompiler(*TM)(*M); 99 100 { 101 // Test with ProcessAllSections = false (the default). 102 auto K = ES.allocateVModule(); 103 cantFail(ObjLayer.addObject( 104 K, MemoryBuffer::getMemBufferCopy(Obj->getBuffer()))); 105 cantFail(ObjLayer.emitAndFinalize(K)); 106 EXPECT_EQ(DebugSectionSeen, false) 107 << "Unexpected debug info section"; 108 cantFail(ObjLayer.removeObject(K)); 109 } 110 111 { 112 // Test with ProcessAllSections = true. 113 ObjLayer.setProcessAllSections(true); 114 auto K = ES.allocateVModule(); 115 cantFail(ObjLayer.addObject(K, std::move(Obj))); 116 cantFail(ObjLayer.emitAndFinalize(K)); 117 EXPECT_EQ(DebugSectionSeen, true) 118 << "Expected debug info section not seen"; 119 cantFail(ObjLayer.removeObject(K)); 120 } 121 } 122 123 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { 124 if (!TM) 125 return; 126 127 SymbolStringPool SSP; 128 ExecutionSession ES(SSP); 129 130 auto MM = std::make_shared<SectionMemoryManagerWrapper>(); 131 132 std::map<orc::VModuleKey, std::shared_ptr<orc::SymbolResolver>> Resolvers; 133 134 RTDyldObjectLinkingLayer ObjLayer(ES, [&](VModuleKey K) { 135 auto I = Resolvers.find(K); 136 assert(I != Resolvers.end() && "Missing resolver"); 137 auto R = std::move(I->second); 138 Resolvers.erase(I); 139 return RTDyldObjectLinkingLayer::Resources{MM, std::move(R)}; 140 }); 141 SimpleCompiler Compile(*TM); 142 143 // Create a pair of modules that will trigger recursive finalization: 144 // Module 1: 145 // int bar() { return 42; } 146 // Module 2: 147 // int bar(); 148 // int foo() { return bar(); } 149 // 150 // Verify that the memory manager is only finalized once (for Module 2). 151 // Failure suggests that finalize is being called on the inner RTDyld 152 // instance (for Module 1) which is unsafe, as it will prevent relocation of 153 // Module 2. 154 155 ModuleBuilder MB1(Context, "", "dummy"); 156 { 157 MB1.getModule()->setDataLayout(TM->createDataLayout()); 158 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar"); 159 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 160 IRBuilder<> Builder(BarEntry); 161 IntegerType *Int32Ty = IntegerType::get(Context, 32); 162 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); 163 Builder.CreateRet(FourtyTwo); 164 } 165 166 auto Obj1 = Compile(*MB1.getModule()); 167 168 ModuleBuilder MB2(Context, "", "dummy"); 169 { 170 MB2.getModule()->setDataLayout(TM->createDataLayout()); 171 Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar"); 172 Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo"); 173 BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl); 174 IRBuilder<> Builder(FooEntry); 175 Builder.CreateRet(Builder.CreateCall(BarDecl)); 176 } 177 auto Obj2 = Compile(*MB2.getModule()); 178 179 auto K1 = ES.allocateVModule(); 180 Resolvers[K1] = std::make_shared<NullResolver>(); 181 cantFail(ObjLayer.addObject(K1, std::move(Obj1))); 182 183 auto K2 = ES.allocateVModule(); 184 auto LegacyLookup = [&](const std::string &Name) { 185 return ObjLayer.findSymbol(Name, true); 186 }; 187 188 Resolvers[K2] = createSymbolResolver( 189 [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) { 190 return cantFail( 191 lookupFlagsWithLegacyFn(SymbolFlags, Symbols, LegacyLookup)); 192 }, 193 [&](std::shared_ptr<AsynchronousSymbolQuery> Query, 194 const SymbolNameSet &Symbols) { 195 return lookupWithLegacyFn(*Query, Symbols, LegacyLookup); 196 }); 197 198 cantFail(ObjLayer.addObject(K2, std::move(Obj2))); 199 cantFail(ObjLayer.emitAndFinalize(K2)); 200 cantFail(ObjLayer.removeObject(K2)); 201 202 // Finalization of module 2 should trigger finalization of module 1. 203 // Verify that finalize on SMMW is only called once. 204 EXPECT_EQ(MM->FinalizationCount, 1) 205 << "Extra call to finalize"; 206 } 207 208 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { 209 if (!TM) 210 return; 211 212 SymbolStringPool SSP; 213 ExecutionSession ES(SSP); 214 215 auto MM = std::make_shared<SectionMemoryManagerWrapper>(); 216 217 RTDyldObjectLinkingLayer ObjLayer(ES, [&MM](VModuleKey K) { 218 return RTDyldObjectLinkingLayer::Resources{ 219 MM, std::make_shared<NullResolver>()}; 220 }); 221 SimpleCompiler Compile(*TM); 222 223 // Create a pair of unrelated modules: 224 // 225 // Module 1: 226 // int foo() { return 42; } 227 // Module 2: 228 // int bar() { return 7; } 229 // 230 // Both modules will share a memory manager. We want to verify that the 231 // second object is not loaded before the first one is finalized. To do this 232 // in a portable way, we abuse the 233 // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is 234 // called once per object before any sections are allocated. 235 236 ModuleBuilder MB1(Context, "", "dummy"); 237 { 238 MB1.getModule()->setDataLayout(TM->createDataLayout()); 239 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo"); 240 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 241 IRBuilder<> Builder(BarEntry); 242 IntegerType *Int32Ty = IntegerType::get(Context, 32); 243 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); 244 Builder.CreateRet(FourtyTwo); 245 } 246 247 auto Obj1 = Compile(*MB1.getModule()); 248 249 ModuleBuilder MB2(Context, "", "dummy"); 250 { 251 MB2.getModule()->setDataLayout(TM->createDataLayout()); 252 Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar"); 253 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 254 IRBuilder<> Builder(BarEntry); 255 IntegerType *Int32Ty = IntegerType::get(Context, 32); 256 Value *Seven = ConstantInt::getSigned(Int32Ty, 7); 257 Builder.CreateRet(Seven); 258 } 259 auto Obj2 = Compile(*MB2.getModule()); 260 261 auto K = ES.allocateVModule(); 262 cantFail(ObjLayer.addObject(K, std::move(Obj1))); 263 cantFail(ObjLayer.addObject(ES.allocateVModule(), std::move(Obj2))); 264 cantFail(ObjLayer.emitAndFinalize(K)); 265 cantFail(ObjLayer.removeObject(K)); 266 267 // Only one call to needsToReserveAllocationSpace should have been made. 268 EXPECT_EQ(MM->NeedsToReserveAllocationSpaceCount, 1) 269 << "More than one call to needsToReserveAllocationSpace " 270 "(multiple unrelated objects loaded prior to finalization)"; 271 } 272 273 TEST_F(RTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) { 274 SymbolStringPool SSP; 275 ExecutionSession ES(SSP); 276 RTDyldObjectLinkingLayer ObjLayer( 277 ES, 278 [](VModuleKey) { 279 return RTDyldObjectLinkingLayer::Resources{ 280 nullptr, std::make_shared<NullResolver>()}; 281 }, 282 [](VModuleKey, const object::ObjectFile &obj, 283 const RuntimeDyld::LoadedObjectInfo &info) {}); 284 } 285 286 } // end anonymous namespace 287