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