From d5111c292db02a50149571df3bda68244a228502 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Thu, 13 May 2021 21:35:34 -0700 Subject: [PATCH] [ORC] Add support for adding LinkGraphs directly to ObjectLinkingLayer. This is separate from (but builds on) the support added in ec6b71df70a for emitting LinkGraphs in the context of an active materialization. This commit makes LinkGraphs a first-class data structure with features equivalent to object files within ObjectLinkingLayer. --- .../ExecutionEngine/Orc/ObjectLinkingLayer.h | 11 ++ .../Orc/ObjectLinkingLayer.cpp | 102 ++++++++++++++++++ unittests/ExecutionEngine/Orc/CMakeLists.txt | 1 + .../Orc/ObjectLinkingLayerTest.cpp | 59 ++++++++++ 4 files changed, 173 insertions(+) create mode 100644 unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp diff --git a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h index e26c5089991..55d0634a82a 100644 --- a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -129,6 +129,17 @@ public: return *this; } + /// Add a LinkGraph to the JITDylib targeted by the given tracker. + Error add(ResourceTrackerSP, std::unique_ptr G); + + /// Add a LinkGraph to the given JITDylib. + Error add(JITDylib &JD, std::unique_ptr G) { + return add(JD.getDefaultResourceTracker(), std::move(G)); + } + + // Un-hide ObjectLayer add methods. + using ObjectLayer::add; + /// Emit an object file. void emit(std::unique_ptr R, std::unique_ptr O) override; diff --git a/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index ccac4b8c545..44dc45f93f2 100644 --- a/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -21,6 +21,101 @@ using namespace llvm; using namespace llvm::jitlink; using namespace llvm::orc; +namespace { + +class LinkGraphMaterializationUnit : public MaterializationUnit { +private: + struct LinkGraphInterface { + SymbolFlagsMap SymbolFlags; + SymbolStringPtr InitSymbol; + }; + +public: + static std::unique_ptr + Create(ObjectLinkingLayer &ObjLinkingLayer, std::unique_ptr G) { + auto LGI = scanLinkGraph(ObjLinkingLayer.getExecutionSession(), *G); + return std::unique_ptr( + new LinkGraphMaterializationUnit(ObjLinkingLayer, std::move(G), + std::move(LGI))); + } + + StringRef getName() const override { return G->getName(); } + void materialize(std::unique_ptr MR) override { + ObjLinkingLayer.emit(std::move(MR), std::move(G)); + } + +private: + static LinkGraphInterface scanLinkGraph(ExecutionSession &ES, LinkGraph &G) { + + LinkGraphInterface LGI; + + for (auto *Sym : G.defined_symbols()) { + // Skip local symbols. + if (Sym->getScope() == Scope::Local) + continue; + assert(Sym->hasName() && "Anonymous non-local symbol?"); + + JITSymbolFlags Flags; + if (Sym->getScope() == Scope::Default) + Flags |= JITSymbolFlags::Exported; + + if (Sym->isCallable()) + Flags |= JITSymbolFlags::Callable; + + LGI.SymbolFlags[ES.intern(Sym->getName())] = Flags; + } + + if (G.getTargetTriple().isOSBinFormatMachO()) + if (hasMachOInitSection(G)) + LGI.InitSymbol = makeInitSymbol(ES, G); + + return LGI; + } + + static bool hasMachOInitSection(LinkGraph &G) { + for (auto &Sec : G.sections()) + if (Sec.getName() == "__DATA,__obj_selrefs" || + Sec.getName() == "__DATA,__objc_classlist" || + Sec.getName() == "__TEXT,__swift5_protos" || + Sec.getName() == "__TEXT,__swift5_proto" || + Sec.getName() == "__DATA,__mod_init_func") + return true; + return false; + } + + static SymbolStringPtr makeInitSymbol(ExecutionSession &ES, LinkGraph &G) { + std::string InitSymString; + raw_string_ostream(InitSymString) + << "$." << G.getName() << ".__inits" << Counter++; + return ES.intern(InitSymString); + } + + LinkGraphMaterializationUnit(ObjectLinkingLayer &ObjLinkingLayer, + std::unique_ptr G, + LinkGraphInterface LGI) + : MaterializationUnit(std::move(LGI.SymbolFlags), + std::move(LGI.InitSymbol)), + ObjLinkingLayer(ObjLinkingLayer), G(std::move(G)) {} + + void discard(const JITDylib &JD, const SymbolStringPtr &Name) override { + for (auto *Sym : G->defined_symbols()) + if (Sym->getName() == *Name) { + assert(Sym->getLinkage() == Linkage::Weak && + "Discarding non-weak definition"); + G->makeExternal(*Sym); + break; + } + } + + ObjectLinkingLayer &ObjLinkingLayer; + std::unique_ptr G; + static std::atomic Counter; +}; + +std::atomic LinkGraphMaterializationUnit::Counter{0}; + +} // end anonymous namespace + namespace llvm { namespace orc { @@ -487,6 +582,13 @@ ObjectLinkingLayer::~ObjectLinkingLayer() { getExecutionSession().deregisterResourceManager(*this); } +Error ObjectLinkingLayer::add(ResourceTrackerSP RT, + std::unique_ptr G) { + auto &JD = RT->getJITDylib(); + return JD.define(LinkGraphMaterializationUnit::Create(*this, std::move(G)), + std::move(RT)); +} + void ObjectLinkingLayer::emit(std::unique_ptr R, std::unique_ptr O) { assert(O && "Object must not be null"); diff --git a/unittests/ExecutionEngine/Orc/CMakeLists.txt b/unittests/ExecutionEngine/Orc/CMakeLists.txt index 48421058a6e..ee0e904c520 100644 --- a/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ b/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_unittest(OrcJITTests IndirectionUtilsTest.cpp JITTargetMachineBuilderTest.cpp LazyCallThroughAndReexportsTest.cpp + ObjectLinkingLayerTest.cpp OrcCAPITest.cpp OrcTestCommon.cpp QueueChannel.cpp diff --git a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp new file mode 100644 index 00000000000..a628b86b9c5 --- /dev/null +++ b/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp @@ -0,0 +1,59 @@ +//===-------- ObjectLinkingLayerTest.cpp - ObjectLinkingLayer tests -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/JITLink/JITLink.h" +#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" +#include "llvm/ExecutionEngine/JITLink/x86_64.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::jitlink; +using namespace llvm::orc; + +namespace { + +auto RWFlags = + sys::Memory::ProtectionFlags(sys::Memory::MF_READ | sys::Memory::MF_WRITE); + +const char BlockContentBytes[] = {0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08}; + +ArrayRef BlockContent(BlockContentBytes); + +class ObjectLinkingLayerTest : public testing::Test { +public: + ~ObjectLinkingLayerTest() { + if (auto Err = ES.endSession()) + ES.reportError(std::move(Err)); + } + +protected: + ExecutionSession ES; + JITDylib &JD = ES.createBareJITDylib("main"); + ObjectLinkingLayer ObjLinkingLayer{ + ES, std::make_unique()}; +}; + +TEST_F(ObjectLinkingLayerTest, AddLinkGraph) { + auto G = + std::make_unique("foo", Triple("x86_64-apple-darwin"), 8, + support::little, x86_64::getEdgeKindName); + + auto &Sec1 = G->createSection("__data", RWFlags); + auto &B1 = G->createContentBlock(Sec1, BlockContent, 0x1000, 8, 0); + G->addDefinedSymbol(B1, 4, "_X", 4, Linkage::Strong, Scope::Default, false, + false); + + EXPECT_THAT_ERROR(ObjLinkingLayer.add(JD, std::move(G)), Succeeded()); + + EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_X"), Succeeded()); +} + +} // end anonymous namespace