1 //===--- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer tests ---===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "OrcTestCommon.h"
10 #include "llvm/ExecutionEngine/ExecutionEngine.h"
11 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
12 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
13 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
14 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
15 #include "llvm/IR/Constants.h"
16 #include "llvm/IR/LLVMContext.h"
17 #include "gtest/gtest.h"
18
19 using namespace llvm;
20 using namespace llvm::orc;
21
22 namespace {
23
24 class RTDyldObjectLinkingLayerExecutionTest : public testing::Test,
25 public OrcExecutionTest {};
26
27 // Adds an object with a debug section to RuntimeDyld and then returns whether
28 // the debug section was passed to the memory manager.
testSetProcessAllSections(std::unique_ptr<MemoryBuffer> Obj,bool ProcessAllSections)29 static bool testSetProcessAllSections(std::unique_ptr<MemoryBuffer> Obj,
30 bool ProcessAllSections) {
31 class MemoryManagerWrapper : public SectionMemoryManager {
32 public:
33 MemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {}
34 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
35 unsigned SectionID, StringRef SectionName,
36 bool IsReadOnly) override {
37 if (SectionName == ".debug_str")
38 DebugSeen = true;
39 return SectionMemoryManager::allocateDataSection(
40 Size, Alignment, SectionID, SectionName, IsReadOnly);
41 }
42
43 private:
44 bool &DebugSeen;
45 };
46
47 bool DebugSectionSeen = false;
48
49 ExecutionSession ES;
50 auto &JD = ES.createBareJITDylib("main");
51 auto Foo = ES.intern("foo");
52
53 RTDyldObjectLinkingLayer ObjLayer(ES, [&DebugSectionSeen]() {
54 return std::make_unique<MemoryManagerWrapper>(DebugSectionSeen);
55 });
56
57 auto OnResolveDoNothing = [](Expected<SymbolMap> R) {
58 cantFail(std::move(R));
59 };
60
61 ObjLayer.setProcessAllSections(ProcessAllSections);
62 cantFail(ObjLayer.add(JD, std::move(Obj)));
63 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
64 SymbolLookupSet(Foo), SymbolState::Resolved, OnResolveDoNothing,
65 NoDependenciesToRegister);
66
67 if (auto Err = ES.endSession())
68 ES.reportError(std::move(Err));
69
70 return DebugSectionSeen;
71 }
72
TEST(RTDyldObjectLinkingLayerTest,TestSetProcessAllSections)73 TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
74 LLVMContext Context;
75 auto M = std::make_unique<Module>("", Context);
76 M->setTargetTriple("x86_64-unknown-linux-gnu");
77 Constant *StrConstant = ConstantDataArray::getString(Context, "forty-two");
78 auto *GV =
79 new GlobalVariable(*M, StrConstant->getType(), true,
80 GlobalValue::ExternalLinkage, StrConstant, "foo");
81 GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
82 GV->setAlignment(Align(1));
83
84 GV->setSection(".debug_str");
85
86 // Initialize the native target in case this is the first unit test
87 // to try to build a TM.
88 OrcNativeTarget::initialize();
89 std::unique_ptr<TargetMachine> TM(EngineBuilder().selectTarget(
90 Triple(M->getTargetTriple()), "", "", SmallVector<std::string, 1>()));
91 if (!TM)
92 return;
93
94 auto Obj = cantFail(SimpleCompiler(*TM)(*M));
95
96 EXPECT_FALSE(testSetProcessAllSections(
97 MemoryBuffer::getMemBufferCopy(Obj->getBuffer()), false))
98 << "Debug section seen despite ProcessAllSections being false";
99 EXPECT_TRUE(testSetProcessAllSections(std::move(Obj), true))
100 << "Expected to see debug section when ProcessAllSections is true";
101 }
102
TEST(RTDyldObjectLinkingLayerTest,TestOverrideObjectFlags)103 TEST(RTDyldObjectLinkingLayerTest, TestOverrideObjectFlags) {
104
105 OrcNativeTarget::initialize();
106
107 std::unique_ptr<TargetMachine> TM(
108 EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",
109 SmallVector<std::string, 1>()));
110
111 if (!TM)
112 return;
113
114 // Our compiler is going to modify symbol visibility settings without telling
115 // ORC. This will test our ability to override the flags later.
116 class FunkySimpleCompiler : public SimpleCompiler {
117 public:
118 FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {}
119
120 Expected<CompileResult> operator()(Module &M) override {
121 auto *Foo = M.getFunction("foo");
122 assert(Foo && "Expected function Foo not found");
123 Foo->setVisibility(GlobalValue::HiddenVisibility);
124 return SimpleCompiler::operator()(M);
125 }
126 };
127
128 // Create a module with two void() functions: foo and bar.
129 ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
130 ThreadSafeModule M;
131 {
132 ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy");
133 MB.getModule()->setDataLayout(TM->createDataLayout());
134
135 Function *FooImpl = MB.createFunctionDecl(
136 FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false),
137 "foo");
138 BasicBlock *FooEntry =
139 BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl);
140 IRBuilder<> B1(FooEntry);
141 B1.CreateRetVoid();
142
143 Function *BarImpl = MB.createFunctionDecl(
144 FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false),
145 "bar");
146 BasicBlock *BarEntry =
147 BasicBlock::Create(*TSCtx.getContext(), "entry", BarImpl);
148 IRBuilder<> B2(BarEntry);
149 B2.CreateRetVoid();
150
151 M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx));
152 }
153
154 // Create a simple stack and set the override flags option.
155 ExecutionSession ES;
156 auto &JD = ES.createBareJITDylib("main");
157 auto Foo = ES.intern("foo");
158 RTDyldObjectLinkingLayer ObjLayer(
159 ES, []() { return std::make_unique<SectionMemoryManager>(); });
160 IRCompileLayer CompileLayer(ES, ObjLayer,
161 std::make_unique<FunkySimpleCompiler>(*TM));
162
163 ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true);
164
165 cantFail(CompileLayer.add(JD, std::move(M)));
166 ES.lookup(
167 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
168 SymbolState::Resolved,
169 [](Expected<SymbolMap> R) { cantFail(std::move(R)); },
170 NoDependenciesToRegister);
171
172 if (auto Err = ES.endSession())
173 ES.reportError(std::move(Err));
174 }
175
TEST(RTDyldObjectLinkingLayerTest,TestAutoClaimResponsibilityForSymbols)176 TEST(RTDyldObjectLinkingLayerTest, TestAutoClaimResponsibilityForSymbols) {
177
178 OrcNativeTarget::initialize();
179
180 std::unique_ptr<TargetMachine> TM(
181 EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",
182 SmallVector<std::string, 1>()));
183
184 if (!TM)
185 return;
186
187 // Our compiler is going to add a new symbol without telling ORC.
188 // This will test our ability to auto-claim responsibility later.
189 class FunkySimpleCompiler : public SimpleCompiler {
190 public:
191 FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {}
192
193 Expected<CompileResult> operator()(Module &M) override {
194 Function *BarImpl = Function::Create(
195 FunctionType::get(Type::getVoidTy(M.getContext()), {}, false),
196 GlobalValue::ExternalLinkage, "bar", &M);
197 BasicBlock *BarEntry =
198 BasicBlock::Create(M.getContext(), "entry", BarImpl);
199 IRBuilder<> B(BarEntry);
200 B.CreateRetVoid();
201
202 return SimpleCompiler::operator()(M);
203 }
204 };
205
206 // Create a module with two void() functions: foo and bar.
207 ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
208 ThreadSafeModule M;
209 {
210 ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy");
211 MB.getModule()->setDataLayout(TM->createDataLayout());
212
213 Function *FooImpl = MB.createFunctionDecl(
214 FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false),
215 "foo");
216 BasicBlock *FooEntry =
217 BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl);
218 IRBuilder<> B(FooEntry);
219 B.CreateRetVoid();
220
221 M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx));
222 }
223
224 // Create a simple stack and set the override flags option.
225 ExecutionSession ES;
226 auto &JD = ES.createBareJITDylib("main");
227 auto Foo = ES.intern("foo");
228 RTDyldObjectLinkingLayer ObjLayer(
229 ES, []() { return std::make_unique<SectionMemoryManager>(); });
230 IRCompileLayer CompileLayer(ES, ObjLayer,
231 std::make_unique<FunkySimpleCompiler>(*TM));
232
233 ObjLayer.setAutoClaimResponsibilityForObjectSymbols(true);
234
235 cantFail(CompileLayer.add(JD, std::move(M)));
236 ES.lookup(
237 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
238 SymbolState::Resolved,
239 [](Expected<SymbolMap> R) { cantFail(std::move(R)); },
240 NoDependenciesToRegister);
241
242 if (auto Err = ES.endSession())
243 ES.reportError(std::move(Err));
244 }
245
246 } // end anonymous namespace
247