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. 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 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 return; 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 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 return; 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 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 return; 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