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 // Returns whether a non-alloc section was passed to the memory manager. 25 static bool testSetProcessAllSections(std::unique_ptr<MemoryBuffer> Obj, 26 bool ProcessAllSections) { 27 class MemoryManagerWrapper : public SectionMemoryManager { 28 public: 29 MemoryManagerWrapper(bool &NonAllocSeen) : NonAllocSeen(NonAllocSeen) {} 30 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 31 unsigned SectionID, StringRef SectionName, 32 bool IsReadOnly) override { 33 // We check for ".note.GNU-stack" here because it is currently the only 34 // non-alloc section seen in the module. If this changes in future any 35 // other non-alloc section would do here. 36 if (SectionName == ".note.GNU-stack") 37 NonAllocSeen = true; 38 return SectionMemoryManager::allocateDataSection( 39 Size, Alignment, SectionID, SectionName, IsReadOnly); 40 } 41 42 private: 43 bool &NonAllocSeen; 44 }; 45 46 bool NonAllocSectionSeen = false; 47 48 ExecutionSession ES; 49 auto &JD = ES.createBareJITDylib("main"); 50 auto Foo = ES.intern("foo"); 51 52 RTDyldObjectLinkingLayer ObjLayer(ES, [&NonAllocSectionSeen]() { 53 return std::make_unique<MemoryManagerWrapper>(NonAllocSectionSeen); 54 }); 55 56 auto OnResolveDoNothing = [](Expected<SymbolMap> R) { 57 cantFail(std::move(R)); 58 }; 59 60 ObjLayer.setProcessAllSections(ProcessAllSections); 61 cantFail(ObjLayer.add(JD, std::move(Obj))); 62 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 63 SymbolLookupSet(Foo), SymbolState::Resolved, OnResolveDoNothing, 64 NoDependenciesToRegister); 65 66 if (auto Err = ES.endSession()) 67 ES.reportError(std::move(Err)); 68 69 return NonAllocSectionSeen; 70 } 71 72 TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) { 73 LLVMContext Context; 74 auto M = std::make_unique<Module>("", Context); 75 M->setTargetTriple("x86_64-unknown-linux-gnu"); 76 77 // These values are only here to ensure that the module is non-empty. 78 // They are no longer relevant to the test. 79 Constant *StrConstant = ConstantDataArray::getString(Context, "forty-two"); 80 auto *GV = 81 new GlobalVariable(*M, StrConstant->getType(), true, 82 GlobalValue::ExternalLinkage, StrConstant, "foo"); 83 GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 84 GV->setAlignment(Align(1)); 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 << "Non-alloc section seen despite ProcessAllSections being false"; 99 EXPECT_TRUE(testSetProcessAllSections(std::move(Obj), true)) 100 << "Expected to see non-alloc section when ProcessAllSections is true"; 101 } 102 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 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