hanchenye-llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

2024 lines
70 KiB
C++
Raw Normal View History

Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
//===- llvm-jitlink.cpp -- Command line interface/tester 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
//
//===----------------------------------------------------------------------===//
//
// This utility provides a simple command line interface to the llvm jitlink
// library, which makes relocatable object files executable in memory. Its
// primary function is as a testing utility for the jitlink library.
//
//===----------------------------------------------------------------------===//
#include "llvm-jitlink.h"
#include "llvm/BinaryFormat/Magic.h"
[Orc] Add JITLink debug support plugin for ELF x86-64 Add a new ObjectLinkingLayer plugin `DebugObjectManagerPlugin` and infrastructure to handle creation of `DebugObject`s as well as their registration in OrcTargetProcess. The current implementation only covers ELF on x86-64, but the infrastructure is not limited to that. The journey starts with a new `LinkGraph` / `JITLinkContext` pair being created for a `MaterializationResponsibility` in ORC's `ObjectLinkingLayer`. It sends a `notifyMaterializing()` notification, which is forwarded to all registered plugins. The `DebugObjectManagerPlugin` aims to create a `DebugObject` form the provided target triple and object buffer. (Future implementations might create `DebugObject`s from a `LinkGraph` in other ways.) On success it will track it as the pending `DebugObject` for the `MaterializationResponsibility`. This patch only implements the `ELFDebugObject` for `x86-64` targets. It follows the RuntimeDyld approach for debug object setup: it captures a copy of the input object, parses all section headers and prepares to patch their load-address fields with their final addresses in target memory. It instructs the plugin to report the section load-addresses once they are available. The plugin overrides `modifyPassConfig()` and installs a JITLink post-allocation pass to capture them. Once JITLink emitted the finalized executable, the plugin emits and registers the `DebugObject`. For emission it requests a new `JITLinkMemoryManager::Allocation` with a single read-only segment, copies the object with patched section load-addresses over to working memory and triggers finalization to target memory. For registration, it notifies the `DebugObjectRegistrar` provided in the constructor and stores the previously pending`DebugObject` as registered for the corresponding MaterializationResponsibility. The `DebugObjectRegistrar` registers the `DebugObject` with the target process. `llvm-jitlink` uses the `TPCDebugObjectRegistrar`, which calls `llvm_orc_registerJITLoaderGDBWrapper()` in the target process via `TargetProcessControl` to emit a `jit_code_entry` compatible with the GDB JIT interface [1]. So far the implementation only supports registration and no removal. It appears to me that it wouldn't raise any new design questions, so I left this as an addition for the near future. [1] https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D97335
2021-03-02 19:37:48 +08:00
#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
#include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
#include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h"
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
[Orc] Add JITLink debug support plugin for ELF x86-64 Add a new ObjectLinkingLayer plugin `DebugObjectManagerPlugin` and infrastructure to handle creation of `DebugObject`s as well as their registration in OrcTargetProcess. The current implementation only covers ELF on x86-64, but the infrastructure is not limited to that. The journey starts with a new `LinkGraph` / `JITLinkContext` pair being created for a `MaterializationResponsibility` in ORC's `ObjectLinkingLayer`. It sends a `notifyMaterializing()` notification, which is forwarded to all registered plugins. The `DebugObjectManagerPlugin` aims to create a `DebugObject` form the provided target triple and object buffer. (Future implementations might create `DebugObject`s from a `LinkGraph` in other ways.) On success it will track it as the pending `DebugObject` for the `MaterializationResponsibility`. This patch only implements the `ELFDebugObject` for `x86-64` targets. It follows the RuntimeDyld approach for debug object setup: it captures a copy of the input object, parses all section headers and prepares to patch their load-address fields with their final addresses in target memory. It instructs the plugin to report the section load-addresses once they are available. The plugin overrides `modifyPassConfig()` and installs a JITLink post-allocation pass to capture them. Once JITLink emitted the finalized executable, the plugin emits and registers the `DebugObject`. For emission it requests a new `JITLinkMemoryManager::Allocation` with a single read-only segment, copies the object with patched section load-addresses over to working memory and triggers finalization to target memory. For registration, it notifies the `DebugObjectRegistrar` provided in the constructor and stores the previously pending`DebugObject` as registered for the corresponding MaterializationResponsibility. The `DebugObjectRegistrar` registers the `DebugObject` with the target process. `llvm-jitlink` uses the `TPCDebugObjectRegistrar`, which calls `llvm_orc_registerJITLoaderGDBWrapper()` in the target process via `TargetProcessControl` to emit a `jit_code_entry` compatible with the GDB JIT interface [1]. So far the implementation only supports registration and no removal. It appears to me that it wouldn't raise any new design questions, so I left this as an addition for the near future. [1] https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D97335
2021-03-02 19:37:48 +08:00
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrAnalysis.h"
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/TargetRegistry.h"
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
#include "llvm/Object/COFF.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
#include <cstring>
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
#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"
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
using namespace llvm;
using namespace llvm::jitlink;
using namespace llvm::orc;
static cl::OptionCategory JITLinkCategory("JITLink Options");
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
cl::desc("input files"),
cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::list<std::string>
LibrarySearchPaths("L",
cl::desc("Add dir to the list of library search paths"),
cl::Prefix, cl::cat(JITLinkCategory));
static cl::list<std::string>
Libraries("l",
cl::desc("Link against library X in the library search paths"),
cl::Prefix, cl::cat(JITLinkCategory));
static cl::list<std::string>
LibrariesHidden("hidden-l",
cl::desc("Link against library X in the library search "
"paths with hidden visibility"),
cl::Prefix, cl::cat(JITLinkCategory));
static cl::list<std::string>
LoadHidden("load_hidden",
cl::desc("Link against library X with hidden visibility"),
cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
cl::init(false), cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::list<std::string>
CheckFiles("check", cl::desc("File containing verifier checks"),
cl::ZeroOrMore, cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
[ORC][JITLink] Add support for weak references, and improve handling of static libraries. This patch substantially updates ORCv2's lookup API in order to support weak references, and to better support static archives. Key changes: -- Each symbol being looked for is now associated with a SymbolLookupFlags value. If the associated value is SymbolLookupFlags::RequiredSymbol then the symbol must be defined in one of the JITDylibs being searched (or be able to be generated in one of these JITDylibs via an attached definition generator) or the lookup will fail with an error. If the associated value is SymbolLookupFlags::WeaklyReferencedSymbol then the symbol is permitted to be undefined, in which case it will simply not appear in the resulting SymbolMap if the rest of the lookup succeeds. Since lookup now requires these flags for each symbol, the lookup method now takes an instance of a new SymbolLookupSet type rather than a SymbolNameSet. SymbolLookupSet is a vector-backed set of (name, flags) pairs. Clients are responsible for ensuring that the set property (i.e. unique elements) holds, though this is usually simple and SymbolLookupSet provides convenience methods to support this. -- Lookups now have an associated LookupKind value, which is either LookupKind::Static or LookupKind::DLSym. Definition generators can inspect the lookup kind when determining whether or not to generate new definitions. The StaticLibraryDefinitionGenerator is updated to only pull in new objects from the archive if the lookup kind is Static. This allows lookup to be re-used to emulate dlsym for JIT'd symbols without pulling in new objects from archives (which would not happen in a normal dlsym call). -- JITLink is updated to allow externals to be assigned weak linkage, and weak externals now use the SymbolLookupFlags::WeaklyReferencedSymbol value for lookups. Unresolved weak references will be assigned the default value of zero. Since this patch was modifying the lookup API anyway, it alo replaces all of the "MatchNonExported" boolean arguments with a "JITDylibLookupFlags" enum for readability. If a JITDylib's associated value is JITDylibLookupFlags::MatchExportedSymbolsOnly then the lookup will only match against exported (non-hidden) symbols in that JITDylib. If a JITDylib's associated value is JITDylibLookupFlags::MatchAllSymbols then the lookup will match against any symbol defined in the JITDylib.
2019-11-26 13:57:27 +08:00
static cl::opt<std::string>
CheckName("check-name", cl::desc("Name of checks to match against"),
cl::init("jitlink-check"), cl::cat(JITLinkCategory));
[ORC][JITLink] Add support for weak references, and improve handling of static libraries. This patch substantially updates ORCv2's lookup API in order to support weak references, and to better support static archives. Key changes: -- Each symbol being looked for is now associated with a SymbolLookupFlags value. If the associated value is SymbolLookupFlags::RequiredSymbol then the symbol must be defined in one of the JITDylibs being searched (or be able to be generated in one of these JITDylibs via an attached definition generator) or the lookup will fail with an error. If the associated value is SymbolLookupFlags::WeaklyReferencedSymbol then the symbol is permitted to be undefined, in which case it will simply not appear in the resulting SymbolMap if the rest of the lookup succeeds. Since lookup now requires these flags for each symbol, the lookup method now takes an instance of a new SymbolLookupSet type rather than a SymbolNameSet. SymbolLookupSet is a vector-backed set of (name, flags) pairs. Clients are responsible for ensuring that the set property (i.e. unique elements) holds, though this is usually simple and SymbolLookupSet provides convenience methods to support this. -- Lookups now have an associated LookupKind value, which is either LookupKind::Static or LookupKind::DLSym. Definition generators can inspect the lookup kind when determining whether or not to generate new definitions. The StaticLibraryDefinitionGenerator is updated to only pull in new objects from the archive if the lookup kind is Static. This allows lookup to be re-used to emulate dlsym for JIT'd symbols without pulling in new objects from archives (which would not happen in a normal dlsym call). -- JITLink is updated to allow externals to be assigned weak linkage, and weak externals now use the SymbolLookupFlags::WeaklyReferencedSymbol value for lookups. Unresolved weak references will be assigned the default value of zero. Since this patch was modifying the lookup API anyway, it alo replaces all of the "MatchNonExported" boolean arguments with a "JITDylibLookupFlags" enum for readability. If a JITDylib's associated value is JITDylibLookupFlags::MatchExportedSymbolsOnly then the lookup will only match against exported (non-hidden) symbols in that JITDylib. If a JITDylib's associated value is JITDylibLookupFlags::MatchAllSymbols then the lookup will match against any symbol defined in the JITDylib.
2019-11-26 13:57:27 +08:00
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::opt<std::string>
EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
cl::init(""), cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::list<std::string> JITDylibs(
"jd",
cl::desc("Specifies the JITDylib to be used for any subsequent "
"input file, -L<seacrh-path>, and -l<library> arguments"),
cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::list<std::string>
Dylibs("preload",
cl::desc("Pre-load dynamic libraries (e.g. language runtimes "
"required by the ORC runtime)"),
cl::ZeroOrMore, cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::list<std::string> InputArgv("args", cl::Positional,
cl::desc("<program arguments>..."),
cl::ZeroOrMore, cl::PositionalEatsArgs,
cl::cat(JITLinkCategory));
static cl::opt<bool>
DebuggerSupport("debugger-support",
cl::desc("Enable debugger suppport (default = !-noexec)"),
cl::init(true), cl::Hidden, cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::opt<bool>
NoProcessSymbols("no-process-syms",
cl::desc("Do not resolve to llvm-jitlink process symbols"),
cl::init(false), cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::list<std::string> AbsoluteDefs(
"abs",
cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
cl::ZeroOrMore, cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::list<std::string>
Aliases("alias", cl::desc("Inject symbol aliases (syntax: <name>=<addr>)"),
cl::ZeroOrMore, cl::cat(JITLinkCategory));
static cl::list<std::string> TestHarnesses("harness", cl::Positional,
cl::desc("Test harness files"),
cl::ZeroOrMore,
cl::PositionalEatsArgs,
cl::cat(JITLinkCategory));
static cl::opt<bool> ShowInitialExecutionSessionState(
"show-init-es",
cl::desc("Print ExecutionSession state before resolving entry point"),
cl::init(false), cl::cat(JITLinkCategory));
static cl::opt<bool> ShowEntryExecutionSessionState(
"show-entry-es",
cl::desc("Print ExecutionSession state after resolving entry point"),
cl::init(false), cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::opt<bool> ShowAddrs(
"show-addrs",
cl::desc("Print registered symbol, section, got and stub addresses"),
cl::init(false), cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::opt<bool> ShowLinkGraph(
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
"show-graph",
cl::desc("Print the link graph after fixups have been applied"),
cl::init(false), cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::opt<bool> ShowSizes(
"show-sizes",
cl::desc("Show sizes pre- and post-dead stripping, and allocations"),
cl::init(false), cl::cat(JITLinkCategory));
static cl::opt<bool> ShowTimes("show-times",
cl::desc("Show times for llvm-jitlink phases"),
cl::init(false), cl::cat(JITLinkCategory));
static cl::opt<std::string> SlabAllocateSizeString(
"slab-allocate",
cl::desc("Allocate from a slab of the given size "
"(allowable suffixes: Kb, Mb, Gb. default = "
"Kb)"),
cl::init(""), cl::cat(JITLinkCategory));
static cl::opt<uint64_t> SlabAddress(
"slab-address",
cl::desc("Set slab target address (requires -slab-allocate and -noexec)"),
cl::init(~0ULL), cl::cat(JITLinkCategory));
static cl::opt<uint64_t> SlabPageSize(
"slab-page-size",
cl::desc("Set page size for slab (requires -slab-allocate and -noexec)"),
cl::init(0), cl::cat(JITLinkCategory));
static cl::opt<bool> ShowRelocatedSectionContents(
"show-relocated-section-contents",
cl::desc("show section contents after fixups have been applied"),
cl::init(false), cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static cl::opt<bool> PhonyExternals(
"phony-externals",
cl::desc("resolve all otherwise unresolved externals to null"),
cl::init(false), cl::cat(JITLinkCategory));
static cl::opt<std::string> OutOfProcessExecutor(
"oop-executor", cl::desc("Launch an out-of-process executor to run code"),
cl::ValueOptional, cl::cat(JITLinkCategory));
static cl::opt<std::string> OutOfProcessExecutorConnect(
"oop-executor-connect",
cl::desc("Connect to an out-of-process executor via TCP"),
cl::cat(JITLinkCategory));
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
static cl::opt<std::string>
OrcRuntime("orc-runtime", cl::desc("Use ORC runtime from given path"),
cl::init(""), cl::cat(JITLinkCategory));
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
static cl::opt<bool> AddSelfRelocations(
"add-self-relocations",
cl::desc("Add relocations to function pointers to the current function"),
cl::init(false), cl::cat(JITLinkCategory));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
ExitOnError ExitOnErr;
[Orc] Add JITLink debug support plugin for ELF x86-64 Add a new ObjectLinkingLayer plugin `DebugObjectManagerPlugin` and infrastructure to handle creation of `DebugObject`s as well as their registration in OrcTargetProcess. The current implementation only covers ELF on x86-64, but the infrastructure is not limited to that. The journey starts with a new `LinkGraph` / `JITLinkContext` pair being created for a `MaterializationResponsibility` in ORC's `ObjectLinkingLayer`. It sends a `notifyMaterializing()` notification, which is forwarded to all registered plugins. The `DebugObjectManagerPlugin` aims to create a `DebugObject` form the provided target triple and object buffer. (Future implementations might create `DebugObject`s from a `LinkGraph` in other ways.) On success it will track it as the pending `DebugObject` for the `MaterializationResponsibility`. This patch only implements the `ELFDebugObject` for `x86-64` targets. It follows the RuntimeDyld approach for debug object setup: it captures a copy of the input object, parses all section headers and prepares to patch their load-address fields with their final addresses in target memory. It instructs the plugin to report the section load-addresses once they are available. The plugin overrides `modifyPassConfig()` and installs a JITLink post-allocation pass to capture them. Once JITLink emitted the finalized executable, the plugin emits and registers the `DebugObject`. For emission it requests a new `JITLinkMemoryManager::Allocation` with a single read-only segment, copies the object with patched section load-addresses over to working memory and triggers finalization to target memory. For registration, it notifies the `DebugObjectRegistrar` provided in the constructor and stores the previously pending`DebugObject` as registered for the corresponding MaterializationResponsibility. The `DebugObjectRegistrar` registers the `DebugObject` with the target process. `llvm-jitlink` uses the `TPCDebugObjectRegistrar`, which calls `llvm_orc_registerJITLoaderGDBWrapper()` in the target process via `TargetProcessControl` to emit a `jit_code_entry` compatible with the GDB JIT interface [1]. So far the implementation only supports registration and no removal. It appears to me that it wouldn't raise any new design questions, so I left this as an addition for the near future. [1] https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D97335
2021-03-02 19:37:48 +08:00
LLVM_ATTRIBUTE_USED void linkComponents() {
errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
<< (void *)&llvm_orc_deregisterEHFrameSectionWrapper
<< (void *)&llvm_orc_registerJITLoaderGDBWrapper;
}
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
static bool UseTestResultOverride = false;
static int64_t TestResultOverride = 0;
extern "C" LLVM_ATTRIBUTE_USED void
llvm_jitlink_setTestResultOverride(int64_t Value) {
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
TestResultOverride = Value;
UseTestResultOverride = true;
}
static Error addSelfRelocations(LinkGraph &G);
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
namespace llvm {
static raw_ostream &
operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) {
return OS << "target addr = "
<< format("0x%016" PRIx64, MRI.getTargetAddress())
<< ", content: " << (const void *)MRI.getContent().data() << " -- "
<< (const void *)(MRI.getContent().data() + MRI.getContent().size())
<< " (" << MRI.getContent().size() << " bytes)";
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
}
static raw_ostream &
operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) {
OS << "Symbols:\n";
for (auto &SKV : SIM)
OS << " \"" << SKV.first() << "\" " << SKV.second << "\n";
return OS;
}
static raw_ostream &
operator<<(raw_ostream &OS, const Session::FileInfo &FI) {
for (auto &SIKV : FI.SectionInfos)
OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n";
for (auto &GOTKV : FI.GOTEntryInfos)
OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n";
for (auto &StubKV : FI.StubInfos)
OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n";
return OS;
}
static raw_ostream &
operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) {
for (auto &FIKV : FIM)
OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second;
return OS;
}
static Error applyHarnessPromotions(Session &S, LinkGraph &G) {
// If this graph is part of the test harness there's nothing to do.
if (S.HarnessFiles.empty() || S.HarnessFiles.count(G.getName()))
return Error::success();
2021-12-15 13:58:43 +08:00
LLVM_DEBUG(dbgs() << "Applying promotions to graph " << G.getName() << "\n");
// If this graph is part of the test then promote any symbols referenced by
// the harness to default scope, remove all symbols that clash with harness
// definitions.
std::vector<Symbol *> DefinitionsToRemove;
for (auto *Sym : G.defined_symbols()) {
if (!Sym->hasName())
continue;
if (Sym->getLinkage() == Linkage::Weak) {
if (!S.CanonicalWeakDefs.count(Sym->getName()) ||
S.CanonicalWeakDefs[Sym->getName()] != G.getName()) {
LLVM_DEBUG({
dbgs() << " Externalizing weak symbol " << Sym->getName() << "\n";
});
DefinitionsToRemove.push_back(Sym);
} else {
LLVM_DEBUG({
dbgs() << " Making weak symbol " << Sym->getName() << " strong\n";
});
if (S.HarnessExternals.count(Sym->getName()))
Sym->setScope(Scope::Default);
else
Sym->setScope(Scope::Hidden);
Sym->setLinkage(Linkage::Strong);
}
} else if (S.HarnessExternals.count(Sym->getName())) {
LLVM_DEBUG(dbgs() << " Promoting " << Sym->getName() << "\n");
Sym->setScope(Scope::Default);
Sym->setLive(true);
continue;
} else if (S.HarnessDefinitions.count(Sym->getName())) {
LLVM_DEBUG(dbgs() << " Externalizing " << Sym->getName() << "\n");
DefinitionsToRemove.push_back(Sym);
}
}
for (auto *Sym : DefinitionsToRemove)
G.makeExternal(*Sym);
return Error::success();
}
static uint64_t computeTotalBlockSizes(LinkGraph &G) {
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
uint64_t TotalSize = 0;
for (auto *B : G.blocks())
TotalSize += B->getSize();
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
return TotalSize;
}
static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) {
constexpr orc::ExecutorAddrDiff DumpWidth = 16;
static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two");
// Put sections in address order.
std::vector<Section *> Sections;
for (auto &S : G.sections())
Sections.push_back(&S);
2021-01-18 02:39:45 +08:00
llvm::sort(Sections, [](const Section *LHS, const Section *RHS) {
if (llvm::empty(LHS->symbols()) && llvm::empty(RHS->symbols()))
return false;
if (llvm::empty(LHS->symbols()))
return false;
if (llvm::empty(RHS->symbols()))
return true;
SectionRange LHSRange(*LHS);
SectionRange RHSRange(*RHS);
return LHSRange.getStart() < RHSRange.getStart();
});
for (auto *S : Sections) {
OS << S->getName() << " content:";
if (llvm::empty(S->symbols())) {
OS << "\n section empty\n";
continue;
}
// Sort symbols into order, then render.
std::vector<Symbol *> Syms(S->symbols().begin(), S->symbols().end());
llvm::sort(Syms, [](const Symbol *LHS, const Symbol *RHS) {
return LHS->getAddress() < RHS->getAddress();
});
orc::ExecutorAddr NextAddr(Syms.front()->getAddress().getValue() &
~(DumpWidth - 1));
for (auto *Sym : Syms) {
bool IsZeroFill = Sym->getBlock().isZeroFill();
auto SymStart = Sym->getAddress();
auto SymSize = Sym->getSize();
auto SymEnd = SymStart + SymSize;
const uint8_t *SymData = IsZeroFill ? nullptr
: reinterpret_cast<const uint8_t *>(
Sym->getSymbolContent().data());
// Pad any space before the symbol starts.
while (NextAddr != SymStart) {
if (NextAddr % DumpWidth == 0)
OS << formatv("\n{0:x16}:", NextAddr);
OS << " ";
++NextAddr;
}
// Render the symbol content.
while (NextAddr != SymEnd) {
if (NextAddr % DumpWidth == 0)
OS << formatv("\n{0:x16}:", NextAddr);
if (IsZeroFill)
OS << " 00";
else
OS << formatv(" {0:x-2}", SymData[NextAddr - SymStart]);
++NextAddr;
}
}
OS << "\n";
}
}
class JITLinkSlabAllocator final : public JITLinkMemoryManager {
private:
struct FinalizedAllocInfo {
FinalizedAllocInfo(sys::MemoryBlock Mem,
std::vector<shared::WrapperFunctionCall> DeallocActions)
: Mem(Mem), DeallocActions(std::move(DeallocActions)) {}
sys::MemoryBlock Mem;
std::vector<shared::WrapperFunctionCall> DeallocActions;
};
public:
static Expected<std::unique_ptr<JITLinkSlabAllocator>>
Create(uint64_t SlabSize) {
Error Err = Error::success();
std::unique_ptr<JITLinkSlabAllocator> Allocator(
new JITLinkSlabAllocator(SlabSize, Err));
if (Err)
return std::move(Err);
return std::move(Allocator);
}
void allocate(const JITLinkDylib *JD, LinkGraph &G,
OnAllocatedFunction OnAllocated) override {
// Local class for allocation.
class IPMMAlloc : public InFlightAlloc {
public:
IPMMAlloc(JITLinkSlabAllocator &Parent, BasicLayout BL,
sys::MemoryBlock StandardSegs, sys::MemoryBlock FinalizeSegs)
: Parent(Parent), BL(std::move(BL)),
StandardSegs(std::move(StandardSegs)),
FinalizeSegs(std::move(FinalizeSegs)) {}
void finalize(OnFinalizedFunction OnFinalized) override {
if (auto Err = applyProtections()) {
OnFinalized(std::move(Err));
return;
}
auto DeallocActions = runFinalizeActions(BL.graphAllocActions());
if (!DeallocActions) {
OnFinalized(DeallocActions.takeError());
return;
}
if (auto Err = Parent.freeBlock(FinalizeSegs)) {
OnFinalized(
joinErrors(std::move(Err), runDeallocActions(*DeallocActions)));
return;
}
OnFinalized(FinalizedAlloc(ExecutorAddr::fromPtr(
new FinalizedAllocInfo(StandardSegs, std::move(*DeallocActions)))));
}
void abandon(OnAbandonedFunction OnAbandoned) override {
OnAbandoned(joinErrors(Parent.freeBlock(StandardSegs),
Parent.freeBlock(FinalizeSegs)));
}
private:
Error applyProtections() {
for (auto &KV : BL.segments()) {
const auto &Group = KV.first;
auto &Seg = KV.second;
auto Prot = toSysMemoryProtectionFlags(Group.getMemProt());
uint64_t SegSize =
alignTo(Seg.ContentSize + Seg.ZeroFillSize, Parent.PageSize);
sys::MemoryBlock MB(Seg.WorkingMem, SegSize);
if (auto EC = sys::Memory::protectMappedMemory(MB, Prot))
return errorCodeToError(EC);
if (Prot & sys::Memory::MF_EXEC)
sys::Memory::InvalidateInstructionCache(MB.base(),
MB.allocatedSize());
}
return Error::success();
}
JITLinkSlabAllocator &Parent;
BasicLayout BL;
sys::MemoryBlock StandardSegs;
sys::MemoryBlock FinalizeSegs;
};
BasicLayout BL(G);
auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(PageSize);
if (!SegsSizes) {
OnAllocated(SegsSizes.takeError());
return;
}
char *AllocBase = nullptr;
{
std::lock_guard<std::mutex> Lock(SlabMutex);
if (SegsSizes->total() > SlabRemaining.allocatedSize()) {
OnAllocated(make_error<StringError>(
"Slab allocator out of memory: request for " +
formatv("{0:x}", SegsSizes->total()) +
" bytes exceeds remaining capacity of " +
formatv("{0:x}", SlabRemaining.allocatedSize()) + " bytes",
inconvertibleErrorCode()));
return;
}
AllocBase = reinterpret_cast<char *>(SlabRemaining.base());
SlabRemaining =
sys::MemoryBlock(AllocBase + SegsSizes->total(),
SlabRemaining.allocatedSize() - SegsSizes->total());
}
sys::MemoryBlock StandardSegs(AllocBase, SegsSizes->StandardSegs);
sys::MemoryBlock FinalizeSegs(AllocBase + SegsSizes->StandardSegs,
SegsSizes->FinalizeSegs);
auto NextStandardSegAddr = ExecutorAddr::fromPtr(StandardSegs.base());
auto NextFinalizeSegAddr = ExecutorAddr::fromPtr(FinalizeSegs.base());
LLVM_DEBUG({
dbgs() << "JITLinkSlabAllocator allocated:\n";
if (SegsSizes->StandardSegs)
dbgs() << formatv(" [ {0:x16} -- {1:x16} ]", NextStandardSegAddr,
NextStandardSegAddr + StandardSegs.allocatedSize())
<< " to stardard segs\n";
else
dbgs() << " no standard segs\n";
if (SegsSizes->FinalizeSegs)
dbgs() << formatv(" [ {0:x16} -- {1:x16} ]", NextFinalizeSegAddr,
NextFinalizeSegAddr + FinalizeSegs.allocatedSize())
<< " to finalize segs\n";
else
dbgs() << " no finalize segs\n";
});
[JITLink][ORC] Major JITLinkMemoryManager refactor. This commit substantially refactors the JITLinkMemoryManager API to: (1) add asynchronous versions of key operations, (2) give memory manager implementations full control over link graph address layout, (3) enable more efficient tracking of allocated memory, and (4) support "allocation actions" and finalize-lifetime memory. Together these changes provide a more usable API, and enable more powerful and efficient memory manager implementations. To support these changes the JITLinkMemoryManager::Allocation inner class has been split into two new classes: InFlightAllocation, and FinalizedAllocation. The allocate method returns an InFlightAllocation that tracks memory (both working and executor memory) prior to finalization. The finalize method returns a FinalizedAllocation object, and the InFlightAllocation is discarded. Breaking Allocation into InFlightAllocation and FinalizedAllocation allows InFlightAllocation subclassses to be written more naturally, and FinalizedAlloc to be implemented and used efficiently (see (3) below). In addition to the memory manager changes this commit also introduces a new MemProt type to represent memory protections (MemProt replaces use of sys::Memory::ProtectionFlags in JITLink), and a new MemDeallocPolicy type that can be used to indicate when a section should be deallocated (see (4) below). Plugin/pass writers who were using sys::Memory::ProtectionFlags will have to switch to MemProt -- this should be straightworward. Clients with out-of-tree memory managers will need to update their implementations. Clients using in-tree memory managers should mostly be able to ignore it. Major features: (1) More asynchrony: The allocate and deallocate methods are now asynchronous by default, with synchronous convenience wrappers supplied. The asynchronous versions allow clients (including JITLink) to request and deallocate memory without blocking. (2) Improved control over graph address layout: Instead of a SegmentRequestMap, JITLinkMemoryManager::allocate now takes a reference to the LinkGraph to be allocated. The memory manager is responsible for calculating the memory requirements for the graph, and laying out the graph (setting working and executor memory addresses) within the allocated memory. This gives memory managers full control over JIT'd memory layout. For clients that don't need or want this degree of control the new "BasicLayout" utility can be used to get a segment-based view of the graph, similar to the one provided by SegmentRequestMap. Once segment addresses are assigned the BasicLayout::apply method can be used to automatically lay out the graph. (3) Efficient tracking of allocated memory. The FinalizedAlloc type is a wrapper for an ExecutorAddr and requires only 64-bits to store in the controller. The meaning of the address held by the FinalizedAlloc is left up to the memory manager implementation, but the FinalizedAlloc type enforces a requirement that deallocate be called on any non-default values prior to destruction. The deallocate method takes a vector<FinalizedAlloc>, allowing for bulk deallocation of many allocations in a single call. Memory manager implementations will typically store the address of some allocation metadata in the executor in the FinalizedAlloc, as holding this metadata in the executor is often cheaper and may allow for clean deallocation even in failure cases where the connection with the controller is lost. (4) Support for "allocation actions" and finalize-lifetime memory. Allocation actions are pairs (finalize_act, deallocate_act) of JITTargetAddress triples (fn, arg_buffer_addr, arg_buffer_size), that can be attached to a finalize request. At finalization time, after memory protections have been applied, each of the "finalize_act" elements will be called in order (skipping any elements whose fn value is zero) as ((char*(*)(const char *, size_t))fn)((const char *)arg_buffer_addr, (size_t)arg_buffer_size); At deallocation time the deallocate elements will be run in reverse order (again skipping any elements where fn is zero). The returned char * should be null to indicate success, or a non-null heap-allocated string error message to indicate failure. These actions allow finalization and deallocation to be extended to include operations like registering and deregistering eh-frames, TLS sections, initializer and deinitializers, and language metadata sections. Previously these operations required separate callWrapper invocations. Compared to callWrapper invocations, actions require no extra IPC/RPC, reducing costs and eliminating a potential source of errors. Finalize lifetime memory can be used to support finalize actions: Sections with finalize lifetime should be destroyed by memory managers immediately after finalization actions have been run. Finalize memory can be used to support finalize actions (e.g. with extra-metadata, or synthesized finalize actions) without incurring permanent memory overhead.
2021-10-11 08:39:24 +08:00
for (auto &KV : BL.segments()) {
auto &Group = KV.first;
auto &Seg = KV.second;
[JITLink][ORC] Major JITLinkMemoryManager refactor. This commit substantially refactors the JITLinkMemoryManager API to: (1) add asynchronous versions of key operations, (2) give memory manager implementations full control over link graph address layout, (3) enable more efficient tracking of allocated memory, and (4) support "allocation actions" and finalize-lifetime memory. Together these changes provide a more usable API, and enable more powerful and efficient memory manager implementations. To support these changes the JITLinkMemoryManager::Allocation inner class has been split into two new classes: InFlightAllocation, and FinalizedAllocation. The allocate method returns an InFlightAllocation that tracks memory (both working and executor memory) prior to finalization. The finalize method returns a FinalizedAllocation object, and the InFlightAllocation is discarded. Breaking Allocation into InFlightAllocation and FinalizedAllocation allows InFlightAllocation subclassses to be written more naturally, and FinalizedAlloc to be implemented and used efficiently (see (3) below). In addition to the memory manager changes this commit also introduces a new MemProt type to represent memory protections (MemProt replaces use of sys::Memory::ProtectionFlags in JITLink), and a new MemDeallocPolicy type that can be used to indicate when a section should be deallocated (see (4) below). Plugin/pass writers who were using sys::Memory::ProtectionFlags will have to switch to MemProt -- this should be straightworward. Clients with out-of-tree memory managers will need to update their implementations. Clients using in-tree memory managers should mostly be able to ignore it. Major features: (1) More asynchrony: The allocate and deallocate methods are now asynchronous by default, with synchronous convenience wrappers supplied. The asynchronous versions allow clients (including JITLink) to request and deallocate memory without blocking. (2) Improved control over graph address layout: Instead of a SegmentRequestMap, JITLinkMemoryManager::allocate now takes a reference to the LinkGraph to be allocated. The memory manager is responsible for calculating the memory requirements for the graph, and laying out the graph (setting working and executor memory addresses) within the allocated memory. This gives memory managers full control over JIT'd memory layout. For clients that don't need or want this degree of control the new "BasicLayout" utility can be used to get a segment-based view of the graph, similar to the one provided by SegmentRequestMap. Once segment addresses are assigned the BasicLayout::apply method can be used to automatically lay out the graph. (3) Efficient tracking of allocated memory. The FinalizedAlloc type is a wrapper for an ExecutorAddr and requires only 64-bits to store in the controller. The meaning of the address held by the FinalizedAlloc is left up to the memory manager implementation, but the FinalizedAlloc type enforces a requirement that deallocate be called on any non-default values prior to destruction. The deallocate method takes a vector<FinalizedAlloc>, allowing for bulk deallocation of many allocations in a single call. Memory manager implementations will typically store the address of some allocation metadata in the executor in the FinalizedAlloc, as holding this metadata in the executor is often cheaper and may allow for clean deallocation even in failure cases where the connection with the controller is lost. (4) Support for "allocation actions" and finalize-lifetime memory. Allocation actions are pairs (finalize_act, deallocate_act) of JITTargetAddress triples (fn, arg_buffer_addr, arg_buffer_size), that can be attached to a finalize request. At finalization time, after memory protections have been applied, each of the "finalize_act" elements will be called in order (skipping any elements whose fn value is zero) as ((char*(*)(const char *, size_t))fn)((const char *)arg_buffer_addr, (size_t)arg_buffer_size); At deallocation time the deallocate elements will be run in reverse order (again skipping any elements where fn is zero). The returned char * should be null to indicate success, or a non-null heap-allocated string error message to indicate failure. These actions allow finalization and deallocation to be extended to include operations like registering and deregistering eh-frames, TLS sections, initializer and deinitializers, and language metadata sections. Previously these operations required separate callWrapper invocations. Compared to callWrapper invocations, actions require no extra IPC/RPC, reducing costs and eliminating a potential source of errors. Finalize lifetime memory can be used to support finalize actions: Sections with finalize lifetime should be destroyed by memory managers immediately after finalization actions have been run. Finalize memory can be used to support finalize actions (e.g. with extra-metadata, or synthesized finalize actions) without incurring permanent memory overhead.
2021-10-11 08:39:24 +08:00
auto &SegAddr =
(Group.getMemDeallocPolicy() == MemDeallocPolicy::Standard)
? NextStandardSegAddr
: NextFinalizeSegAddr;
[JITLink][ORC] Major JITLinkMemoryManager refactor. This commit substantially refactors the JITLinkMemoryManager API to: (1) add asynchronous versions of key operations, (2) give memory manager implementations full control over link graph address layout, (3) enable more efficient tracking of allocated memory, and (4) support "allocation actions" and finalize-lifetime memory. Together these changes provide a more usable API, and enable more powerful and efficient memory manager implementations. To support these changes the JITLinkMemoryManager::Allocation inner class has been split into two new classes: InFlightAllocation, and FinalizedAllocation. The allocate method returns an InFlightAllocation that tracks memory (both working and executor memory) prior to finalization. The finalize method returns a FinalizedAllocation object, and the InFlightAllocation is discarded. Breaking Allocation into InFlightAllocation and FinalizedAllocation allows InFlightAllocation subclassses to be written more naturally, and FinalizedAlloc to be implemented and used efficiently (see (3) below). In addition to the memory manager changes this commit also introduces a new MemProt type to represent memory protections (MemProt replaces use of sys::Memory::ProtectionFlags in JITLink), and a new MemDeallocPolicy type that can be used to indicate when a section should be deallocated (see (4) below). Plugin/pass writers who were using sys::Memory::ProtectionFlags will have to switch to MemProt -- this should be straightworward. Clients with out-of-tree memory managers will need to update their implementations. Clients using in-tree memory managers should mostly be able to ignore it. Major features: (1) More asynchrony: The allocate and deallocate methods are now asynchronous by default, with synchronous convenience wrappers supplied. The asynchronous versions allow clients (including JITLink) to request and deallocate memory without blocking. (2) Improved control over graph address layout: Instead of a SegmentRequestMap, JITLinkMemoryManager::allocate now takes a reference to the LinkGraph to be allocated. The memory manager is responsible for calculating the memory requirements for the graph, and laying out the graph (setting working and executor memory addresses) within the allocated memory. This gives memory managers full control over JIT'd memory layout. For clients that don't need or want this degree of control the new "BasicLayout" utility can be used to get a segment-based view of the graph, similar to the one provided by SegmentRequestMap. Once segment addresses are assigned the BasicLayout::apply method can be used to automatically lay out the graph. (3) Efficient tracking of allocated memory. The FinalizedAlloc type is a wrapper for an ExecutorAddr and requires only 64-bits to store in the controller. The meaning of the address held by the FinalizedAlloc is left up to the memory manager implementation, but the FinalizedAlloc type enforces a requirement that deallocate be called on any non-default values prior to destruction. The deallocate method takes a vector<FinalizedAlloc>, allowing for bulk deallocation of many allocations in a single call. Memory manager implementations will typically store the address of some allocation metadata in the executor in the FinalizedAlloc, as holding this metadata in the executor is often cheaper and may allow for clean deallocation even in failure cases where the connection with the controller is lost. (4) Support for "allocation actions" and finalize-lifetime memory. Allocation actions are pairs (finalize_act, deallocate_act) of JITTargetAddress triples (fn, arg_buffer_addr, arg_buffer_size), that can be attached to a finalize request. At finalization time, after memory protections have been applied, each of the "finalize_act" elements will be called in order (skipping any elements whose fn value is zero) as ((char*(*)(const char *, size_t))fn)((const char *)arg_buffer_addr, (size_t)arg_buffer_size); At deallocation time the deallocate elements will be run in reverse order (again skipping any elements where fn is zero). The returned char * should be null to indicate success, or a non-null heap-allocated string error message to indicate failure. These actions allow finalization and deallocation to be extended to include operations like registering and deregistering eh-frames, TLS sections, initializer and deinitializers, and language metadata sections. Previously these operations required separate callWrapper invocations. Compared to callWrapper invocations, actions require no extra IPC/RPC, reducing costs and eliminating a potential source of errors. Finalize lifetime memory can be used to support finalize actions: Sections with finalize lifetime should be destroyed by memory managers immediately after finalization actions have been run. Finalize memory can be used to support finalize actions (e.g. with extra-metadata, or synthesized finalize actions) without incurring permanent memory overhead.
2021-10-11 08:39:24 +08:00
LLVM_DEBUG({
dbgs() << " " << Group << " -> " << formatv("{0:x16}", SegAddr)
<< "\n";
});
Seg.WorkingMem = SegAddr.toPtr<char *>();
Seg.Addr = SegAddr + NextSlabDelta;
SegAddr += alignTo(Seg.ContentSize + Seg.ZeroFillSize, PageSize);
[JITLink][ORC] Major JITLinkMemoryManager refactor. This commit substantially refactors the JITLinkMemoryManager API to: (1) add asynchronous versions of key operations, (2) give memory manager implementations full control over link graph address layout, (3) enable more efficient tracking of allocated memory, and (4) support "allocation actions" and finalize-lifetime memory. Together these changes provide a more usable API, and enable more powerful and efficient memory manager implementations. To support these changes the JITLinkMemoryManager::Allocation inner class has been split into two new classes: InFlightAllocation, and FinalizedAllocation. The allocate method returns an InFlightAllocation that tracks memory (both working and executor memory) prior to finalization. The finalize method returns a FinalizedAllocation object, and the InFlightAllocation is discarded. Breaking Allocation into InFlightAllocation and FinalizedAllocation allows InFlightAllocation subclassses to be written more naturally, and FinalizedAlloc to be implemented and used efficiently (see (3) below). In addition to the memory manager changes this commit also introduces a new MemProt type to represent memory protections (MemProt replaces use of sys::Memory::ProtectionFlags in JITLink), and a new MemDeallocPolicy type that can be used to indicate when a section should be deallocated (see (4) below). Plugin/pass writers who were using sys::Memory::ProtectionFlags will have to switch to MemProt -- this should be straightworward. Clients with out-of-tree memory managers will need to update their implementations. Clients using in-tree memory managers should mostly be able to ignore it. Major features: (1) More asynchrony: The allocate and deallocate methods are now asynchronous by default, with synchronous convenience wrappers supplied. The asynchronous versions allow clients (including JITLink) to request and deallocate memory without blocking. (2) Improved control over graph address layout: Instead of a SegmentRequestMap, JITLinkMemoryManager::allocate now takes a reference to the LinkGraph to be allocated. The memory manager is responsible for calculating the memory requirements for the graph, and laying out the graph (setting working and executor memory addresses) within the allocated memory. This gives memory managers full control over JIT'd memory layout. For clients that don't need or want this degree of control the new "BasicLayout" utility can be used to get a segment-based view of the graph, similar to the one provided by SegmentRequestMap. Once segment addresses are assigned the BasicLayout::apply method can be used to automatically lay out the graph. (3) Efficient tracking of allocated memory. The FinalizedAlloc type is a wrapper for an ExecutorAddr and requires only 64-bits to store in the controller. The meaning of the address held by the FinalizedAlloc is left up to the memory manager implementation, but the FinalizedAlloc type enforces a requirement that deallocate be called on any non-default values prior to destruction. The deallocate method takes a vector<FinalizedAlloc>, allowing for bulk deallocation of many allocations in a single call. Memory manager implementations will typically store the address of some allocation metadata in the executor in the FinalizedAlloc, as holding this metadata in the executor is often cheaper and may allow for clean deallocation even in failure cases where the connection with the controller is lost. (4) Support for "allocation actions" and finalize-lifetime memory. Allocation actions are pairs (finalize_act, deallocate_act) of JITTargetAddress triples (fn, arg_buffer_addr, arg_buffer_size), that can be attached to a finalize request. At finalization time, after memory protections have been applied, each of the "finalize_act" elements will be called in order (skipping any elements whose fn value is zero) as ((char*(*)(const char *, size_t))fn)((const char *)arg_buffer_addr, (size_t)arg_buffer_size); At deallocation time the deallocate elements will be run in reverse order (again skipping any elements where fn is zero). The returned char * should be null to indicate success, or a non-null heap-allocated string error message to indicate failure. These actions allow finalization and deallocation to be extended to include operations like registering and deregistering eh-frames, TLS sections, initializer and deinitializers, and language metadata sections. Previously these operations required separate callWrapper invocations. Compared to callWrapper invocations, actions require no extra IPC/RPC, reducing costs and eliminating a potential source of errors. Finalize lifetime memory can be used to support finalize actions: Sections with finalize lifetime should be destroyed by memory managers immediately after finalization actions have been run. Finalize memory can be used to support finalize actions (e.g. with extra-metadata, or synthesized finalize actions) without incurring permanent memory overhead.
2021-10-11 08:39:24 +08:00
// Zero out the zero-fill memory.
if (Seg.ZeroFillSize != 0)
memset(Seg.WorkingMem + Seg.ContentSize, 0, Seg.ZeroFillSize);
}
NextSlabDelta += SegsSizes->total();
if (auto Err = BL.apply()) {
OnAllocated(std::move(Err));
return;
}
OnAllocated(std::unique_ptr<InProcessMemoryManager::InFlightAlloc>(
new IPMMAlloc(*this, std::move(BL), std::move(StandardSegs),
std::move(FinalizeSegs))));
}
void deallocate(std::vector<FinalizedAlloc> FinalizedAllocs,
OnDeallocatedFunction OnDeallocated) override {
Error Err = Error::success();
for (auto &FA : FinalizedAllocs) {
std::unique_ptr<FinalizedAllocInfo> FAI(
FA.release().toPtr<FinalizedAllocInfo *>());
// FIXME: Run dealloc actions.
Err = joinErrors(std::move(Err), freeBlock(FAI->Mem));
}
OnDeallocated(std::move(Err));
}
private:
JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) {
ErrorAsOutParameter _(&Err);
if (!SlabPageSize) {
if (auto PageSizeOrErr = sys::Process::getPageSize())
PageSize = *PageSizeOrErr;
else {
Err = PageSizeOrErr.takeError();
return;
}
if (PageSize == 0) {
Err = make_error<StringError>("Page size is zero",
inconvertibleErrorCode());
return;
}
} else
PageSize = SlabPageSize;
if (!isPowerOf2_64(PageSize)) {
Err = make_error<StringError>("Page size is not a power of 2",
inconvertibleErrorCode());
return;
}
// Round slab request up to page size.
SlabSize = (SlabSize + PageSize - 1) & ~(PageSize - 1);
const sys::Memory::ProtectionFlags ReadWrite =
static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
sys::Memory::MF_WRITE);
std::error_code EC;
SlabRemaining =
sys::Memory::allocateMappedMemory(SlabSize, nullptr, ReadWrite, EC);
if (EC) {
Err = errorCodeToError(EC);
return;
}
// Calculate the target address delta to link as-if slab were at
// SlabAddress.
if (SlabAddress != ~0ULL)
NextSlabDelta = ExecutorAddr(SlabAddress) -
ExecutorAddr::fromPtr(SlabRemaining.base());
}
Error freeBlock(sys::MemoryBlock MB) {
// FIXME: Return memory to slab.
return Error::success();
}
std::mutex SlabMutex;
sys::MemoryBlock SlabRemaining;
uint64_t PageSize = 0;
int64_t NextSlabDelta = 0;
};
Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
SizeString = SizeString.trim();
uint64_t Units = 1024;
if (SizeString.endswith_insensitive("kb"))
SizeString = SizeString.drop_back(2).rtrim();
else if (SizeString.endswith_insensitive("mb")) {
Units = 1024 * 1024;
SizeString = SizeString.drop_back(2).rtrim();
} else if (SizeString.endswith_insensitive("gb")) {
Units = 1024 * 1024 * 1024;
SizeString = SizeString.drop_back(2).rtrim();
}
uint64_t SlabSize = 0;
if (SizeString.getAsInteger(10, SlabSize))
return make_error<StringError>("Invalid numeric format for slab size",
inconvertibleErrorCode());
return SlabSize * Units;
}
static std::unique_ptr<JITLinkMemoryManager> createMemoryManager() {
if (!SlabAllocateSizeString.empty()) {
auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize));
}
return ExitOnErr(InProcessMemoryManager::Create());
}
static Expected<MaterializationUnit::Interface>
getTestObjectFileInterface(Session &S, MemoryBufferRef O) {
// Get the standard interface for this object, but ignore the symbols field.
// We'll handle that manually to include promotion.
auto I = getObjectFileInterface(S.ES, O);
if (!I)
return I.takeError();
I->SymbolFlags.clear();
// If creating an object file was going to fail it would have happened above,
// so we can 'cantFail' this.
auto Obj = cantFail(object::ObjectFile::createObjectFile(O));
// The init symbol must be included in the SymbolFlags map if present.
if (I->InitSymbol)
I->SymbolFlags[I->InitSymbol] =
JITSymbolFlags::MaterializationSideEffectsOnly;
for (auto &Sym : Obj->symbols()) {
Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
if (!SymFlagsOrErr)
// TODO: Test this error.
return SymFlagsOrErr.takeError();
// Skip symbols not defined in this object file.
if ((*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined))
continue;
auto Name = Sym.getName();
if (!Name)
return Name.takeError();
// Skip symbols that have type SF_File.
if (auto SymType = Sym.getType()) {
if (*SymType == object::SymbolRef::ST_File)
continue;
} else
return SymType.takeError();
auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
if (!SymFlags)
return SymFlags.takeError();
if (SymFlags->isWeak()) {
// If this is a weak symbol that's not defined in the harness then we
// need to either mark it as strong (if this is the first definition
// that we've seen) or discard it.
if (S.HarnessDefinitions.count(*Name) || S.CanonicalWeakDefs.count(*Name))
continue;
S.CanonicalWeakDefs[*Name] = O.getBufferIdentifier();
*SymFlags &= ~JITSymbolFlags::Weak;
if (!S.HarnessExternals.count(*Name))
*SymFlags &= ~JITSymbolFlags::Exported;
} else if (S.HarnessExternals.count(*Name)) {
*SymFlags |= JITSymbolFlags::Exported;
} else if (S.HarnessDefinitions.count(*Name) ||
!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
continue;
auto InternedName = S.ES.intern(*Name);
I->SymbolFlags[InternedName] = std::move(*SymFlags);
}
return I;
}
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
static Error loadProcessSymbols(Session &S) {
auto FilterMainEntryPoint =
[EPName = S.ES.intern(EntryPointName)](SymbolStringPtr Name) {
return Name != EPName;
};
S.MainJD->addGenerator(
ExitOnErr(orc::EPCDynamicLibrarySearchGenerator::GetForTargetProcess(
S.ES, std::move(FilterMainEntryPoint))));
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
return Error::success();
}
static Error loadDylibs(Session &S) {
LLVM_DEBUG(dbgs() << "Loading dylibs...\n");
for (const auto &Dylib : Dylibs) {
LLVM_DEBUG(dbgs() << " " << Dylib << "\n");
auto G = orc::EPCDynamicLibrarySearchGenerator::Load(S.ES, Dylib.c_str());
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
if (!G)
return G.takeError();
S.MainJD->addGenerator(std::move(*G));
}
return Error::success();
}
static Expected<std::unique_ptr<ExecutorProcessControl>> launchExecutor() {
#ifndef LLVM_ON_UNIX
// FIXME: Add support for Windows.
return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr +
" not supported on non-unix platforms",
inconvertibleErrorCode());
#elif !LLVM_ENABLE_THREADS
// Out of process mode using SimpleRemoteEPC depends on threads.
return make_error<StringError>(
"-" + OutOfProcessExecutor.ArgStr +
" requires threads, but LLVM was built with "
"LLVM_ENABLE_THREADS=Off",
inconvertibleErrorCode());
#else
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 SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
std::make_unique<DynamicThreadPoolTaskDispatcher>(),
SimpleRemoteEPC::Setup(), FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
#endif
}
#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
static Error createTCPSocketError(Twine Details) {
return make_error<StringError>(
formatv("Failed to connect TCP socket '{0}': {1}",
OutOfProcessExecutorConnect, Details),
inconvertibleErrorCode());
}
static Expected<int> connectTCPSocket(std::string Host, std::string PortStr) {
addrinfo *AI;
addrinfo Hints{};
Hints.ai_family = AF_INET;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_flags = AI_NUMERICSERV;
if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))
return createTCPSocketError("Address resolution failed (" +
StringRef(gai_strerror(EC)) + ")");
// Cycle through the returned addrinfo structures and connect to the first
// reachable endpoint.
int SockFD;
addrinfo *Server;
for (Server = AI; Server != nullptr; Server = Server->ai_next) {
// socket might fail, e.g. if the address family is not supported. Skip to
// the next addrinfo structure in such a case.
if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
continue;
// If connect returns null, we exit the loop with a working socket.
if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
break;
close(SockFD);
}
freeaddrinfo(AI);
// If we reached the end of the loop without connecting to a valid endpoint,
// dump the last error that was logged in socket() or connect().
if (Server == nullptr)
return createTCPSocketError(std::strerror(errno));
return SockFD;
}
#endif
static Expected<std::unique_ptr<ExecutorProcessControl>> connectToExecutor() {
#ifndef LLVM_ON_UNIX
// FIXME: Add TCP support for Windows.
return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr +
" not supported on non-unix platforms",
inconvertibleErrorCode());
#elif !LLVM_ENABLE_THREADS
// Out of process mode using SimpleRemoteEPC depends on threads.
return make_error<StringError>(
"-" + OutOfProcessExecutorConnect.ArgStr +
" requires threads, but LLVM was built with "
"LLVM_ENABLE_THREADS=Off",
inconvertibleErrorCode());
#else
StringRef Host, PortStr;
std::tie(Host, PortStr) = StringRef(OutOfProcessExecutorConnect).split(':');
if (Host.empty())
return createTCPSocketError("Host name for -" +
OutOfProcessExecutorConnect.ArgStr +
" can not be empty");
if (PortStr.empty())
return createTCPSocketError("Port number in -" +
OutOfProcessExecutorConnect.ArgStr +
" can not be empty");
int Port = 0;
if (PortStr.getAsInteger(10, Port))
return createTCPSocketError("Port number '" + PortStr +
"' is not a valid integer");
Expected<int> SockFD = connectTCPSocket(Host.str(), PortStr.str());
if (!SockFD)
return SockFD.takeError();
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
std::make_unique<DynamicThreadPoolTaskDispatcher>(),
SimpleRemoteEPC::Setup(), *SockFD, *SockFD);
#endif
}
class PhonyExternalsGenerator : public DefinitionGenerator {
public:
[ORC] Update Symbol Lookup / DefinitionGenerator system. This patch moves definition generation out from the session lock, instead running it under a per-dylib generator lock. It also makes the DefinitionGenerator::tryToGenerate method optionally asynchronous: Generators are handed an opaque LookupState object which can be captured to stop/restart the lookup process. The new scheme provides the following benefits and guarantees: (1) Queries that do not need to attempt definition generation (because all requested symbols matched against existing definitions in the JITDylib) can proceed without being blocked by any running definition generators. (2) Definition generators can capture the LookupState to continue their work asynchronously. This allows generators to run for an arbitrary amount of time without blocking a thread. Definition generators that do not need to run asynchronously can return without capturing the LookupState to eliminate unnecessary recursion and improve lookup performance. (3) Definition generators still do not need to worry about concurrency or re-entrance: Since they are still run under a (per-dylib) lock, generators will never be re-entered concurrently, or given overlapping symbol sets to generate. Finally, the new system distinguishes between symbols that are candidates for generation (generation candidates) and symbols that failed to match for a query (due to symbol visibility). This fixes a bug where an unresolved symbol could trigger generation of a duplicate definition for an existing hidden symbol.
2020-10-14 08:24:18 +08:00
Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
JITDylibLookupFlags JDLookupFlags,
const SymbolLookupSet &LookupSet) override {
SymbolMap PhonySymbols;
for (auto &KV : LookupSet)
PhonySymbols[KV.first] = JITEvaluatedSymbol(0, JITSymbolFlags::Exported);
return JD.define(absoluteSymbols(std::move(PhonySymbols)));
}
};
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
Expected<std::unique_ptr<Session>> Session::Create(Triple TT) {
std::unique_ptr<ExecutorProcessControl> EPC;
if (OutOfProcessExecutor.getNumOccurrences()) {
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
/// If -oop-executor is passed then launch the executor.
if (auto REPC = launchExecutor())
EPC = std::move(*REPC);
else
return REPC.takeError();
} else if (OutOfProcessExecutorConnect.getNumOccurrences()) {
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
/// If -oop-executor-connect is passed then connect to the executor.
if (auto REPC = connectToExecutor())
EPC = std::move(*REPC);
else
return REPC.takeError();
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
} else {
/// Otherwise use SelfExecutorProcessControl to target the current process.
auto PageSize = sys::Process::getPageSize();
if (!PageSize)
return PageSize.takeError();
EPC = std::make_unique<SelfExecutorProcessControl>(
std::make_shared<SymbolStringPool>(),
std::make_unique<InPlaceTaskDispatcher>(), std::move(TT), *PageSize,
createMemoryManager());
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
}
Error Err = Error::success();
std::unique_ptr<Session> S(new Session(std::move(EPC), Err));
if (Err)
return std::move(Err);
return std::move(S);
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
}
[ORC] Add support for resource tracking/removal (removable code). This patch introduces new APIs to support resource tracking and removal in Orc. It is intended as a thread-safe generalization of the removeModule concept from OrcV1. Clients can now create ResourceTracker objects (using JITDylib::createResourceTracker) to track resources for each MaterializationUnit (code, data, aliases, absolute symbols, etc.) added to the JIT. Every MaterializationUnit will be associated with a ResourceTracker, and ResourceTrackers can be re-used for multiple MaterializationUnits. Each JITDylib has a default ResourceTracker that will be used for MaterializationUnits added to that JITDylib if no ResourceTracker is explicitly specified. Two operations can be performed on ResourceTrackers: transferTo and remove. The transferTo operation transfers tracking of the resources to a different ResourceTracker object, allowing ResourceTrackers to be merged to reduce administrative overhead (the source tracker is invalidated in the process). The remove operation removes all resources associated with a ResourceTracker, including any symbols defined by MaterializationUnits associated with the tracker, and also invalidates the tracker. These operations are thread safe, and should work regardless of the the state of the MaterializationUnits. In the case of resource transfer any existing resources associated with the source tracker will be transferred to the destination tracker, and all future resources for those units will be automatically associated with the destination tracker. In the case of resource removal all already-allocated resources will be deallocated, any if any program representations associated with the tracker have not been compiled yet they will be destroyed. If any program representations are currently being compiled then they will be prevented from completing: their MaterializationResponsibility will return errors on any attempt to update the JIT state. Clients (usually Layer writers) wishing to track resources can implement the ResourceManager API to receive notifications when ResourceTrackers are transferred or removed. The MaterializationResponsibility::withResourceKeyDo method can be used to create associations between the key for a ResourceTracker and an allocated resource in a thread-safe way. RTDyldObjectLinkingLayer and ObjectLinkingLayer are updated to use the ResourceManager API to enable tracking and removal of memory allocated by the JIT linker. The new JITDylib::clear method can be used to trigger removal of every ResourceTracker associated with the JITDylib (note that this will only remove resources for the JITDylib, it does not run static destructors). This patch includes unit tests showing basic usage. A follow-up patch will update the Kaleidoscope and BuildingAJIT tutorial series to OrcV2 and will use this API to release code associated with anonymous expressions.
2020-09-12 00:50:41 +08:00
Session::~Session() {
if (auto Err = ES.endSession())
ES.reportError(std::move(Err));
}
Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err)
: ES(std::move(EPC)),
ObjLayer(ES, ES.getExecutorProcessControl().getMemMgr()) {
/// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
/// Session.
class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin {
public:
JITLinkSessionPlugin(Session &S) : S(S) {}
void modifyPassConfig(MaterializationResponsibility &MR, LinkGraph &G,
2020-07-17 11:38:41 +08:00
PassConfiguration &PassConfig) override {
S.modifyPassConfig(G.getTargetTriple(), PassConfig);
}
[ORC] Add support for resource tracking/removal (removable code). This patch introduces new APIs to support resource tracking and removal in Orc. It is intended as a thread-safe generalization of the removeModule concept from OrcV1. Clients can now create ResourceTracker objects (using JITDylib::createResourceTracker) to track resources for each MaterializationUnit (code, data, aliases, absolute symbols, etc.) added to the JIT. Every MaterializationUnit will be associated with a ResourceTracker, and ResourceTrackers can be re-used for multiple MaterializationUnits. Each JITDylib has a default ResourceTracker that will be used for MaterializationUnits added to that JITDylib if no ResourceTracker is explicitly specified. Two operations can be performed on ResourceTrackers: transferTo and remove. The transferTo operation transfers tracking of the resources to a different ResourceTracker object, allowing ResourceTrackers to be merged to reduce administrative overhead (the source tracker is invalidated in the process). The remove operation removes all resources associated with a ResourceTracker, including any symbols defined by MaterializationUnits associated with the tracker, and also invalidates the tracker. These operations are thread safe, and should work regardless of the the state of the MaterializationUnits. In the case of resource transfer any existing resources associated with the source tracker will be transferred to the destination tracker, and all future resources for those units will be automatically associated with the destination tracker. In the case of resource removal all already-allocated resources will be deallocated, any if any program representations associated with the tracker have not been compiled yet they will be destroyed. If any program representations are currently being compiled then they will be prevented from completing: their MaterializationResponsibility will return errors on any attempt to update the JIT state. Clients (usually Layer writers) wishing to track resources can implement the ResourceManager API to receive notifications when ResourceTrackers are transferred or removed. The MaterializationResponsibility::withResourceKeyDo method can be used to create associations between the key for a ResourceTracker and an allocated resource in a thread-safe way. RTDyldObjectLinkingLayer and ObjectLinkingLayer are updated to use the ResourceManager API to enable tracking and removal of memory allocated by the JIT linker. The new JITDylib::clear method can be used to trigger removal of every ResourceTracker associated with the JITDylib (note that this will only remove resources for the JITDylib, it does not run static destructors). This patch includes unit tests showing basic usage. A follow-up patch will update the Kaleidoscope and BuildingAJIT tutorial series to OrcV2 and will use this API to release code associated with anonymous expressions.
2020-09-12 00:50:41 +08:00
Error notifyFailed(MaterializationResponsibility &MR) override {
return Error::success();
}
Error notifyRemovingResources(ResourceKey K) override {
return Error::success();
}
void notifyTransferringResources(ResourceKey DstKey,
ResourceKey SrcKey) override {}
private:
Session &S;
};
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
ErrorAsOutParameter _(&Err);
if (auto MainJDOrErr = ES.createJITDylib("main"))
MainJD = &*MainJDOrErr;
else {
Err = MainJDOrErr.takeError();
return;
}
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
if (!NoProcessSymbols)
ExitOnErr(loadProcessSymbols(*this));
ExitOnErr(loadDylibs(*this));
auto &TT = ES.getExecutorProcessControl().getTargetTriple();
if (DebuggerSupport && TT.isOSBinFormatMachO())
ObjLayer.addPlugin(ExitOnErr(
GDBJITDebugInfoRegistrationPlugin::Create(this->ES, *MainJD, TT)));
// Set up the platform.
if (TT.isOSBinFormatMachO() && !OrcRuntime.empty()) {
if (auto P =
MachOPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str()))
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
ES.setPlatform(std::move(*P));
else {
Err = P.takeError();
return;
}
} else if (TT.isOSBinFormatELF() && !OrcRuntime.empty()) {
if (auto P =
ELFNixPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str()))
ES.setPlatform(std::move(*P));
else {
Err = P.takeError();
return;
}
} else if (!TT.isOSWindows() && !TT.isOSBinFormatMachO()) {
if (!NoExec)
ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
ES, ExitOnErr(EPCEHFrameRegistrar::Create(this->ES))));
if (DebuggerSupport)
ObjLayer.addPlugin(std::make_unique<DebugObjectManagerPlugin>(
ES, ExitOnErr(createJITLoaderGDBRegistrar(this->ES))));
}
[Orc] Add JITLink debug support plugin for ELF x86-64 Add a new ObjectLinkingLayer plugin `DebugObjectManagerPlugin` and infrastructure to handle creation of `DebugObject`s as well as their registration in OrcTargetProcess. The current implementation only covers ELF on x86-64, but the infrastructure is not limited to that. The journey starts with a new `LinkGraph` / `JITLinkContext` pair being created for a `MaterializationResponsibility` in ORC's `ObjectLinkingLayer`. It sends a `notifyMaterializing()` notification, which is forwarded to all registered plugins. The `DebugObjectManagerPlugin` aims to create a `DebugObject` form the provided target triple and object buffer. (Future implementations might create `DebugObject`s from a `LinkGraph` in other ways.) On success it will track it as the pending `DebugObject` for the `MaterializationResponsibility`. This patch only implements the `ELFDebugObject` for `x86-64` targets. It follows the RuntimeDyld approach for debug object setup: it captures a copy of the input object, parses all section headers and prepares to patch their load-address fields with their final addresses in target memory. It instructs the plugin to report the section load-addresses once they are available. The plugin overrides `modifyPassConfig()` and installs a JITLink post-allocation pass to capture them. Once JITLink emitted the finalized executable, the plugin emits and registers the `DebugObject`. For emission it requests a new `JITLinkMemoryManager::Allocation` with a single read-only segment, copies the object with patched section load-addresses over to working memory and triggers finalization to target memory. For registration, it notifies the `DebugObjectRegistrar` provided in the constructor and stores the previously pending`DebugObject` as registered for the corresponding MaterializationResponsibility. The `DebugObjectRegistrar` registers the `DebugObject` with the target process. `llvm-jitlink` uses the `TPCDebugObjectRegistrar`, which calls `llvm_orc_registerJITLoaderGDBWrapper()` in the target process via `TargetProcessControl` to emit a `jit_code_entry` compatible with the GDB JIT interface [1]. So far the implementation only supports registration and no removal. It appears to me that it wouldn't raise any new design questions, so I left this as an addition for the near future. [1] https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D97335
2021-03-02 19:37:48 +08:00
ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
// Process any harness files.
for (auto &HarnessFile : TestHarnesses) {
HarnessFiles.insert(HarnessFile);
auto ObjBuffer =
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(HarnessFile)));
auto ObjInterface =
ExitOnErr(getObjectFileInterface(ES, ObjBuffer->getMemBufferRef()));
for (auto &KV : ObjInterface.SymbolFlags)
HarnessDefinitions.insert(*KV.first);
auto Obj = ExitOnErr(
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
for (auto &Sym : Obj->symbols()) {
uint32_t SymFlags = ExitOnErr(Sym.getFlags());
auto Name = ExitOnErr(Sym.getName());
if (Name.empty())
continue;
if (SymFlags & object::BasicSymbolRef::SF_Undefined)
HarnessExternals.insert(Name);
}
}
// If a name is defined by some harness file then it's a definition, not an
// external.
for (auto &DefName : HarnessDefinitions)
HarnessExternals.erase(DefName.getKey());
}
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
void Session::dumpSessionInfo(raw_ostream &OS) {
OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
}
void Session::modifyPassConfig(const Triple &TT,
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
PassConfiguration &PassConfig) {
if (!CheckFiles.empty())
PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) {
auto &EPC = ES.getExecutorProcessControl();
if (EPC.getTargetTriple().getObjectFormat() == Triple::ELF)
return registerELFGraphInfo(*this, G);
if (EPC.getTargetTriple().getObjectFormat() == Triple::MachO)
return registerMachOGraphInfo(*this, G);
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
return make_error<StringError>("Unsupported object format for GOT/stub "
"registration",
inconvertibleErrorCode());
});
if (ShowLinkGraph)
PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
outs() << "Link graph \"" << G.getName() << "\" post-fixup:\n";
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
G.dump(outs());
return Error::success();
});
PassConfig.PrePrunePasses.push_back(
[this](LinkGraph &G) { return applyHarnessPromotions(*this, G); });
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
if (ShowSizes) {
PassConfig.PrePrunePasses.push_back([this](LinkGraph &G) -> Error {
SizeBeforePruning += computeTotalBlockSizes(G);
return Error::success();
});
PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) -> Error {
SizeAfterFixups += computeTotalBlockSizes(G);
return Error::success();
});
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
}
if (ShowRelocatedSectionContents)
PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
outs() << "Relocated section contents for " << G.getName() << ":\n";
dumpSectionContents(outs(), G);
return Error::success();
});
if (AddSelfRelocations)
PassConfig.PostPrunePasses.push_back(addSelfRelocations);
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
}
Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) {
auto FileInfoItr = FileInfos.find(FileName);
if (FileInfoItr == FileInfos.end())
return make_error<StringError>("file \"" + FileName + "\" not recognized",
inconvertibleErrorCode());
return FileInfoItr->second;
}
Expected<Session::MemoryRegionInfo &>
Session::findSectionInfo(StringRef FileName, StringRef SectionName) {
auto FI = findFileInfo(FileName);
if (!FI)
return FI.takeError();
auto SecInfoItr = FI->SectionInfos.find(SectionName);
if (SecInfoItr == FI->SectionInfos.end())
return make_error<StringError>("no section \"" + SectionName +
"\" registered for file \"" + FileName +
"\"",
inconvertibleErrorCode());
return SecInfoItr->second;
}
Expected<Session::MemoryRegionInfo &>
Session::findStubInfo(StringRef FileName, StringRef TargetName) {
auto FI = findFileInfo(FileName);
if (!FI)
return FI.takeError();
auto StubInfoItr = FI->StubInfos.find(TargetName);
if (StubInfoItr == FI->StubInfos.end())
return make_error<StringError>("no stub for \"" + TargetName +
"\" registered for file \"" + FileName +
"\"",
inconvertibleErrorCode());
return StubInfoItr->second;
}
Expected<Session::MemoryRegionInfo &>
Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) {
auto FI = findFileInfo(FileName);
if (!FI)
return FI.takeError();
auto GOTInfoItr = FI->GOTEntryInfos.find(TargetName);
if (GOTInfoItr == FI->GOTEntryInfos.end())
return make_error<StringError>("no GOT entry for \"" + TargetName +
"\" registered for file \"" + FileName +
"\"",
inconvertibleErrorCode());
return GOTInfoItr->second;
}
bool Session::isSymbolRegistered(StringRef SymbolName) {
return SymbolInfos.count(SymbolName);
}
Expected<Session::MemoryRegionInfo &>
Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) {
auto SymInfoItr = SymbolInfos.find(SymbolName);
if (SymInfoItr == SymbolInfos.end())
return make_error<StringError>(ErrorMsgStem + ": symbol " + SymbolName +
" not found",
inconvertibleErrorCode());
return SymInfoItr->second;
}
} // end namespace llvm
static Triple getFirstFileTriple() {
static Triple FirstTT = []() {
assert(!InputFiles.empty() && "InputFiles can not be empty");
for (auto InputFile : InputFiles) {
auto ObjBuffer =
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile)));
switch (identify_magic(ObjBuffer->getBuffer())) {
case file_magic::elf_relocatable:
case file_magic::macho_object:
case file_magic::coff_object: {
auto Obj = ExitOnErr(
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
return Obj->makeTriple();
}
default:
break;
}
}
return Triple();
}();
return FirstTT;
}
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
static Error sanitizeArguments(const Triple &TT, const char *ArgV0) {
// -noexec and --args should not be used together.
if (NoExec && !InputArgv.empty())
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
errs() << "Warning: --args passed to -noexec run will be ignored.\n";
// Set the entry point name if not specified.
if (EntryPointName.empty())
EntryPointName = TT.getObjectFormat() == Triple::MachO ? "_main" : "main";
// Disable debugger support by default in noexec tests.
if (DebuggerSupport.getNumOccurrences() == 0 && NoExec)
DebuggerSupport = false;
// If -slab-allocate is passed, check that we're not trying to use it in
// -oop-executor or -oop-executor-connect mode.
//
// FIXME: Remove once we enable remote slab allocation.
if (SlabAllocateSizeString != "") {
if (OutOfProcessExecutor.getNumOccurrences() ||
OutOfProcessExecutorConnect.getNumOccurrences())
return make_error<StringError>(
"-slab-allocate cannot be used with -oop-executor or "
"-oop-executor-connect",
inconvertibleErrorCode());
}
// If -slab-address is passed, require -slab-allocate and -noexec
if (SlabAddress != ~0ULL) {
if (SlabAllocateSizeString == "" || !NoExec)
return make_error<StringError>(
"-slab-address requires -slab-allocate and -noexec",
inconvertibleErrorCode());
if (SlabPageSize == 0)
errs() << "Warning: -slab-address used without -slab-page-size.\n";
}
if (SlabPageSize != 0) {
// -slab-page-size requires slab alloc.
if (SlabAllocateSizeString == "")
return make_error<StringError>("-slab-page-size requires -slab-allocate",
inconvertibleErrorCode());
// Check -slab-page-size / -noexec interactions.
if (!NoExec) {
if (auto RealPageSize = sys::Process::getPageSize()) {
if (SlabPageSize % *RealPageSize)
return make_error<StringError>(
"-slab-page-size must be a multiple of real page size for exec "
"tests (did you mean to use -noexec ?)\n",
inconvertibleErrorCode());
} else {
errs() << "Could not retrieve process page size:\n";
logAllUnhandledErrors(RealPageSize.takeError(), errs(), "");
errs() << "Executing with slab page size = "
<< formatv("{0:x}", SlabPageSize) << ".\n"
<< "Tool may crash if " << formatv("{0:x}", SlabPageSize)
<< " is not a multiple of the real process page size.\n"
<< "(did you mean to use -noexec ?)";
}
}
}
// 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);
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
sys::path::append(OOPExecutorPath, "llvm-jitlink-executor");
OutOfProcessExecutor = OOPExecutorPath.str().str();
}
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
return Error::success();
}
static void addPhonyExternalsGenerator(Session &S) {
S.MainJD->addGenerator(std::make_unique<PhonyExternalsGenerator>());
}
static Error createJITDylibs(Session &S,
std::map<unsigned, JITDylib *> &IdxToJD) {
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
// First, set up JITDylibs.
LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
{
// Create a "main" JITLinkDylib.
IdxToJD[0] = S.MainJD;
S.JDSearchOrder.push_back({S.MainJD, JITDylibLookupFlags::MatchAllSymbols});
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
LLVM_DEBUG(dbgs() << " 0: " << S.MainJD->getName() << "\n");
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
// Add any extra JITDylibs from the command line.
for (auto JDItr = JITDylibs.begin(), JDEnd = JITDylibs.end();
JDItr != JDEnd; ++JDItr) {
auto JD = S.ES.createJITDylib(*JDItr);
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
if (!JD)
return JD.takeError();
unsigned JDIdx = JITDylibs.getPosition(JDItr - JITDylibs.begin());
IdxToJD[JDIdx] = &*JD;
S.JDSearchOrder.push_back({&*JD, JITDylibLookupFlags::MatchAllSymbols});
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD->getName() << "\n");
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
}
}
LLVM_DEBUG({
dbgs() << "Dylib search order is [ ";
for (auto &KV : S.JDSearchOrder)
dbgs() << KV.first->getName() << " ";
dbgs() << "]\n";
});
return Error::success();
}
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static Error addAbsoluteSymbols(Session &S,
const std::map<unsigned, JITDylib *> &IdxToJD) {
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
// Define absolute symbols.
LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n");
for (auto AbsDefItr = AbsoluteDefs.begin(), AbsDefEnd = AbsoluteDefs.end();
AbsDefItr != AbsDefEnd; ++AbsDefItr) {
unsigned AbsDefArgIdx =
AbsoluteDefs.getPosition(AbsDefItr - AbsoluteDefs.begin());
auto &JD = *std::prev(IdxToJD.lower_bound(AbsDefArgIdx))->second;
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
StringRef AbsDefStmt = *AbsDefItr;
size_t EqIdx = AbsDefStmt.find_first_of('=');
if (EqIdx == StringRef::npos)
return make_error<StringError>("Invalid absolute define \"" + AbsDefStmt +
"\". Syntax: <name>=<addr>",
inconvertibleErrorCode());
StringRef Name = AbsDefStmt.substr(0, EqIdx).trim();
StringRef AddrStr = AbsDefStmt.substr(EqIdx + 1).trim();
uint64_t Addr;
if (AddrStr.getAsInteger(0, Addr))
return make_error<StringError>("Invalid address expression \"" + AddrStr +
"\" in absolute symbol definition \"" +
AbsDefStmt + "\"",
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
inconvertibleErrorCode());
JITEvaluatedSymbol AbsDef(Addr, JITSymbolFlags::Exported);
if (auto Err = JD.define(absoluteSymbols({{S.ES.intern(Name), AbsDef}})))
return Err;
// Register the absolute symbol with the session symbol infos.
S.SymbolInfos[Name] = {ArrayRef<char>(), Addr};
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
}
return Error::success();
}
static Error addAliases(Session &S,
const std::map<unsigned, JITDylib *> &IdxToJD) {
// Define absolute symbols.
LLVM_DEBUG(dbgs() << "Defining aliases...\n");
for (auto AliasItr = Aliases.begin(), AliasEnd = Aliases.end();
AliasItr != AliasEnd; ++AliasItr) {
unsigned AliasArgIdx = Aliases.getPosition(AliasItr - Aliases.begin());
auto &JD = *std::prev(IdxToJD.lower_bound(AliasArgIdx))->second;
StringRef AliasStmt = *AliasItr;
size_t EqIdx = AliasStmt.find_first_of('=');
if (EqIdx == StringRef::npos)
return make_error<StringError>("Invalid alias definition \"" + AliasStmt +
"\". Syntax: <name>=<addr>",
inconvertibleErrorCode());
StringRef Alias = AliasStmt.substr(0, EqIdx).trim();
StringRef Aliasee = AliasStmt.substr(EqIdx + 1).trim();
SymbolAliasMap SAM;
SAM[S.ES.intern(Alias)] = {S.ES.intern(Aliasee), JITSymbolFlags::Exported};
if (auto Err = JD.define(symbolAliases(std::move(SAM))))
return Err;
}
return Error::success();
}
static Error addTestHarnesses(Session &S) {
LLVM_DEBUG(dbgs() << "Adding test harness objects...\n");
for (auto HarnessFile : TestHarnesses) {
LLVM_DEBUG(dbgs() << " " << HarnessFile << "\n");
auto ObjBuffer = errorOrToExpected(MemoryBuffer::getFile(HarnessFile));
if (!ObjBuffer)
return ObjBuffer.takeError();
if (auto Err = S.ObjLayer.add(*S.MainJD, std::move(*ObjBuffer)))
return Err;
}
return Error::success();
}
static Error addObjects(Session &S,
const std::map<unsigned, JITDylib *> &IdxToJD) {
// Load each object into the corresponding JITDylib..
LLVM_DEBUG(dbgs() << "Adding objects...\n");
for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end();
InputFileItr != InputFileEnd; ++InputFileItr) {
unsigned InputFileArgIdx =
InputFiles.getPosition(InputFileItr - InputFiles.begin());
const std::string &InputFile = *InputFileItr;
if (StringRef(InputFile).endswith(".a"))
continue;
auto &JD = *std::prev(IdxToJD.lower_bound(InputFileArgIdx))->second;
LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile
<< "\" to " << JD.getName() << "\n";);
auto ObjBuffer = errorOrToExpected(MemoryBuffer::getFile(InputFile));
if (!ObjBuffer)
return ObjBuffer.takeError();
if (S.HarnessFiles.empty()) {
if (auto Err = S.ObjLayer.add(JD, std::move(*ObjBuffer)))
return Err;
} else {
// We're in -harness mode. Use a custom interface for this
// test object.
auto ObjInterface =
getTestObjectFileInterface(S, (*ObjBuffer)->getMemBufferRef());
if (!ObjInterface)
return ObjInterface.takeError();
if (auto Err = S.ObjLayer.add(JD, std::move(*ObjBuffer),
std::move(*ObjInterface)))
return Err;
}
}
return Error::success();
}
static Expected<MaterializationUnit::Interface>
getObjectFileInterfaceHidden(ExecutionSession &ES, MemoryBufferRef ObjBuffer) {
auto I = getObjectFileInterface(ES, ObjBuffer);
if (I) {
for (auto &KV : I->SymbolFlags)
KV.second &= ~JITSymbolFlags::Exported;
}
return I;
}
static Error addLibraries(Session &S,
const std::map<unsigned, JITDylib *> &IdxToJD) {
// 1. Collect search paths for each JITDylib.
DenseMap<const JITDylib *, SmallVector<StringRef, 2>> JDSearchPaths;
for (auto LSPItr = LibrarySearchPaths.begin(),
LSPEnd = LibrarySearchPaths.end();
LSPItr != LSPEnd; ++LSPItr) {
unsigned LibrarySearchPathIdx =
LibrarySearchPaths.getPosition(LSPItr - LibrarySearchPaths.begin());
auto &JD = *std::prev(IdxToJD.lower_bound(LibrarySearchPathIdx))->second;
StringRef LibrarySearchPath = *LSPItr;
if (sys::fs::get_file_type(LibrarySearchPath) !=
sys::fs::file_type::directory_file)
return make_error<StringError>("While linking " + JD.getName() + ", -L" +
LibrarySearchPath +
" does not point to a directory",
inconvertibleErrorCode());
JDSearchPaths[&JD].push_back(*LSPItr);
}
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
LLVM_DEBUG({
if (!JDSearchPaths.empty())
dbgs() << "Search paths:\n";
for (auto &KV : JDSearchPaths) {
dbgs() << " " << KV.first->getName() << ": [";
for (auto &LibSearchPath : KV.second)
dbgs() << " \"" << LibSearchPath << "\"";
dbgs() << " ]\n";
}
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
});
// 2. Collect library loads
struct LibraryLoad {
StringRef LibName;
bool IsPath = false;
unsigned Position;
StringRef *CandidateExtensions;
enum { Standard, Hidden } Modifier;
};
std::vector<LibraryLoad> LibraryLoads;
// Add archive files from the inputs to LibraryLoads.
for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end();
InputFileItr != InputFileEnd; ++InputFileItr) {
StringRef InputFile = *InputFileItr;
if (!InputFile.endswith(".a"))
continue;
LibraryLoad LL;
LL.LibName = InputFile;
LL.IsPath = true;
LL.Position = InputFiles.getPosition(InputFileItr - InputFiles.begin());
LL.CandidateExtensions = nullptr;
LL.Modifier = LibraryLoad::Standard;
LibraryLoads.push_back(std::move(LL));
}
// Add -load_hidden arguments to LibraryLoads.
for (auto LibItr = LoadHidden.begin(), LibEnd = LoadHidden.end();
LibItr != LibEnd; ++LibItr) {
LibraryLoad LL;
LL.LibName = *LibItr;
LL.IsPath = true;
LL.Position = LoadHidden.getPosition(LibItr - LoadHidden.begin());
LL.CandidateExtensions = nullptr;
LL.Modifier = LibraryLoad::Hidden;
LibraryLoads.push_back(std::move(LL));
}
StringRef StandardExtensions[] = {".so", ".dylib", ".a"};
StringRef ArchiveExtensionsOnly[] = {".a"};
// Add -lx arguments to LibraryLoads.
for (auto LibItr = Libraries.begin(), LibEnd = Libraries.end();
LibItr != LibEnd; ++LibItr) {
LibraryLoad LL;
LL.LibName = *LibItr;
LL.Position = Libraries.getPosition(LibItr - Libraries.begin());
LL.CandidateExtensions = StandardExtensions;
LL.Modifier = LibraryLoad::Standard;
LibraryLoads.push_back(std::move(LL));
}
// Add -hidden-lx arguments to LibraryLoads.
for (auto LibHiddenItr = LibrariesHidden.begin(),
LibHiddenEnd = LibrariesHidden.end();
LibHiddenItr != LibHiddenEnd; ++LibHiddenItr) {
LibraryLoad LL;
LL.LibName = *LibHiddenItr;
LL.Position =
LibrariesHidden.getPosition(LibHiddenItr - LibrariesHidden.begin());
LL.CandidateExtensions = ArchiveExtensionsOnly;
LL.Modifier = LibraryLoad::Hidden;
LibraryLoads.push_back(std::move(LL));
}
// If there are any load-<modified> options then turn on flag overrides
// to avoid flag mismatch errors.
if (!LibrariesHidden.empty() || !LoadHidden.empty())
S.ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true);
// Sort library loads by position in the argument list.
llvm::sort(LibraryLoads, [](const LibraryLoad &LHS, const LibraryLoad &RHS) {
return LHS.Position < RHS.Position;
});
// 3. Process library loads.
auto AddArchive = [&](const char *Path, const LibraryLoad &LL)
-> Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> {
unique_function<Expected<MaterializationUnit::Interface>(
ExecutionSession & ES, MemoryBufferRef ObjBuffer)>
GetObjFileInterface;
switch (LL.Modifier) {
case LibraryLoad::Standard:
GetObjFileInterface = getObjectFileInterface;
break;
case LibraryLoad::Hidden:
GetObjFileInterface = getObjectFileInterfaceHidden;
break;
}
return StaticLibraryDefinitionGenerator::Load(
S.ObjLayer, Path, S.ES.getExecutorProcessControl().getTargetTriple(),
std::move(GetObjFileInterface));
};
for (auto &LL : LibraryLoads) {
bool LibFound = false;
auto &JD = *std::prev(IdxToJD.lower_bound(LL.Position))->second;
// If this is the name of a JITDylib then link against that.
if (auto *LJD = S.ES.getJITDylibByName(LL.LibName)) {
JD.addToLinkOrder(*LJD);
continue;
}
if (LL.IsPath) {
auto G = AddArchive(LL.LibName.str().c_str(), LL);
if (!G)
return createFileError(LL.LibName, G.takeError());
JD.addGenerator(std::move(*G));
LLVM_DEBUG({
dbgs() << "Adding generator for static library " << LL.LibName << " to "
<< JD.getName() << "\n";
});
continue;
}
// Otherwise look through the search paths.
auto JDSearchPathsItr = JDSearchPaths.find(&JD);
if (JDSearchPathsItr != JDSearchPaths.end()) {
for (StringRef SearchPath : JDSearchPathsItr->second) {
for (const char *LibExt : {".dylib", ".so", ".a"}) {
SmallVector<char, 256> LibPath;
LibPath.reserve(SearchPath.size() + strlen("lib") +
LL.LibName.size() + strlen(LibExt) +
2); // +2 for pathsep, null term.
llvm::copy(SearchPath, std::back_inserter(LibPath));
sys::path::append(LibPath, "lib" + LL.LibName + LibExt);
LibPath.push_back('\0');
// Skip missing or non-regular paths.
if (sys::fs::get_file_type(LibPath.data()) !=
sys::fs::file_type::regular_file) {
continue;
}
file_magic Magic;
if (auto EC = identify_magic(LibPath, Magic)) {
// If there was an error loading the file then skip it.
LLVM_DEBUG({
dbgs() << "Library search found \"" << LibPath
<< "\", but could not identify file type (" << EC.message()
<< "). Skipping.\n";
});
continue;
}
// We identified the magic. Assume that we can load it -- we'll reset
// in the default case.
LibFound = true;
switch (Magic) {
case file_magic::elf_shared_object:
case file_magic::macho_dynamically_linked_shared_lib: {
// TODO: On first reference to LibPath this should create a JITDylib
// with a generator and add it to JD's links-against list. Subsquent
// references should use the JITDylib created on the first
// reference.
auto G =
EPCDynamicLibrarySearchGenerator::Load(S.ES, LibPath.data());
if (!G)
return G.takeError();
LLVM_DEBUG({
dbgs() << "Adding generator for dynamic library "
<< LibPath.data() << " to " << JD.getName() << "\n";
});
JD.addGenerator(std::move(*G));
break;
}
case file_magic::archive:
case file_magic::macho_universal_binary: {
auto G = AddArchive(LibPath.data(), LL);
if (!G)
return G.takeError();
JD.addGenerator(std::move(*G));
LLVM_DEBUG({
dbgs() << "Adding generator for static library " << LibPath.data()
<< " to " << JD.getName() << "\n";
});
break;
}
default:
// This file isn't a recognized library kind.
LLVM_DEBUG({
dbgs() << "Library search found \"" << LibPath
<< "\", but file type is not supported. Skipping.\n";
});
LibFound = false;
break;
}
if (LibFound)
break;
}
if (LibFound)
break;
}
}
if (!LibFound)
return make_error<StringError>("While linking " + JD.getName() +
", could not find library for -l" +
LL.LibName,
inconvertibleErrorCode());
}
return Error::success();
}
static Error addSessionInputs(Session &S) {
std::map<unsigned, JITDylib *> IdxToJD;
if (auto Err = createJITDylibs(S, IdxToJD))
return Err;
if (auto Err = addAbsoluteSymbols(S, IdxToJD))
return Err;
if (auto Err = addAliases(S, IdxToJD))
return Err;
if (!TestHarnesses.empty())
if (auto Err = addTestHarnesses(S))
return Err;
if (auto Err = addObjects(S, IdxToJD))
return Err;
if (auto Err = addLibraries(S, IdxToJD))
return Err;
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
return Error::success();
}
namespace {
struct TargetInfo {
const Target *TheTarget;
std::unique_ptr<MCSubtargetInfo> STI;
std::unique_ptr<MCRegisterInfo> MRI;
std::unique_ptr<MCAsmInfo> MAI;
std::unique_ptr<MCContext> Ctx;
std::unique_ptr<MCDisassembler> Disassembler;
std::unique_ptr<MCInstrInfo> MII;
std::unique_ptr<MCInstrAnalysis> MIA;
std::unique_ptr<MCInstPrinter> InstPrinter;
};
} // anonymous namespace
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
static TargetInfo getTargetInfo(const Triple &TT) {
auto TripleName = TT.str();
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
std::string ErrorStr;
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, ErrorStr);
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
if (!TheTarget)
ExitOnErr(make_error<StringError>("Error accessing target '" + TripleName +
"': " + ErrorStr,
inconvertibleErrorCode()));
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TripleName, "", ""));
if (!STI)
ExitOnErr(
make_error<StringError>("Unable to create subtarget for " + TripleName,
inconvertibleErrorCode()));
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
if (!MRI)
ExitOnErr(make_error<StringError>("Unable to create target register info "
"for " +
TripleName,
inconvertibleErrorCode()));
MCTargetOptions MCOptions;
std::unique_ptr<MCAsmInfo> MAI(
TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
if (!MAI)
ExitOnErr(make_error<StringError>("Unable to create target asm info " +
TripleName,
inconvertibleErrorCode()));
auto Ctx = std::make_unique<MCContext>(Triple(TripleName), MAI.get(),
MRI.get(), STI.get());
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
std::unique_ptr<MCDisassembler> Disassembler(
TheTarget->createMCDisassembler(*STI, *Ctx));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
if (!Disassembler)
ExitOnErr(make_error<StringError>("Unable to create disassembler for " +
TripleName,
inconvertibleErrorCode()));
std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
if (!MII)
ExitOnErr(make_error<StringError>("Unable to create instruction info for" +
TripleName,
inconvertibleErrorCode()));
std::unique_ptr<MCInstrAnalysis> MIA(
TheTarget->createMCInstrAnalysis(MII.get()));
if (!MIA)
ExitOnErr(make_error<StringError>(
"Unable to create instruction analysis for" + TripleName,
inconvertibleErrorCode()));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
std::unique_ptr<MCInstPrinter> InstPrinter(
TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
if (!InstPrinter)
ExitOnErr(make_error<StringError>(
"Unable to create instruction printer for" + TripleName,
inconvertibleErrorCode()));
return {TheTarget, std::move(STI), std::move(MRI),
std::move(MAI), std::move(Ctx), std::move(Disassembler),
std::move(MII), std::move(MIA), std::move(InstPrinter)};
}
static Error runChecks(Session &S) {
const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple();
if (CheckFiles.empty())
return Error::success();
LLVM_DEBUG(dbgs() << "Running checks...\n");
auto TI = getTargetInfo(TT);
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
auto IsSymbolValid = [&S](StringRef Symbol) {
return S.isSymbolRegistered(Symbol);
};
auto GetSymbolInfo = [&S](StringRef Symbol) {
return S.findSymbolInfo(Symbol, "Can not get symbol info");
};
auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) {
return S.findSectionInfo(FileName, SectionName);
};
auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
return S.findStubInfo(FileName, SectionName);
};
auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
return S.findGOTEntryInfo(FileName, SectionName);
};
RuntimeDyldChecker Checker(
IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
TT.isLittleEndian() ? support::little : support::big,
TI.Disassembler.get(), TI.InstPrinter.get(), dbgs());
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
[ORC][JITLink] Add support for weak references, and improve handling of static libraries. This patch substantially updates ORCv2's lookup API in order to support weak references, and to better support static archives. Key changes: -- Each symbol being looked for is now associated with a SymbolLookupFlags value. If the associated value is SymbolLookupFlags::RequiredSymbol then the symbol must be defined in one of the JITDylibs being searched (or be able to be generated in one of these JITDylibs via an attached definition generator) or the lookup will fail with an error. If the associated value is SymbolLookupFlags::WeaklyReferencedSymbol then the symbol is permitted to be undefined, in which case it will simply not appear in the resulting SymbolMap if the rest of the lookup succeeds. Since lookup now requires these flags for each symbol, the lookup method now takes an instance of a new SymbolLookupSet type rather than a SymbolNameSet. SymbolLookupSet is a vector-backed set of (name, flags) pairs. Clients are responsible for ensuring that the set property (i.e. unique elements) holds, though this is usually simple and SymbolLookupSet provides convenience methods to support this. -- Lookups now have an associated LookupKind value, which is either LookupKind::Static or LookupKind::DLSym. Definition generators can inspect the lookup kind when determining whether or not to generate new definitions. The StaticLibraryDefinitionGenerator is updated to only pull in new objects from the archive if the lookup kind is Static. This allows lookup to be re-used to emulate dlsym for JIT'd symbols without pulling in new objects from archives (which would not happen in a normal dlsym call). -- JITLink is updated to allow externals to be assigned weak linkage, and weak externals now use the SymbolLookupFlags::WeaklyReferencedSymbol value for lookups. Unresolved weak references will be assigned the default value of zero. Since this patch was modifying the lookup API anyway, it alo replaces all of the "MatchNonExported" boolean arguments with a "JITDylibLookupFlags" enum for readability. If a JITDylib's associated value is JITDylibLookupFlags::MatchExportedSymbolsOnly then the lookup will only match against exported (non-hidden) symbols in that JITDylib. If a JITDylib's associated value is JITDylibLookupFlags::MatchAllSymbols then the lookup will match against any symbol defined in the JITDylib.
2019-11-26 13:57:27 +08:00
std::string CheckLineStart = "# " + CheckName + ":";
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
for (auto &CheckFile : CheckFiles) {
auto CheckerFileBuf =
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile)));
[ORC][JITLink] Add support for weak references, and improve handling of static libraries. This patch substantially updates ORCv2's lookup API in order to support weak references, and to better support static archives. Key changes: -- Each symbol being looked for is now associated with a SymbolLookupFlags value. If the associated value is SymbolLookupFlags::RequiredSymbol then the symbol must be defined in one of the JITDylibs being searched (or be able to be generated in one of these JITDylibs via an attached definition generator) or the lookup will fail with an error. If the associated value is SymbolLookupFlags::WeaklyReferencedSymbol then the symbol is permitted to be undefined, in which case it will simply not appear in the resulting SymbolMap if the rest of the lookup succeeds. Since lookup now requires these flags for each symbol, the lookup method now takes an instance of a new SymbolLookupSet type rather than a SymbolNameSet. SymbolLookupSet is a vector-backed set of (name, flags) pairs. Clients are responsible for ensuring that the set property (i.e. unique elements) holds, though this is usually simple and SymbolLookupSet provides convenience methods to support this. -- Lookups now have an associated LookupKind value, which is either LookupKind::Static or LookupKind::DLSym. Definition generators can inspect the lookup kind when determining whether or not to generate new definitions. The StaticLibraryDefinitionGenerator is updated to only pull in new objects from the archive if the lookup kind is Static. This allows lookup to be re-used to emulate dlsym for JIT'd symbols without pulling in new objects from archives (which would not happen in a normal dlsym call). -- JITLink is updated to allow externals to be assigned weak linkage, and weak externals now use the SymbolLookupFlags::WeaklyReferencedSymbol value for lookups. Unresolved weak references will be assigned the default value of zero. Since this patch was modifying the lookup API anyway, it alo replaces all of the "MatchNonExported" boolean arguments with a "JITDylibLookupFlags" enum for readability. If a JITDylib's associated value is JITDylibLookupFlags::MatchExportedSymbolsOnly then the lookup will only match against exported (non-hidden) symbols in that JITDylib. If a JITDylib's associated value is JITDylibLookupFlags::MatchAllSymbols then the lookup will match against any symbol defined in the JITDylib.
2019-11-26 13:57:27 +08:00
if (!Checker.checkAllRulesInBuffer(CheckLineStart, &*CheckerFileBuf))
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
ExitOnErr(make_error<StringError>(
"Some checks in " + CheckFile + " failed", inconvertibleErrorCode()));
}
return Error::success();
}
static Error addSelfRelocations(LinkGraph &G) {
auto TI = getTargetInfo(G.getTargetTriple());
for (auto *Sym : G.defined_symbols())
if (Sym->isCallable())
if (auto Err = addFunctionPointerRelocationsToCurrentSymbol(
*Sym, G, *TI.Disassembler, *TI.MIA))
return Err;
return Error::success();
}
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
static void dumpSessionStats(Session &S) {
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
if (!ShowSizes)
return;
if (!OrcRuntime.empty())
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
outs() << "Note: Session stats include runtime and entry point lookup, but "
"not JITDylib initialization/deinitialization.\n";
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
if (ShowSizes)
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
outs() << " Total size of all blocks before pruning: "
<< S.SizeBeforePruning
<< "\n Total size of all blocks after fixups: " << S.SizeAfterFixups
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
<< "\n";
}
static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
return S.ES.lookup(S.JDSearchOrder, S.ES.intern(EntryPointName));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
}
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
static Expected<JITEvaluatedSymbol> getOrcRuntimeEntryPoint(Session &S) {
std::string RuntimeEntryPoint = "__orc_rt_run_program_wrapper";
const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple();
if (TT.getObjectFormat() == Triple::MachO)
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
RuntimeEntryPoint = '_' + RuntimeEntryPoint;
return S.ES.lookup(S.JDSearchOrder, S.ES.intern(RuntimeEntryPoint));
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
}
static Expected<int> runWithRuntime(Session &S, ExecutorAddr EntryPointAddr) {
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
StringRef DemangledEntryPoint = EntryPointName;
const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple();
if (TT.getObjectFormat() == Triple::MachO &&
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
DemangledEntryPoint.front() == '_')
DemangledEntryPoint = DemangledEntryPoint.drop_front();
using SPSRunProgramSig =
int64_t(SPSString, SPSString, SPSSequence<SPSString>);
int64_t Result;
if (auto Err = S.ES.callSPSWrapper<SPSRunProgramSig>(
EntryPointAddr, Result, S.MainJD->getName(), DemangledEntryPoint,
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
static_cast<std::vector<std::string> &>(InputArgv)))
return std::move(Err);
return Result;
}
static Expected<int> runWithoutRuntime(Session &S,
ExecutorAddr EntryPointAddr) {
return S.ES.getExecutorProcessControl().runAsMain(EntryPointAddr, InputArgv);
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
}
namespace {
struct JITLinkTimers {
TimerGroup JITLinkTG{"llvm-jitlink timers", "timers for llvm-jitlink phases"};
Timer LoadObjectsTimer{"load", "time to load/add object files", JITLinkTG};
Timer LinkTimer{"link", "time to link object files", JITLinkTG};
Timer RunTimer{"run", "time to execute jitlink'd code", JITLinkTG};
};
} // namespace
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
int main(int argc, char *argv[]) {
InitLLVM X(argc, argv);
InitializeAllTargetInfos();
InitializeAllTargetMCs();
InitializeAllDisassemblers();
cl::HideUnrelatedOptions({&JITLinkCategory, &getColorCategory()});
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool");
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
/// If timers are enabled, create a JITLinkTimers instance.
std::unique_ptr<JITLinkTimers> Timers =
ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
ExitOnErr(sanitizeArguments(getFirstFileTriple(), argv[0]));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
auto S = ExitOnErr(Session::Create(getFirstFileTriple()));
{
TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
ExitOnErr(addSessionInputs(*S));
}
if (PhonyExternals)
addPhonyExternalsGenerator(*S);
if (ShowInitialExecutionSessionState)
S->ES.dump(outs());
JITEvaluatedSymbol EntryPoint = nullptr;
{
TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
// Find the entry-point function unconditionally, since we want to force
// it to be materialized to collect stats.
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
EntryPoint = ExitOnErr(getMainEntryPoint(*S));
LLVM_DEBUG({
dbgs() << "Using entry point \"" << EntryPointName
<< "\": " << formatv("{0:x16}", EntryPoint.getAddress()) << "\n";
});
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
// If we're running with the ORC runtime then replace the entry-point
// with the __orc_rt_run_program symbol.
if (!OrcRuntime.empty()) {
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
EntryPoint = ExitOnErr(getOrcRuntimeEntryPoint(*S));
LLVM_DEBUG({
dbgs() << "(called via __orc_rt_run_program_wrapper at "
<< formatv("{0:x16}", EntryPoint.getAddress()) << ")\n";
});
}
}
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
if (ShowEntryExecutionSessionState)
S->ES.dump(outs());
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
if (ShowAddrs)
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
S->dumpSessionInfo(outs());
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
ExitOnErr(runChecks(*S));
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
[ORC] Add generic initializer/deinitializer support. Initializers and deinitializers are used to implement C++ static constructors and destructors, runtime registration for some languages (e.g. with the Objective-C runtime for Objective-C/C++ code) and other tasks that would typically be performed when a shared-object/dylib is loaded or unloaded by a statically compiled program. MCJIT and ORC have historically provided limited support for discovering and running initializers/deinitializers by scanning the llvm.global_ctors and llvm.global_dtors variables and recording the functions to be run. This approach suffers from several drawbacks: (1) It only works for IR inputs, not for object files (including cached JIT'd objects). (2) It only works for initializers described by llvm.global_ctors and llvm.global_dtors, however not all initializers are described in this way (Objective-C, for example, describes initializers via specially named metadata sections). (3) To make the initializer/deinitializer functions described by llvm.global_ctors and llvm.global_dtors searchable they must be promoted to extern linkage, polluting the JIT symbol table (extra care must be taken to ensure this promotion does not result in symbol name clashes). This patch introduces several interdependent changes to ORCv2 to support the construction of new initialization schemes, and includes an implementation of a backwards-compatible llvm.global_ctor/llvm.global_dtor scanning scheme, and a MachO specific scheme that handles Objective-C runtime registration (if the Objective-C runtime is available) enabling execution of LLVM IR compiled from Objective-C and Swift. The major changes included in this patch are: (1) The MaterializationUnit and MaterializationResponsibility classes are extended to describe an optional "initializer" symbol for the module (see the getInitializerSymbol method on each class). The presence or absence of this symbol indicates whether the module contains any initializers or deinitializers. The initializer symbol otherwise behaves like any other: searching for it triggers materialization. (2) A new Platform interface is introduced in llvm/ExecutionEngine/Orc/Core.h which provides the following callback interface: - Error setupJITDylib(JITDylib &JD): Can be used to install standard symbols in JITDylibs upon creation. E.g. __dso_handle. - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU): Generally used to record initializer symbols. - Error notifyRemoving(JITDylib &JD, VModuleKey K): Used to notify a platform that a module is being removed. Platform implementations can use these callbacks to track outstanding initializers and implement a platform-specific approach for executing them. For example, the MachOPlatform installs a plugin in the JIT linker to scan for both __mod_inits sections (for C++ static constructors) and ObjC metadata sections. If discovered, these are processed in the usual platform order: Objective-C registration is carried out first, then static initializers are executed, ensuring that calls to Objective-C from static initializers will be safe. This patch updates LLJIT to use the new scheme for initialization. Two LLJIT::PlatformSupport classes are implemented: A GenericIR platform and a MachO platform. The GenericIR platform implements a modified version of the previous llvm.global-ctor scraping scheme to provide support for Windows and Linux. LLJIT's MachO platform uses the MachOPlatform class to provide MachO specific initialization as described above. Reviewers: sgraenitz, dblaikie Subscribers: mgorny, hiraditya, mgrang, ributzka, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D74300
2019-12-16 18:50:40 +08:00
dumpSessionStats(*S);
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
if (NoExec)
return 0;
int Result = 0;
{
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
LLVM_DEBUG(dbgs() << "Running \"" << EntryPointName << "\"...\n");
TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
if (!OrcRuntime.empty())
Result =
ExitOnErr(runWithRuntime(*S, ExecutorAddr(EntryPoint.getAddress())));
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
else
Result = ExitOnErr(
runWithoutRuntime(*S, ExecutorAddr(EntryPoint.getAddress())));
}
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
// Destroy the session.
ExitOnErr(S->ES.endSession());
[ORC][ORC-RT] Introduce ORC-runtime based MachO-Platform. Adds support for MachO static initializers/deinitializers and eh-frame registration via the ORC runtime. This commit introduces cooperative support code into the ORC runtime and ORC LLVM libraries (especially the MachOPlatform class) to support macho runtime features for JIT'd code. This commit introduces support for static initializers, static destructors (via cxa_atexit interposition), and eh-frame registration. Near-future commits will add support for MachO native thread-local variables, and language runtime registration (e.g. for Objective-C and Swift). The llvm-jitlink tool is updated to use the ORC runtime where available, and regression tests for the new MachOPlatform support are added to compiler-rt. Notable changes on the ORC runtime side: 1. The new macho_platform.h / macho_platform.cpp files contain the bulk of the runtime-side support. This includes eh-frame registration; jit versions of dlopen, dlsym, and dlclose; a cxa_atexit interpose to record static destructors, and an '__orc_rt_macho_run_program' function that defines running a JIT'd MachO program in terms of the jit- dlopen/dlsym/dlclose functions. 2. Replaces JITTargetAddress (and casting operations) with ExecutorAddress (copied from LLVM) to improve type-safety of address management. 3. Adds serialization support for ExecutorAddress and unordered_map types to the runtime-side Simple Packed Serialization code. 4. Adds orc-runtime regression tests to ensure that static initializers and cxa-atexit interposes work as expected. Notable changes on the LLVM side: 1. The MachOPlatform class is updated to: 1.1. Load the ORC runtime into the ExecutionSession. 1.2. Set up standard aliases for macho-specific runtime functions. E.g. ___cxa_atexit -> ___orc_rt_macho_cxa_atexit. 1.3. Install the MachOPlatformPlugin to scrape LinkGraphs for information needed to support MachO features (e.g. eh-frames, mod-inits), and communicate this information to the runtime. 1.4. Provide entry-points that the runtime can call to request initializers, perform symbol lookup, and request deinitialiers (the latter is implemented as an empty placeholder as macho object deinits are rarely used). 1.5. Create a MachO header object for each JITDylib (defining the __mh_header and __dso_handle symbols). 2. The llvm-jitlink tool (and llvm-jitlink-executor) are updated to use the runtime when available. 3. A `lookupInitSymbolsAsync` method is added to the Platform base class. This can be used to issue an async lookup for initializer symbols. The existing `lookupInitSymbols` method is retained (the GenericIRPlatform code is still using it), but is deprecated and will be removed soon. 4. JIT-dispatch support code is added to ExecutorProcessControl. The JIT-dispatch system allows handlers in the JIT process to be associated with 'tag' symbols in the executor, and allows the executor to make remote procedure calls back to the JIT process (via __orc_rt_jit_dispatch) using those tags. The primary use case is ORC runtime code that needs to call bakc to handlers in orc::Platform subclasses. E.g. __orc_rt_macho_jit_dlopen calling back to MachOPlatform::rt_getInitializers using __orc_rt_macho_get_initializers_tag. (The system is generic however, and could be used by non-runtime code). The new ExecutorProcessControl::JITDispatchInfo struct provides the address (in the executor) of the jit-dispatch function and a jit-dispatch context object, and implementations of the dispatch function are added to SelfExecutorProcessControl and OrcRPCExecutorProcessControl. 5. OrcRPCTPCServer is updated to support JIT-dispatch calls over ORC-RPC. 6. Serialization support for StringMap is added to the LLVM-side Simple Packed Serialization code. 7. A JITLink::allocateBuffer operation is introduced to allocate writable memory attached to the graph. This is used by the MachO header synthesis code, and will be generically useful for other clients who want to create new graph content from scratch.
2021-07-14 19:09:36 +08:00
S.reset();
// If the executing code set a test result override then use that.
if (UseTestResultOverride)
Result = TestResultOverride;
return Result;
Initial implementation of JITLink - A replacement for RuntimeDyld. Summary: JITLink is a jit-linker that performs the same high-level task as RuntimeDyld: it parses relocatable object files and makes their contents runnable in a target process. JITLink aims to improve on RuntimeDyld in several ways: (1) A clear design intended to maximize code-sharing while minimizing coupling. RuntimeDyld has been developed in an ad-hoc fashion for a number of years and this had led to intermingling of code for multiple architectures (e.g. in RuntimeDyldELF::processRelocationRef) in a way that makes the code more difficult to read, reason about, extend. JITLink is designed to isolate format and architecture specific code, while still sharing generic code. (2) Support for native code models. RuntimeDyld required the use of large code models (where calls to external functions are made indirectly via registers) for many of platforms due to its restrictive model for stub generation (one "stub" per symbol). JITLink allows arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be added naturally. (3) Native support for asynchronous linking. JITLink uses asynchronous calls for symbol resolution and finalization: these callbacks are passed a continuation function that they must call to complete the linker's work. This allows for cleaner interoperation with the new concurrent ORC JIT APIs, while still being easily implementable in synchronous style if asynchrony is not needed. To maximise sharing, the design has a hierarchy of common code: (1) Generic atom-graph data structure and algorithms (e.g. dead stripping and | memory allocation) that are intended to be shared by all architectures. | + -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to | atom-graph parsing. | + -- (3) Architecture specific code that uses (1) and (2). E.g. JITLinkerMachO_x86_64, which adds x86-64 specific relocation support to (2) to build and patch up the atom graph. To support asynchronous symbol resolution and finalization, the callbacks for these operations take continuations as arguments: using JITLinkAsyncLookupContinuation = std::function<void(Expected<AsyncLookupResult> LR)>; using JITLinkAsyncLookupFunction = std::function<void(const DenseSet<StringRef> &Symbols, JITLinkAsyncLookupContinuation LookupContinuation)>; using FinalizeContinuation = std::function<void(Error)>; virtual void finalizeAsync(FinalizeContinuation OnFinalize); In addition to its headline features, JITLink also makes other improvements: - Dead stripping support: symbols that are not used (e.g. redundant ODR definitions) are discarded, and take up no memory in the target process (In contrast, RuntimeDyld supported pointer equality for weak definitions, but the redundant definitions stayed resident in memory). - Improved exception handling support. JITLink provides a much more extensive eh-frame parser than RuntimeDyld, and is able to correctly fix up many eh-frame sections that RuntimeDyld currently (silently) fails on. - More extensive validation and error handling throughout. This initial patch supports linking MachO/x86-64 only. Work on support for other architectures and formats will happen in-tree. Differential Revision: https://reviews.llvm.org/D58704 llvm-svn: 358818
2019-04-21 01:10:34 +08:00
}