xref: /llvm-project/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp (revision 7fc871591f1399cd88ff301ed84fa67dc3bf7a6b)
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 #include <string>
19 
20 using namespace llvm;
21 using namespace llvm::orc;
22 
23 namespace {
24 
25 // Returns whether a non-alloc section was passed to the memory manager.
testSetProcessAllSections(std::unique_ptr<MemoryBuffer> Obj,bool ProcessAllSections)26 static bool testSetProcessAllSections(std::unique_ptr<MemoryBuffer> Obj,
27                                       bool ProcessAllSections) {
28   class MemoryManagerWrapper : public SectionMemoryManager {
29   public:
30     MemoryManagerWrapper(bool &NonAllocSeen) : NonAllocSeen(NonAllocSeen) {}
31     uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
32                                  unsigned SectionID, StringRef SectionName,
33                                  bool IsReadOnly) override {
34       // We check for ".note.GNU-stack" here because it is currently the only
35       // non-alloc section seen in the module. If this changes in future any
36       // other non-alloc section would do here.
37       if (SectionName == ".note.GNU-stack")
38         NonAllocSeen = true;
39       return SectionMemoryManager::allocateDataSection(
40           Size, Alignment, SectionID, SectionName, IsReadOnly);
41     }
42 
43   private:
44     bool &NonAllocSeen;
45   };
46 
47   bool NonAllocSectionSeen = false;
48 
49   ExecutionSession ES(std::make_unique<UnsupportedExecutorProcessControl>());
50   auto &JD = ES.createBareJITDylib("main");
51   auto Foo = ES.intern("foo");
52 
53   RTDyldObjectLinkingLayer ObjLayer(ES, [&NonAllocSectionSeen]() {
54     return std::make_unique<MemoryManagerWrapper>(NonAllocSectionSeen);
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 NonAllocSectionSeen;
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 
78   // These values are only here to ensure that the module is non-empty.
79   // They are no longer relevant to the test.
80   Constant *StrConstant = ConstantDataArray::getString(Context, "forty-two");
81   auto *GV =
82       new GlobalVariable(*M, StrConstant->getType(), true,
83                          GlobalValue::ExternalLinkage, StrConstant, "foo");
84   GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
85   GV->setAlignment(Align(1));
86 
87   // Initialize the native target in case this is the first unit test
88   // to try to build a TM.
89   OrcNativeTarget::initialize();
90   std::unique_ptr<TargetMachine> TM(EngineBuilder().selectTarget(
91       Triple(M->getTargetTriple()), "", "", SmallVector<std::string, 1>()));
92   if (!TM)
93     GTEST_SKIP();
94 
95   auto Obj = cantFail(SimpleCompiler(*TM)(*M));
96 
97   EXPECT_FALSE(testSetProcessAllSections(
98       MemoryBuffer::getMemBufferCopy(Obj->getBuffer()), false))
99       << "Non-alloc section seen despite ProcessAllSections being false";
100   EXPECT_TRUE(testSetProcessAllSections(std::move(Obj), true))
101       << "Expected to see non-alloc section when ProcessAllSections is true";
102 }
103 
TEST(RTDyldObjectLinkingLayerTest,TestOverrideObjectFlags)104 TEST(RTDyldObjectLinkingLayerTest, TestOverrideObjectFlags) {
105 
106   OrcNativeTarget::initialize();
107 
108   std::unique_ptr<TargetMachine> TM(
109       EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",
110                                    SmallVector<std::string, 1>()));
111 
112   if (!TM)
113     GTEST_SKIP();
114 
115   // Our compiler is going to modify symbol visibility settings without telling
116   // ORC. This will test our ability to override the flags later.
117   class FunkySimpleCompiler : public SimpleCompiler {
118   public:
119     FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {}
120 
121     Expected<CompileResult> operator()(Module &M) override {
122       auto *Foo = M.getFunction("foo");
123       assert(Foo && "Expected function Foo not found");
124       Foo->setVisibility(GlobalValue::HiddenVisibility);
125       return SimpleCompiler::operator()(M);
126     }
127   };
128 
129   // Create a module with two void() functions: foo and bar.
130   ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
131   ThreadSafeModule M;
132   {
133     ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy");
134     MB.getModule()->setDataLayout(TM->createDataLayout());
135 
136     Function *FooImpl = MB.createFunctionDecl(
137         FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false),
138         "foo");
139     BasicBlock *FooEntry =
140         BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl);
141     IRBuilder<> B1(FooEntry);
142     B1.CreateRetVoid();
143 
144     Function *BarImpl = MB.createFunctionDecl(
145         FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false),
146         "bar");
147     BasicBlock *BarEntry =
148         BasicBlock::Create(*TSCtx.getContext(), "entry", BarImpl);
149     IRBuilder<> B2(BarEntry);
150     B2.CreateRetVoid();
151 
152     M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx));
153   }
154 
155   // Create a simple stack and set the override flags option.
156   ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
157   auto &JD = ES.createBareJITDylib("main");
158   auto Foo = ES.intern("foo");
159   RTDyldObjectLinkingLayer ObjLayer(
160       ES, []() { return std::make_unique<SectionMemoryManager>(); });
161   IRCompileLayer CompileLayer(ES, ObjLayer,
162                               std::make_unique<FunkySimpleCompiler>(*TM));
163 
164   ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true);
165 
166   cantFail(CompileLayer.add(JD, std::move(M)));
167   ES.lookup(
168       LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
169       SymbolState::Resolved,
170       [](Expected<SymbolMap> R) { cantFail(std::move(R)); },
171       NoDependenciesToRegister);
172 
173   if (auto Err = ES.endSession())
174     ES.reportError(std::move(Err));
175 }
176 
TEST(RTDyldObjectLinkingLayerTest,TestAutoClaimResponsibilityForSymbols)177 TEST(RTDyldObjectLinkingLayerTest, TestAutoClaimResponsibilityForSymbols) {
178 
179   OrcNativeTarget::initialize();
180 
181   std::unique_ptr<TargetMachine> TM(
182       EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",
183                                    SmallVector<std::string, 1>()));
184 
185   if (!TM)
186     GTEST_SKIP();
187 
188   // Our compiler is going to add a new symbol without telling ORC.
189   // This will test our ability to auto-claim responsibility later.
190   class FunkySimpleCompiler : public SimpleCompiler {
191   public:
192     FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {}
193 
194     Expected<CompileResult> operator()(Module &M) override {
195       Function *BarImpl = Function::Create(
196           FunctionType::get(Type::getVoidTy(M.getContext()), {}, false),
197           GlobalValue::ExternalLinkage, "bar", &M);
198       BasicBlock *BarEntry =
199           BasicBlock::Create(M.getContext(), "entry", BarImpl);
200       IRBuilder<> B(BarEntry);
201       B.CreateRetVoid();
202 
203       return SimpleCompiler::operator()(M);
204     }
205   };
206 
207   // Create a module with two void() functions: foo and bar.
208   ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
209   ThreadSafeModule M;
210   {
211     ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy");
212     MB.getModule()->setDataLayout(TM->createDataLayout());
213 
214     Function *FooImpl = MB.createFunctionDecl(
215         FunctionType::get(Type::getVoidTy(*TSCtx.getContext()), {}, false),
216         "foo");
217     BasicBlock *FooEntry =
218         BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl);
219     IRBuilder<> B(FooEntry);
220     B.CreateRetVoid();
221 
222     M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx));
223   }
224 
225   // Create a simple stack and set the override flags option.
226   ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
227   auto &JD = ES.createBareJITDylib("main");
228   auto Foo = ES.intern("foo");
229   RTDyldObjectLinkingLayer ObjLayer(
230       ES, []() { return std::make_unique<SectionMemoryManager>(); });
231   IRCompileLayer CompileLayer(ES, ObjLayer,
232                               std::make_unique<FunkySimpleCompiler>(*TM));
233 
234   ObjLayer.setAutoClaimResponsibilityForObjectSymbols(true);
235 
236   cantFail(CompileLayer.add(JD, std::move(M)));
237   ES.lookup(
238       LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
239       SymbolState::Resolved,
240       [](Expected<SymbolMap> R) { cantFail(std::move(R)); },
241       NoDependenciesToRegister);
242 
243   if (auto Err = ES.endSession())
244     ES.reportError(std::move(Err));
245 }
246 
247 } // end anonymous namespace
248