From 6498b0e991babe71e69ab02e1afa7f5535f2be0f Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Sun, 26 Sep 2021 10:53:21 +1000 Subject: [PATCH] Reintroduce "[ORC] Introduce EPCGenericRTDyldMemoryManager." This reintroduces "[ORC] Introduce EPCGenericRTDyldMemoryManager." (bef55a2b47a938ef35cbd7b61a1e5fa74e68c9ed) and "[lli] Add ChildTarget dependence on OrcTargetProcess library." (7a219d801bf2c3006482cf3cbd3170b3b4ea2e1b) which were reverted in 99951a56842d8e4cd0706cd17a04f77b5d0f6dd0 due to bot failures. The root cause of the bot failures should be fixed by "[ORC] Fix uninitialized variable." (0371049277912afc201da721fa659ecef7ab7fba) and "[ORC] Wait for handleDisconnect to complete in SimpleRemoteEPC::disconnect." (320832cc9b7e7fea5fc8afbed75c34c4a43287ba). --- .../Orc/EPCGenericRTDyldMemoryManager.h | 133 +++++++++ .../llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h | 3 + .../Orc/TargetProcess/RegisterEHFrames.h | 16 ++ llvm/lib/ExecutionEngine/Orc/CMakeLists.txt | 1 + .../Orc/EPCGenericRTDyldMemoryManager.cpp | 315 +++++++++++++++++++++ .../lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp | 4 + .../Orc/TargetProcess/OrcRTBootstrap.cpp | 6 + .../Orc/TargetProcess/RegisterEHFrames.cpp | 18 ++ .../TargetProcess/SimpleExecutorMemoryManager.cpp | 10 + llvm/tools/lli/ChildTarget/CMakeLists.txt | 5 +- llvm/tools/lli/ChildTarget/ChildTarget.cpp | 91 +++--- ...{RemoteJITUtils.h => ForwardingMemoryManager.h} | 62 ++-- llvm/tools/lli/lli.cpp | 49 ++-- 13 files changed, 617 insertions(+), 96 deletions(-) create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h create mode 100644 llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp rename llvm/tools/lli/{RemoteJITUtils.h => ForwardingMemoryManager.h} (68%) diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h new file mode 100644 index 0000000..b6fdfb9 --- /dev/null +++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h @@ -0,0 +1,133 @@ +//===---- EPCGenericRTDyldMemoryManager.h - EPC-based MemMgr ----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Defines a RuntimeDyld::MemoryManager that uses EPC and the ORC runtime +// bootstrap functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_EPCGENERICRTDYLDMEMORYMANAGER_H +#define LLVM_EXECUTIONENGINE_ORC_EPCGENERICRTDYLDMEMORYMANAGER_H + +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" + +#define DEBUG_TYPE "orc" + +namespace llvm { +namespace orc { + +/// Remote-mapped RuntimeDyld-compatible memory manager. +class EPCGenericRTDyldMemoryManager : public RuntimeDyld::MemoryManager { +public: + /// Symbol addresses for memory access. + struct SymbolAddrs { + ExecutorAddr Instance; + ExecutorAddr Reserve; + ExecutorAddr Finalize; + ExecutorAddr Deallocate; + ExecutorAddr RegisterEHFrame; + ExecutorAddr DeregisterEHFrame; + }; + + /// Create an EPCGenericRTDyldMemoryManager using the given EPC, looking up + /// the default symbol names in the bootstrap symbol set. + static Expected> + CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC); + + /// Create an EPCGenericRTDyldMemoryManager using the given EPC and symbol + /// addrs. + EPCGenericRTDyldMemoryManager(ExecutorProcessControl &EPC, SymbolAddrs SAs); + + EPCGenericRTDyldMemoryManager(const EPCGenericRTDyldMemoryManager &) = delete; + EPCGenericRTDyldMemoryManager & + operator=(const EPCGenericRTDyldMemoryManager &) = delete; + EPCGenericRTDyldMemoryManager(EPCGenericRTDyldMemoryManager &&) = delete; + EPCGenericRTDyldMemoryManager & + operator=(EPCGenericRTDyldMemoryManager &&) = delete; + ~EPCGenericRTDyldMemoryManager(); + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + StringRef SectionName) override; + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly) override; + + void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, + uintptr_t RODataSize, uint32_t RODataAlign, + uintptr_t RWDataSize, + uint32_t RWDataAlign) override; + + bool needsToReserveAllocationSpace() override; + + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override; + + void deregisterEHFrames() override; + + void notifyObjectLoaded(RuntimeDyld &Dyld, + const object::ObjectFile &Obj) override; + + bool finalizeMemory(std::string *ErrMsg = nullptr) override; + +private: + struct Alloc { + public: + Alloc(uint64_t Size, unsigned Align) + : Size(Size), Align(Align), + Contents(std::make_unique(Size + Align - 1)) {} + + uint64_t Size; + unsigned Align; + std::unique_ptr Contents; + ExecutorAddr RemoteAddr; + }; + + struct EHFrame { + ExecutorAddr Addr; + uint64_t Size; + }; + + // Group of section allocations to be allocated together in the executor. The + // RemoteCodeAddr will stand in as the id of the group for deallocation + // purposes. + struct AllocGroup { + AllocGroup() = default; + AllocGroup(const AllocGroup &) = delete; + AllocGroup &operator=(const AllocGroup &) = delete; + AllocGroup(AllocGroup &&) = default; + AllocGroup &operator=(AllocGroup &&) = default; + + ExecutorAddrRange RemoteCode; + ExecutorAddrRange RemoteROData; + ExecutorAddrRange RemoteRWData; + std::vector UnfinalizedEHFrames; + std::vector CodeAllocs, RODataAllocs, RWDataAllocs; + }; + + // Maps all allocations in Allocs to aligned blocks + void mapAllocsToRemoteAddrs(RuntimeDyld &Dyld, std::vector &Allocs, + ExecutorAddr NextAddr); + + ExecutorProcessControl &EPC; + SymbolAddrs SAs; + + std::mutex M; + std::vector Unmapped; + std::vector Unfinalized; + std::vector FinalizedAllocs; + std::string ErrMsg; +}; + +} // end namespace orc +} // end namespace llvm + +#undef DEBUG_TYPE + +#endif // LLVM_EXECUTIONENGINE_ORC_EPCGENERICRTDYLDMEMORYMANAGER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h index a339904..3ef43f3 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h @@ -37,6 +37,9 @@ extern const char *MemoryWriteUInt32sWrapperName; extern const char *MemoryWriteUInt64sWrapperName; extern const char *MemoryWriteBuffersWrapperName; +extern const char *RegisterEHFrameSectionCustomDirectWrapperName; +extern const char *DeregisterEHFrameSectionCustomDirectWrapperName; + extern const char *RunAsMainWrapperName; using SPSSimpleExecutorDylibManagerOpenSignature = diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h index 3b4aabb..6d12be3 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h @@ -33,6 +33,22 @@ Error deregisterEHFrameSection(const void *EHFrameSectionAddr, } // end namespace orc } // end namespace llvm +/// An eh-frame registration utility suitable for use as a support function +/// call. This function expects the direct address and size of the eh-frame +/// section to register as its arguments (it does not treat its arguments as +/// pointers to an SPS-serialized arg buffer). +extern "C" llvm::orc::shared::detail::CWrapperFunctionResult +llvm_orc_registerEHFrameSectionCustomDirectWrapper( + const char *EHFrameSectionAddr, uint64_t Size); + +/// An eh-frame deregistration utility suitable for use as a support function +/// call. This function expects the direct address and size of the eh-frame +/// section to register as its arguments (it does not treat its arguments as +/// pointers to an SPS-serialized arg buffer). +extern "C" llvm::orc::shared::detail::CWrapperFunctionResult +llvm_orc_deregisterEHFrameSectionCustomDirectWrapper( + const char *EHFrameSectionAddr, uint64_t Size); + extern "C" llvm::orc::shared::detail::CWrapperFunctionResult llvm_orc_registerEHFrameSectionWrapper(const char *Data, uint64_t Size); diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt index cce5077..8d69cc3 100644 --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -9,6 +9,7 @@ add_llvm_component_library(LLVMOrcJIT EPCEHFrameRegistrar.cpp EPCGenericDylibManager.cpp EPCGenericJITLinkMemoryManager.cpp + EPCGenericRTDyldMemoryManager.cpp EPCIndirectionUtils.cpp ExecutionUtils.cpp IndirectionUtils.cpp diff --git a/llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp b/llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp new file mode 100644 index 0000000..cb5e724 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp @@ -0,0 +1,315 @@ +//===----- EPCGenericRTDyldMemoryManager.cpp - EPC-bbasde MemMgr -----===// +// +// 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/EPCGenericRTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h" +#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/FormatVariadic.h" + +#define DEBUG_TYPE "orc" + +namespace llvm { +namespace orc { + +Expected> +EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols( + ExecutorProcessControl &EPC) { + SymbolAddrs SAs; + if (auto Err = EPC.getBootstrapSymbols( + {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName}, + {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName}, + {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName}, + {SAs.Deallocate, + rt::SimpleExecutorMemoryManagerDeallocateWrapperName}, + {SAs.RegisterEHFrame, + rt::RegisterEHFrameSectionCustomDirectWrapperName}, + {SAs.DeregisterEHFrame, + rt::DeregisterEHFrameSectionCustomDirectWrapperName}})) + return std::move(Err); + return std::make_unique(EPC, std::move(SAs)); +} + +EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager( + ExecutorProcessControl &EPC, SymbolAddrs SAs) + : EPC(EPC), SAs(std::move(SAs)) { + LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n"); +} + +EPCGenericRTDyldMemoryManager::~EPCGenericRTDyldMemoryManager() { + LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n"); + if (!ErrMsg.empty()) + errs() << "Destroying with existing errors:\n" << ErrMsg << "\n"; + + Error Err = Error::success(); + if (auto Err2 = EPC.callSPSWrapper< + rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>( + SAs.Reserve.getValue(), Err, SAs.Instance, FinalizedAllocs)) { + // FIXME: Report errors through EPC once that functionality is available. + logAllUnhandledErrors(std::move(Err2), errs(), ""); + return; + } + + if (Err) + logAllUnhandledErrors(std::move(Err), errs(), ""); +} + +uint8_t *EPCGenericRTDyldMemoryManager::allocateCodeSection( + uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName) { + std::lock_guard Lock(M); + LLVM_DEBUG({ + dbgs() << "Allocator " << (void *)this << " allocating code section " + << SectionName << ": size = " << formatv("{0:x}", Size) + << " bytes, alignment = " << Alignment << "\n"; + }); + auto &Seg = Unmapped.back().CodeAllocs; + Seg.emplace_back(Size, Alignment); + return reinterpret_cast( + alignAddr(Seg.back().Contents.get(), Align(Alignment))); +} + +uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection( + uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName, bool IsReadOnly) { + std::lock_guard Lock(M); + LLVM_DEBUG({ + dbgs() << "Allocator " << (void *)this << " allocating " + << (IsReadOnly ? "ro" : "rw") << "-data section " << SectionName + << ": size = " << formatv("{0:x}", Size) << " bytes, alignment " + << Alignment << ")\n"; + }); + + auto &Seg = + IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs; + + Seg.emplace_back(Size, Alignment); + return reinterpret_cast( + alignAddr(Seg.back().Contents.get(), Align(Alignment))); +} + +void EPCGenericRTDyldMemoryManager::reserveAllocationSpace( + uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize, + uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) { + + { + std::lock_guard Lock(M); + // If there's already an error then bail out. + if (!ErrMsg.empty()) + return; + + if (!isPowerOf2_32(CodeAlign) || CodeAlign > EPC.getPageSize()) { + ErrMsg = "Invalid code alignment in reserveAllocationSpace"; + return; + } + if (!isPowerOf2_32(RODataAlign) || RODataAlign > EPC.getPageSize()) { + ErrMsg = "Invalid ro-data alignment in reserveAllocationSpace"; + return; + } + if (!isPowerOf2_32(RWDataAlign) || RWDataAlign > EPC.getPageSize()) { + ErrMsg = "Invalid rw-data alignment in reserveAllocationSpace"; + return; + } + } + + uint64_t TotalSize = 0; + TotalSize += alignTo(CodeSize, EPC.getPageSize()); + TotalSize += alignTo(RODataSize, EPC.getPageSize()); + TotalSize += alignTo(RWDataSize, EPC.getPageSize()); + + LLVM_DEBUG({ + dbgs() << "Allocator " << (void *)this << " reserving " + << formatv("{0:x}", TotalSize) << " bytes.\n"; + }); + + Expected TargetAllocAddr((ExecutorAddr())); + if (auto Err = EPC.callSPSWrapper< + rt::SPSSimpleExecutorMemoryManagerReserveSignature>( + SAs.Reserve.getValue(), TargetAllocAddr, SAs.Instance, TotalSize)) { + std::lock_guard Lock(M); + ErrMsg = toString(std::move(Err)); + return; + } + if (!TargetAllocAddr) { + std::lock_guard Lock(M); + ErrMsg = toString(TargetAllocAddr.takeError()); + return; + } + + std::lock_guard Lock(M); + Unmapped.push_back(AllocGroup()); + Unmapped.back().RemoteCode = { + *TargetAllocAddr, ExecutorAddrDiff(alignTo(CodeSize, EPC.getPageSize()))}; + Unmapped.back().RemoteROData = { + Unmapped.back().RemoteCode.End, + ExecutorAddrDiff(alignTo(RODataSize, EPC.getPageSize()))}; + Unmapped.back().RemoteRWData = { + Unmapped.back().RemoteROData.End, + ExecutorAddrDiff(alignTo(RWDataSize, EPC.getPageSize()))}; +} + +bool EPCGenericRTDyldMemoryManager::needsToReserveAllocationSpace() { + return true; +} + +void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr, + uint64_t LoadAddr, + size_t Size) { + LLVM_DEBUG({ + dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame " + << formatv("[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) << "\n"; + }); + std::lock_guard Lock(M); + // Bail out early if there's already an error. + if (!ErrMsg.empty()) + return; + + ExecutorAddr LA(LoadAddr); + for (auto &Alloc : llvm::reverse(Unfinalized)) { + if (Alloc.RemoteCode.contains(LA) || Alloc.RemoteROData.contains(LA) || + Alloc.RemoteRWData.contains(LA)) { + Alloc.UnfinalizedEHFrames.push_back({LA, Size}); + return; + } + } + ErrMsg = "eh-frame does not lie inside unfinalized alloc"; +} + +void EPCGenericRTDyldMemoryManager::deregisterEHFrames() { + // This is a no-op for us: We've registered a deallocation action for it. +} + +void EPCGenericRTDyldMemoryManager::notifyObjectLoaded( + RuntimeDyld &Dyld, const object::ObjectFile &Obj) { + std::lock_guard Lock(M); + LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " applied mappings:\n"); + for (auto &ObjAllocs : Unmapped) { + mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs, + ObjAllocs.RemoteCode.Start); + mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs, + ObjAllocs.RemoteROData.Start); + mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs, + ObjAllocs.RemoteRWData.Start); + Unfinalized.push_back(std::move(ObjAllocs)); + } + Unmapped.clear(); +} + +bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) { + LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n"); + + // If there's an error then bail out here. + std::vector Allocs; + { + std::lock_guard Lock(M); + if (ErrMsg && !this->ErrMsg.empty()) { + *ErrMsg = std::move(this->ErrMsg); + return true; + } + std::swap(Allocs, Unfinalized); + } + + // Loop over unfinalized objects to make finalization requests. + for (auto &ObjAllocs : Allocs) { + + tpctypes::WireProtectionFlags SegProts[3] = { + tpctypes::toWireProtectionFlags( + static_cast(sys::Memory::MF_READ | + sys::Memory::MF_EXEC)), + tpctypes::toWireProtectionFlags(sys::Memory::MF_READ), + tpctypes::toWireProtectionFlags( + static_cast(sys::Memory::MF_READ | + sys::Memory::MF_WRITE))}; + + ExecutorAddrRange *RemoteAddrs[3] = {&ObjAllocs.RemoteCode, + &ObjAllocs.RemoteROData, + &ObjAllocs.RemoteRWData}; + + std::vector *SegSections[3] = {&ObjAllocs.CodeAllocs, + &ObjAllocs.RODataAllocs, + &ObjAllocs.RWDataAllocs}; + + tpctypes::FinalizeRequest FR; + std::unique_ptr AggregateContents[3]; + + for (unsigned I = 0; I != 3; ++I) { + FR.Segments.push_back({}); + auto &Seg = FR.Segments.back(); + Seg.Prot = SegProts[I]; + Seg.Addr = RemoteAddrs[I]->Start; + for (auto &SecAlloc : *SegSections[I]) { + Seg.Size = alignTo(Seg.Size, SecAlloc.Align); + Seg.Size += SecAlloc.Size; + } + AggregateContents[I] = std::make_unique(Seg.Size); + size_t SecOffset = 0; + for (auto &SecAlloc : *SegSections[I]) { + SecOffset = alignTo(SecOffset, SecAlloc.Align); + memcpy(&AggregateContents[I][SecOffset], + reinterpret_cast( + alignAddr(SecAlloc.Contents.get(), Align(SecAlloc.Align))), + SecAlloc.Size); + SecOffset += SecAlloc.Size; + // FIXME: Can we reset SecAlloc.Content here, now that it's copied into + // the aggregated content? + } + Seg.Content = {AggregateContents[I].get(), SecOffset}; + } + + for (auto &Frame : ObjAllocs.UnfinalizedEHFrames) + FR.Actions.push_back({{SAs.RegisterEHFrame, Frame.Addr, Frame.Size}, + {SAs.DeregisterEHFrame, Frame.Addr, Frame.Size}}); + + // We'll also need to make an extra allocation for the eh-frame wrapper call + // arguments. + Error FinalizeErr = Error::success(); + if (auto Err = EPC.callSPSWrapper< + rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>( + SAs.Finalize.getValue(), FinalizeErr, SAs.Instance, + std::move(FR))) { + std::lock_guard Lock(M); + this->ErrMsg = toString(std::move(Err)); + dbgs() << "Serialization error: " << this->ErrMsg << "\n"; + if (ErrMsg) + *ErrMsg = this->ErrMsg; + return true; + } + if (FinalizeErr) { + std::lock_guard Lock(M); + this->ErrMsg = toString(std::move(FinalizeErr)); + dbgs() << "Finalization error: " << this->ErrMsg << "\n"; + if (ErrMsg) + *ErrMsg = this->ErrMsg; + return true; + } + } + + return false; +} + +void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs( + RuntimeDyld &Dyld, std::vector &Allocs, ExecutorAddr NextAddr) { + for (auto &Alloc : Allocs) { + NextAddr.setValue(alignTo(NextAddr.getValue(), Alloc.Align)); + LLVM_DEBUG({ + dbgs() << " " << static_cast(Alloc.Contents.get()) << " -> " + << format("0x%016" PRIx64, NextAddr.getValue()) << "\n"; + }); + Dyld.mapSectionAddress(reinterpret_cast(alignAddr( + Alloc.Contents.get(), Align(Alloc.Align))), + NextAddr.getValue()); + Alloc.RemoteAddr = NextAddr; + // Only advance NextAddr if it was non-null to begin with, + // otherwise leave it as null. + if (NextAddr) + NextAddr += ExecutorAddrDiff(Alloc.Size); + } +} + +} // end namespace orc +} // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp index 6c3032c..02044e4 100644 --- a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp @@ -36,6 +36,10 @@ const char *MemoryWriteUInt64sWrapperName = "__llvm_orc_bootstrap_mem_write_uint64s_wrapper"; const char *MemoryWriteBuffersWrapperName = "__llvm_orc_bootstrap_mem_write_buffers_wrapper"; +const char *RegisterEHFrameSectionCustomDirectWrapperName = + "__llvm_orc_bootstrap_register_ehframe_section_custom_direct_wrapper"; +const char *DeregisterEHFrameSectionCustomDirectWrapperName = + "__llvm_orc_bootstrap_deregister_ehframe_section_custom_direct_wrapper"; const char *RunAsMainWrapperName = "__llvm_orc_bootstrap_run_as_main_wrapper"; } // end namespace rt diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp index f61bb6e..356bb0b 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp @@ -10,6 +10,7 @@ #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" +#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h" #define DEBUG_TYPE "orc" @@ -71,6 +72,11 @@ void addTo(StringMap &M) { shared::SPSMemoryAccessUInt64Write>); M[rt::MemoryWriteBuffersWrapperName] = ExecutorAddr::fromPtr(&writeBuffersWrapper); + M[rt::RegisterEHFrameSectionCustomDirectWrapperName] = ExecutorAddr::fromPtr( + &llvm_orc_registerEHFrameSectionCustomDirectWrapper); + M[rt::DeregisterEHFrameSectionCustomDirectWrapperName] = + ExecutorAddr::fromPtr( + &llvm_orc_deregisterEHFrameSectionCustomDirectWrapper); M[rt::RunAsMainWrapperName] = ExecutorAddr::fromPtr(&runAsMainWrapper); } diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp index 3e4c61f..ee67e61 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp @@ -158,6 +158,24 @@ Error deregisterEHFrameSection(const void *EHFrameSectionAddr, } // end namespace orc } // end namespace llvm +extern "C" llvm::orc::shared::detail::CWrapperFunctionResult +llvm_orc_registerEHFrameSectionCustomDirectWrapper( + const char *EHFrameSectionAddr, uint64_t Size) { + if (auto Err = registerEHFrameSection(EHFrameSectionAddr, Size)) + return WrapperFunctionResult::createOutOfBandError(toString(std::move(Err))) + .release(); + return llvm::orc::shared::detail::CWrapperFunctionResult(); +} + +extern "C" llvm::orc::shared::detail::CWrapperFunctionResult +llvm_orc_deregisterEHFrameSectionCustomDirectWrapper( + const char *EHFrameSectionAddr, uint64_t Size) { + if (auto Err = deregisterEHFrameSection(EHFrameSectionAddr, Size)) + return WrapperFunctionResult::createOutOfBandError(toString(std::move(Err))) + .release(); + return llvm::orc::shared::detail::CWrapperFunctionResult(); +} + static Error registerEHFrameWrapper(JITTargetAddress Addr, uint64_t Size) { return llvm::orc::registerEHFrameSection( jitTargetAddressToPointer(Addr), Size); diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.cpp index 83b39b8..c25d188 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.cpp @@ -38,6 +38,16 @@ Error SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest &FR) { std::vector DeallocationActions; size_t SuccessfulFinalizationActions = 0; + if (FR.Segments.empty()) { + // NOTE: Finalizing nothing is currently a no-op. Should it be an error? + if (FR.Actions.empty()) + return Error::success(); + else + return make_error("Finalization actions attached to empty " + "finalization request", + inconvertibleErrorCode()); + } + for (auto &Seg : FR.Segments) Base = std::min(Base, Seg.Addr); diff --git a/llvm/tools/lli/ChildTarget/CMakeLists.txt b/llvm/tools/lli/ChildTarget/CMakeLists.txt index c5795ee..ea28756 100644 --- a/llvm/tools/lli/ChildTarget/CMakeLists.txt +++ b/llvm/tools/lli/ChildTarget/CMakeLists.txt @@ -1,7 +1,7 @@ set(LLVM_LINK_COMPONENTS - OrcShared OrcJIT - RuntimeDyld + OrcShared + OrcTargetProcess Support ) @@ -11,4 +11,3 @@ add_llvm_utility(lli-child-target DEPENDS intrinsics_gen ) - diff --git a/llvm/tools/lli/ChildTarget/ChildTarget.cpp b/llvm/tools/lli/ChildTarget/ChildTarget.cpp index 5772bac..dd57c65 100644 --- a/llvm/tools/lli/ChildTarget/ChildTarget.cpp +++ b/llvm/tools/lli/ChildTarget/ChildTarget.cpp @@ -1,69 +1,80 @@ -#include "llvm/ExecutionEngine/Orc/OrcABISupport.h" -#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h" +//===----------- ChildTarget.cpp - Out-of-proc executor for lli -----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Simple out-of-process executor for lli. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h" -#include "llvm/Support/Debug.h" +#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" +#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" +#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h" #include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/Process.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include #include -#include "../RemoteJITUtils.h" - using namespace llvm; using namespace llvm::orc; -using namespace llvm::sys; - -#ifdef __x86_64__ -typedef OrcX86_64_SysV HostOrcArch; -#else -typedef OrcGenericABI HostOrcArch; -#endif ExitOnError ExitOnErr; int main(int argc, char *argv[]) { +#if LLVM_ENABLE_THREADS if (argc != 3) { errs() << "Usage: " << argv[0] << " \n"; return 1; } - ExitOnErr.setBanner(std::string(argv[0]) + ":"); - - int InFD; - int OutFD; - { - std::istringstream InFDStream(argv[1]), OutFDStream(argv[2]); - InFDStream >> InFD; - OutFDStream >> OutFD; - } - if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) { errs() << "Error loading program symbols.\n"; return 1; } - auto SymbolLookup = [](const std::string &Name) { - return RTDyldMemoryManager::getSymbolAddressInProcess(Name); - }; + ExitOnErr.setBanner(std::string(argv[0]) + ": "); - auto RegisterEHFrames = [](uint8_t *Addr, uint32_t Size) { - RTDyldMemoryManager::registerEHFramesInProcess(Addr, Size); - }; - - auto DeregisterEHFrames = [](uint8_t *Addr, uint32_t Size) { - RTDyldMemoryManager::deregisterEHFramesInProcess(Addr, Size); - }; - - shared::FDRawByteChannel Channel(InFD, OutFD); - typedef remote::OrcRemoteTargetServer - JITServer; - JITServer Server(Channel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames); + int InFD = 0; + int OutFD = 0; + { + std::istringstream InFDStream(argv[1]), OutFDStream(argv[2]); + InFDStream >> InFD; + OutFDStream >> OutFD; + } - while (!Server.receivedTerminate()) - ExitOnErr(Server.handleOne()); + auto Server = + ExitOnErr(SimpleRemoteEPCServer::Create( + [](SimpleRemoteEPCServer::Setup &S) -> Error { + S.setDispatcher( + std::make_unique()); + S.bootstrapSymbols() = + SimpleRemoteEPCServer::defaultBootstrapSymbols(); + S.services().push_back( + std::make_unique()); + return Error::success(); + }, + InFD, OutFD)); + + ExitOnErr(Server->waitForDisconnect()); close(InFD); close(OutFD); return 0; + +#else + errs() << argv[0] + << " error: this tool requires threads, but LLVM was " + "built with LLVM_ENABLE_THREADS=Off\n"; + return 1; +#endif } diff --git a/llvm/tools/lli/RemoteJITUtils.h b/llvm/tools/lli/ForwardingMemoryManager.h similarity index 68% rename from llvm/tools/lli/RemoteJITUtils.h rename to llvm/tools/lli/ForwardingMemoryManager.h index cc8d034..99a545e 100644 --- a/llvm/tools/lli/RemoteJITUtils.h +++ b/llvm/tools/lli/ForwardingMemoryManager.h @@ -10,21 +10,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H -#define LLVM_TOOLS_LLI_REMOTEJITUTILS_H +#ifndef LLVM_TOOLS_LLI_FORWARDINGMEMORYMANAGER_H +#define LLVM_TOOLS_LLI_FORWARDINGMEMORYMANAGER_H -#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h" +#include "llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include -#else -#include -#endif - -// launch the remote process (see lli.cpp) and return a channel to it. -std::unique_ptr launchRemote(); namespace llvm { @@ -70,9 +60,7 @@ public: MemMgr->registerEHFrames(Addr, LoadAddr, Size); } - void deregisterEHFrames() override { - MemMgr->deregisterEHFrames(); - } + void deregisterEHFrames() override { MemMgr->deregisterEHFrames(); } bool finalizeMemory(std::string *ErrMsg = nullptr) override { return MemMgr->finalizeMemory(ErrMsg); @@ -90,8 +78,7 @@ public: return Resolver->findSymbol(Name); } - JITSymbol - findSymbolInLogicalDylib(const std::string &Name) override { + JITSymbol findSymbolInLogicalDylib(const std::string &Name) override { return Resolver->findSymbolInLogicalDylib(Name); } @@ -100,17 +87,31 @@ private: std::shared_ptr Resolver; }; -template class RemoteResolver : public LegacyJITSymbolResolver { public: - - RemoteResolver(RemoteT &R) : R(R) {} + static Expected> + Create(orc::ExecutorProcessControl &EPC) { + auto DylibMgr = + orc::EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(EPC); + if (!DylibMgr) + return DylibMgr.takeError(); + auto H = DylibMgr->open("", 0); + if (!H) + return H.takeError(); + return std::unique_ptr( + new RemoteResolver(std::move(*DylibMgr), std::move(*H))); + } JITSymbol findSymbol(const std::string &Name) override { - if (auto Addr = R.getSymbolAddress(Name)) - return JITSymbol(*Addr, JITSymbolFlags::Exported); - else - return Addr.takeError(); + orc::RemoteSymbolLookupSet R; + R.push_back({std::move(Name), false}); + if (auto Addrs = DylibMgr.lookup(H, R)) { + if (Addrs->size() != 1) + return make_error("Unexpected remote lookup result", + inconvertibleErrorCode()); + return JITSymbol(Addrs->front().getValue(), JITSymbolFlags::Exported); + } else + return Addrs.takeError(); } JITSymbol findSymbolInLogicalDylib(const std::string &Name) override { @@ -118,8 +119,13 @@ public: } public: - RemoteT &R; + RemoteResolver(orc::EPCGenericDylibManager DylibMgr, + orc::tpctypes::DylibHandle H) + : DylibMgr(std::move(DylibMgr)), H(std::move(H)) {} + + orc::EPCGenericDylibManager DylibMgr; + orc::tpctypes::DylibHandle H; }; -} +} // namespace llvm -#endif +#endif // LLVM_TOOLS_LLI_FORWARDINGMEMORYMANAGER_H diff --git a/llvm/tools/lli/lli.cpp b/llvm/tools/lli/lli.cpp index 170cc3b..6f75c75 100644 --- a/llvm/tools/lli/lli.cpp +++ b/llvm/tools/lli/lli.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ExecutionUtils.h" -#include "RemoteJITUtils.h" +#include "ForwardingMemoryManager.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/BitcodeReader.h" @@ -30,11 +30,12 @@ #include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" #include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h" +#include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" -#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h" #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" @@ -68,6 +69,12 @@ #include "llvm/Transforms/Instrumentation.h" #include +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include +#else +#include +#endif + #ifdef __CYGWIN__ #include #if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007 @@ -418,6 +425,7 @@ CodeGenOpt::Level getOptLevel() { Error loadDylibs(); int runOrcJIT(const char *ProgName); void disallowOrcOptions(); +Expected> launchRemote(); //===----------------------------------------------------------------------===// // main Driver function @@ -658,6 +666,10 @@ int main(int argc, char **argv, char * const *envp) { #endif } + std::unique_ptr EPC = + RemoteMCJIT ? ExitOnErr(launchRemote()) + : ExitOnErr(orc::SelfExecutorProcessControl::Create()); + if (!RemoteMCJIT) { // If the program doesn't explicitly call exit, we will need the Exit // function later on to make an explicit call, so get the function now. @@ -708,22 +720,10 @@ int main(int argc, char **argv, char * const *envp) { // it couldn't. This is a limitation of the LLI implementation, not the // MCJIT itself. FIXME. - // Lanch the remote process and get a channel to it. - std::unique_ptr C = launchRemote(); - if (!C) { - WithColor::error(errs(), argv[0]) << "failed to launch remote JIT.\n"; - exit(1); - } - - // Create a remote target client running over the channel. - llvm::orc::ExecutionSession ES( - std::make_unique()); - ES.setErrorReporter([&](Error Err) { ExitOnErr(std::move(Err)); }); - typedef orc::remote::OrcRemoteTargetClient MyRemote; - auto R = ExitOnErr(MyRemote::Create(*C, ES)); - // Create a remote memory manager. - auto RemoteMM = ExitOnErr(R->createRemoteMemoryManager()); + auto RemoteMM = ExitOnErr( + orc::EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols( + *EPC)); // Forward MCJIT's memory manager calls to the remote memory manager. static_cast(RTDyldMM)->setMemMgr( @@ -731,8 +731,7 @@ int main(int argc, char **argv, char * const *envp) { // Forward MCJIT's symbol resolution calls to the remote. static_cast(RTDyldMM)->setResolver( - std::make_unique>(*R)); - + ExitOnErr(RemoteResolver::Create(*EPC))); // Grab the target address of the JIT'd main function on the remote and call // it. // FIXME: argv and envp handling. @@ -740,7 +739,7 @@ int main(int argc, char **argv, char * const *envp) { EE->finalizeObject(); LLVM_DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" << format("%llx", Entry) << "\n"); - Result = ExitOnErr(R->callIntVoid(Entry)); + Result = ExitOnErr(EPC->runAsMain(Entry, {})); // Like static constructors, the remote target MCJIT support doesn't handle // this yet. It could. FIXME. @@ -751,7 +750,7 @@ int main(int argc, char **argv, char * const *envp) { EE.reset(); // Signal the remote target that we're done JITing. - ExitOnErr(R->terminateSession()); + ExitOnErr(EPC->disconnect()); } return Result; @@ -1098,7 +1097,7 @@ void disallowOrcOptions() { } } -std::unique_ptr launchRemote() { +Expected> launchRemote() { #ifndef LLVM_ON_UNIX llvm_unreachable("launchRemote not supported on non-Unix platforms"); #else @@ -1147,8 +1146,8 @@ std::unique_ptr launchRemote() { close(PipeFD[0][0]); close(PipeFD[1][1]); - // Return an RPC channel connected to our end of the pipes. - return std::make_unique(PipeFD[1][0], - PipeFD[0][1]); + // Return a SimpleRemoteEPC instance connected to our end of the pipes. + return orc::SimpleRemoteEPC::Create( + PipeFD[1][0], PipeFD[0][1]); #endif } -- 2.7.4