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( 74 ES, [&MM](VModuleKey) { return MM; }, 75 [](orc::VModuleKey) { return std::make_shared<NullResolver>(); }); 76 77 LLVMContext Context; 78 auto M = llvm::make_unique<Module>("", Context); 79 M->setTargetTriple("x86_64-unknown-linux-gnu"); 80 Type *Int32Ty = IntegerType::get(Context, 32); 81 GlobalVariable *GV = 82 new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage, 83 ConstantInt::get(Int32Ty, 42), "foo"); 84 85 GV->setSection(".debug_str"); 86 87 88 // Initialize the native target in case this is the first unit test 89 // to try to build a TM. 90 OrcNativeTarget::initialize(); 91 std::unique_ptr<TargetMachine> TM( 92 EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "", 93 SmallVector<std::string, 1>())); 94 if (!TM) 95 return; 96 97 auto Obj = 98 std::make_shared<object::OwningBinary<object::ObjectFile>>( 99 SimpleCompiler(*TM)(*M)); 100 101 { 102 // Test with ProcessAllSections = false (the default). 103 auto K = ES.allocateVModule(); 104 cantFail(ObjLayer.addObject(K, Obj)); 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, 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, [&MM](VModuleKey) { return MM; }, 135 [&](VModuleKey K) { 136 auto I = Resolvers.find(K); 137 assert(I != Resolvers.end() && 138 "Missing resolver"); 139 auto R = std::move(I->second); 140 Resolvers.erase(I); 141 return R; 142 }); 143 SimpleCompiler Compile(*TM); 144 145 // Create a pair of modules that will trigger recursive finalization: 146 // Module 1: 147 // int bar() { return 42; } 148 // Module 2: 149 // int bar(); 150 // int foo() { return bar(); } 151 // 152 // Verify that the memory manager is only finalized once (for Module 2). 153 // Failure suggests that finalize is being called on the inner RTDyld 154 // instance (for Module 1) which is unsafe, as it will prevent relocation of 155 // Module 2. 156 157 ModuleBuilder MB1(Context, "", "dummy"); 158 { 159 MB1.getModule()->setDataLayout(TM->createDataLayout()); 160 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar"); 161 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 162 IRBuilder<> Builder(BarEntry); 163 IntegerType *Int32Ty = IntegerType::get(Context, 32); 164 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); 165 Builder.CreateRet(FourtyTwo); 166 } 167 168 auto Obj1 = 169 std::make_shared<object::OwningBinary<object::ObjectFile>>( 170 Compile(*MB1.getModule())); 171 172 ModuleBuilder MB2(Context, "", "dummy"); 173 { 174 MB2.getModule()->setDataLayout(TM->createDataLayout()); 175 Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar"); 176 Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo"); 177 BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl); 178 IRBuilder<> Builder(FooEntry); 179 Builder.CreateRet(Builder.CreateCall(BarDecl)); 180 } 181 auto Obj2 = 182 std::make_shared<object::OwningBinary<object::ObjectFile>>( 183 Compile(*MB2.getModule())); 184 185 auto K1 = ES.allocateVModule(); 186 Resolvers[K1] = std::make_shared<NullResolver>(); 187 cantFail(ObjLayer.addObject(K1, std::move(Obj1))); 188 189 auto K2 = ES.allocateVModule(); 190 auto LegacyLookup = [&](const std::string &Name) { 191 return ObjLayer.findSymbol(Name, true); 192 }; 193 194 Resolvers[K2] = createSymbolResolver( 195 [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) { 196 return cantFail( 197 lookupFlagsWithLegacyFn(SymbolFlags, Symbols, LegacyLookup)); 198 }, 199 [&](AsynchronousSymbolQuery &Query, const SymbolNameSet &Symbols) { 200 return lookupWithLegacyFn(Query, Symbols, LegacyLookup); 201 }); 202 203 cantFail(ObjLayer.addObject(K2, std::move(Obj2))); 204 cantFail(ObjLayer.emitAndFinalize(K2)); 205 cantFail(ObjLayer.removeObject(K2)); 206 207 // Finalization of module 2 should trigger finalization of module 1. 208 // Verify that finalize on SMMW is only called once. 209 EXPECT_EQ(MM->FinalizationCount, 1) 210 << "Extra call to finalize"; 211 } 212 213 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { 214 if (!TM) 215 return; 216 217 SymbolStringPool SSP; 218 ExecutionSession ES(SSP); 219 220 auto MM = std::make_shared<SectionMemoryManagerWrapper>(); 221 222 RTDyldObjectLinkingLayer ObjLayer( 223 ES, [&MM](VModuleKey) { return MM; }, 224 [](VModuleKey) { return std::make_shared<NullResolver>(); }); 225 SimpleCompiler Compile(*TM); 226 227 // Create a pair of unrelated modules: 228 // 229 // Module 1: 230 // int foo() { return 42; } 231 // Module 2: 232 // int bar() { return 7; } 233 // 234 // Both modules will share a memory manager. We want to verify that the 235 // second object is not loaded before the first one is finalized. To do this 236 // in a portable way, we abuse the 237 // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is 238 // called once per object before any sections are allocated. 239 240 ModuleBuilder MB1(Context, "", "dummy"); 241 { 242 MB1.getModule()->setDataLayout(TM->createDataLayout()); 243 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo"); 244 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 245 IRBuilder<> Builder(BarEntry); 246 IntegerType *Int32Ty = IntegerType::get(Context, 32); 247 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); 248 Builder.CreateRet(FourtyTwo); 249 } 250 251 auto Obj1 = 252 std::make_shared<object::OwningBinary<object::ObjectFile>>( 253 Compile(*MB1.getModule())); 254 255 ModuleBuilder MB2(Context, "", "dummy"); 256 { 257 MB2.getModule()->setDataLayout(TM->createDataLayout()); 258 Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar"); 259 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 260 IRBuilder<> Builder(BarEntry); 261 IntegerType *Int32Ty = IntegerType::get(Context, 32); 262 Value *Seven = ConstantInt::getSigned(Int32Ty, 7); 263 Builder.CreateRet(Seven); 264 } 265 auto Obj2 = 266 std::make_shared<object::OwningBinary<object::ObjectFile>>( 267 Compile(*MB2.getModule())); 268 269 auto K = ES.allocateVModule(); 270 cantFail(ObjLayer.addObject(K, std::move(Obj1))); 271 cantFail(ObjLayer.addObject(ES.allocateVModule(), std::move(Obj2))); 272 cantFail(ObjLayer.emitAndFinalize(K)); 273 cantFail(ObjLayer.removeObject(K)); 274 275 // Only one call to needsToReserveAllocationSpace should have been made. 276 EXPECT_EQ(MM->NeedsToReserveAllocationSpaceCount, 1) 277 << "More than one call to needsToReserveAllocationSpace " 278 "(multiple unrelated objects loaded prior to finalization)"; 279 } 280 281 TEST_F(RTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) { 282 SymbolStringPool SSP; 283 ExecutionSession ES(SSP); 284 RTDyldObjectLinkingLayer ObjLayer( 285 ES, [](VModuleKey) { return nullptr; }, 286 [](VModuleKey) { return std::make_shared<NullResolver>(); }, 287 [](VModuleKey, const RTDyldObjectLinkingLayer::ObjectPtr &obj, 288 const RuntimeDyld::LoadedObjectInfo &info) {}); 289 } 290 291 } // end anonymous namespace 292