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/NullResolver.h"
16 #include "llvm/ExecutionEngine/SectionMemoryManager.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 Obj =
89     std::make_shared<object::OwningBinary<object::ObjectFile>>(
90       SimpleCompiler(*TM)(*M));
91 
92   bool DebugSectionSeen = false;
93   auto SMMW =
94     std::make_shared<SectionMemoryManagerWrapper>(DebugSectionSeen);
95   auto Resolver =
96     createLambdaResolver(
97       [](const std::string &Name) {
98         return JITSymbol(nullptr);
99       },
100       [](const std::string &Name) {
101         return JITSymbol(nullptr);
102       });
103 
104   {
105     // Test with ProcessAllSections = false (the default).
106     auto H = ObjLayer.addObject(Obj, SMMW, &*Resolver);
107     ObjLayer.emitAndFinalize(H);
108     EXPECT_EQ(DebugSectionSeen, false)
109       << "Unexpected debug info section";
110     ObjLayer.removeObject(H);
111   }
112 
113   {
114     // Test with ProcessAllSections = true.
115     ObjLayer.setProcessAllSections(true);
116     auto H = ObjLayer.addObject(Obj, SMMW, &*Resolver);
117     ObjLayer.emitAndFinalize(H);
118     EXPECT_EQ(DebugSectionSeen, true)
119       << "Expected debug info section not seen";
120     ObjLayer.removeObject(H);
121   }
122 }
123 
124 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
125   if (!TM)
126     return;
127 
128   RTDyldObjectLinkingLayer ObjLayer;
129   SimpleCompiler Compile(*TM);
130 
131   // Create a pair of modules that will trigger recursive finalization:
132   // Module 1:
133   //   int bar() { return 42; }
134   // Module 2:
135   //   int bar();
136   //   int foo() { return bar(); }
137   //
138   // Verify that the memory manager is only finalized once (for Module 2).
139   // Failure suggests that finalize is being called on the inner RTDyld
140   // instance (for Module 1) which is unsafe, as it will prevent relocation of
141   // Module 2.
142 
143   ModuleBuilder MB1(Context, "", "dummy");
144   {
145     MB1.getModule()->setDataLayout(TM->createDataLayout());
146     Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar");
147     BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
148     IRBuilder<> Builder(BarEntry);
149     IntegerType *Int32Ty = IntegerType::get(Context, 32);
150     Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
151     Builder.CreateRet(FourtyTwo);
152   }
153 
154   auto Obj1 =
155     std::make_shared<object::OwningBinary<object::ObjectFile>>(
156       Compile(*MB1.getModule()));
157 
158   ModuleBuilder MB2(Context, "", "dummy");
159   {
160     MB2.getModule()->setDataLayout(TM->createDataLayout());
161     Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar");
162     Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo");
163     BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
164     IRBuilder<> Builder(FooEntry);
165     Builder.CreateRet(Builder.CreateCall(BarDecl));
166   }
167   auto Obj2 =
168     std::make_shared<object::OwningBinary<object::ObjectFile>>(
169       Compile(*MB2.getModule()));
170 
171   auto Resolver =
172     createLambdaResolver(
173       [&](const std::string &Name) {
174         if (auto Sym = ObjLayer.findSymbol(Name, true))
175           return Sym;
176         return JITSymbol(nullptr);
177       },
178       [](const std::string &Name) {
179         return JITSymbol(nullptr);
180       });
181 
182   auto SMMW = std::make_shared<SectionMemoryManagerWrapper>();
183   ObjLayer.addObject(std::move(Obj1), SMMW, &*Resolver);
184   auto H = ObjLayer.addObject(std::move(Obj2), SMMW, &*Resolver);
185   ObjLayer.emitAndFinalize(H);
186   ObjLayer.removeObject(H);
187 
188   // Finalization of module 2 should trigger finalization of module 1.
189   // Verify that finalize on SMMW is only called once.
190   EXPECT_EQ(SMMW->FinalizationCount, 1)
191       << "Extra call to finalize";
192 }
193 
194 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
195   if (!TM)
196     return;
197 
198   RTDyldObjectLinkingLayer ObjLayer;
199   SimpleCompiler Compile(*TM);
200 
201   // Create a pair of unrelated modules:
202   //
203   // Module 1:
204   //   int foo() { return 42; }
205   // Module 2:
206   //   int bar() { return 7; }
207   //
208   // Both modules will share a memory manager. We want to verify that the
209   // second object is not loaded before the first one is finalized. To do this
210   // in a portable way, we abuse the
211   // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
212   // called once per object before any sections are allocated.
213 
214   ModuleBuilder MB1(Context, "", "dummy");
215   {
216     MB1.getModule()->setDataLayout(TM->createDataLayout());
217     Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo");
218     BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
219     IRBuilder<> Builder(BarEntry);
220     IntegerType *Int32Ty = IntegerType::get(Context, 32);
221     Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
222     Builder.CreateRet(FourtyTwo);
223   }
224 
225   auto Obj1 =
226     std::make_shared<object::OwningBinary<object::ObjectFile>>(
227       Compile(*MB1.getModule()));
228 
229   ModuleBuilder MB2(Context, "", "dummy");
230   {
231     MB2.getModule()->setDataLayout(TM->createDataLayout());
232     Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar");
233     BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
234     IRBuilder<> Builder(BarEntry);
235     IntegerType *Int32Ty = IntegerType::get(Context, 32);
236     Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
237     Builder.CreateRet(Seven);
238   }
239   auto Obj2 =
240     std::make_shared<object::OwningBinary<object::ObjectFile>>(
241       Compile(*MB2.getModule()));
242 
243   auto SMMW = std::make_shared<SectionMemoryManagerWrapper>();
244   NullResolver NR;
245   auto H = ObjLayer.addObject(std::move(Obj1), SMMW, &NR);
246   ObjLayer.addObject(std::move(Obj2), SMMW, &NR);
247   ObjLayer.emitAndFinalize(H);
248   ObjLayer.removeObject(H);
249 
250   // Only one call to needsToReserveAllocationSpace should have been made.
251   EXPECT_EQ(SMMW->NeedsToReserveAllocationSpaceCount, 1)
252       << "More than one call to needsToReserveAllocationSpace "
253          "(multiple unrelated objects loaded prior to finalization)";
254 }
255 
256 } // end anonymous namespace
257