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 "OrcTestCommon.h" 11 #include "llvm/ExecutionEngine/ExecutionEngine.h" 12 #include "llvm/ExecutionEngine/SectionMemoryManager.h" 13 #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 14 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" 15 #include "llvm/ExecutionEngine/Orc/NullResolver.h" 16 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 17 #include "llvm/IR/Constants.h" 18 #include "llvm/IR/LLVMContext.h" 19 #include "gtest/gtest.h" 20 21 using namespace llvm; 22 using namespace llvm::orc; 23 24 namespace { 25 26 class RTDyldObjectLinkingLayerExecutionTest : public testing::Test, 27 public OrcExecutionTest { 28 29 }; 30 31 class SectionMemoryManagerWrapper : public SectionMemoryManager { 32 public: 33 int FinalizationCount = 0; 34 int NeedsToReserveAllocationSpaceCount = 0; 35 36 bool needsToReserveAllocationSpace() override { 37 ++NeedsToReserveAllocationSpaceCount; 38 return SectionMemoryManager::needsToReserveAllocationSpace(); 39 } 40 41 bool finalizeMemory(std::string *ErrMsg = nullptr) override { 42 ++FinalizationCount; 43 return SectionMemoryManager::finalizeMemory(ErrMsg); 44 } 45 }; 46 47 TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { 48 class SectionMemoryManagerWrapper : public SectionMemoryManager { 49 public: 50 SectionMemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {} 51 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 52 unsigned SectionID, 53 StringRef SectionName, 54 bool IsReadOnly) override { 55 if (SectionName == ".debug_str") 56 DebugSeen = true; 57 return SectionMemoryManager::allocateDataSection(Size, Alignment, 58 SectionID, 59 SectionName, 60 IsReadOnly); 61 } 62 private: 63 bool &DebugSeen; 64 }; 65 66 RTDyldObjectLinkingLayer<> ObjLayer; 67 68 LLVMContext Context; 69 auto M = llvm::make_unique<Module>("", Context); 70 M->setTargetTriple("x86_64-unknown-linux-gnu"); 71 Type *Int32Ty = IntegerType::get(Context, 32); 72 GlobalVariable *GV = 73 new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage, 74 ConstantInt::get(Int32Ty, 42), "foo"); 75 76 GV->setSection(".debug_str"); 77 78 79 // Initialize the native target in case this is the first unit test 80 // to try to build a TM. 81 OrcNativeTarget::initialize(); 82 std::unique_ptr<TargetMachine> TM( 83 EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "", 84 SmallVector<std::string, 1>())); 85 if (!TM) 86 return; 87 88 auto OwningObj = SimpleCompiler(*TM)(*M); 89 std::vector<object::ObjectFile*> Objs; 90 Objs.push_back(OwningObj.getBinary()); 91 92 bool DebugSectionSeen = false; 93 SectionMemoryManagerWrapper SMMW(DebugSectionSeen); 94 auto Resolver = 95 createLambdaResolver( 96 [](const std::string &Name) { 97 return JITSymbol(nullptr); 98 }, 99 [](const std::string &Name) { 100 return JITSymbol(nullptr); 101 }); 102 103 { 104 // Test with ProcessAllSections = false (the default). 105 auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver); 106 ObjLayer.emitAndFinalize(H); 107 EXPECT_EQ(DebugSectionSeen, false) 108 << "Unexpected debug info section"; 109 ObjLayer.removeObjectSet(H); 110 } 111 112 { 113 // Test with ProcessAllSections = true. 114 ObjLayer.setProcessAllSections(true); 115 auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver); 116 ObjLayer.emitAndFinalize(H); 117 EXPECT_EQ(DebugSectionSeen, true) 118 << "Expected debug info section not seen"; 119 ObjLayer.removeObjectSet(H); 120 } 121 } 122 123 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { 124 if (!TM) 125 return; 126 127 RTDyldObjectLinkingLayer<> ObjLayer; 128 SimpleCompiler Compile(*TM); 129 130 // Create a pair of modules that will trigger recursive finalization: 131 // Module 1: 132 // int bar() { return 42; } 133 // Module 2: 134 // int bar(); 135 // int foo() { return bar(); } 136 // 137 // Verify that the memory manager is only finalized once (for Module 2). 138 // Failure suggests that finalize is being called on the inner RTDyld 139 // instance (for Module 1) which is unsafe, as it will prevent relocation of 140 // Module 2. 141 142 ModuleBuilder MB1(Context, "", "dummy"); 143 { 144 MB1.getModule()->setDataLayout(TM->createDataLayout()); 145 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar"); 146 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 147 IRBuilder<> Builder(BarEntry); 148 IntegerType *Int32Ty = IntegerType::get(Context, 32); 149 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); 150 Builder.CreateRet(FourtyTwo); 151 } 152 153 auto Obj1 = Compile(*MB1.getModule()); 154 std::vector<object::ObjectFile*> Obj1Set; 155 Obj1Set.push_back(Obj1.getBinary()); 156 157 ModuleBuilder MB2(Context, "", "dummy"); 158 { 159 MB2.getModule()->setDataLayout(TM->createDataLayout()); 160 Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar"); 161 Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo"); 162 BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl); 163 IRBuilder<> Builder(FooEntry); 164 Builder.CreateRet(Builder.CreateCall(BarDecl)); 165 } 166 auto Obj2 = Compile(*MB2.getModule()); 167 std::vector<object::ObjectFile*> Obj2Set; 168 Obj2Set.push_back(Obj2.getBinary()); 169 170 auto Resolver = 171 createLambdaResolver( 172 [&](const std::string &Name) { 173 if (auto Sym = ObjLayer.findSymbol(Name, true)) 174 return Sym; 175 return JITSymbol(nullptr); 176 }, 177 [](const std::string &Name) { 178 return JITSymbol(nullptr); 179 }); 180 181 SectionMemoryManagerWrapper SMMW; 182 ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &*Resolver); 183 auto H = ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &*Resolver); 184 ObjLayer.emitAndFinalize(H); 185 186 // Finalization of module 2 should trigger finalization of module 1. 187 // Verify that finalize on SMMW is only called once. 188 EXPECT_EQ(SMMW.FinalizationCount, 1) 189 << "Extra call to finalize"; 190 } 191 192 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { 193 if (!TM) 194 return; 195 196 RTDyldObjectLinkingLayer<> ObjLayer; 197 SimpleCompiler Compile(*TM); 198 199 // Create a pair of unrelated modules: 200 // 201 // Module 1: 202 // int foo() { return 42; } 203 // Module 2: 204 // int bar() { return 7; } 205 // 206 // Both modules will share a memory manager. We want to verify that the 207 // second object is not loaded before the first one is finalized. To do this 208 // in a portable way, we abuse the 209 // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is 210 // called once per object before any sections are allocated. 211 212 ModuleBuilder MB1(Context, "", "dummy"); 213 { 214 MB1.getModule()->setDataLayout(TM->createDataLayout()); 215 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo"); 216 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 217 IRBuilder<> Builder(BarEntry); 218 IntegerType *Int32Ty = IntegerType::get(Context, 32); 219 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); 220 Builder.CreateRet(FourtyTwo); 221 } 222 223 auto Obj1 = Compile(*MB1.getModule()); 224 std::vector<object::ObjectFile*> Obj1Set; 225 Obj1Set.push_back(Obj1.getBinary()); 226 227 ModuleBuilder MB2(Context, "", "dummy"); 228 { 229 MB2.getModule()->setDataLayout(TM->createDataLayout()); 230 Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar"); 231 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 232 IRBuilder<> Builder(BarEntry); 233 IntegerType *Int32Ty = IntegerType::get(Context, 32); 234 Value *Seven = ConstantInt::getSigned(Int32Ty, 7); 235 Builder.CreateRet(Seven); 236 } 237 auto Obj2 = Compile(*MB2.getModule()); 238 std::vector<object::ObjectFile*> Obj2Set; 239 Obj2Set.push_back(Obj2.getBinary()); 240 241 SectionMemoryManagerWrapper SMMW; 242 NullResolver NR; 243 auto H = ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &NR); 244 ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &NR); 245 ObjLayer.emitAndFinalize(H); 246 247 // Only one call to needsToReserveAllocationSpace should have been made. 248 EXPECT_EQ(SMMW.NeedsToReserveAllocationSpaceCount, 1) 249 << "More than one call to needsToReserveAllocationSpace " 250 "(multiple unrelated objects loaded prior to finalization)"; 251 } 252 253 } // end anonymous namespace 254