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