[llvm] 1d0676b - [ORC] Break up OrcJIT library, add Orc-RPC based remote TargetProcessControl

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 12 22:05:57 PST 2020


Author: Lang Hames
Date: 2020-11-13T17:05:13+11:00
New Revision: 1d0676b54c4e3a517719220def96dfdbc26d8048

URL: https://github.com/llvm/llvm-project/commit/1d0676b54c4e3a517719220def96dfdbc26d8048
DIFF: https://github.com/llvm/llvm-project/commit/1d0676b54c4e3a517719220def96dfdbc26d8048.diff

LOG: [ORC] Break up OrcJIT library, add Orc-RPC based remote TargetProcessControl
implementation.

This patch aims to improve support for out-of-process JITing using OrcV2. It
introduces two new class templates, OrcRPCTargetProcessControlBase and
OrcRPCTPCServer, which together implement the TargetProcessControl API by
forwarding operations to an execution process via an Orc-RPC Endpoint. These
utilities are used to implement out-of-process JITing from llvm-jitlink to
a new llvm-jitlink-executor tool.

This patch also breaks the OrcJIT library into three parts:
  -- OrcTargetProcess: Contains code needed by the JIT execution process.
  -- OrcShared: Contains code needed by the JIT execution and compiler
     processes
  -- OrcJIT: Everything else.

This break-up allows JIT executor processes to link against OrcTargetProcess
and OrcShared only, without having to link in all of OrcJIT. Clients executing
JIT'd code in-process should start linking against OrcTargetProcess as well as
OrcJIT.

In the near future these changes will enable:
  -- Removal of the OrcRemoteTargetClient/OrcRemoteTargetServer class templates
     which provided similar functionality in OrcV1.
  -- Restoration of Chapter 5 of the Building-A-JIT tutorial series, which will
     serve as a simple usage example for these APIs.
  -- Implementation of lazy, cross-target compilation in lli's -jit-kind=orc-lazy
     mode.

Added: 
    llvm/include/llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h
    llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
    llvm/include/llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h
    llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h
    llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h
    llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h
    llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
    llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt
    llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt.rej
    llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp
    llvm/lib/ExecutionEngine/Orc/Shared/RPCError.cpp
    llvm/lib/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.cpp
    llvm/lib/ExecutionEngine/Orc/TPCEHFrameRegistrar.cpp
    llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
    llvm/lib/ExecutionEngine/Orc/TargetProcess/LLVMBuild.txt
    llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp
    llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp
    llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
    llvm/tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt
    llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp

Modified: 
    llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
    llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
    llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
    llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
    llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
    llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
    llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
    llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
    llvm/lib/ExecutionEngine/CMakeLists.txt
    llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
    llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
    llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
    llvm/lib/ExecutionEngine/LLVMBuild.txt
    llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
    llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
    llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
    llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
    llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
    llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
    llvm/tools/lli/CMakeLists.txt
    llvm/tools/lli/ChildTarget/CMakeLists.txt
    llvm/tools/lli/LLVMBuild.txt
    llvm/tools/lli/lli.cpp
    llvm/tools/llvm-jitlink/CMakeLists.txt
    llvm/tools/llvm-jitlink/LLVMBuild.txt
    llvm/tools/llvm-jitlink/llvm-jitlink.cpp
    llvm/tools/llvm-jitlink/llvm-jitlink.h
    llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
    llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt

Removed: 
    llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt
    llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt
    llvm/lib/ExecutionEngine/OrcError/OrcError.cpp
    llvm/lib/ExecutionEngine/OrcError/RPCError.cpp


################################################################################
diff  --git a/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp b/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
index d2ce26bddd72..4e36631ef97d 100644
--- a/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
+++ b/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
@@ -134,7 +134,8 @@ int main(int argc, char *argv[]) {
   ExitOnErr.setBanner(std::string(argv[0]) + ": ");
 
   // (1) Create LLJIT instance.
-  auto TPC = ExitOnErr(SelfTargetProcessControl::Create());
+  auto SSP = std::make_shared<SymbolStringPool>();
+  auto TPC = ExitOnErr(SelfTargetProcessControl::Create(std::move(SSP)));
   auto J = ExitOnErr(LLJITBuilder().setTargetProcessControl(*TPC).create());
 
   // (2) Install transform to print modules as they are compiled:

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
index 72394d7c9985..ec78d9db40b6 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
@@ -21,14 +21,6 @@
 namespace llvm {
 namespace jitlink {
 
-/// Registers all FDEs in the given eh-frame section with the current process.
-Error registerEHFrameSection(const void *EHFrameSectionAddr,
-                             size_t EHFrameSectionSize);
-
-/// Deregisters all FDEs in the given eh-frame section with the current process.
-Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
-                               size_t EHFrameSectionSize);
-
 /// Supports registration/deregistration of EH-frames in a target process.
 class EHFrameRegistrar {
 public:

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
index 5e22837fa930..f0b4d9bcd49c 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
@@ -801,6 +801,17 @@ class LinkGraph {
   /// Returns the endianness of content in this graph.
   support::endianness getEndianness() const { return Endianness; }
 
+  /// Allocate a copy of the given String using the LinkGraph's allocator.
+  /// This can be useful when renaming symbols or adding new content to the
+  /// graph.
+  StringRef allocateString(Twine Source) {
+    SmallString<256> TmpBuffer;
+    auto SourceStr = Source.toStringRef(TmpBuffer);
+    auto *AllocatedBuffer = Allocator.Allocate<char>(SourceStr.size());
+    llvm::copy(SourceStr, AllocatedBuffer);
+    return StringRef(AllocatedBuffer, SourceStr.size());
+  }
+
   /// Create a section with the given name, protection flags, and alignment.
   Section &createSection(StringRef Name, sys::Memory::ProtectionFlags Prot) {
     std::unique_ptr<Section> Sec(new Section(Name, Prot, Sections.size()));

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
index 0270f8f7d68d..1dc2af49b78e 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
@@ -41,17 +41,6 @@ namespace orc {
 
 class ObjectLayer;
 
-/// Run a main function, returning the result.
-///
-/// If the optional ProgramName argument is given then it will be inserted
-/// before the strings in Args as the first argument to the called function.
-///
-/// It is legal to have an empty argument list and no program name, however
-/// many main functions will expect a name argument at least, and will fail
-/// if none is provided.
-int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
-              Optional<StringRef> ProgramName = None);
-
 /// This iterator provides a convenient way to iterate over the elements
 ///        of an llvm.global_ctors/llvm.global_dtors instance.
 ///

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h
new file mode 100644
index 000000000000..f63dcd0f3471
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h
@@ -0,0 +1,411 @@
+//===--- OrcRPCTargetProcessControl.h - Remote target control ---*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for interacting with target processes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
+#define LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
+
+#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
+#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
+#include "llvm/Support/MSVCErrorWorkarounds.h"
+
+namespace llvm {
+namespace orc {
+
+/// JITLinkMemoryManager implementation for a process connected via an ORC RPC
+/// endpoint.
+template <typename OrcRPCTPCImplT>
+class OrcRPCTPCJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
+private:
+  struct HostAlloc {
+    std::unique_ptr<char[]> Mem;
+    uint64_t Size;
+  };
+
+  struct TargetAlloc {
+    JITTargetAddress Address = 0;
+    uint64_t AllocatedSize = 0;
+  };
+
+  using HostAllocMap = DenseMap<int, HostAlloc>;
+  using TargetAllocMap = DenseMap<int, TargetAlloc>;
+
+public:
+  class OrcRPCAllocation : public Allocation {
+  public:
+    OrcRPCAllocation(OrcRPCTPCJITLinkMemoryManager<OrcRPCTPCImplT> &Parent,
+                     HostAllocMap HostAllocs, TargetAllocMap TargetAllocs)
+        : Parent(Parent), HostAllocs(std::move(HostAllocs)),
+          TargetAllocs(std::move(TargetAllocs)) {
+      assert(HostAllocs.size() == TargetAllocs.size() &&
+             "HostAllocs size should match TargetAllocs");
+    }
+
+    ~OrcRPCAllocation() override {
+      assert(TargetAllocs.empty() && "failed to deallocate");
+    }
+
+    MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
+      auto I = HostAllocs.find(Seg);
+      assert(I != HostAllocs.end() && "No host allocation for segment");
+      auto &HA = I->second;
+      return {HA.Mem.get(), HA.Size};
+    }
+
+    JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
+      auto I = TargetAllocs.find(Seg);
+      assert(I != TargetAllocs.end() && "No target allocation for segment");
+      return I->second.Address;
+    }
+
+    void finalizeAsync(FinalizeContinuation OnFinalize) override {
+
+      std::vector<tpctypes::BufferWrite> BufferWrites;
+      orcrpctpc::ReleaseOrFinalizeMemRequest FMR;
+
+      for (auto &KV : HostAllocs) {
+        assert(TargetAllocs.count(KV.first) &&
+               "No target allocation for buffer");
+        auto &HA = KV.second;
+        auto &TA = TargetAllocs[KV.first];
+        BufferWrites.push_back({TA.Address, StringRef(HA.Mem.get(), HA.Size)});
+        FMR.push_back({orcrpctpc::toWireProtectionFlags(
+                           static_cast<sys::Memory::ProtectionFlags>(KV.first)),
+                       TA.Address, TA.AllocatedSize});
+      }
+
+      DEBUG_WITH_TYPE("orc", {
+        dbgs() << "finalizeAsync " << (void *)this << ":\n";
+        auto FMRI = FMR.begin();
+        for (auto &B : BufferWrites) {
+          auto Prot = FMRI->Prot;
+          ++FMRI;
+          dbgs() << "  Writing " << formatv("{0:x16}", B.Buffer.size())
+                 << " bytes to " << ((Prot & orcrpctpc::WPF_Read) ? 'R' : '-')
+                 << ((Prot & orcrpctpc::WPF_Write) ? 'W' : '-')
+                 << ((Prot & orcrpctpc::WPF_Exec) ? 'X' : '-')
+                 << " segment: local " << (void *)B.Buffer.data()
+                 << " -> target " << formatv("{0:x16}", B.Address) << "\n";
+        }
+      });
+      if (auto Err =
+              Parent.Parent.getMemoryAccess().writeBuffers(BufferWrites)) {
+        OnFinalize(std::move(Err));
+        return;
+      }
+
+      DEBUG_WITH_TYPE("orc", dbgs() << " Applying permissions...\n");
+      if (auto Err =
+              Parent.getEndpoint().template callAsync<orcrpctpc::FinalizeMem>(
+                  [OF = std::move(OnFinalize)](Error Err2) {
+                    // FIXME: Dispatch to work queue.
+                    std::thread([OF = std::move(OF),
+                                 Err3 = std::move(Err2)]() mutable {
+                      DEBUG_WITH_TYPE(
+                          "orc", { dbgs() << "  finalizeAsync complete\n"; });
+                      OF(std::move(Err3));
+                    }).detach();
+                    return Error::success();
+                  },
+                  FMR)) {
+        DEBUG_WITH_TYPE("orc", dbgs() << "    failed.\n");
+        Parent.getEndpoint().abandonPendingResponses();
+        Parent.reportError(std::move(Err));
+      }
+      DEBUG_WITH_TYPE("orc", {
+        dbgs() << "Leaving finalizeAsync (finalization may continue in "
+                  "background)\n";
+      });
+    }
+
+    Error deallocate() override {
+      orcrpctpc::ReleaseOrFinalizeMemRequest RMR;
+      for (auto &KV : TargetAllocs)
+        RMR.push_back({orcrpctpc::toWireProtectionFlags(
+                           static_cast<sys::Memory::ProtectionFlags>(KV.first)),
+                       KV.second.Address, KV.second.AllocatedSize});
+      TargetAllocs.clear();
+
+      return Parent.getEndpoint().template callB<orcrpctpc::ReleaseMem>(RMR);
+    }
+
+  private:
+    OrcRPCTPCJITLinkMemoryManager<OrcRPCTPCImplT> &Parent;
+    HostAllocMap HostAllocs;
+    TargetAllocMap TargetAllocs;
+  };
+
+  OrcRPCTPCJITLinkMemoryManager(OrcRPCTPCImplT &Parent) : Parent(Parent) {}
+
+  Expected<std::unique_ptr<Allocation>>
+  allocate(const SegmentsRequestMap &Request) override {
+    orcrpctpc::ReserveMemRequest RMR;
+    HostAllocMap HostAllocs;
+
+    for (auto &KV : Request) {
+      RMR.push_back({orcrpctpc::toWireProtectionFlags(
+                         static_cast<sys::Memory::ProtectionFlags>(KV.first)),
+                     KV.second.getContentSize() + KV.second.getZeroFillSize(),
+                     KV.second.getAlignment()});
+      HostAllocs[KV.first] = {
+          std::make_unique<char[]>(KV.second.getContentSize()),
+          KV.second.getContentSize()};
+    }
+
+    DEBUG_WITH_TYPE("orc", {
+      dbgs() << "Orc remote memmgr got request:\n";
+      for (auto &KV : Request)
+        dbgs() << "  permissions: "
+               << ((KV.first & sys::Memory::MF_READ) ? 'R' : '-')
+               << ((KV.first & sys::Memory::MF_WRITE) ? 'W' : '-')
+               << ((KV.first & sys::Memory::MF_EXEC) ? 'X' : '-')
+               << ", content size: "
+               << formatv("{0:x16}", KV.second.getContentSize())
+               << " + zero-fill-size: "
+               << formatv("{0:x16}", KV.second.getZeroFillSize())
+               << ", align: " << KV.second.getAlignment() << "\n";
+    });
+
+    // FIXME: LLVM RPC needs to be fixed to support alt
+    // serialization/deserialization on return types. For now just
+    // translate from std::map to DenseMap manually.
+    auto TmpTargetAllocs =
+        Parent.getEndpoint().template callB<orcrpctpc::ReserveMem>(RMR);
+    if (!TmpTargetAllocs)
+      return TmpTargetAllocs.takeError();
+
+    if (TmpTargetAllocs->size() != RMR.size())
+      return make_error<StringError>(
+          "Number of target allocations does not match request",
+          inconvertibleErrorCode());
+
+    TargetAllocMap TargetAllocs;
+    for (auto &E : *TmpTargetAllocs)
+      TargetAllocs[orcrpctpc::fromWireProtectionFlags(E.Prot)] = {
+          E.Address, E.AllocatedSize};
+
+    DEBUG_WITH_TYPE("orc", {
+      auto HAI = HostAllocs.begin();
+      for (auto &KV : TargetAllocs)
+        dbgs() << "  permissions: "
+               << ((KV.first & sys::Memory::MF_READ) ? 'R' : '-')
+               << ((KV.first & sys::Memory::MF_WRITE) ? 'W' : '-')
+               << ((KV.first & sys::Memory::MF_EXEC) ? 'X' : '-')
+               << " assigned local " << (void *)HAI->second.Mem.get()
+               << ", target " << formatv("{0:x16}", KV.second.Address) << "\n";
+    });
+
+    return std::make_unique<OrcRPCAllocation>(*this, std::move(HostAllocs),
+                                              std::move(TargetAllocs));
+  }
+
+private:
+  void reportError(Error Err) { Parent.reportError(std::move(Err)); }
+
+  decltype(std::declval<OrcRPCTPCImplT>().getEndpoint()) getEndpoint() {
+    return Parent.getEndpoint();
+  }
+
+  OrcRPCTPCImplT &Parent;
+};
+
+/// TargetProcessControl::MemoryAccess implementation for a process connected
+/// via an ORC RPC endpoint.
+template <typename OrcRPCTPCImplT>
+class OrcRPCTPCMemoryAccess : public TargetProcessControl::MemoryAccess {
+public:
+  OrcRPCTPCMemoryAccess(OrcRPCTPCImplT &Parent) : Parent(Parent) {}
+
+  void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
+                   WriteResultFn OnWriteComplete) override {
+    writeViaRPC<orcrpctpc::WriteUInt8s>(Ws, std::move(OnWriteComplete));
+  }
+
+  void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
+                    WriteResultFn OnWriteComplete) override {
+    writeViaRPC<orcrpctpc::WriteUInt16s>(Ws, std::move(OnWriteComplete));
+  }
+
+  void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
+                    WriteResultFn OnWriteComplete) override {
+    writeViaRPC<orcrpctpc::WriteUInt32s>(Ws, std::move(OnWriteComplete));
+  }
+
+  void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
+                    WriteResultFn OnWriteComplete) override {
+    writeViaRPC<orcrpctpc::WriteUInt64s>(Ws, std::move(OnWriteComplete));
+  }
+
+  void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
+                    WriteResultFn OnWriteComplete) override {
+    writeViaRPC<orcrpctpc::WriteBuffers>(Ws, std::move(OnWriteComplete));
+  }
+
+private:
+  template <typename WriteRPCFunction, typename WriteElementT>
+  void writeViaRPC(ArrayRef<WriteElementT> Ws, WriteResultFn OnWriteComplete) {
+    if (auto Err = Parent.getEndpoint().template callAsync<WriteRPCFunction>(
+            [OWC = std::move(OnWriteComplete)](Error Err2) mutable -> Error {
+              OWC(std::move(Err2));
+              return Error::success();
+            },
+            Ws)) {
+      Parent.reportError(std::move(Err));
+      Parent.getEndpoint().abandonPendingResponses();
+    }
+  }
+
+  OrcRPCTPCImplT &Parent;
+};
+
+// TargetProcessControl for a process connected via an ORC RPC Endpoint.
+template <typename RPCEndpointT>
+class OrcRPCTargetProcessControlBase : public TargetProcessControl {
+public:
+  using ErrorReporter = unique_function<void(Error)>;
+
+  using OnCloseConnectionFunction = unique_function<Error(Error)>;
+
+  OrcRPCTargetProcessControlBase(std::shared_ptr<SymbolStringPool> SSP,
+                                 RPCEndpointT &EP, ErrorReporter ReportError)
+      : TargetProcessControl(std::move(SSP)),
+        ReportError(std::move(ReportError)), EP(EP) {}
+
+  void reportError(Error Err) { ReportError(std::move(Err)); }
+
+  RPCEndpointT &getEndpoint() { return EP; }
+
+  Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
+    DEBUG_WITH_TYPE("orc", {
+      dbgs() << "Loading dylib \"" << (DylibPath ? DylibPath : "") << "\" ";
+      if (!DylibPath)
+        dbgs() << "(process symbols)";
+      dbgs() << "\n";
+    });
+    if (!DylibPath)
+      DylibPath = "";
+    auto H = EP.template callB<orcrpctpc::LoadDylib>(DylibPath);
+    DEBUG_WITH_TYPE("orc", {
+      if (H)
+        dbgs() << "  got handle " << formatv("{0:x16}", *H) << "\n";
+      else
+        dbgs() << "  error, unable to load\n";
+    });
+    return H;
+  }
+
+  Expected<std::vector<tpctypes::LookupResult>>
+  lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) override {
+    std::vector<orcrpctpc::RemoteLookupRequest> RR;
+    for (auto &E : Request) {
+      RR.push_back({});
+      RR.back().first = E.Handle;
+      for (auto &KV : E.Symbols)
+        RR.back().second.push_back(
+            {(*KV.first).str(),
+             KV.second == SymbolLookupFlags::WeaklyReferencedSymbol});
+    }
+    DEBUG_WITH_TYPE("orc", {
+      dbgs() << "Compound lookup:\n";
+      for (auto &R : Request) {
+        dbgs() << "  In " << formatv("{0:x16}", R.Handle) << ": {";
+        bool First = true;
+        for (auto &KV : R.Symbols) {
+          dbgs() << (First ? "" : ",") << " " << *KV.first;
+          First = false;
+        }
+        dbgs() << " }\n";
+      }
+    });
+    return EP.template callB<orcrpctpc::LookupSymbols>(RR);
+  }
+
+  Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
+                              ArrayRef<std::string> Args) override {
+    DEBUG_WITH_TYPE("orc", {
+      dbgs() << "Running as main: " << formatv("{0:x16}", MainFnAddr)
+             << ", args = [";
+      for (unsigned I = 0; I != Args.size(); ++I)
+        dbgs() << (I ? "," : "") << " \"" << Args[I] << "\"";
+      dbgs() << "]\n";
+    });
+    auto Result = EP.template callB<orcrpctpc::RunMain>(MainFnAddr, Args);
+    DEBUG_WITH_TYPE("orc", {
+      dbgs() << "  call to " << formatv("{0:x16}", MainFnAddr);
+      if (Result)
+        dbgs() << " returned result " << *Result << "\n";
+      else
+        dbgs() << " failed\n";
+    });
+    return Result;
+  }
+
+  Expected<tpctypes::WrapperFunctionResult>
+  runWrapper(JITTargetAddress WrapperFnAddr,
+             ArrayRef<uint8_t> ArgBuffer) override {
+    DEBUG_WITH_TYPE("orc", {
+      dbgs() << "Running as wrapper function "
+             << formatv("{0:x16}", WrapperFnAddr) << " with "
+             << formatv("{0:x16}", ArgBuffer.size()) << " argument buffer\n";
+    });
+    auto Result =
+        EP.template callB<orcrpctpc::RunWrapper>(WrapperFnAddr, ArgBuffer);
+    // dbgs() << "Returned from runWrapper...\n";
+    return Result;
+  }
+
+  Error closeConnection(OnCloseConnectionFunction OnCloseConnection) {
+    DEBUG_WITH_TYPE("orc", dbgs() << "Closing connection to remote\n");
+    return EP.template callAsync<orcrpctpc::CloseConnection>(
+        std::move(OnCloseConnection));
+  }
+
+  Error closeConnectionAndWait() {
+    std::promise<MSVCPError> P;
+    auto F = P.get_future();
+    if (auto Err = closeConnection([&](Error Err2) -> Error {
+          P.set_value(std::move(Err2));
+          return Error::success();
+        })) {
+      EP.abandonAllPendingResponses();
+      return joinErrors(std::move(Err), F.get());
+    }
+    return F.get();
+  }
+
+protected:
+  /// Subclasses must call this during construction to initialize the
+  /// TargetTriple and PageSize members.
+  Error initializeORCRPCTPCBase() {
+    if (auto TripleOrErr = EP.template callB<orcrpctpc::GetTargetTriple>())
+      TargetTriple = Triple(*TripleOrErr);
+    else
+      return TripleOrErr.takeError();
+
+    if (auto PageSizeOrErr = EP.template callB<orcrpctpc::GetPageSize>())
+      PageSize = *PageSizeOrErr;
+    else
+      return PageSizeOrErr.takeError();
+
+    return Error::success();
+  }
+
+private:
+  ErrorReporter ReportError;
+  RPCEndpointT &EP;
+};
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h b/llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
index 25edb289a5f9..9faa1afe546c 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
@@ -15,6 +15,9 @@
 
 #include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
 
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
 #if !defined(_MSC_VER) && !defined(__MINGW32__)
 #include <unistd.h>
 #else
@@ -31,11 +34,13 @@ class FDRawByteChannel final : public RawByteChannel {
   FDRawByteChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
 
   llvm::Error readBytes(char *Dst, unsigned Size) override {
+    // dbgs() << "Reading " << Size << " bytes: [";
     assert(Dst && "Attempt to read into null.");
     ssize_t Completed = 0;
     while (Completed < static_cast<ssize_t>(Size)) {
       ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
       if (Read <= 0) {
+        // dbgs() << " <<<\n";
         auto ErrNo = errno;
         if (ErrNo == EAGAIN || ErrNo == EINTR)
           continue;
@@ -43,17 +48,22 @@ class FDRawByteChannel final : public RawByteChannel {
           return llvm::errorCodeToError(
               std::error_code(errno, std::generic_category()));
       }
+      // for (size_t I = 0; I != Read; ++I)
+      //  dbgs() << " " << formatv("{0:x2}", Dst[Completed + I]);
       Completed += Read;
     }
+    // dbgs() << " ]\n";
     return llvm::Error::success();
   }
 
   llvm::Error appendBytes(const char *Src, unsigned Size) override {
+    // dbgs() << "Appending " << Size << " bytes: [";
     assert(Src && "Attempt to append from null.");
     ssize_t Completed = 0;
     while (Completed < static_cast<ssize_t>(Size)) {
       ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
       if (Written < 0) {
+        // dbgs() << " <<<\n";
         auto ErrNo = errno;
         if (ErrNo == EAGAIN || ErrNo == EINTR)
           continue;
@@ -61,8 +71,11 @@ class FDRawByteChannel final : public RawByteChannel {
           return llvm::errorCodeToError(
               std::error_code(errno, std::generic_category()));
       }
+      // for (size_t I = 0; I != Written; ++I)
+      //  dbgs() << " " << formatv("{0:x2}", Src[Completed + I]);
       Completed += Written;
     }
+    // dbgs() << " ]\n";
     return llvm::Error::success();
   }
 

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h b/llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
index 948a1b061e3b..0dc05f4d1c17 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
@@ -9,6 +9,8 @@
 #ifndef LLVM_EXECUTIONENGINE_ORC_RPC_RPCSERIALIZATION_H
 #define LLVM_EXECUTIONENGINE_ORC_RPC_RPCSERIALIZATION_H
 
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ExecutionEngine/Orc/OrcError.h"
 #include "llvm/Support/thread.h"
 #include <map>
@@ -166,6 +168,19 @@ class RPCTypeName<std::tuple<ArgTs...>> {
   }
 };
 
+template <typename T> class RPCTypeName<Optional<T>> {
+public:
+  static const char *getName() {
+    static std::string Name = [] {
+      std::string Name;
+      raw_string_ostream(Name)
+          << "Optional<" << RPCTypeName<T>::getName() << ">";
+      return Name;
+    }();
+    return Name.data();
+  }
+};
+
 template <typename T>
 class RPCTypeName<std::vector<T>> {
 public:
@@ -574,6 +589,31 @@ class SerializationTraits<ChannelT, std::tuple<ArgTs...>> {
   }
 };
 
+template <typename ChannelT, typename T>
+class SerializationTraits<ChannelT, Optional<T>> {
+public:
+  /// Serialize an Optional<T>.
+  static Error serialize(ChannelT &C, const Optional<T> &O) {
+    if (auto Err = serializeSeq(C, O != None))
+      return Err;
+    if (O)
+      if (auto Err = serializeSeq(C, *O))
+        return Err;
+    return Error::success();
+  }
+
+  /// Deserialize an Optional<T>.
+  static Error deserialize(ChannelT &C, Optional<T> &O) {
+    bool HasValue = false;
+    if (auto Err = deserializeSeq(C, HasValue))
+      return Err;
+    if (HasValue)
+      if (auto Err = deserializeSeq(C, *O))
+        return Err;
+    return Error::success();
+  };
+};
+
 /// SerializationTraits default specialization for std::vector.
 template <typename ChannelT, typename T>
 class SerializationTraits<ChannelT, std::vector<T>> {
@@ -609,6 +649,22 @@ class SerializationTraits<ChannelT, std::vector<T>> {
   }
 };
 
+/// Enable vector serialization from an ArrayRef.
+template <typename ChannelT, typename T>
+class SerializationTraits<ChannelT, std::vector<T>, ArrayRef<T>> {
+public:
+  static Error serialize(ChannelT &C, ArrayRef<T> V) {
+    if (auto Err = serializeSeq(C, static_cast<uint64_t>(V.size())))
+      return Err;
+
+    for (const auto &E : V)
+      if (auto Err = serializeSeq(C, E))
+        return Err;
+
+    return Error::success();
+  }
+};
+
 template <typename ChannelT, typename T, typename T2>
 class SerializationTraits<ChannelT, std::set<T>, std::set<T2>> {
 public:
@@ -695,6 +751,55 @@ class SerializationTraits<ChannelT, std::map<K, V>, std::map<K2, V2>> {
   }
 };
 
+template <typename ChannelT, typename K, typename V, typename K2, typename V2>
+class SerializationTraits<ChannelT, std::map<K, V>, DenseMap<K2, V2>> {
+public:
+  /// Serialize a std::map<K, V> from DenseMap<K2, V2>.
+  static Error serialize(ChannelT &C, const DenseMap<K2, V2> &M) {
+    if (auto Err = serializeSeq(C, static_cast<uint64_t>(M.size())))
+      return Err;
+
+    for (auto &E : M) {
+      if (auto Err =
+              SerializationTraits<ChannelT, K, K2>::serialize(C, E.first))
+        return Err;
+
+      if (auto Err =
+              SerializationTraits<ChannelT, V, V2>::serialize(C, E.second))
+        return Err;
+    }
+
+    return Error::success();
+  }
+
+  /// Serialize a std::map<K, V> from DenseMap<K2, V2>.
+  static Error deserialize(ChannelT &C, DenseMap<K2, V2> &M) {
+    assert(M.empty() && "Expected default-constructed map to deserialize into");
+
+    uint64_t Count = 0;
+    if (auto Err = deserializeSeq(C, Count))
+      return Err;
+
+    while (Count-- != 0) {
+      std::pair<K2, V2> Val;
+      if (auto Err =
+              SerializationTraits<ChannelT, K, K2>::deserialize(C, Val.first))
+        return Err;
+
+      if (auto Err =
+              SerializationTraits<ChannelT, V, V2>::deserialize(C, Val.second))
+        return Err;
+
+      auto Added = M.insert(Val).second;
+      if (!Added)
+        return make_error<StringError>("Duplicate element in deserialized map",
+                                       orcError(OrcErrorCode::UnknownORCError));
+    }
+
+    return Error::success();
+  }
+};
+
 } // end namespace rpc
 } // end namespace orc
 } // end namespace llvm

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
new file mode 100644
index 000000000000..9f958989f46d
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
@@ -0,0 +1,174 @@
+//===--- TargetProcessControlTypes.h -- Shared Core/TPC types ---*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// TargetProcessControl types that are used by both the Orc and
+// OrcTargetProcess libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+
+#include <vector>
+
+namespace llvm {
+namespace orc {
+namespace tpctypes {
+
+template <typename T> struct UIntWrite {
+  UIntWrite() = default;
+  UIntWrite(JITTargetAddress Address, T Value)
+      : Address(Address), Value(Value) {}
+
+  JITTargetAddress Address = 0;
+  T Value = 0;
+};
+
+/// Describes a write to a uint8_t.
+using UInt8Write = UIntWrite<uint8_t>;
+
+/// Describes a write to a uint16_t.
+using UInt16Write = UIntWrite<uint16_t>;
+
+/// Describes a write to a uint32_t.
+using UInt32Write = UIntWrite<uint32_t>;
+
+/// Describes a write to a uint64_t.
+using UInt64Write = UIntWrite<uint64_t>;
+
+/// Describes a write to a buffer.
+/// For use with TargetProcessControl::MemoryAccess objects.
+struct BufferWrite {
+  BufferWrite() = default;
+  BufferWrite(JITTargetAddress Address, StringRef Buffer)
+      : Address(Address), Buffer(Buffer) {}
+
+  JITTargetAddress Address = 0;
+  StringRef Buffer;
+};
+
+/// A handle used to represent a loaded dylib in the target process.
+using DylibHandle = JITTargetAddress;
+
+/// A pair of a dylib and a set of symbols to be looked up.
+struct LookupRequest {
+  LookupRequest(DylibHandle Handle, const SymbolLookupSet &Symbols)
+      : Handle(Handle), Symbols(Symbols) {}
+  DylibHandle Handle;
+  const SymbolLookupSet &Symbols;
+};
+
+using LookupResult = std::vector<JITTargetAddress>;
+
+/// Either a uint8_t array or a uint8_t*.
+union CWrapperFunctionResultData {
+  uint8_t Value[8];
+  uint8_t *ValuePtr;
+};
+
+/// C ABI compatible wrapper function result.
+///
+/// This can be safely returned from extern "C" functions, but should be used
+/// to construct a WrapperFunctionResult for safety.
+struct CWrapperFunctionResult {
+  uint64_t Size;
+  CWrapperFunctionResultData Data;
+  void (*Destroy)(CWrapperFunctionResultData Data, uint64_t Size);
+};
+
+/// C++ wrapper function result: Same as CWrapperFunctionResult but
+/// auto-releases memory.
+class WrapperFunctionResult {
+public:
+  /// Create a default WrapperFunctionResult.
+  WrapperFunctionResult() { zeroInit(R); }
+
+  /// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
+  /// instance takes ownership of the result object and will automatically
+  /// call the Destroy member upon destruction.
+  WrapperFunctionResult(CWrapperFunctionResult R) : R(R) {}
+
+  WrapperFunctionResult(const WrapperFunctionResult &) = delete;
+  WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
+
+  WrapperFunctionResult(WrapperFunctionResult &&Other) {
+    zeroInit(R);
+    std::swap(R, Other.R);
+  }
+
+  WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
+    CWrapperFunctionResult Tmp;
+    zeroInit(Tmp);
+    std::swap(Tmp, Other.R);
+    std::swap(R, Tmp);
+    return *this;
+  }
+
+  ~WrapperFunctionResult() {
+    if (R.Destroy)
+      R.Destroy(R.Data, R.Size);
+  }
+
+  /// Relinquish ownership of and return the CWrapperFunctionResult.
+  CWrapperFunctionResult release() {
+    CWrapperFunctionResult Tmp;
+    zeroInit(Tmp);
+    std::swap(R, Tmp);
+    return Tmp;
+  }
+
+  /// Get an ArrayRef covering the data in the result.
+  ArrayRef<uint8_t> getData() const {
+    if (R.Size <= 8)
+      return ArrayRef<uint8_t>(R.Data.Value, R.Size);
+    return ArrayRef<uint8_t>(R.Data.ValuePtr, R.Size);
+  }
+
+  /// Create a WrapperFunctionResult from the given integer, provided its
+  /// size is no greater than 64 bits.
+  template <typename T,
+            typename _ = std::enable_if_t<std::is_integral<T>::value &&
+                                          sizeof(T) <= sizeof(uint64_t)>>
+  static WrapperFunctionResult from(T Value) {
+    CWrapperFunctionResult R;
+    R.Size = sizeof(T);
+    memcpy(&R.Data.Value, Value, R.Size);
+    R.Destroy = nullptr;
+    return R;
+  }
+
+  /// Create a WrapperFunctionResult from the given string.
+  static WrapperFunctionResult from(StringRef S);
+
+  /// Always free Data.ValuePtr by calling free on it.
+  static void destroyWithFree(CWrapperFunctionResultData Data, uint64_t Size);
+
+  /// Always free Data.ValuePtr by calling delete[] on it.
+  static void destroyWithDeleteArray(CWrapperFunctionResultData Data,
+                                     uint64_t Size);
+
+private:
+  void zeroInit(CWrapperFunctionResult &R) {
+    R.Size = 0;
+    R.Data.ValuePtr = nullptr;
+    R.Destroy = nullptr;
+  }
+
+  CWrapperFunctionResult R;
+};
+
+} // end namespace tpctypes
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
index 3b5c4b9cf8cd..07720f5c0f33 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
@@ -31,7 +31,7 @@ class TPCDynamicLibrarySearchGenerator : public DefinitionGenerator {
   /// will be searched for. If the predicate is not given then all symbols will
   /// be searched for.
   TPCDynamicLibrarySearchGenerator(TargetProcessControl &TPC,
-                                   TargetProcessControl::DylibHandle H,
+                                   tpctypes::DylibHandle H,
                                    SymbolPredicate Allow = SymbolPredicate())
       : TPC(TPC), H(H), Allow(std::move(Allow)) {}
 
@@ -56,7 +56,7 @@ class TPCDynamicLibrarySearchGenerator : public DefinitionGenerator {
 
 private:
   TargetProcessControl &TPC;
-  TargetProcessControl::DylibHandle H;
+  tpctypes::DylibHandle H;
   SymbolPredicate Allow;
 };
 

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h b/llvm/include/llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h
new file mode 100644
index 000000000000..519f818907f9
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h
@@ -0,0 +1,54 @@
+//===-- TPCEHFrameRegistrar.h - TPC based eh-frame registration -*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// TargetProcessControl based eh-frame registration.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H
+#define LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H
+
+#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
+
+namespace llvm {
+namespace orc {
+
+/// Register/Deregisters EH frames in a remote process via a
+/// TargetProcessControl instance.
+class TPCEHFrameRegistrar : public jitlink::EHFrameRegistrar {
+public:
+  /// Create from a TargetProcessControl instance alone. This will use
+  /// the TPC's lookupSymbols method to find the registration/deregistration
+  /// funciton addresses by name.
+  static Expected<std::unique_ptr<TPCEHFrameRegistrar>>
+  Create(TargetProcessControl &TPC);
+
+  /// Create a TPCEHFrameRegistrar with the given TargetProcessControl
+  /// object and registration/deregistration function addresses.
+  TPCEHFrameRegistrar(TargetProcessControl &TPC,
+                      JITTargetAddress RegisterEHFrameWrapperFnAddr,
+                      JITTargetAddress DeregisterEHFRameWrapperFnAddr)
+      : TPC(TPC), RegisterEHFrameWrapperFnAddr(RegisterEHFrameWrapperFnAddr),
+        DeregisterEHFrameWrapperFnAddr(DeregisterEHFRameWrapperFnAddr) {}
+
+  Error registerEHFrames(JITTargetAddress EHFrameSectionAddr,
+                         size_t EHFrameSectionSize) override;
+  Error deregisterEHFrames(JITTargetAddress EHFrameSectionAddr,
+                           size_t EHFrameSectionSize) override;
+
+private:
+  TargetProcessControl &TPC;
+  JITTargetAddress RegisterEHFrameWrapperFnAddr;
+  JITTargetAddress DeregisterEHFrameWrapperFnAddr;
+};
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h
new file mode 100644
index 000000000000..2b759dea6333
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h
@@ -0,0 +1,614 @@
+//===-- OrcRPCTPCServer.h -- OrcRPCTargetProcessControl Server --*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// OrcRPCTargetProcessControl server class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H
+
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
+#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
+#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/Process.h"
+
+#include <atomic>
+
+namespace llvm {
+namespace orc {
+
+namespace orcrpctpc {
+
+enum WireProtectionFlags : uint8_t {
+  WPF_None = 0,
+  WPF_Read = 1U << 0,
+  WPF_Write = 1U << 1,
+  WPF_Exec = 1U << 2,
+  LLVM_MARK_AS_BITMASK_ENUM(WPF_Exec)
+};
+
+/// Convert from sys::Memory::ProtectionFlags
+inline WireProtectionFlags
+toWireProtectionFlags(sys::Memory::ProtectionFlags PF) {
+  WireProtectionFlags WPF = WPF_None;
+  if (PF & sys::Memory::MF_READ)
+    WPF |= WPF_Read;
+  if (PF & sys::Memory::MF_WRITE)
+    WPF |= WPF_Write;
+  if (PF & sys::Memory::MF_EXEC)
+    WPF |= WPF_Exec;
+  return WPF;
+}
+
+inline sys::Memory::ProtectionFlags
+fromWireProtectionFlags(WireProtectionFlags WPF) {
+  int PF = 0;
+  if (WPF & WPF_Read)
+    PF |= sys::Memory::MF_READ;
+  if (WPF & WPF_Write)
+    PF |= sys::Memory::MF_WRITE;
+  if (WPF & WPF_Exec)
+    PF |= sys::Memory::MF_EXEC;
+  return static_cast<sys::Memory::ProtectionFlags>(PF);
+}
+
+struct ReserveMemRequestElement {
+  WireProtectionFlags Prot = WPF_None;
+  uint64_t Size = 0;
+  uint64_t Alignment = 0;
+};
+
+using ReserveMemRequest = std::vector<ReserveMemRequestElement>;
+
+struct ReserveMemResultElement {
+  WireProtectionFlags Prot = WPF_None;
+  JITTargetAddress Address = 0;
+  uint64_t AllocatedSize = 0;
+};
+
+using ReserveMemResult = std::vector<ReserveMemResultElement>;
+
+struct ReleaseOrFinalizeMemRequestElement {
+  WireProtectionFlags Prot = WPF_None;
+  JITTargetAddress Address = 0;
+  uint64_t Size = 0;
+};
+
+using ReleaseOrFinalizeMemRequest =
+    std::vector<ReleaseOrFinalizeMemRequestElement>;
+
+} // end namespace orcrpctpc
+
+namespace rpc {
+
+template <> class RPCTypeName<tpctypes::UInt8Write> {
+public:
+  static const char *getName() { return "UInt8Write"; }
+};
+
+template <> class RPCTypeName<tpctypes::UInt16Write> {
+public:
+  static const char *getName() { return "UInt16Write"; }
+};
+
+template <> class RPCTypeName<tpctypes::UInt32Write> {
+public:
+  static const char *getName() { return "UInt32Write"; }
+};
+
+template <> class RPCTypeName<tpctypes::UInt64Write> {
+public:
+  static const char *getName() { return "UInt64Write"; }
+};
+
+template <> class RPCTypeName<tpctypes::BufferWrite> {
+public:
+  static const char *getName() { return "BufferWrite"; }
+};
+
+template <> class RPCTypeName<orcrpctpc::ReserveMemRequestElement> {
+public:
+  static const char *getName() { return "ReserveMemRequestElement"; }
+};
+
+template <> class RPCTypeName<orcrpctpc::ReserveMemResultElement> {
+public:
+  static const char *getName() { return "ReserveMemResultElement"; }
+};
+
+template <> class RPCTypeName<orcrpctpc::ReleaseOrFinalizeMemRequestElement> {
+public:
+  static const char *getName() { return "ReleaseOrFinalizeMemRequestElement"; }
+};
+
+template <> class RPCTypeName<tpctypes::WrapperFunctionResult> {
+public:
+  static const char *getName() { return "WrapperFunctionResult"; }
+};
+
+template <typename ChannelT, typename WriteT>
+class SerializationTraits<
+    ChannelT, WriteT, WriteT,
+    std::enable_if_t<std::is_same<WriteT, tpctypes::UInt8Write>::value ||
+                     std::is_same<WriteT, tpctypes::UInt16Write>::value ||
+                     std::is_same<WriteT, tpctypes::UInt32Write>::value ||
+                     std::is_same<WriteT, tpctypes::UInt64Write>::value>> {
+public:
+  static Error serialize(ChannelT &C, const WriteT &W) {
+    return serializeSeq(C, W.Address, W.Value);
+  }
+  static Error deserialize(ChannelT &C, WriteT &W) {
+    return deserializeSeq(C, W.Address, W.Value);
+  }
+};
+
+template <typename ChannelT>
+class SerializationTraits<
+    ChannelT, tpctypes::BufferWrite, tpctypes::BufferWrite,
+    std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
+public:
+  static Error serialize(ChannelT &C, const tpctypes::BufferWrite &W) {
+    uint64_t Size = W.Buffer.size();
+    if (auto Err = serializeSeq(C, W.Address, Size))
+      return Err;
+
+    return C.appendBytes(W.Buffer.data(), Size);
+  }
+  static Error deserialize(ChannelT &C, tpctypes::BufferWrite &W) {
+    JITTargetAddress Address;
+    uint64_t Size;
+
+    if (auto Err = deserializeSeq(C, Address, Size))
+      return Err;
+
+    char *Buffer = jitTargetAddressToPointer<char *>(Address);
+
+    if (auto Err = C.readBytes(Buffer, Size))
+      return Err;
+
+    W = {Address, StringRef(Buffer, Size)};
+    return Error::success();
+  }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, orcrpctpc::ReserveMemRequestElement> {
+public:
+  static Error serialize(ChannelT &C,
+                         const orcrpctpc::ReserveMemRequestElement &E) {
+    return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Size, E.Alignment);
+  }
+
+  static Error deserialize(ChannelT &C,
+                           orcrpctpc::ReserveMemRequestElement &E) {
+    return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot), E.Size,
+                          E.Alignment);
+  }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, orcrpctpc::ReserveMemResultElement> {
+public:
+  static Error serialize(ChannelT &C,
+                         const orcrpctpc::ReserveMemResultElement &E) {
+    return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Address,
+                        E.AllocatedSize);
+  }
+
+  static Error deserialize(ChannelT &C, orcrpctpc::ReserveMemResultElement &E) {
+    return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot), E.Address,
+                          E.AllocatedSize);
+  }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT,
+                          orcrpctpc::ReleaseOrFinalizeMemRequestElement> {
+public:
+  static Error
+  serialize(ChannelT &C,
+            const orcrpctpc::ReleaseOrFinalizeMemRequestElement &E) {
+    return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Address, E.Size);
+  }
+
+  static Error deserialize(ChannelT &C,
+                           orcrpctpc::ReleaseOrFinalizeMemRequestElement &E) {
+    return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot), E.Address,
+                          E.Size);
+  }
+};
+
+template <typename ChannelT>
+class SerializationTraits<
+    ChannelT, tpctypes::WrapperFunctionResult, tpctypes::WrapperFunctionResult,
+    std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
+public:
+  static Error serialize(ChannelT &C,
+                         const tpctypes::WrapperFunctionResult &E) {
+    auto Data = E.getData();
+    if (auto Err = serializeSeq(C, static_cast<uint64_t>(Data.size())))
+      return Err;
+    if (Data.size() == 0)
+      return Error::success();
+    return C.appendBytes(reinterpret_cast<const char *>(Data.data()),
+                         Data.size());
+  }
+
+  static Error deserialize(ChannelT &C, tpctypes::WrapperFunctionResult &E) {
+    tpctypes::CWrapperFunctionResult R;
+
+    R.Size = 0;
+    R.Data.ValuePtr = nullptr;
+    R.Destroy = nullptr;
+
+    if (auto Err = deserializeSeq(C, R.Size))
+      return Err;
+    if (R.Size == 0)
+      return Error::success();
+    R.Data.ValuePtr = new uint8_t[R.Size];
+    if (auto Err =
+            C.readBytes(reinterpret_cast<char *>(R.Data.ValuePtr), R.Size)) {
+      R.Destroy = tpctypes::WrapperFunctionResult::destroyWithDeleteArray;
+      return Err;
+    }
+
+    E = tpctypes::WrapperFunctionResult(R);
+    return Error::success();
+  }
+};
+
+} // end namespace rpc
+
+namespace orcrpctpc {
+
+using RemoteSymbolLookupSet = std::vector<std::pair<std::string, bool>>;
+using RemoteLookupRequest =
+    std::pair<tpctypes::DylibHandle, RemoteSymbolLookupSet>;
+
+class GetTargetTriple : public rpc::Function<GetTargetTriple, std::string()> {
+public:
+  static const char *getName() { return "GetTargetTriple"; }
+};
+
+class GetPageSize : public rpc::Function<GetPageSize, uint64_t()> {
+public:
+  static const char *getName() { return "GetPageSize"; }
+};
+
+class ReserveMem : public rpc::Function<ReserveMem, Expected<ReserveMemResult>(
+                                                        ReserveMemRequest)> {
+public:
+  static const char *getName() { return "ReserveMem"; }
+};
+
+class FinalizeMem
+    : public rpc::Function<FinalizeMem, Error(ReleaseOrFinalizeMemRequest)> {
+public:
+  static const char *getName() { return "FinalizeMem"; }
+};
+
+class ReleaseMem
+    : public rpc::Function<ReleaseMem, Error(ReleaseOrFinalizeMemRequest)> {
+public:
+  static const char *getName() { return "ReleaseMem"; }
+};
+
+class WriteUInt8s
+    : public rpc::Function<WriteUInt8s,
+                           Error(std::vector<tpctypes::UInt8Write>)> {
+public:
+  static const char *getName() { return "WriteUInt8s"; }
+};
+
+class WriteUInt16s
+    : public rpc::Function<WriteUInt16s,
+                           Error(std::vector<tpctypes::UInt16Write>)> {
+public:
+  static const char *getName() { return "WriteUInt16s"; }
+};
+
+class WriteUInt32s
+    : public rpc::Function<WriteUInt32s,
+                           Error(std::vector<tpctypes::UInt32Write>)> {
+public:
+  static const char *getName() { return "WriteUInt32s"; }
+};
+
+class WriteUInt64s
+    : public rpc::Function<WriteUInt64s,
+                           Error(std::vector<tpctypes::UInt64Write>)> {
+public:
+  static const char *getName() { return "WriteUInt64s"; }
+};
+
+class WriteBuffers
+    : public rpc::Function<WriteBuffers,
+                           Error(std::vector<tpctypes::BufferWrite>)> {
+public:
+  static const char *getName() { return "WriteBuffers"; }
+};
+
+class LoadDylib
+    : public rpc::Function<LoadDylib, Expected<tpctypes::DylibHandle>(
+                                          std::string DylibPath)> {
+public:
+  static const char *getName() { return "LoadDylib"; }
+};
+
+class LookupSymbols
+    : public rpc::Function<LookupSymbols,
+                           Expected<std::vector<tpctypes::LookupResult>>(
+                               std::vector<RemoteLookupRequest>)> {
+public:
+  static const char *getName() { return "LookupSymbols"; }
+};
+
+class RunMain
+    : public rpc::Function<RunMain, int32_t(JITTargetAddress MainAddr,
+                                            std::vector<std::string> Args)> {
+public:
+  static const char *getName() { return "RunMain"; }
+};
+
+class RunWrapper
+    : public rpc::Function<RunWrapper,
+                           tpctypes::WrapperFunctionResult(
+                               JITTargetAddress, std::vector<uint8_t>)> {
+public:
+  static const char *getName() { return "RunWrapper"; }
+};
+
+class CloseConnection : public rpc::Function<CloseConnection, void()> {
+public:
+  static const char *getName() { return "CloseConnection"; }
+};
+
+} // end namespace orcrpctpc
+
+/// TargetProcessControl for a process connected via an ORC RPC Endpoint.
+template <typename RPCEndpointT> class OrcRPCTPCServer {
+public:
+  /// Create an OrcRPCTPCServer from the given endpoint.
+  OrcRPCTPCServer(RPCEndpointT &EP) : EP(EP) {
+    using ThisT = OrcRPCTPCServer<RPCEndpointT>;
+
+    TripleStr = sys::getProcessTriple();
+    PageSize = sys::Process::getPageSizeEstimate();
+
+    EP.template addHandler<orcrpctpc::GetTargetTriple>(*this,
+                                                       &ThisT::getTargetTriple);
+    EP.template addHandler<orcrpctpc::GetPageSize>(*this, &ThisT::getPageSize);
+
+    EP.template addHandler<orcrpctpc::ReserveMem>(*this, &ThisT::reserveMemory);
+    EP.template addHandler<orcrpctpc::FinalizeMem>(*this,
+                                                   &ThisT::finalizeMemory);
+    EP.template addHandler<orcrpctpc::ReleaseMem>(*this, &ThisT::releaseMemory);
+
+    EP.template addHandler<orcrpctpc::WriteUInt8s>(
+        handleWriteUInt<tpctypes::UInt8Write>);
+    EP.template addHandler<orcrpctpc::WriteUInt16s>(
+        handleWriteUInt<tpctypes::UInt16Write>);
+    EP.template addHandler<orcrpctpc::WriteUInt32s>(
+        handleWriteUInt<tpctypes::UInt32Write>);
+    EP.template addHandler<orcrpctpc::WriteUInt64s>(
+        handleWriteUInt<tpctypes::UInt64Write>);
+    EP.template addHandler<orcrpctpc::WriteBuffers>(handleWriteBuffer);
+
+    EP.template addHandler<orcrpctpc::LoadDylib>(*this, &ThisT::loadDylib);
+    EP.template addHandler<orcrpctpc::LookupSymbols>(*this,
+                                                     &ThisT::lookupSymbols);
+
+    EP.template addHandler<orcrpctpc::RunMain>(*this, &ThisT::runMain);
+    EP.template addHandler<orcrpctpc::RunWrapper>(*this, &ThisT::runWrapper);
+
+    EP.template addHandler<orcrpctpc::CloseConnection>(*this,
+                                                       &ThisT::closeConnection);
+  }
+
+  /// Set the ProgramName to be used as the first argv element when running
+  /// functions via runAsMain.
+  void setProgramName(Optional<std::string> ProgramName = None) {
+    this->ProgramName = std::move(ProgramName);
+  }
+
+  /// Get the RPC endpoint for this server.
+  RPCEndpointT &getEndpoint() { return EP; }
+
+  /// Run the server loop.
+  Error run() {
+    while (!Finished) {
+      if (auto Err = EP.handleOne())
+        return Err;
+    }
+    return Error::success();
+  }
+
+private:
+  std::string getTargetTriple() { return TripleStr; }
+  uint64_t getPageSize() { return PageSize; }
+
+  template <typename WriteT>
+  static void handleWriteUInt(const std::vector<WriteT> &Ws) {
+    using ValueT = decltype(std::declval<WriteT>().Value);
+    for (auto &W : Ws)
+      *jitTargetAddressToPointer<ValueT *>(W.Address) = W.Value;
+  }
+
+  std::string getProtStr(orcrpctpc::WireProtectionFlags WPF) {
+    std::string Result;
+    Result += (WPF & orcrpctpc::WPF_Read) ? 'R' : '-';
+    Result += (WPF & orcrpctpc::WPF_Write) ? 'W' : '-';
+    Result += (WPF & orcrpctpc::WPF_Exec) ? 'X' : '-';
+    return Result;
+  }
+
+  static void handleWriteBuffer(const std::vector<tpctypes::BufferWrite> &Ws) {
+    for (auto &W : Ws) {
+      memcpy(jitTargetAddressToPointer<char *>(W.Address), W.Buffer.data(),
+             W.Buffer.size());
+    }
+  }
+
+  Expected<orcrpctpc::ReserveMemResult>
+  reserveMemory(const orcrpctpc::ReserveMemRequest &Request) {
+    orcrpctpc::ReserveMemResult Allocs;
+    auto PF = sys::Memory::MF_READ | sys::Memory::MF_WRITE;
+
+    uint64_t TotalSize = 0;
+
+    for (const auto &E : Request) {
+      uint64_t Size = alignTo(E.Size, PageSize);
+      uint16_t Align = E.Alignment;
+
+      if ((Align > PageSize) || (PageSize % Align))
+        return make_error<StringError>(
+            "Page alignmen does not satisfy requested alignment",
+            inconvertibleErrorCode());
+
+      TotalSize += Size;
+    }
+
+    // Allocate memory slab.
+    std::error_code EC;
+    auto MB = sys::Memory::allocateMappedMemory(TotalSize, nullptr, PF, EC);
+    if (EC)
+      return make_error<StringError>("Unable to allocate memory: " +
+                                         EC.message(),
+                                     inconvertibleErrorCode());
+
+    // Zero-fill the whole thing.
+    memset(MB.base(), 0, MB.allocatedSize());
+
+    // Carve up sections to return.
+    uint64_t SectionBase = 0;
+    for (const auto &E : Request) {
+      uint64_t SectionSize = alignTo(E.Size, PageSize);
+      Allocs.push_back({E.Prot,
+                        pointerToJITTargetAddress(MB.base()) + SectionBase,
+                        SectionSize});
+      SectionBase += SectionSize;
+    }
+
+    return Allocs;
+  }
+
+  Error finalizeMemory(const orcrpctpc::ReleaseOrFinalizeMemRequest &FMR) {
+    for (const auto &E : FMR) {
+      sys::MemoryBlock MB(jitTargetAddressToPointer<void *>(E.Address), E.Size);
+
+      auto PF = orcrpctpc::fromWireProtectionFlags(E.Prot);
+      if (auto EC =
+              sys::Memory::protectMappedMemory(MB, static_cast<unsigned>(PF)))
+        return make_error<StringError>("error protecting memory: " +
+                                           EC.message(),
+                                       inconvertibleErrorCode());
+    }
+    return Error::success();
+  }
+
+  Error releaseMemory(const orcrpctpc::ReleaseOrFinalizeMemRequest &RMR) {
+    for (const auto &E : RMR) {
+      sys::MemoryBlock MB(jitTargetAddressToPointer<void *>(E.Address), E.Size);
+
+      if (auto EC = sys::Memory::releaseMappedMemory(MB))
+        return make_error<StringError>("error release memory: " + EC.message(),
+                                       inconvertibleErrorCode());
+    }
+    return Error::success();
+  }
+
+  Expected<tpctypes::DylibHandle> loadDylib(const std::string &Path) {
+    std::string ErrMsg;
+    const char *DLPath = !Path.empty() ? Path.c_str() : nullptr;
+    auto DL = sys::DynamicLibrary::getPermanentLibrary(DLPath, &ErrMsg);
+    if (!DL.isValid())
+      return make_error<StringError>(std::move(ErrMsg),
+                                     inconvertibleErrorCode());
+
+    tpctypes::DylibHandle H = Dylibs.size();
+    Dylibs[H] = std::move(DL);
+    return H;
+  }
+
+  Expected<std::vector<tpctypes::LookupResult>>
+  lookupSymbols(const std::vector<orcrpctpc::RemoteLookupRequest> &Request) {
+    std::vector<tpctypes::LookupResult> Result;
+
+    for (const auto &E : Request) {
+      auto I = Dylibs.find(E.first);
+      if (I == Dylibs.end())
+        return make_error<StringError>("Unrecognized handle",
+                                       inconvertibleErrorCode());
+      auto &DL = I->second;
+      Result.push_back({});
+
+      for (const auto &KV : E.second) {
+        auto &SymString = KV.first;
+        bool WeakReference = KV.second;
+
+        const char *Sym = SymString.c_str();
+#ifdef __APPLE__
+        if (*Sym == '_')
+          ++Sym;
+#endif
+
+        void *Addr = DL.getAddressOfSymbol(Sym);
+        if (!Addr && !WeakReference)
+          return make_error<StringError>(Twine("Missing definition for ") + Sym,
+                                         inconvertibleErrorCode());
+
+        Result.back().push_back(pointerToJITTargetAddress(Addr));
+      }
+    }
+
+    return Result;
+  }
+
+  int32_t runMain(JITTargetAddress MainFnAddr,
+                  const std::vector<std::string> &Args) {
+    Optional<StringRef> ProgramNameOverride;
+    if (ProgramName)
+      ProgramNameOverride = *ProgramName;
+
+    return runAsMain(
+        jitTargetAddressToFunction<int (*)(int, char *[])>(MainFnAddr), Args,
+        ProgramNameOverride);
+  }
+
+  tpctypes::WrapperFunctionResult
+  runWrapper(JITTargetAddress WrapperFnAddr,
+             const std::vector<uint8_t> &ArgBuffer) {
+    using WrapperFnTy = tpctypes::CWrapperFunctionResult (*)(
+        const uint8_t *Data, uint64_t Size);
+    auto *WrapperFn = jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
+    return WrapperFn(ArgBuffer.data(), ArgBuffer.size());
+  }
+
+  void closeConnection() { Finished = true; }
+
+  std::string TripleStr;
+  uint64_t PageSize = 0;
+  Optional<std::string> ProgramName;
+  RPCEndpointT &EP;
+  std::atomic<bool> Finished{false};
+  DenseMap<tpctypes::DylibHandle, sys::DynamicLibrary> Dylibs;
+};
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h
new file mode 100644
index 000000000000..811c50e3ce4d
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h
@@ -0,0 +1,41 @@
+//===----- RegisterEHFrames.h -- Register EH frame sections -----*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Support for dynamically registering and deregistering eh-frame sections
+// in-process via libunwind.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H
+
+#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
+#include "llvm/Support/Error.h"
+#include <vector>
+
+namespace llvm {
+namespace orc {
+
+/// Register frames in the given eh-frame section with libunwind.
+Error registerEHFrameSection(const void *EHFrameSectionAddr,
+                             size_t EHFrameSectionSize);
+
+/// Unregister frames in the given eh-frame section with libunwind.
+Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
+                               size_t EHFrameSectionSize);
+
+} // end namespace orc
+} // end namespace llvm
+
+extern "C" llvm::orc::tpctypes::CWrapperFunctionResult
+llvm_orc_registerEHFrameSectionWrapper(uint8_t *Data, uint64_t Size);
+
+extern "C" llvm::orc::tpctypes::CWrapperFunctionResult
+llvm_orc_deregisterEHFrameSectionWrapper(uint8_t *Data, uint64_t Size);
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h
new file mode 100644
index 000000000000..1d2f6d2be089
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h
@@ -0,0 +1,38 @@
+//===-- TargetExecutionUtils.h - Utils for execution in target --*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for execution in the target process.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace llvm {
+namespace orc {
+
+/// Run a main function, returning the result.
+///
+/// If the optional ProgramName argument is given then it will be inserted
+/// before the strings in Args as the first argument to the called function.
+///
+/// It is legal to have an empty argument list and no program name, however
+/// many main functions will expect a name argument at least, and will fail
+/// if none is provided.
+int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
+              Optional<StringRef> ProgramName = None);
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
index d3349753284e..504a5ea0f9e9 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/Triple.h"
 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
 #include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/MSVCErrorWorkarounds.h"
 
@@ -33,76 +34,55 @@ class TargetProcessControl {
   /// APIs for manipulating memory in the target process.
   class MemoryAccess {
   public:
-    template <typename T> struct UIntWrite {
-      UIntWrite() = default;
-      UIntWrite(JITTargetAddress Address, T Value)
-          : Address(Address), Value(Value) {}
-
-      JITTargetAddress Address = 0;
-      T Value = 0;
-    };
-
-    using UInt8Write = UIntWrite<uint8_t>;
-    using UInt16Write = UIntWrite<uint16_t>;
-    using UInt32Write = UIntWrite<uint32_t>;
-    using UInt64Write = UIntWrite<uint64_t>;
-
-    struct BufferWrite {
-      BufferWrite(JITTargetAddress Address, StringRef Buffer)
-          : Address(Address), Buffer(Buffer) {}
-
-      JITTargetAddress Address = 0;
-      StringRef Buffer;
-    };
-
+    /// Callback function for asynchronous writes.
     using WriteResultFn = unique_function<void(Error)>;
 
     virtual ~MemoryAccess();
 
-    virtual void writeUInt8s(ArrayRef<UInt8Write> Ws,
+    virtual void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
                              WriteResultFn OnWriteComplete) = 0;
 
-    virtual void writeUInt16s(ArrayRef<UInt16Write> Ws,
+    virtual void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
                               WriteResultFn OnWriteComplete) = 0;
 
-    virtual void writeUInt32s(ArrayRef<UInt32Write> Ws,
+    virtual void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
                               WriteResultFn OnWriteComplete) = 0;
 
-    virtual void writeUInt64s(ArrayRef<UInt64Write> Ws,
+    virtual void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
                               WriteResultFn OnWriteComplete) = 0;
 
-    virtual void writeBuffers(ArrayRef<BufferWrite> Ws,
+    virtual void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
                               WriteResultFn OnWriteComplete) = 0;
 
-    Error writeUInt8s(ArrayRef<UInt8Write> Ws) {
+    Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) {
       std::promise<MSVCPError> ResultP;
       auto ResultF = ResultP.get_future();
       writeUInt8s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
       return ResultF.get();
     }
 
-    Error writeUInt16s(ArrayRef<UInt16Write> Ws) {
+    Error writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws) {
       std::promise<MSVCPError> ResultP;
       auto ResultF = ResultP.get_future();
       writeUInt16s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
       return ResultF.get();
     }
 
-    Error writeUInt32s(ArrayRef<UInt32Write> Ws) {
+    Error writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws) {
       std::promise<MSVCPError> ResultP;
       auto ResultF = ResultP.get_future();
       writeUInt32s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
       return ResultF.get();
     }
 
-    Error writeUInt64s(ArrayRef<UInt64Write> Ws) {
+    Error writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws) {
       std::promise<MSVCPError> ResultP;
       auto ResultF = ResultP.get_future();
       writeUInt64s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
       return ResultF.get();
     }
 
-    Error writeBuffers(ArrayRef<BufferWrite> Ws) {
+    Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
       std::promise<MSVCPError> ResultP;
       auto ResultF = ResultP.get_future();
       writeBuffers(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
@@ -110,43 +90,30 @@ class TargetProcessControl {
     }
   };
 
-  /// A handle for a library opened via loadDylib.
-  ///
-  /// Note that this handle does not necessarily represent a JITDylib: it may
-  /// be a regular dynamic library or shared object (e.g. one opened via a
-  /// dlopen in the target process).
-  using DylibHandle = JITTargetAddress;
-
-  /// Request lookup within the given DylibHandle.
-  struct LookupRequestElement {
-    LookupRequestElement(DylibHandle Handle, const SymbolLookupSet &Symbols)
-        : Handle(Handle), Symbols(Symbols) {}
-    DylibHandle Handle;
-    const SymbolLookupSet &Symbols;
-  };
-
-  using LookupRequest = ArrayRef<LookupRequestElement>;
+  virtual ~TargetProcessControl();
 
-  using LookupResult = std::vector<std::vector<JITTargetAddress>>;
+  /// Intern a symbol name in the SymbolStringPool.
+  SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
 
-  virtual ~TargetProcessControl();
+  /// Return a shared pointer to the SymbolStringPool for this instance.
+  std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
 
   /// Return the Triple for the target process.
-  const Triple &getTargetTriple() const { return TT; }
+  const Triple &getTargetTriple() const { return TargetTriple; }
 
   /// Get the page size for the target process.
   unsigned getPageSize() const { return PageSize; }
 
-  /// Return a JITLinkMemoryManager for the target process.
-  jitlink::JITLinkMemoryManager &getMemMgr() const { return *MemMgr; }
-
   /// Return a MemoryAccess object for the target process.
   MemoryAccess &getMemoryAccess() const { return *MemAccess; }
 
+  /// Return a JITLinkMemoryManager for the target process.
+  jitlink::JITLinkMemoryManager &getMemMgr() const { return *MemMgr; }
+
   /// Load the dynamic library at the given path and return a handle to it.
   /// If LibraryPath is null this function will return the global handle for
   /// the target process.
-  virtual Expected<DylibHandle> loadDylib(const char *DylibPath) = 0;
+  virtual Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) = 0;
 
   /// Search for symbols in the target process.
   ///
@@ -154,14 +121,37 @@ class TargetProcessControl {
   /// that correspond to the lookup order. If a required symbol is not
   /// found then this method will return an error. If a weakly referenced
   /// symbol is not found then it be assigned a '0' value in the result.
-  virtual Expected<LookupResult> lookupSymbols(LookupRequest Request) = 0;
+  /// that correspond to the lookup order.
+  virtual Expected<std::vector<tpctypes::LookupResult>>
+  lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) = 0;
+
+  /// Run function with a main-like signature.
+  virtual Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
+                                      ArrayRef<std::string> Args) = 0;
+
+  /// Run a wrapper function with signature:
+  ///
+  /// \code{.cpp}
+  ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
+  /// \endcode{.cpp}
+  ///
+  virtual Expected<tpctypes::WrapperFunctionResult>
+  runWrapper(JITTargetAddress WrapperFnAddr, ArrayRef<uint8_t> ArgBuffer) = 0;
+
+  /// Disconnect from the target process.
+  ///
+  /// This should be called after the JIT session is shut down.
+  virtual Error disconnect() = 0;
 
 protected:
+  TargetProcessControl(std::shared_ptr<SymbolStringPool> SSP)
+      : SSP(std::move(SSP)) {}
 
-  Triple TT;
+  std::shared_ptr<SymbolStringPool> SSP;
+  Triple TargetTriple;
   unsigned PageSize = 0;
-  jitlink::JITLinkMemoryManager *MemMgr = nullptr;
   MemoryAccess *MemAccess = nullptr;
+  jitlink::JITLinkMemoryManager *MemMgr = nullptr;
 };
 
 /// A TargetProcessControl implementation targeting the current process.
@@ -169,33 +159,44 @@ class SelfTargetProcessControl : public TargetProcessControl,
                                  private TargetProcessControl::MemoryAccess {
 public:
   SelfTargetProcessControl(
-      Triple TT, unsigned PageSize,
-      std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
+      std::shared_ptr<SymbolStringPool> SSP, Triple TargetTriple,
+      unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
 
   /// Create a SelfTargetProcessControl with the given memory manager.
   /// If no memory manager is given a jitlink::InProcessMemoryManager will
   /// be used by default.
   static Expected<std::unique_ptr<SelfTargetProcessControl>>
-  Create(std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
+  Create(std::shared_ptr<SymbolStringPool> SSP,
+         std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
+
+  Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
+
+  Expected<std::vector<tpctypes::LookupResult>>
+  lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) override;
+
+  Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
+                              ArrayRef<std::string> Args) override;
 
-  Expected<DylibHandle> loadDylib(const char *DylibPath) override;
+  Expected<tpctypes::WrapperFunctionResult>
+  runWrapper(JITTargetAddress WrapperFnAddr,
+             ArrayRef<uint8_t> ArgBuffer) override;
 
-  Expected<LookupResult> lookupSymbols(LookupRequest Request) override;
+  Error disconnect() override;
 
 private:
-  void writeUInt8s(ArrayRef<UInt8Write> Ws,
+  void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
                    WriteResultFn OnWriteComplete) override;
 
-  void writeUInt16s(ArrayRef<UInt16Write> Ws,
+  void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
                     WriteResultFn OnWriteComplete) override;
 
-  void writeUInt32s(ArrayRef<UInt32Write> Ws,
+  void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
                     WriteResultFn OnWriteComplete) override;
 
-  void writeUInt64s(ArrayRef<UInt64Write> Ws,
+  void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
                     WriteResultFn OnWriteComplete) override;
 
-  void writeBuffers(ArrayRef<BufferWrite> Ws,
+  void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
                     WriteResultFn OnWriteComplete) override;
 
   std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;

diff  --git a/llvm/lib/ExecutionEngine/CMakeLists.txt b/llvm/lib/ExecutionEngine/CMakeLists.txt
index 9b5dd44e079e..a13fcc784e4b 100644
--- a/llvm/lib/ExecutionEngine/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/CMakeLists.txt
@@ -21,7 +21,6 @@ endif()
 add_subdirectory(Interpreter)
 add_subdirectory(JITLink)
 add_subdirectory(MCJIT)
-add_subdirectory(OrcError)
 add_subdirectory(Orc)
 add_subdirectory(RuntimeDyld)
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
index 86836e54f20e..20c53980b512 100644
--- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
@@ -22,4 +22,6 @@ add_llvm_component_library(LLVMJITLink
 target_link_libraries(LLVMJITLink
   PRIVATE
   LLVMObject
+  LLVMOrcTargetProcess
+  LLVMSupport
 )

diff  --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
index b94a2b36b5f1..7a89476687d2 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
@@ -11,6 +11,7 @@
 
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/Config/config.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
 #include "llvm/Support/DynamicLibrary.h"
 
 #define DEBUG_TYPE "jitlink"
@@ -630,142 +631,18 @@ Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
   return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
 }
 
-#if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) &&          \
-    !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
-extern "C" void __register_frame(const void *);
-extern "C" void __deregister_frame(const void *);
-
-Error registerFrameWrapper(const void *P) {
-  __register_frame(P);
-  return Error::success();
-}
-
-Error deregisterFrameWrapper(const void *P) {
-  __deregister_frame(P);
-  return Error::success();
-}
-
-#else
-
-// The building compiler does not have __(de)register_frame but
-// it may be found at runtime in a dynamically-loaded library.
-// For example, this happens when building LLVM with Visual C++
-// but using the MingW runtime.
-static Error registerFrameWrapper(const void *P) {
-  static void((*RegisterFrame)(const void *)) = 0;
-
-  if (!RegisterFrame)
-    *(void **)&RegisterFrame =
-        llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
-
-  if (RegisterFrame) {
-    RegisterFrame(P);
-    return Error::success();
-  }
-
-  return make_error<JITLinkError>("could not register eh-frame: "
-                                  "__register_frame function not found");
-}
-
-static Error deregisterFrameWrapper(const void *P) {
-  static void((*DeregisterFrame)(const void *)) = 0;
-
-  if (!DeregisterFrame)
-    *(void **)&DeregisterFrame =
-        llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
-            "__deregister_frame");
-
-  if (DeregisterFrame) {
-    DeregisterFrame(P);
-    return Error::success();
-  }
-
-  return make_error<JITLinkError>("could not deregister eh-frame: "
-                                  "__deregister_frame function not found");
-}
-#endif
-
-#ifdef __APPLE__
-
-template <typename HandleFDEFn>
-Error walkAppleEHFrameSection(const char *const SectionStart,
-                              size_t SectionSize,
-                              HandleFDEFn HandleFDE) {
-  const char *CurCFIRecord = SectionStart;
-  const char *End = SectionStart + SectionSize;
-  uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
-
-  while (CurCFIRecord != End && Size != 0) {
-    const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
-    if (Size == 0xffffffff)
-      Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
-    else
-      Size += 4;
-    uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
-
-    LLVM_DEBUG({
-      dbgs() << "Registering eh-frame section:\n";
-      dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
-             << (void *)CurCFIRecord << ": [";
-      for (unsigned I = 0; I < Size; ++I)
-        dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
-      dbgs() << " ]\n";
-    });
-
-    if (Offset != 0)
-      if (auto Err = HandleFDE(CurCFIRecord))
-        return Err;
-
-    CurCFIRecord += Size;
-
-    Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
-  }
-
-  return Error::success();
-}
-
-#endif // __APPLE__
-
-Error registerEHFrameSection(const void *EHFrameSectionAddr,
-                             size_t EHFrameSectionSize) {
-#ifdef __APPLE__
-  // On Darwin __register_frame has to be called for each FDE entry.
-  return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
-                                 EHFrameSectionSize,
-                                 registerFrameWrapper);
-#else
-  // On Linux __register_frame takes a single argument:
-  // a pointer to the start of the .eh_frame section.
-
-  // How can it find the end? Because crtendS.o is linked
-  // in and it has an .eh_frame section with four zero chars.
-  return registerFrameWrapper(EHFrameSectionAddr);
-#endif
-}
-
-Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
-                               size_t EHFrameSectionSize) {
-#ifdef __APPLE__
-  return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
-                                 EHFrameSectionSize,
-                                 deregisterFrameWrapper);
-#else
-  return deregisterFrameWrapper(EHFrameSectionAddr);
-#endif
-}
-
 EHFrameRegistrar::~EHFrameRegistrar() {}
 
 Error InProcessEHFrameRegistrar::registerEHFrames(
     JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
-  return registerEHFrameSection(
+  return orc::registerEHFrameSection(
       jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
       EHFrameSectionSize);
 }
 
 Error InProcessEHFrameRegistrar::deregisterEHFrames(
     JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
-  return deregisterEHFrameSection(
+  return orc::deregisterEHFrameSection(
       jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
       EHFrameSectionSize);
 }

diff  --git a/llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt b/llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
index e7721a184b98..f73246beb224 100644
--- a/llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
+++ b/llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
@@ -18,4 +18,4 @@
 type = Library
 name = JITLink
 parent = ExecutionEngine
-required_libraries = BinaryFormat Object Support
+required_libraries = BinaryFormat Object OrcTargetProcess Support

diff  --git a/llvm/lib/ExecutionEngine/LLVMBuild.txt b/llvm/lib/ExecutionEngine/LLVMBuild.txt
index 9bc6775f78a0..13872da4a564 100644
--- a/llvm/lib/ExecutionEngine/LLVMBuild.txt
+++ b/llvm/lib/ExecutionEngine/LLVMBuild.txt
@@ -16,7 +16,7 @@
 
 [common]
 subdirectories = Interpreter MCJIT JITLink RuntimeDyld IntelJITEvents
-                 OProfileJIT Orc OrcError PerfJITEvents
+                 OProfileJIT Orc PerfJITEvents
 
 [component_0]
 type = Library

diff  --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
index 6396fb5d1187..2ab410dbf578 100644
--- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
@@ -23,6 +23,7 @@ add_llvm_component_library(LLVMOrcJIT
   TargetProcessControl.cpp
   ThreadSafeModule.cpp
   TPCDynamicLibrarySearchGenerator.cpp
+  TPCEHFrameRegistrar.cpp
   TPCIndirectionUtils.cpp
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
@@ -31,6 +32,9 @@ add_llvm_component_library(LLVMOrcJIT
   intrinsics_gen
   )
 
+add_subdirectory(Shared)
+add_subdirectory(TargetProcess)
+
 target_link_libraries(LLVMOrcJIT
   PRIVATE
   LLVMAnalysis

diff  --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
index 5f9faf693c82..6a1a41a13a1b 100644
--- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
@@ -21,32 +21,6 @@
 namespace llvm {
 namespace orc {
 
-int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
-              Optional<StringRef> ProgramName) {
-  std::vector<std::unique_ptr<char[]>> ArgVStorage;
-  std::vector<char *> ArgV;
-
-  ArgVStorage.reserve(Args.size() + (ProgramName ? 1 : 0));
-  ArgV.reserve(Args.size() + 1 + (ProgramName ? 1 : 0));
-
-  if (ProgramName) {
-    ArgVStorage.push_back(std::make_unique<char[]>(ProgramName->size() + 1));
-    llvm::copy(*ProgramName, &ArgVStorage.back()[0]);
-    ArgVStorage.back()[ProgramName->size()] = '\0';
-    ArgV.push_back(ArgVStorage.back().get());
-  }
-
-  for (auto &Arg : Args) {
-    ArgVStorage.push_back(std::make_unique<char[]>(Arg.size() + 1));
-    llvm::copy(Arg, &ArgVStorage.back()[0]);
-    ArgVStorage.back()[Arg.size()] = '\0';
-    ArgV.push_back(ArgVStorage.back().get());
-  }
-  ArgV.push_back(nullptr);
-
-  return Main(Args.size() + !!ProgramName, ArgV.data());
-}
-
 CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End)
   : InitList(
       GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr),

diff  --git a/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt b/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
index 4a78243551ca..5d580d8fb40d 100644
--- a/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
+++ b/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
@@ -14,9 +14,12 @@
 ;
 ;===------------------------------------------------------------------------===;
 
+[common]
+subdirectories = Shared TargetProcess
+
 [component_0]
 type = Library
 name = OrcJIT
 parent = ExecutionEngine
-required_libraries = Core ExecutionEngine JITLink Object OrcError MC Passes
+required_libraries = Core ExecutionEngine JITLink Object OrcShared MC Passes
                      RuntimeDyld Support Target TransformUtils

diff  --git a/llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
similarity index 60%
rename from llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt
rename to llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
index bd968d55e670..57c06d739ec7 100644
--- a/llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
@@ -1,6 +1,7 @@
-add_llvm_component_library(LLVMOrcError
+add_llvm_component_library(LLVMOrcShared
   OrcError.cpp
   RPCError.cpp
+  TargetProcessControlTypes.cpp
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
   )

diff  --git a/llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt b/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt
similarity index 83%
rename from llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt
rename to llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt
index 65e7916916f3..68f2ab08c9ca 100644
--- a/llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt
@@ -1,4 +1,4 @@
-;===- ./lib/ExecutionEngine/OrcError/LLVMBuild.txt -------------*- Conf -*--===;
+;===- ./lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt ------------*- Conf -*--===;
 ;
 ; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 ; See https://llvm.org/LICENSE.txt for license information.
@@ -16,6 +16,6 @@
 
 [component_0]
 type = Library
-name = OrcError
-parent = ExecutionEngine
+name = OrcShared
+parent = OrcJIT
 required_libraries = Support

diff  --git a/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt.rej b/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt.rej
new file mode 100644
index 000000000000..49d4038c2bf5
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt.rej
@@ -0,0 +1,27 @@
+***************
+*** 1,4 ****
+- ;===- ./lib/ExecutionEngine/OrcError/LLVMBuild.txt -------------*- Conf -*--===;
+  ;
+  ; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+  ; See https://llvm.org/LICENSE.txt for license information.
+--- 1,4 ----
++ ;===- ./tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt -*- Conf -*--===;
+  ;
+  ; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+  ; See https://llvm.org/LICENSE.txt for license information.
+***************
+*** 15,21 ****
+  ;===------------------------------------------------------------------------===;
+  
+  [component_0]
+- type = Library
+- name = OrcError
+- parent = ExecutionEngine
+- required_libraries = Support
+--- 15,20 ----
+  ;===------------------------------------------------------------------------===;
+  
+  [component_0]
++ type = Tool
++ name = llvm-jitlink-executor
++ parent = llvm-jitlink

diff  --git a/llvm/lib/ExecutionEngine/OrcError/OrcError.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp
similarity index 96%
rename from llvm/lib/ExecutionEngine/OrcError/OrcError.cpp
rename to llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp
index cc99e154fbec..9b1c028d7047 100644
--- a/llvm/lib/ExecutionEngine/OrcError/OrcError.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp
@@ -71,7 +71,7 @@ class OrcErrorCategory : public std::error_category {
 };
 
 static ManagedStatic<OrcErrorCategory> OrcErrCat;
-}
+} // namespace
 
 namespace llvm {
 namespace orc {
@@ -84,9 +84,8 @@ std::error_code orcError(OrcErrorCode ErrCode) {
   return std::error_code(static_cast<UT>(ErrCode), *OrcErrCat);
 }
 
-
 DuplicateDefinition::DuplicateDefinition(std::string SymbolName)
-  : SymbolName(std::move(SymbolName)) {}
+    : SymbolName(std::move(SymbolName)) {}
 
 std::error_code DuplicateDefinition::convertToErrorCode() const {
   return orcError(OrcErrorCode::DuplicateDefinition);
@@ -101,7 +100,7 @@ const std::string &DuplicateDefinition::getSymbolName() const {
 }
 
 JITSymbolNotFound::JITSymbolNotFound(std::string SymbolName)
-  : SymbolName(std::move(SymbolName)) {}
+    : SymbolName(std::move(SymbolName)) {}
 
 std::error_code JITSymbolNotFound::convertToErrorCode() const {
   typedef std::underlying_type<OrcErrorCode>::type UT;
@@ -117,5 +116,5 @@ const std::string &JITSymbolNotFound::getSymbolName() const {
   return SymbolName;
 }
 
-}
-}
+} // namespace orc
+} // namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/OrcError/RPCError.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/RPCError.cpp
similarity index 99%
rename from llvm/lib/ExecutionEngine/OrcError/RPCError.cpp
rename to llvm/lib/ExecutionEngine/Orc/Shared/RPCError.cpp
index 3cf78fd9f7ba..a13db4863953 100644
--- a/llvm/lib/ExecutionEngine/OrcError/RPCError.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/RPCError.cpp
@@ -14,8 +14,8 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/raw_ostream.h"
 
-#include <system_error>
 #include <string>
+#include <system_error>
 
 char llvm::orc::rpc::RPCFatalError::ID = 0;
 char llvm::orc::rpc::ConnectionClosed::ID = 0;
@@ -53,7 +53,6 @@ void CouldNotNegotiate::log(raw_ostream &OS) const {
   OS << "Could not negotiate RPC function " << Signature;
 }
 
-
 } // end namespace rpc
 } // end namespace orc
 } // end namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.cpp
new file mode 100644
index 000000000000..0b77eac8b4a6
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.cpp
@@ -0,0 +1,43 @@
+//===---------- TargetProcessControlTypes.cpp - Shared TPC types ----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// TargetProcessControl types.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
+
+namespace llvm {
+namespace orc {
+namespace tpctypes {
+
+WrapperFunctionResult WrapperFunctionResult::from(StringRef S) {
+  CWrapperFunctionResult R = {0, {.ValuePtr = nullptr}, nullptr};
+  R.Size = S.size();
+  if (R.Size > sizeof(uint64_t)) {
+    R.Data.ValuePtr = new uint8_t[R.Size];
+    memcpy(R.Data.ValuePtr, S.data(), R.Size);
+    R.Destroy = destroyWithDeleteArray;
+  } else
+    memcpy(R.Data.Value, S.data(), R.Size);
+  return R;
+}
+
+void WrapperFunctionResult::destroyWithFree(CWrapperFunctionResultData Data,
+                                            uint64_t Size) {
+  free(Data.ValuePtr);
+}
+
+void WrapperFunctionResult::destroyWithDeleteArray(
+    CWrapperFunctionResultData Data, uint64_t Size) {
+  delete[] Data.ValuePtr;
+}
+
+} // end namespace tpctypes
+} // end namespace orc
+} // end namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
index ab58641b3478..f275c634a6d5 100644
--- a/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
@@ -41,7 +41,7 @@ Error TPCDynamicLibrarySearchGenerator::tryToGenerate(
 
   SymbolMap NewSymbols;
 
-  TargetProcessControl::LookupRequestElement Request(H, LookupSymbols);
+  tpctypes::LookupRequest Request(H, LookupSymbols);
   auto Result = TPC.lookupSymbols(Request);
   if (!Result)
     return Result.takeError();

diff  --git a/llvm/lib/ExecutionEngine/Orc/TPCEHFrameRegistrar.cpp b/llvm/lib/ExecutionEngine/Orc/TPCEHFrameRegistrar.cpp
new file mode 100644
index 000000000000..4f901ce6d445
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TPCEHFrameRegistrar.cpp
@@ -0,0 +1,80 @@
+//===------ TPCEHFrameRegistrar.cpp - TPC-based eh-frame registration -----===//
+//
+// 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/TPCEHFrameRegistrar.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+namespace llvm {
+namespace orc {
+
+Expected<std::unique_ptr<TPCEHFrameRegistrar>>
+TPCEHFrameRegistrar::Create(TargetProcessControl &TPC) {
+  // FIXME: Proper mangling here -- we really need to decouple linker mangling
+  // from DataLayout.
+
+  // Find the addresses of the registration/deregistration functions in the
+  // target process.
+  auto ProcessHandle = TPC.loadDylib(nullptr);
+  if (!ProcessHandle)
+    return ProcessHandle.takeError();
+
+  std::string RegisterWrapperName, DeregisterWrapperName;
+  if (TPC.getTargetTriple().isOSBinFormatMachO()) {
+    RegisterWrapperName += '_';
+    DeregisterWrapperName += '_';
+  }
+  RegisterWrapperName += "llvm_orc_registerEHFrameSectionWrapper";
+  DeregisterWrapperName += "llvm_orc_deregisterEHFrameSectionWrapper";
+
+  SymbolLookupSet RegistrationSymbols;
+  RegistrationSymbols.add(TPC.intern(RegisterWrapperName));
+  RegistrationSymbols.add(TPC.intern(DeregisterWrapperName));
+
+  auto Result = TPC.lookupSymbols({{*ProcessHandle, RegistrationSymbols}});
+  if (!Result)
+    return Result.takeError();
+
+  assert(Result->size() == 1 && "Unexpected number of dylibs in result");
+  assert((*Result)[0].size() == 2 &&
+         "Unexpected number of addresses in result");
+
+  auto RegisterEHFrameWrapperFnAddr = (*Result)[0][0];
+  auto DeregisterEHFrameWrapperFnAddr = (*Result)[0][1];
+
+  return std::make_unique<TPCEHFrameRegistrar>(
+      TPC, RegisterEHFrameWrapperFnAddr, DeregisterEHFrameWrapperFnAddr);
+}
+
+Error TPCEHFrameRegistrar::registerEHFrames(JITTargetAddress EHFrameSectionAddr,
+                                            size_t EHFrameSectionSize) {
+  constexpr size_t ArgBufferSize = sizeof(uint64_t) + sizeof(uint64_t);
+  uint8_t ArgBuffer[ArgBufferSize];
+  BinaryStreamWriter ArgWriter(
+      MutableArrayRef<uint8_t>(ArgBuffer, ArgBufferSize),
+      support::endianness::big);
+  cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionAddr)));
+  cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionSize)));
+
+  return TPC.runWrapper(RegisterEHFrameWrapperFnAddr, ArgBuffer).takeError();
+}
+
+Error TPCEHFrameRegistrar::deregisterEHFrames(
+    JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
+  constexpr size_t ArgBufferSize = sizeof(uint64_t) + sizeof(uint64_t);
+  uint8_t ArgBuffer[ArgBufferSize];
+  BinaryStreamWriter ArgWriter(
+      MutableArrayRef<uint8_t>(ArgBuffer, ArgBufferSize),
+      support::endianness::big);
+  cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionAddr)));
+  cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionSize)));
+
+  return TPC.runWrapper(DeregisterEHFrameWrapperFnAddr, ArgBuffer).takeError();
+}
+
+} // end namespace orc
+} // end namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
index de13f064189a..d827cf7b273b 100644
--- a/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
@@ -160,7 +160,7 @@ Error TPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
   switch (TPCIU.getABISupport().getPointerSize()) {
   case 4: {
     unsigned ASIdx = 0;
-    std::vector<TargetProcessControl::MemoryAccess::UInt32Write> PtrUpdates;
+    std::vector<tpctypes::UInt32Write> PtrUpdates;
     for (auto &SI : StubInits)
       PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
                             static_cast<uint32_t>(SI.second.first)});
@@ -168,7 +168,7 @@ Error TPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
   }
   case 8: {
     unsigned ASIdx = 0;
-    std::vector<TargetProcessControl::MemoryAccess::UInt64Write> PtrUpdates;
+    std::vector<tpctypes::UInt64Write> PtrUpdates;
     for (auto &SI : StubInits)
       PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
                             static_cast<uint64_t>(SI.second.first)});
@@ -213,11 +213,11 @@ Error TPCIndirectStubsManager::updatePointer(StringRef Name,
   auto &MemAccess = TPCIU.getTargetProcessControl().getMemoryAccess();
   switch (TPCIU.getABISupport().getPointerSize()) {
   case 4: {
-    TargetProcessControl::MemoryAccess::UInt32Write PUpdate(PtrAddr, NewAddr);
+    tpctypes::UInt32Write PUpdate(PtrAddr, NewAddr);
     return MemAccess.writeUInt32s(PUpdate);
   }
   case 8: {
-    TargetProcessControl::MemoryAccess::UInt64Write PUpdate(PtrAddr, NewAddr);
+    tpctypes::UInt64Write PUpdate(PtrAddr, NewAddr);
     return MemAccess.writeUInt64s(PUpdate);
   }
   default:

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
new file mode 100644
index 000000000000..b561ce232ce4
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_llvm_component_library(LLVMOrcTargetProcess
+  RegisterEHFrames.cpp
+  TargetExecutionUtils.cpp
+  ADDITIONAL_HEADER_DIRS
+  ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
+  )

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LLVMBuild.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LLVMBuild.txt
new file mode 100644
index 000000000000..781e6188a702
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LLVMBuild.txt
@@ -0,0 +1,21 @@
+;===- ./lib/ExecutionEngine/OrcTargetProcess/LLVMBuild.txt -----*- Conf -*--===;
+;
+; 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
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+;   http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = OrcTargetProcess
+parent = OrcJIT
+required_libraries = OrcShared Support

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp
new file mode 100644
index 000000000000..e32916dfcd96
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp
@@ -0,0 +1,207 @@
+//===--------- RegisterEHFrames.cpp - Register EH frame sections ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
+
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "llvm/Support/FormatVariadic.h"
+
+#define DEBUG_TYPE "orc"
+
+using namespace llvm;
+using namespace llvm::orc;
+using namespace llvm::orc::tpctypes;
+
+namespace llvm {
+namespace orc {
+
+#if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) &&          \
+    !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+
+extern "C" void __register_frame(const void *);
+extern "C" void __deregister_frame(const void *);
+
+Error registerFrameWrapper(const void *P) {
+  __register_frame(P);
+  return Error::success();
+}
+
+Error deregisterFrameWrapper(const void *P) {
+  __deregister_frame(P);
+  return Error::success();
+}
+
+#else
+
+// The building compiler does not have __(de)register_frame but
+// it may be found at runtime in a dynamically-loaded library.
+// For example, this happens when building LLVM with Visual C++
+// but using the MingW runtime.
+static Error registerFrameWrapper(const void *P) {
+  static void((*RegisterFrame)(const void *)) = 0;
+
+  if (!RegisterFrame)
+    *(void **)&RegisterFrame =
+        llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
+
+  if (RegisterFrame) {
+    RegisterFrame(P);
+    return Error::success();
+  }
+
+  return make_error<StringError>("could not register eh-frame: "
+                                 "__register_frame function not found",
+                                 inconvertibleErrorCode());
+}
+
+static Error deregisterFrameWrapper(const void *P) {
+  static void((*DeregisterFrame)(const void *)) = 0;
+
+  if (!DeregisterFrame)
+    *(void **)&DeregisterFrame =
+        llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
+            "__deregister_frame");
+
+  if (DeregisterFrame) {
+    DeregisterFrame(P);
+    return Error::success();
+  }
+
+  return make_error<StringError>("could not deregister eh-frame: "
+                                 "__deregister_frame function not found",
+                                 inconvertibleErrorCode());
+}
+#endif
+
+#ifdef __APPLE__
+
+template <typename HandleFDEFn>
+Error walkAppleEHFrameSection(const char *const SectionStart,
+                              size_t SectionSize, HandleFDEFn HandleFDE) {
+  const char *CurCFIRecord = SectionStart;
+  const char *End = SectionStart + SectionSize;
+  uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
+
+  while (CurCFIRecord != End && Size != 0) {
+    const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
+    if (Size == 0xffffffff)
+      Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
+    else
+      Size += 4;
+    uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
+
+    LLVM_DEBUG({
+      dbgs() << "Registering eh-frame section:\n";
+      dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
+             << (void *)CurCFIRecord << ": [";
+      for (unsigned I = 0; I < Size; ++I)
+        dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
+      dbgs() << " ]\n";
+    });
+
+    if (Offset != 0)
+      if (auto Err = HandleFDE(CurCFIRecord))
+        return Err;
+
+    CurCFIRecord += Size;
+
+    Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
+  }
+
+  return Error::success();
+}
+
+#endif // __APPLE__
+
+Error registerEHFrameSection(const void *EHFrameSectionAddr,
+                             size_t EHFrameSectionSize) {
+#ifdef __APPLE__
+  // On Darwin __register_frame has to be called for each FDE entry.
+  return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
+                                 EHFrameSectionSize, registerFrameWrapper);
+#else
+  // On Linux __register_frame takes a single argument:
+  // a pointer to the start of the .eh_frame section.
+
+  // How can it find the end? Because crtendS.o is linked
+  // in and it has an .eh_frame section with four zero chars.
+  return registerFrameWrapper(EHFrameSectionAddr);
+#endif
+}
+
+Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
+                               size_t EHFrameSectionSize) {
+#ifdef __APPLE__
+  return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
+                                 EHFrameSectionSize, deregisterFrameWrapper);
+#else
+  return deregisterFrameWrapper(EHFrameSectionAddr);
+#endif
+}
+
+} // end namespace orc
+} // end namespace llvm
+
+extern "C" CWrapperFunctionResult
+llvm_orc_registerEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) {
+  if (Size != sizeof(uint64_t) + sizeof(uint64_t))
+    return WrapperFunctionResult::from(
+               "Invalid arguments to llvm_orc_registerEHFrameSectionWrapper")
+        .release();
+
+  uint64_t EHFrameSectionAddr;
+  uint64_t EHFrameSectionSize;
+
+  {
+    BinaryStreamReader ArgReader(ArrayRef<uint8_t>(Data, Size),
+                                 support::endianness::big);
+    cantFail(ArgReader.readInteger(EHFrameSectionAddr));
+    cantFail(ArgReader.readInteger(EHFrameSectionSize));
+  }
+
+  if (auto Err = registerEHFrameSection(
+          jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
+          EHFrameSectionSize)) {
+    auto ErrMsg = toString(std::move(Err));
+    return WrapperFunctionResult::from(ErrMsg).release();
+  }
+  return WrapperFunctionResult().release();
+}
+
+extern "C" CWrapperFunctionResult
+llvm_orc_deregisterEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) {
+  if (Size != sizeof(uint64_t) + sizeof(uint64_t))
+    return WrapperFunctionResult::from(
+               "Invalid arguments to llvm_orc_registerEHFrameSectionWrapper")
+        .release();
+
+  uint64_t EHFrameSectionAddr;
+  uint64_t EHFrameSectionSize;
+
+  {
+    BinaryStreamReader ArgReader(ArrayRef<uint8_t>(Data, Size),
+                                 support::endianness::big);
+    cantFail(ArgReader.readInteger(EHFrameSectionAddr));
+    cantFail(ArgReader.readInteger(EHFrameSectionSize));
+  }
+
+  if (auto Err = deregisterEHFrameSection(
+          jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
+          EHFrameSectionSize)) {
+    auto ErrMsg = toString(std::move(Err));
+    return WrapperFunctionResult::from(ErrMsg).release();
+  }
+  return WrapperFunctionResult().release();
+}

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp
new file mode 100644
index 000000000000..a8e6c049cf4b
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp
@@ -0,0 +1,43 @@
+//===--- TargetExecutionUtils.cpp - Execution utils for target processes --===//
+//
+// 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/TargetProcess/TargetExecutionUtils.h"
+
+#include <vector>
+
+namespace llvm {
+namespace orc {
+
+int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
+              Optional<StringRef> ProgramName) {
+  std::vector<std::unique_ptr<char[]>> ArgVStorage;
+  std::vector<char *> ArgV;
+
+  ArgVStorage.reserve(Args.size() + (ProgramName ? 1 : 0));
+  ArgV.reserve(Args.size() + 1 + (ProgramName ? 1 : 0));
+
+  if (ProgramName) {
+    ArgVStorage.push_back(std::make_unique<char[]>(ProgramName->size() + 1));
+    llvm::copy(*ProgramName, &ArgVStorage.back()[0]);
+    ArgVStorage.back()[ProgramName->size()] = '\0';
+    ArgV.push_back(ArgVStorage.back().get());
+  }
+
+  for (const auto &Arg : Args) {
+    ArgVStorage.push_back(std::make_unique<char[]>(Arg.size() + 1));
+    llvm::copy(Arg, &ArgVStorage.back()[0]);
+    ArgVStorage.back()[Arg.size()] = '\0';
+    ArgV.push_back(ArgVStorage.back().get());
+  }
+  ArgV.push_back(nullptr);
+
+  return Main(Args.size() + !!ProgramName, ArgV.data());
+}
+
+} // End namespace orc.
+} // End namespace llvm.

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
index 1e7736d1f40d..bbbc2d60d936 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
@@ -9,6 +9,7 @@
 #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
 
 #include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/Process.h"
 
@@ -22,23 +23,25 @@ TargetProcessControl::MemoryAccess::~MemoryAccess() {}
 TargetProcessControl::~TargetProcessControl() {}
 
 SelfTargetProcessControl::SelfTargetProcessControl(
-    Triple TT, unsigned PageSize,
-    std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
+    std::shared_ptr<SymbolStringPool> SSP, Triple TargetTriple,
+    unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)
+    : TargetProcessControl(std::move(SSP)) {
 
   OwnedMemMgr = std::move(MemMgr);
   if (!OwnedMemMgr)
     OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>();
 
-  this->TT = std::move(TT);
+  this->TargetTriple = std::move(TargetTriple);
   this->PageSize = PageSize;
   this->MemMgr = OwnedMemMgr.get();
   this->MemAccess = this;
-  if (this->TT.isOSBinFormatMachO())
+  if (this->TargetTriple.isOSBinFormatMachO())
     GlobalManglingPrefix = '_';
 }
 
 Expected<std::unique_ptr<SelfTargetProcessControl>>
 SelfTargetProcessControl::Create(
+    std::shared_ptr<SymbolStringPool> SSP,
     std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
   auto PageSize = sys::Process::getPageSize();
   if (!PageSize)
@@ -46,11 +49,11 @@ SelfTargetProcessControl::Create(
 
   Triple TT(sys::getProcessTriple());
 
-  return std::make_unique<SelfTargetProcessControl>(std::move(TT), *PageSize,
-                                                    std::move(MemMgr));
+  return std::make_unique<SelfTargetProcessControl>(
+      std::move(SSP), std::move(TT), *PageSize, std::move(MemMgr));
 }
 
-Expected<TargetProcessControl::DylibHandle>
+Expected<tpctypes::DylibHandle>
 SelfTargetProcessControl::loadDylib(const char *DylibPath) {
   std::string ErrMsg;
   auto Dylib = std::make_unique<sys::DynamicLibrary>(
@@ -61,9 +64,10 @@ SelfTargetProcessControl::loadDylib(const char *DylibPath) {
   return pointerToJITTargetAddress(DynamicLibraries.back().get());
 }
 
-Expected<TargetProcessControl::LookupResult>
-SelfTargetProcessControl::lookupSymbols(LookupRequest Request) {
-  LookupResult R;
+Expected<std::vector<tpctypes::LookupResult>>
+SelfTargetProcessControl::lookupSymbols(
+    ArrayRef<tpctypes::LookupRequest> Request) {
+  std::vector<tpctypes::LookupResult> R;
 
   for (auto &Elem : Request) {
     auto *Dylib = jitTargetAddressToPointer<sys::DynamicLibrary *>(Elem.Handle);
@@ -92,35 +96,53 @@ SelfTargetProcessControl::lookupSymbols(LookupRequest Request) {
   return R;
 }
 
-void SelfTargetProcessControl::writeUInt8s(ArrayRef<UInt8Write> Ws,
+Expected<int32_t>
+SelfTargetProcessControl::runAsMain(JITTargetAddress MainFnAddr,
+                                    ArrayRef<std::string> Args) {
+  using MainTy = int (*)(int, char *[]);
+  return orc::runAsMain(jitTargetAddressToFunction<MainTy>(MainFnAddr), Args);
+}
+
+Expected<tpctypes::WrapperFunctionResult>
+SelfTargetProcessControl::runWrapper(JITTargetAddress WrapperFnAddr,
+                                     ArrayRef<uint8_t> ArgBuffer) {
+  using WrapperFnTy =
+      tpctypes::CWrapperFunctionResult (*)(const uint8_t *Data, uint64_t Size);
+  auto *WrapperFn = jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
+  return WrapperFn(ArgBuffer.data(), ArgBuffer.size());
+};
+
+Error SelfTargetProcessControl::disconnect() { return Error::success(); }
+
+void SelfTargetProcessControl::writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
                                            WriteResultFn OnWriteComplete) {
   for (auto &W : Ws)
     *jitTargetAddressToPointer<uint8_t *>(W.Address) = W.Value;
   OnWriteComplete(Error::success());
 }
 
-void SelfTargetProcessControl::writeUInt16s(ArrayRef<UInt16Write> Ws,
+void SelfTargetProcessControl::writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
                                             WriteResultFn OnWriteComplete) {
   for (auto &W : Ws)
     *jitTargetAddressToPointer<uint16_t *>(W.Address) = W.Value;
   OnWriteComplete(Error::success());
 }
 
-void SelfTargetProcessControl::writeUInt32s(ArrayRef<UInt32Write> Ws,
+void SelfTargetProcessControl::writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
                                             WriteResultFn OnWriteComplete) {
   for (auto &W : Ws)
     *jitTargetAddressToPointer<uint32_t *>(W.Address) = W.Value;
   OnWriteComplete(Error::success());
 }
 
-void SelfTargetProcessControl::writeUInt64s(ArrayRef<UInt64Write> Ws,
+void SelfTargetProcessControl::writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
                                             WriteResultFn OnWriteComplete) {
   for (auto &W : Ws)
     *jitTargetAddressToPointer<uint64_t *>(W.Address) = W.Value;
   OnWriteComplete(Error::success());
 }
 
-void SelfTargetProcessControl::writeBuffers(ArrayRef<BufferWrite> Ws,
+void SelfTargetProcessControl::writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
                                             WriteResultFn OnWriteComplete) {
   for (auto &W : Ws)
     memcpy(jitTargetAddressToPointer<char *>(W.Address), W.Buffer.data(),

diff  --git a/llvm/tools/lli/CMakeLists.txt b/llvm/tools/lli/CMakeLists.txt
index bc6ef213b8fd..098e9dd3e743 100644
--- a/llvm/tools/lli/CMakeLists.txt
+++ b/llvm/tools/lli/CMakeLists.txt
@@ -11,8 +11,9 @@ set(LLVM_LINK_COMPONENTS
   MC
   MCJIT
   Object
-  OrcError
+  OrcShared
   OrcJIT
+  OrcTargetProcess
   Passes
   RuntimeDyld
   SelectionDAG

diff  --git a/llvm/tools/lli/ChildTarget/CMakeLists.txt b/llvm/tools/lli/ChildTarget/CMakeLists.txt
index d3d15bef6c5b..c5795eebd71a 100644
--- a/llvm/tools/lli/ChildTarget/CMakeLists.txt
+++ b/llvm/tools/lli/ChildTarget/CMakeLists.txt
@@ -1,5 +1,5 @@
 set(LLVM_LINK_COMPONENTS
-  OrcError
+  OrcShared
   OrcJIT
   RuntimeDyld
   Support

diff  --git a/llvm/tools/lli/LLVMBuild.txt b/llvm/tools/lli/LLVMBuild.txt
index 133543a26fce..0d473cbe9238 100644
--- a/llvm/tools/lli/LLVMBuild.txt
+++ b/llvm/tools/lli/LLVMBuild.txt
@@ -28,6 +28,9 @@ required_libraries =
  Instrumentation
  Interpreter
  MCJIT
+ OrcJIT
+ OrcShared
+ OrcTargetProcess
  Native
  NativeCodeGen
  SelectionDAG

diff  --git a/llvm/tools/lli/lli.cpp b/llvm/tools/lli/lli.cpp
index 1ebd1435f2f3..e9b48a8542ec 100644
--- a/llvm/tools/lli/lli.cpp
+++ b/llvm/tools/lli/lli.cpp
@@ -31,6 +31,7 @@
 #include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h"
 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LLVMContext.h"

diff  --git a/llvm/tools/llvm-jitlink/CMakeLists.txt b/llvm/tools/llvm-jitlink/CMakeLists.txt
index bfe691d976ba..8d511b17fca2 100644
--- a/llvm/tools/llvm-jitlink/CMakeLists.txt
+++ b/llvm/tools/llvm-jitlink/CMakeLists.txt
@@ -1,3 +1,7 @@
+if ( LLVM_INCLUDE_UTILS )
+  add_subdirectory(llvm-jitlink-executor)
+endif()
+
 set(LLVM_LINK_COMPONENTS
   AllTargetsDescs
   AllTargetsDisassemblers
@@ -8,6 +12,8 @@ set(LLVM_LINK_COMPONENTS
   MC
   Object
   OrcJIT
+  OrcShared
+  OrcTargetProcess
   RuntimeDyld
   Support
   )

diff  --git a/llvm/tools/llvm-jitlink/LLVMBuild.txt b/llvm/tools/llvm-jitlink/LLVMBuild.txt
index 224bab58c215..8aa0ef8161e6 100644
--- a/llvm/tools/llvm-jitlink/LLVMBuild.txt
+++ b/llvm/tools/llvm-jitlink/LLVMBuild.txt
@@ -18,5 +18,5 @@
 type = Tool
 name = llvm-jitlink
 parent = Tools
-required_libraries = JITLink BinaryFormat MC Object RuntimeDyld Support
-                     all-targets
+required_libraries = JITLink BinaryFormat MC Object OrcJIT OrcTargetProcess
+                     Support all-targets

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
new file mode 100644
index 000000000000..f6d882d1a8f0
--- /dev/null
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS
+  OrcShared
+  OrcTargetProcess
+  Support
+  )
+
+add_llvm_utility(llvm-jitlink-executor
+  llvm-jitlink-executor.cpp
+
+  DEPENDS
+  intrinsics_gen
+)
+
+export_executable_symbols(llvm-jitlink-executor)

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt
new file mode 100644
index 000000000000..0d96143673dd
--- /dev/null
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt
@@ -0,0 +1,21 @@
+;===- ./tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt -*- Conf -*--===;
+;
+; 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
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+;   http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Tool
+name = llvm-jitlink-executor
+parent = llvm-jitlink
+required_libraries = OrcTargetProcess Support

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
new file mode 100644
index 000000000000..78227f3f423b
--- /dev/null
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
@@ -0,0 +1,127 @@
+//===- llvm-jitlink-executor.cpp - Out-of-proc executor for llvm-jitlink -===//
+//
+// 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 llvm-jitlink.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include <sstream>
+
+#ifdef LLVM_ON_UNIX
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#endif
+
+using namespace llvm;
+using namespace llvm::orc;
+
+ExitOnError ExitOnErr;
+
+LLVM_ATTRIBUTE_USED void linkComponents() {
+  errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
+         << (void *)&llvm_orc_deregisterEHFrameSectionWrapper;
+}
+
+void printErrorAndExit(Twine ErrMsg) {
+  errs() << "error: " << ErrMsg.str() << "\n\n"
+         << "Usage:\n"
+         << "  llvm-jitlink-executor filedescs=<infd>,<outfd> [args...]\n"
+         << "  llvm-jitlink-executor listen=<host>:<port> [args...]\n";
+  exit(1);
+}
+
+int openListener(std::string Host, int Port) {
+#ifndef LLVM_ON_UNIX
+  // FIXME: Add TCP support for Windows.
+  printErrorAndExit("listen option not supported");
+#else
+  int SockFD = socket(PF_INET, SOCK_STREAM, 0);
+  struct sockaddr_in ServerAddr, ClientAddr;
+  socklen_t ClientAddrLen = sizeof(ClientAddr);
+  memset(&ServerAddr, 0, sizeof(ServerAddr));
+  ServerAddr.sin_family = PF_INET;
+  ServerAddr.sin_family = INADDR_ANY;
+  ServerAddr.sin_port = htons(Port);
+
+  {
+    // lose the "Address already in use" error message
+    int Yes = 1;
+    if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1) {
+      errs() << "Error calling setsockopt.\n";
+      exit(1);
+    }
+  }
+
+  if (bind(SockFD, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) < 0) {
+    errs() << "Error on binding.\n";
+    exit(1);
+  }
+
+  listen(SockFD, 1);
+  return accept(SockFD, (struct sockaddr *)&ClientAddr, &ClientAddrLen);
+#endif
+}
+
+int main(int argc, char *argv[]) {
+
+  ExitOnErr.setBanner(std::string(argv[0]) + ": ");
+
+  int InFD = 0;
+  int OutFD = 0;
+
+  if (argc < 2)
+    printErrorAndExit("insufficient arguments");
+  else {
+    StringRef Arg1 = argv[1];
+    StringRef SpecifierType, Specifier;
+    std::tie(SpecifierType, Specifier) = Arg1.split('=');
+    if (SpecifierType == "filedescs") {
+      StringRef FD1Str, FD2Str;
+      std::tie(FD1Str, FD2Str) = Specifier.split(',');
+      if (FD1Str.getAsInteger(10, InFD))
+        printErrorAndExit(FD1Str + " is not a valid file descriptor");
+      if (FD2Str.getAsInteger(10, OutFD))
+        printErrorAndExit(FD2Str + " is not a valid file descriptor");
+    } else if (SpecifierType == "listen") {
+      StringRef Host, PortStr;
+      std::tie(Host, PortStr) = Specifier.split(':');
+
+      int Port = 0;
+      if (PortStr.getAsInteger(10, Port))
+        printErrorAndExit("port" + PortStr + " is not a valid integer");
+
+      InFD = OutFD = openListener(Host.str(), Port);
+    } else
+      printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
+  }
+
+  ExitOnErr.setBanner(std::string(argv[0]) + ":");
+
+  using JITLinkExecutorEndpoint =
+      rpc::MultiThreadedRPCEndpoint<rpc::FDRawByteChannel>;
+
+  rpc::registerStringError<rpc::FDRawByteChannel>();
+
+  rpc::FDRawByteChannel C(InFD, OutFD);
+  JITLinkExecutorEndpoint EP(C, true);
+  OrcRPCTPCServer<JITLinkExecutorEndpoint> Server(EP);
+  Server.setProgramName(std::string("llvm-jitlink-executor"));
+
+  ExitOnErr(Server.run());
+
+  return 0;
+}

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index 8c3b99824fe3..4e899cf2d156 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -15,9 +15,9 @@
 #include "llvm-jitlink.h"
 
 #include "llvm/BinaryFormat/Magic.h"
-#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
 #include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h"
+#include "llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
@@ -41,6 +41,13 @@
 #include <list>
 #include <string>
 
+#ifdef LLVM_ON_UNIX
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif // LLVM_ON_UNIX
+
 #define DEBUG_TYPE "llvm_jitlink"
 
 using namespace llvm;
@@ -138,6 +145,14 @@ static cl::opt<bool> PhonyExternals(
     cl::desc("resolve all otherwise unresolved externals to null"),
     cl::init(false));
 
+static cl::opt<std::string> OutOfProcessExecutor(
+    "oop-executor", cl::desc("Launch an out-of-process executor to run code"),
+    cl::ValueOptional);
+
+static cl::opt<std::string> OutOfProcessExecutorConnect(
+    "oop-executor-connect",
+    cl::desc("Connect to an out-of-process executor via TCP"));
+
 ExitOnError ExitOnErr;
 
 namespace llvm {
@@ -561,6 +576,165 @@ Error LLVMJITLinkObjectLinkingLayer::add(ResourceTrackerSP RT,
   return JD.define(std::move(MU), std::move(RT));
 }
 
+Expected<std::unique_ptr<TargetProcessControl>>
+LLVMJITLinkRemoteTargetProcessControl::LaunchExecutor() {
+#ifndef LLVM_ON_UNIX
+  // FIXME: Add support for Windows.
+  return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr +
+                                     " not supported on non-unix platforms",
+                                 inconvertibleErrorCode());
+#else
+
+  rpc::registerStringError<LLVMJITLinkChannel>();
+
+  constexpr int ReadEnd = 0;
+  constexpr int WriteEnd = 1;
+
+  // Pipe FDs.
+  int ToExecutor[2];
+  int FromExecutor[2];
+
+  pid_t ChildPID;
+
+  // Create pipes to/from the executor..
+  if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
+    return make_error<StringError>("Unable to create pipe for executor",
+                                   inconvertibleErrorCode());
+
+  ChildPID = fork();
+
+  if (ChildPID == 0) {
+    // In the child...
+
+    // Close the parent ends of the pipes
+    close(ToExecutor[WriteEnd]);
+    close(FromExecutor[ReadEnd]);
+
+    // Execute the child process.
+    std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
+    {
+      ExecutorPath = std::make_unique<char[]>(OutOfProcessExecutor.size() + 1);
+      strcpy(ExecutorPath.get(), OutOfProcessExecutor.data());
+
+      std::string FDSpecifierStr("filedescs=");
+      FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
+      FDSpecifierStr += ',';
+      FDSpecifierStr += utostr(FromExecutor[WriteEnd]);
+      FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
+      strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
+    }
+
+    char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};
+    int RC = execvp(ExecutorPath.get(), Args);
+    if (RC != 0) {
+      errs() << "unable to launch out-of-process executor \""
+             << ExecutorPath.get() << "\"\n";
+      exit(1);
+    }
+  }
+  // else we're the parent...
+
+  // Close the child ends of the pipes
+  close(ToExecutor[ReadEnd]);
+  close(FromExecutor[WriteEnd]);
+
+  // Return an RPC channel connected to our end of the pipes.
+  auto SSP = std::make_shared<SymbolStringPool>();
+  auto Channel = std::make_unique<rpc::FDRawByteChannel>(FromExecutor[ReadEnd],
+                                                         ToExecutor[WriteEnd]);
+  auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
+
+  auto ReportError = [](Error Err) {
+    logAllUnhandledErrors(std::move(Err), errs(), "");
+  };
+
+  Error Err = Error::success();
+  std::unique_ptr<LLVMJITLinkRemoteTargetProcessControl> RTPC(
+      new LLVMJITLinkRemoteTargetProcessControl(
+          std::move(SSP), std::move(Channel), std::move(Endpoint),
+          std::move(ReportError), Err));
+  if (Err)
+    return std::move(Err);
+  return std::move(RTPC);
+#endif
+}
+
+Expected<std::unique_ptr<TargetProcessControl>>
+LLVMJITLinkRemoteTargetProcessControl::ConnectToExecutor() {
+#ifndef LLVM_ON_UNIX
+  // FIXME: Add TCP support for Windows.
+  return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr +
+                                     " not supported on non-unix platforms",
+                                 inconvertibleErrorCode());
+#else
+
+  rpc::registerStringError<LLVMJITLinkChannel>();
+
+  StringRef HostNameStr, PortStr;
+  std::tie(HostNameStr, PortStr) =
+      StringRef(OutOfProcessExecutorConnect).split(':');
+
+  if (HostNameStr.empty())
+    return make_error<StringError>("host name for -" +
+                                       OutOfProcessExecutorConnect.ArgStr +
+                                       " can not be empty",
+                                   inconvertibleErrorCode());
+  if (PortStr.empty())
+    return make_error<StringError>(
+        "port for -" + OutOfProcessExecutorConnect.ArgStr + " can not be empty",
+        inconvertibleErrorCode());
+
+  std::string HostName = HostNameStr.str();
+  int Port = 0;
+  if (PortStr.getAsInteger(10, Port))
+    return make_error<StringError>("port number " + PortStr +
+                                       " is not a valid integer",
+                                   inconvertibleErrorCode());
+
+  int SockFD = socket(PF_INET, SOCK_STREAM, 0);
+  hostent *Server = gethostbyname(HostName.c_str());
+  sockaddr_in ServAddr;
+  memset(&ServAddr, 0, sizeof(ServAddr));
+  ServAddr.sin_family = PF_INET;
+  memmove(&Server->h_addr, &ServAddr.sin_addr.s_addr, Server->h_length);
+  ServAddr.sin_port = htons(Port);
+  if (connect(SockFD, reinterpret_cast<sockaddr *>(&ServAddr),
+              sizeof(ServAddr)) < 0)
+    return make_error<StringError>("Failed to connect to " + HostName + ":" +
+                                       Twine(Port),
+                                   inconvertibleErrorCode());
+
+  auto SSP = std::make_shared<SymbolStringPool>();
+  auto Channel = std::make_unique<rpc::FDRawByteChannel>(SockFD, SockFD);
+  auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
+
+  auto ReportError = [](Error Err) {
+    logAllUnhandledErrors(std::move(Err), errs(), "");
+  };
+
+  Error Err = Error::success();
+  std::unique_ptr<LLVMJITLinkRemoteTargetProcessControl> RTPC(
+      new LLVMJITLinkRemoteTargetProcessControl(
+          std::move(SSP), std::move(Channel), std::move(Endpoint),
+          std::move(ReportError), Err));
+  if (Err)
+    return std::move(Err);
+  return std::move(RTPC);
+#endif
+}
+
+Error LLVMJITLinkRemoteTargetProcessControl::disconnect() {
+  std::promise<MSVCPError> P;
+  auto F = P.get_future();
+  auto Err = closeConnection([&](Error Err) -> Error {
+    P.set_value(std::move(Err));
+    Finished = true;
+    return Error::success();
+  });
+  ListenerThread.join();
+  return joinErrors(std::move(Err), F.get());
+};
+
 class PhonyExternalsGenerator : public DefinitionGenerator {
 public:
   Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
@@ -574,13 +748,30 @@ class PhonyExternalsGenerator : public DefinitionGenerator {
 };
 
 Expected<std::unique_ptr<Session>> Session::Create(Triple TT) {
-  Error Err = Error::success();
 
   auto PageSize = sys::Process::getPageSize();
   if (!PageSize)
     return PageSize.takeError();
 
-  std::unique_ptr<Session> S(new Session(std::move(TT), *PageSize, Err));
+  /// If -oop-executor is passed then launch the executor.
+  std::unique_ptr<TargetProcessControl> TPC;
+  if (OutOfProcessExecutor.getNumOccurrences()) {
+    if (auto RTPC = LLVMJITLinkRemoteTargetProcessControl::LaunchExecutor())
+      TPC = std::move(*RTPC);
+    else
+      return RTPC.takeError();
+  } else if (OutOfProcessExecutorConnect.getNumOccurrences()) {
+    if (auto RTPC = LLVMJITLinkRemoteTargetProcessControl::ConnectToExecutor())
+      TPC = std::move(*RTPC);
+    else
+      return RTPC.takeError();
+  } else
+    TPC = std::make_unique<SelfTargetProcessControl>(
+        std::make_shared<SymbolStringPool>(), std::move(TT), *PageSize,
+        createMemoryManager());
+
+  Error Err = Error::success();
+  std::unique_ptr<Session> S(new Session(std::move(TPC), Err));
   if (Err)
     return std::move(Err);
   return std::move(S);
@@ -593,10 +784,8 @@ Session::~Session() {
 
 // FIXME: Move to createJITDylib if/when we start using Platform support in
 // llvm-jitlink.
-Session::Session(Triple TT, uint64_t PageSize, Error &Err)
-    : TPC(std::make_unique<SelfTargetProcessControl>(std::move(TT), PageSize,
-                                                     createMemoryManager())),
-      ObjLayer(*this, TPC->getMemMgr()) {
+Session::Session(std::unique_ptr<TargetProcessControl> TPC, Error &Err)
+    : TPC(std::move(TPC)), ObjLayer(*this, this->TPC->getMemMgr()) {
 
   /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
   /// Session.
@@ -630,9 +819,9 @@ Session::Session(Triple TT, uint64_t PageSize, Error &Err)
     return;
   }
 
-  if (!NoExec && !TT.isOSWindows())
+  if (!NoExec && !this->TPC->getTargetTriple().isOSWindows())
     ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
-        ES, std::make_unique<InProcessEHFrameRegistrar>()));
+        ES, ExitOnErr(TPCEHFrameRegistrar::Create(*this->TPC))));
 
   ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
 
@@ -785,22 +974,28 @@ Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) {
 } // end namespace llvm
 
 static Triple getFirstFileTriple() {
-  assert(!InputFiles.empty() && "InputFiles can not be empty");
-  auto ObjBuffer =
-      ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
-  auto Obj = ExitOnErr(
-      object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
-  return Obj->makeTriple();
+  static Triple FirstTT = []() {
+    assert(!InputFiles.empty() && "InputFiles can not be empty");
+    auto ObjBuffer =
+        ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
+    auto Obj = ExitOnErr(
+        object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
+    return Obj->makeTriple();
+  }();
+
+  return FirstTT;
 }
 
-static Error sanitizeArguments(const Session &S) {
+static Error sanitizeArguments(const Triple &TT, const char *ArgV0) {
+  // Set the entry point name if not specified.
   if (EntryPointName.empty()) {
-    if (S.TPC->getTargetTriple().getObjectFormat() == Triple::MachO)
+    if (TT.getObjectFormat() == Triple::MachO)
       EntryPointName = "_main";
     else
       EntryPointName = "main";
   }
 
+  // -noexec and --args should not be used together.
   if (NoExec && !InputArgv.empty())
     outs() << "Warning: --args passed to -noexec run will be ignored.\n";
 
@@ -812,14 +1007,35 @@ static Error sanitizeArguments(const Session &S) {
           inconvertibleErrorCode());
   }
 
+  // Only one of -oop-executor and -oop-executor-connect can be used.
+  if (!!OutOfProcessExecutor.getNumOccurrences() &&
+      !!OutOfProcessExecutorConnect.getNumOccurrences())
+    return make_error<StringError>(
+        "Only one of -" + OutOfProcessExecutor.ArgStr + " and -" +
+            OutOfProcessExecutorConnect.ArgStr + " can be specified",
+        inconvertibleErrorCode());
+
+  // If -oop-executor was used but no value was specified then use a sensible
+  // default.
+  if (!!OutOfProcessExecutor.getNumOccurrences() &&
+      OutOfProcessExecutor.empty()) {
+    SmallString<256> OOPExecutorPath(sys::fs::getMainExecutable(
+        ArgV0, reinterpret_cast<void *>(&sanitizeArguments)));
+    sys::path::remove_filename(OOPExecutorPath);
+    if (OOPExecutorPath.back() != '/')
+      OOPExecutorPath += '/';
+    OOPExecutorPath += "llvm-jitlink-executor";
+    OutOfProcessExecutor = OOPExecutorPath.str().str();
+  }
+
   return Error::success();
 }
 
 static Error loadProcessSymbols(Session &S) {
-  auto InternedEntryPointName = S.ES.intern(EntryPointName);
-  auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) {
-    return Name != InternedEntryPointName;
-  };
+  auto FilterMainEntryPoint =
+      [EPName = S.ES.intern(EntryPointName)](SymbolStringPtr Name) {
+        return Name != EPName;
+      };
   S.MainJD->addGenerator(
       ExitOnErr(orc::TPCDynamicLibrarySearchGenerator::GetForTargetProcess(
           *S.TPC, std::move(FilterMainEntryPoint))));
@@ -827,15 +1043,12 @@ static Error loadProcessSymbols(Session &S) {
   return Error::success();
 }
 
-static Error loadDylibs() {
-  // FIXME: This should all be handled inside DynamicLibrary.
+static Error loadDylibs(Session &S) {
   for (const auto &Dylib : Dylibs) {
-    if (!sys::fs::is_regular_file(Dylib))
-      return make_error<StringError>("\"" + Dylib + "\" is not a regular file",
-                                     inconvertibleErrorCode());
-    std::string ErrMsg;
-    if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
-      return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
+    auto G = orc::TPCDynamicLibrarySearchGenerator::Load(*S.TPC, Dylib.c_str());
+    if (!G)
+      return G.takeError();
+    S.MainJD->addGenerator(std::move(*G));
   }
 
   return Error::success();
@@ -1072,9 +1285,9 @@ int main(int argc, char *argv[]) {
   std::unique_ptr<JITLinkTimers> Timers =
       ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
 
-  auto S = ExitOnErr(Session::Create(getFirstFileTriple()));
+  ExitOnErr(sanitizeArguments(getFirstFileTriple(), argv[0]));
 
-  ExitOnErr(sanitizeArguments(*S));
+  auto S = ExitOnErr(Session::Create(getFirstFileTriple()));
 
   {
     TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
@@ -1083,7 +1296,7 @@ int main(int argc, char *argv[]) {
 
   if (!NoProcessSymbols)
     ExitOnErr(loadProcessSymbols(*S));
-  ExitOnErr(loadDylibs());
+  ExitOnErr(loadDylibs(*S));
 
   if (PhonyExternals)
     addPhonyExternalsGenerator(*S);
@@ -1110,11 +1323,12 @@ int main(int argc, char *argv[]) {
 
   int Result = 0;
   {
-    using MainTy = int (*)(int, char *[]);
-    auto EntryFn = jitTargetAddressToFunction<MainTy>(EntryPoint.getAddress());
     TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
-    Result = runAsMain(EntryFn, InputArgv, StringRef(InputFiles.front()));
+    Result = ExitOnErr(S->TPC->runAsMain(EntryPoint.getAddress(), InputArgv));
   }
 
+  ExitOnErr(S->ES.endSession());
+  ExitOnErr(S->TPC->disconnect());
+
   return Result;
 }

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink.h b/llvm/tools/llvm-jitlink/llvm-jitlink.h
index f0ede14050fd..5132eb204be1 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.h
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.h
@@ -18,6 +18,9 @@
 #include "llvm/ADT/Triple.h"
 #include "llvm/ExecutionEngine/Orc/Core.h"
 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h"
+#include "llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h"
+#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
 #include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
 #include "llvm/Support/Error.h"
@@ -45,9 +48,71 @@ class LLVMJITLinkObjectLinkingLayer : public orc::ObjectLinkingLayer {
   Session &S;
 };
 
+using LLVMJITLinkChannel = orc::rpc::FDRawByteChannel;
+using LLVMJITLinkRPCEndpoint =
+    orc::rpc::MultiThreadedRPCEndpoint<LLVMJITLinkChannel>;
+using LLVMJITLinkRemoteMemoryManager =
+    orc::OrcRPCTPCJITLinkMemoryManager<LLVMJITLinkRPCEndpoint>;
+using LLVMJITLinkRemoteMemoryAccess =
+    orc::OrcRPCTPCMemoryAccess<LLVMJITLinkRPCEndpoint>;
+
+class LLVMJITLinkRemoteTargetProcessControl
+    : public orc::OrcRPCTargetProcessControlBase<LLVMJITLinkRPCEndpoint> {
+public:
+  using BaseT = orc::OrcRPCTargetProcessControlBase<LLVMJITLinkRPCEndpoint>;
+  static Expected<std::unique_ptr<TargetProcessControl>> LaunchExecutor();
+
+  static Expected<std::unique_ptr<TargetProcessControl>> ConnectToExecutor();
+
+  Error disconnect() override;
+
+private:
+  using LLVMJITLinkRemoteMemoryAccess =
+      orc::OrcRPCTPCMemoryAccess<LLVMJITLinkRemoteTargetProcessControl>;
+
+  using LLVMJITLinkRemoteMemoryManager =
+      orc::OrcRPCTPCJITLinkMemoryManager<LLVMJITLinkRemoteTargetProcessControl>;
+
+  LLVMJITLinkRemoteTargetProcessControl(
+      std::shared_ptr<orc::SymbolStringPool> SSP,
+      std::unique_ptr<LLVMJITLinkChannel> Channel,
+      std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint,
+      ErrorReporter ReportError, Error &Err)
+      : BaseT(std::move(SSP), *Endpoint, std::move(ReportError)),
+        Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) {
+    ErrorAsOutParameter _(&Err);
+
+    ListenerThread = std::thread([&]() {
+      while (!Finished) {
+        if (auto Err = this->Endpoint->handleOne()) {
+          reportError(std::move(Err));
+          return;
+        }
+      }
+    });
+
+    if (auto Err2 = initializeORCRPCTPCBase()) {
+      Err = joinErrors(std::move(Err2), disconnect());
+      return;
+    }
+
+    OwnedMemAccess = std::make_unique<LLVMJITLinkRemoteMemoryAccess>(*this);
+    MemAccess = OwnedMemAccess.get();
+    OwnedMemMgr = std::make_unique<LLVMJITLinkRemoteMemoryManager>(*this);
+    MemMgr = OwnedMemMgr.get();
+  }
+
+  std::unique_ptr<LLVMJITLinkChannel> Channel;
+  std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint;
+  std::unique_ptr<TargetProcessControl::MemoryAccess> OwnedMemAccess;
+  std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
+  std::atomic<bool> Finished{false};
+  std::thread ListenerThread;
+};
+
 struct Session {
-  orc::ExecutionSession ES;
   std::unique_ptr<orc::TargetProcessControl> TPC;
+  orc::ExecutionSession ES;
   orc::JITDylib *MainJD;
   LLVMJITLinkObjectLinkingLayer ObjLayer;
   std::vector<orc::JITDylib *> JDSearchOrder;
@@ -93,7 +158,7 @@ struct Session {
   DenseMap<StringRef, StringRef> CanonicalWeakDefs;
 
 private:
-  Session(Triple TT, uint64_t PageSize, Error &Err);
+  Session(std::unique_ptr<orc::TargetProcessControl> TPC, Error &Err);
 };
 
 /// Record symbols, GOT entries, stubs, and sections for ELF file.

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
index 28eb128ac55d..58aacfc25bf3 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
@@ -2,6 +2,8 @@ set(LLVM_LINK_COMPONENTS
   ${LLVM_TARGETS_TO_BUILD}
   JITLink
   Object
+  OrcShared
+  OrcTargetProcess
   RuntimeDyld
   Support
   )

diff  --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
index b382e4c4d731..48d6888fad11 100644
--- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -3,8 +3,8 @@ set(LLVM_LINK_COMPONENTS
   Core
   ExecutionEngine
   Object
-  OrcError
   OrcJIT
+  OrcShared
   Passes
   RuntimeDyld
   Support


        


More information about the llvm-commits mailing list