llvm-project/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h

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

248 lines
8.4 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
//===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing.
//
//===----------------------------------------------------------------------===//
#ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
#define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#define DEBUG_TYPE "jitlink"
namespace llvm {
class MemoryBufferRef;
namespace jitlink {
/// Base class for a JIT linker.
///
/// A JITLinkerBase instance links one object file into an ongoing JIT
/// session. Symbol resolution and finalization operations are pluggable,
/// and called using continuation passing (passing a continuation for the
/// remaining linker work) to allow them to be performed asynchronously.
class JITLinkerBase {
public:
JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, PassConfiguration Passes)
: Ctx(std::move(Ctx)), Passes(std::move(Passes)) {
assert(this->Ctx && "Ctx can not be null");
}
virtual ~JITLinkerBase();
protected:
struct SegmentLayout {
using BlocksList = std::vector<Block *>;
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
BlocksList ContentBlocks;
BlocksList ZeroFillBlocks;
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 SegmentLayoutMap = DenseMap<unsigned, SegmentLayout>;
// Phase 1:
// 1.1: Build link graph
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
// 1.2: Run pre-prune passes
// 1.2: Prune graph
// 1.3: Run post-prune passes
// 1.4: Sort blocks into segments
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
// 1.5: Allocate segment memory
// 1.6: Identify externals and make an async call to resolve function
void linkPhase1(std::unique_ptr<JITLinkerBase> Self);
// Phase 2:
// 2.1: Apply resolution results
// 2.2: Fix up block contents
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.3: Call OnResolved callback
// 2.3: Make an async call to transfer and finalize memory.
void linkPhase2(std::unique_ptr<JITLinkerBase> Self,
Expected<AsyncLookupResult> LookupResult,
SegmentLayoutMap Layout);
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
// Phase 3:
// 3.1: Call OnFinalized callback, handing off allocation.
void linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err);
// Build a graph from the given object buffer.
// To be implemented by the client.
virtual Expected<std::unique_ptr<LinkGraph>>
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
buildGraph(MemoryBufferRef ObjBuffer) = 0;
// For debug dumping of the link graph.
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
virtual StringRef getEdgeKindName(Edge::Kind K) const = 0;
// Alight a JITTargetAddress to conform with block alignment requirements.
static JITTargetAddress alignToBlock(JITTargetAddress Addr, Block &B) {
uint64_t Delta = (B.getAlignmentOffset() - Addr) % B.getAlignment();
return Addr + Delta;
}
// Alight a pointer to conform with block alignment requirements.
static char *alignToBlock(char *P, Block &B) {
uint64_t PAddr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(P));
uint64_t Delta = (B.getAlignmentOffset() - PAddr) % B.getAlignment();
return P + Delta;
}
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
private:
// Run all passes in the given pass list, bailing out immediately if any pass
// returns an error.
Error runPasses(LinkGraphPassList &Passes);
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
// Copy block contents and apply relocations.
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
// Implemented in JITLinker.
virtual Error
copyAndFixUpBlocks(const SegmentLayoutMap &Layout,
JITLinkMemoryManager::Allocation &Alloc) const = 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
SegmentLayoutMap layOutBlocks();
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
Error allocateSegments(const SegmentLayoutMap &Layout);
DenseSet<StringRef> getExternalSymbolNames() const;
void applyLookupResult(AsyncLookupResult LR);
void deallocateAndBailOut(Error 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
void dumpGraph(raw_ostream &OS);
std::unique_ptr<JITLinkContext> Ctx;
PassConfiguration Passes;
std::unique_ptr<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
std::unique_ptr<JITLinkMemoryManager::Allocation> Alloc;
};
template <typename LinkerImpl> class JITLinker : public JITLinkerBase {
public:
using JITLinkerBase::JITLinkerBase;
/// Link constructs a LinkerImpl instance and calls linkPhase1.
/// Link should be called with the constructor arguments for LinkerImpl, which
/// will be forwarded to the constructor.
template <typename... ArgTs> static void link(ArgTs &&... Args) {
auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...);
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
// Ownership of the linker is passed into the linker's doLink function to
// allow it to be passed on to async continuations.
//
// FIXME: Remove LTmp once we have c++17.
// C++17 sequencing rules guarantee that function name expressions are
// sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be
// well formed.
auto &LTmp = *L;
LTmp.linkPhase1(std::move(L));
}
private:
const LinkerImpl &impl() const {
return static_cast<const LinkerImpl &>(*this);
}
Error
copyAndFixUpBlocks(const SegmentLayoutMap &Layout,
JITLinkMemoryManager::Allocation &Alloc) const override {
LLVM_DEBUG(dbgs() << "Copying and fixing up blocks:\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
for (auto &KV : Layout) {
auto &Prot = KV.first;
auto &SegLayout = KV.second;
auto SegMem = Alloc.getWorkingMemory(
static_cast<sys::Memory::ProtectionFlags>(Prot));
char *LastBlockEnd = SegMem.data();
char *BlockDataPtr = LastBlockEnd;
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() << " Processing segment "
<< static_cast<sys::Memory::ProtectionFlags>(Prot) << " [ "
<< (const void *)SegMem.data() << " .. "
<< (const void *)((char *)SegMem.data() + SegMem.size())
<< " ]\n Processing content sections:\n";
});
for (auto *B : SegLayout.ContentBlocks) {
LLVM_DEBUG(dbgs() << " " << *B << ":\n");
// Pad to alignment/alignment-offset.
BlockDataPtr = alignToBlock(BlockDataPtr, *B);
LLVM_DEBUG({
dbgs() << " Bumped block pointer to "
<< (const void *)BlockDataPtr << " to meet block alignment "
<< B->getAlignment() << " and alignment offset "
<< B->getAlignmentOffset() << "\n";
});
// Zero pad up to alignment.
LLVM_DEBUG({
if (LastBlockEnd != BlockDataPtr)
dbgs() << " Zero padding from " << (const void *)LastBlockEnd
<< " to " << (const void *)BlockDataPtr << "\n";
});
while (LastBlockEnd != BlockDataPtr)
*LastBlockEnd++ = 0;
// Copy initial block content.
LLVM_DEBUG({
dbgs() << " Copying block " << *B << " content, "
<< B->getContent().size() << " bytes, from "
<< (const void *)B->getContent().data() << " to "
<< (const void *)BlockDataPtr << "\n";
});
memcpy(BlockDataPtr, B->getContent().data(), B->getContent().size());
// Copy Block data and apply fixups.
LLVM_DEBUG(dbgs() << " Applying fixups.\n");
for (auto &E : B->edges()) {
// Skip non-relocation edges.
if (!E.isRelocation())
continue;
// Dispatch to LinkerImpl for fixup.
if (auto Err = impl().applyFixup(*B, E, BlockDataPtr))
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
}
// Point the block's content to the fixed up buffer.
B->setContent(StringRef(BlockDataPtr, B->getContent().size()));
// Update block end pointer.
LastBlockEnd = BlockDataPtr + B->getContent().size();
BlockDataPtr = LastBlockEnd;
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
}
// Zero pad the rest of the segment.
LLVM_DEBUG({
dbgs() << " Zero padding end of segment from "
<< (const void *)LastBlockEnd << " to "
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
<< (const void *)((char *)SegMem.data() + SegMem.size()) << "\n";
});
while (LastBlockEnd != SegMem.data() + SegMem.size())
*LastBlockEnd++ = 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
}
return Error::success();
}
};
/// Removes dead symbols/blocks/addressables.
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
///
/// Finds the set of symbols and addressables reachable from any symbol
/// initially marked live. All symbols/addressables not marked live at the end
/// of this process are removed.
void prune(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
} // end namespace jitlink
} // end namespace llvm
#undef DEBUG_TYPE // "jitlink"
#endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H