302 lines · cpp
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-exception6//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 20using namespace llvm;21using namespace llvm::orc;22 23namespace {24 25// Returns whether a non-alloc section was passed to the memory manager.26static 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 only35 // non-alloc section seen in the module. If this changes in future any36 // 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(54 ES, [&NonAllocSectionSeen](const MemoryBuffer &) {55 return std::make_unique<MemoryManagerWrapper>(NonAllocSectionSeen);56 });57 58 auto OnResolveDoNothing = [](Expected<SymbolMap> R) {59 cantFail(std::move(R));60 };61 62 ObjLayer.setProcessAllSections(ProcessAllSections);63 cantFail(ObjLayer.add(JD, std::move(Obj)));64 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),65 SymbolLookupSet(Foo), SymbolState::Resolved, OnResolveDoNothing,66 NoDependenciesToRegister);67 68 if (auto Err = ES.endSession())69 ES.reportError(std::move(Err));70 71 return NonAllocSectionSeen;72}73 74TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {75 LLVMContext Context;76 auto M = std::make_unique<Module>("", Context);77 M->setTargetTriple(Triple("x86_64-unknown-linux-gnu"));78 79 // These values are only here to ensure that the module is non-empty.80 // They are no longer relevant to the test.81 Constant *StrConstant = ConstantDataArray::getString(Context, "forty-two");82 auto *GV =83 new GlobalVariable(*M, StrConstant->getType(), true,84 GlobalValue::ExternalLinkage, StrConstant, "foo");85 GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);86 GV->setAlignment(Align(1));87 88 // Initialize the native target in case this is the first unit test89 // to try to build a TM.90 OrcNativeTarget::initialize();91 std::unique_ptr<TargetMachine> TM(EngineBuilder().selectTarget(92 M->getTargetTriple(), "", "", SmallVector<std::string, 1>()));93 if (!TM)94 GTEST_SKIP();95 96 auto Obj = cantFail(SimpleCompiler(*TM)(*M));97 98 EXPECT_FALSE(testSetProcessAllSections(99 MemoryBuffer::getMemBufferCopy(Obj->getBuffer()), false))100 << "Non-alloc section seen despite ProcessAllSections being false";101 EXPECT_TRUE(testSetProcessAllSections(std::move(Obj), true))102 << "Expected to see non-alloc section when ProcessAllSections is true";103}104 105TEST(RTDyldObjectLinkingLayerTest, TestOverrideObjectFlags) {106 107 OrcNativeTarget::initialize();108 109 std::unique_ptr<TargetMachine> TM(110 EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",111 SmallVector<std::string, 1>()));112 113 if (!TM)114 GTEST_SKIP();115 116 // Our compiler is going to modify symbol visibility settings without telling117 // ORC. This will test our ability to override the flags later.118 class FunkySimpleCompiler : public SimpleCompiler {119 public:120 FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {}121 122 Expected<CompileResult> operator()(Module &M) override {123 auto *Foo = M.getFunction("foo");124 assert(Foo && "Expected function Foo not found");125 Foo->setVisibility(GlobalValue::HiddenVisibility);126 return SimpleCompiler::operator()(M);127 }128 };129 130 // Create a module with two void() functions: foo and bar.131 ThreadSafeModule M;132 {133 auto Ctx = std::make_unique<LLVMContext>();134 ModuleBuilder MB(*Ctx, TM->getTargetTriple().str(), "dummy");135 MB.getModule()->setDataLayout(TM->createDataLayout());136 137 Function *FooImpl = MB.createFunctionDecl(138 FunctionType::get(Type::getVoidTy(*Ctx), {}, false), "foo");139 BasicBlock *FooEntry = BasicBlock::Create(*Ctx, "entry", FooImpl);140 IRBuilder<> B1(FooEntry);141 B1.CreateRetVoid();142 143 Function *BarImpl = MB.createFunctionDecl(144 FunctionType::get(Type::getVoidTy(*Ctx), {}, false), "bar");145 BasicBlock *BarEntry = BasicBlock::Create(*Ctx, "entry", BarImpl);146 IRBuilder<> B2(BarEntry);147 B2.CreateRetVoid();148 149 M = ThreadSafeModule(MB.takeModule(), std::move(Ctx));150 }151 152 // Create a simple stack and set the override flags option.153 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};154 auto &JD = ES.createBareJITDylib("main");155 auto Foo = ES.intern("foo");156 RTDyldObjectLinkingLayer ObjLayer(ES, [](const MemoryBuffer &) {157 return std::make_unique<SectionMemoryManager>();158 });159 IRCompileLayer CompileLayer(ES, ObjLayer,160 std::make_unique<FunkySimpleCompiler>(*TM));161 162 ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true);163 164 cantFail(CompileLayer.add(JD, std::move(M)));165 ES.lookup(166 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),167 SymbolState::Resolved,168 [](Expected<SymbolMap> R) { cantFail(std::move(R)); },169 NoDependenciesToRegister);170 171 if (auto Err = ES.endSession())172 ES.reportError(std::move(Err));173}174 175TEST(RTDyldObjectLinkingLayerTest, TestAutoClaimResponsibilityForSymbols) {176 177 OrcNativeTarget::initialize();178 179 std::unique_ptr<TargetMachine> TM(180 EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",181 SmallVector<std::string, 1>()));182 183 if (!TM)184 GTEST_SKIP();185 186 // Our compiler is going to add a new symbol without telling ORC.187 // This will test our ability to auto-claim responsibility later.188 class FunkySimpleCompiler : public SimpleCompiler {189 public:190 FunkySimpleCompiler(TargetMachine &TM) : SimpleCompiler(TM) {}191 192 Expected<CompileResult> operator()(Module &M) override {193 Function *BarImpl = Function::Create(194 FunctionType::get(Type::getVoidTy(M.getContext()), {}, false),195 GlobalValue::ExternalLinkage, "bar", &M);196 BasicBlock *BarEntry =197 BasicBlock::Create(M.getContext(), "entry", BarImpl);198 IRBuilder<> B(BarEntry);199 B.CreateRetVoid();200 201 return SimpleCompiler::operator()(M);202 }203 };204 205 // Create a module with two void() functions: foo and bar.206 ThreadSafeModule M;207 {208 auto Ctx = std::make_unique<LLVMContext>();209 ModuleBuilder MB(*Ctx, TM->getTargetTriple().str(), "dummy");210 MB.getModule()->setDataLayout(TM->createDataLayout());211 212 Function *FooImpl = MB.createFunctionDecl(213 FunctionType::get(Type::getVoidTy(*Ctx), {}, false), "foo");214 BasicBlock *FooEntry = BasicBlock::Create(*Ctx, "entry", FooImpl);215 IRBuilder<> B(FooEntry);216 B.CreateRetVoid();217 218 M = ThreadSafeModule(MB.takeModule(), std::move(Ctx));219 }220 221 // Create a simple stack and set the override flags option.222 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};223 auto &JD = ES.createBareJITDylib("main");224 auto Foo = ES.intern("foo");225 RTDyldObjectLinkingLayer ObjLayer(ES, [](const MemoryBuffer &) {226 return std::make_unique<SectionMemoryManager>();227 });228 IRCompileLayer CompileLayer(ES, ObjLayer,229 std::make_unique<FunkySimpleCompiler>(*TM));230 231 ObjLayer.setAutoClaimResponsibilityForObjectSymbols(true);232 233 cantFail(CompileLayer.add(JD, std::move(M)));234 ES.lookup(235 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),236 SymbolState::Resolved,237 [](Expected<SymbolMap> R) { cantFail(std::move(R)); },238 NoDependenciesToRegister);239 240 if (auto Err = ES.endSession())241 ES.reportError(std::move(Err));242}243 244TEST(RTDyldObjectLinkingLayerTest, TestMemoryBufferNamePropagation) {245 OrcNativeTarget::initialize();246 247 std::unique_ptr<TargetMachine> TM(248 EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",249 SmallVector<std::string, 1>()));250 251 if (!TM)252 GTEST_SKIP();253 254 // Create a module with two void() functions: foo and bar.255 ThreadSafeModule M;256 {257 auto Ctx = std::make_unique<LLVMContext>();258 ModuleBuilder MB(*Ctx, TM->getTargetTriple().str(), "dummy");259 MB.getModule()->setDataLayout(TM->createDataLayout());260 261 Function *FooImpl = MB.createFunctionDecl(262 FunctionType::get(Type::getVoidTy(*Ctx), {}, false), "foo");263 BasicBlock *FooEntry = BasicBlock::Create(*Ctx, "entry", FooImpl);264 IRBuilder<> B1(FooEntry);265 B1.CreateRetVoid();266 267 M = ThreadSafeModule(MB.takeModule(), std::move(Ctx));268 }269 270 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};271 auto &JD = ES.createBareJITDylib("main");272 auto Foo = ES.intern("foo");273 std::string ObjectIdentifer;274 275 RTDyldObjectLinkingLayer ObjLayer(276 ES, [&ObjectIdentifer](const MemoryBuffer &Obj) {277 // Capture the name of the object so that we can confirm that it278 // contains the module name.279 ObjectIdentifer = Obj.getBufferIdentifier().str();280 return std::make_unique<SectionMemoryManager>();281 });282 IRCompileLayer CompileLayer(ES, ObjLayer,283 std::make_unique<SimpleCompiler>(*TM));284 285 // Capture the module name before we move the module.286 std::string ModuleName = M.getModuleUnlocked()->getName().str();287 288 cantFail(CompileLayer.add(JD, std::move(M)));289 ES.lookup(290 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),291 SymbolState::Resolved,292 [](Expected<SymbolMap> R) { cantFail(std::move(R)); },293 NoDependenciesToRegister);294 295 if (auto Err = ES.endSession())296 ES.reportError(std::move(Err));297 298 EXPECT_TRUE(ObjectIdentifer.find(ModuleName) != std::string::npos);299}300 301} // end anonymous namespace302