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"
|
|
|
|
|
2019-07-04 08:05:12 +08:00
|
|
|
#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.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/MC/MCAsmInfo.h"
|
|
|
|
#include "llvm/MC/MCContext.h"
|
|
|
|
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
|
|
|
|
#include "llvm/MC/MCInstPrinter.h"
|
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
|
|
#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/DynamicLibrary.h"
|
|
|
|
#include "llvm/Support/InitLLVM.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2019-09-07 03:21:55 +08:00
|
|
|
#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/TargetRegistry.h"
|
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2019-08-27 23:51:19 +08:00
|
|
|
#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 <list>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "llvm-jitlink"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::jitlink;
|
|
|
|
using namespace llvm::orc;
|
|
|
|
|
|
|
|
static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
|
|
|
|
cl::desc("input files"));
|
|
|
|
|
|
|
|
static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
|
|
|
|
cl::init(false));
|
|
|
|
|
|
|
|
static cl::list<std::string>
|
|
|
|
CheckFiles("check", cl::desc("File containing verifier checks"),
|
|
|
|
cl::ZeroOrMore);
|
|
|
|
|
|
|
|
static cl::opt<std::string>
|
|
|
|
EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
|
|
|
|
cl::init(""));
|
|
|
|
|
|
|
|
static cl::list<std::string> JITLinkDylibs(
|
|
|
|
"jld", cl::desc("Specifies the JITDylib to be used for any subsequent "
|
|
|
|
"input file arguments"));
|
|
|
|
|
|
|
|
static cl::list<std::string>
|
|
|
|
Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),
|
|
|
|
cl::ZeroOrMore);
|
|
|
|
|
2019-04-25 01:23:05 +08:00
|
|
|
static cl::list<std::string> InputArgv("args", cl::Positional,
|
|
|
|
cl::desc("<program arguments>..."),
|
|
|
|
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
|
|
|
|
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));
|
|
|
|
|
2019-04-22 07:50:24 +08:00
|
|
|
static cl::list<std::string> AbsoluteDefs(
|
|
|
|
"define-abs",
|
|
|
|
cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
|
|
|
|
cl::ZeroOrMore);
|
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));
|
|
|
|
|
2019-10-04 11:55:26 +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",
|
2019-10-04 11:55:26 +08:00
|
|
|
cl::desc("Print the link graph after fixups have been applied"),
|
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::init(false));
|
|
|
|
|
|
|
|
static cl::opt<bool> ShowSizes(
|
2019-04-22 04:34:19 +08:00
|
|
|
"show-sizes",
|
|
|
|
cl::desc("Show sizes pre- and post-dead stripping, and allocations"),
|
|
|
|
cl::init(false));
|
|
|
|
|
2019-08-27 23:51:19 +08:00
|
|
|
static cl::opt<bool> ShowTimes("show-times",
|
|
|
|
cl::desc("Show times for llvm-jitlink phases"),
|
|
|
|
cl::init(false));
|
|
|
|
|
2019-09-07 03:21:55 +08:00
|
|
|
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(""));
|
|
|
|
|
2019-04-22 04:34:19 +08:00
|
|
|
static cl::opt<bool> ShowRelocatedSectionContents(
|
|
|
|
"show-relocated-section-contents",
|
|
|
|
cl::desc("show section contents after fixups have been applied"),
|
|
|
|
cl::init(false));
|
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;
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
|
|
|
static raw_ostream &
|
|
|
|
operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) {
|
2019-05-13 06:26:33 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
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;
|
2019-10-04 11:55:26 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) {
|
2019-04-22 04:34:19 +08:00
|
|
|
constexpr JITTargetAddress 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);
|
|
|
|
|
|
|
|
std::sort(Sections.begin(), Sections.end(),
|
|
|
|
[](const Section *LHS, const Section *RHS) {
|
2019-10-04 11:55:26 +08:00
|
|
|
if (LHS->symbols_empty() && RHS->symbols_empty())
|
2019-04-22 04:34:19 +08:00
|
|
|
return false;
|
2019-10-04 11:55:26 +08:00
|
|
|
if (LHS->symbols_empty())
|
2019-04-22 04:34:19 +08:00
|
|
|
return false;
|
2019-10-04 11:55:26 +08:00
|
|
|
if (RHS->symbols_empty())
|
2019-04-22 04:34:19 +08:00
|
|
|
return true;
|
2019-10-04 11:55:26 +08:00
|
|
|
SectionRange LHSRange(*LHS);
|
|
|
|
SectionRange RHSRange(*RHS);
|
|
|
|
return LHSRange.getStart() < RHSRange.getStart();
|
2019-04-22 04:34:19 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
for (auto *S : Sections) {
|
|
|
|
OS << S->getName() << " content:";
|
2019-10-04 11:55:26 +08:00
|
|
|
if (S->symbols_empty()) {
|
2019-04-22 04:34:19 +08:00
|
|
|
OS << "\n section empty\n";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
// 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();
|
|
|
|
});
|
|
|
|
|
|
|
|
JITTargetAddress NextAddr = Syms.front()->getAddress() & ~(DumpWidth - 1);
|
|
|
|
for (auto *Sym : Syms) {
|
|
|
|
bool IsZeroFill = Sym->getBlock().isZeroFill();
|
|
|
|
JITTargetAddress SymStart = Sym->getAddress();
|
|
|
|
JITTargetAddress SymSize = Sym->getSize();
|
|
|
|
JITTargetAddress SymEnd = SymStart + SymSize;
|
|
|
|
const uint8_t *SymData =
|
|
|
|
IsZeroFill ? nullptr : Sym->getSymbolContent().bytes_begin();
|
|
|
|
|
|
|
|
// Pad any space before the symbol starts.
|
|
|
|
while (NextAddr != SymStart) {
|
2019-04-22 04:34:19 +08:00
|
|
|
if (NextAddr % DumpWidth == 0)
|
|
|
|
OS << formatv("\n{0:x16}:", NextAddr);
|
|
|
|
OS << " ";
|
|
|
|
++NextAddr;
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
// Render the symbol content.
|
|
|
|
while (NextAddr != SymEnd) {
|
2019-04-22 04:34:19 +08:00
|
|
|
if (NextAddr % DumpWidth == 0)
|
|
|
|
OS << formatv("\n{0:x16}:", NextAddr);
|
|
|
|
if (IsZeroFill)
|
|
|
|
OS << " 00";
|
|
|
|
else
|
2019-10-04 11:55:26 +08:00
|
|
|
OS << formatv(" {0:x-2}", SymData[NextAddr - SymStart]);
|
2019-04-22 04:34:19 +08:00
|
|
|
++NextAddr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-07 03:21:55 +08:00
|
|
|
class JITLinkSlabAllocator final : public JITLinkMemoryManager {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
|
|
|
|
allocate(const SegmentsRequestMap &Request) override {
|
|
|
|
|
|
|
|
using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
|
|
|
|
|
|
|
|
// Local class for allocation.
|
|
|
|
class IPMMAlloc : public Allocation {
|
|
|
|
public:
|
|
|
|
IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
|
|
|
|
MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
|
|
|
|
assert(SegBlocks.count(Seg) && "No allocation for segment");
|
|
|
|
return {static_cast<char *>(SegBlocks[Seg].base()),
|
|
|
|
SegBlocks[Seg].allocatedSize()};
|
|
|
|
}
|
|
|
|
JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
|
|
|
|
assert(SegBlocks.count(Seg) && "No allocation for segment");
|
|
|
|
return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
|
|
|
|
}
|
|
|
|
void finalizeAsync(FinalizeContinuation OnFinalize) override {
|
|
|
|
OnFinalize(applyProtections());
|
|
|
|
}
|
|
|
|
Error deallocate() override {
|
|
|
|
for (auto &KV : SegBlocks)
|
|
|
|
if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
|
|
|
|
return errorCodeToError(EC);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Error applyProtections() {
|
|
|
|
for (auto &KV : SegBlocks) {
|
|
|
|
auto &Prot = KV.first;
|
|
|
|
auto &Block = KV.second;
|
|
|
|
if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
|
|
|
|
return errorCodeToError(EC);
|
|
|
|
if (Prot & sys::Memory::MF_EXEC)
|
|
|
|
sys::Memory::InvalidateInstructionCache(Block.base(),
|
|
|
|
Block.allocatedSize());
|
|
|
|
}
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
AllocationMap SegBlocks;
|
|
|
|
};
|
|
|
|
|
|
|
|
AllocationMap Blocks;
|
|
|
|
|
|
|
|
for (auto &KV : Request) {
|
|
|
|
auto &Seg = KV.second;
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
if (Seg.getAlignment() > PageSize)
|
2019-09-07 03:21:55 +08:00
|
|
|
return make_error<StringError>("Cannot request higher than page "
|
|
|
|
"alignment",
|
|
|
|
inconvertibleErrorCode());
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
if (PageSize % Seg.getAlignment() != 0)
|
2019-09-07 03:21:55 +08:00
|
|
|
return make_error<StringError>("Page size is not a multiple of "
|
|
|
|
"alignment",
|
|
|
|
inconvertibleErrorCode());
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
uint64_t ZeroFillStart = Seg.getContentSize();
|
2019-09-07 03:21:55 +08:00
|
|
|
uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
|
|
|
|
|
|
|
|
// Round segment size up to page boundary.
|
|
|
|
SegmentSize = (SegmentSize + PageSize - 1) & ~(PageSize - 1);
|
|
|
|
|
|
|
|
// Take segment bytes from the front of the slab.
|
|
|
|
void *SlabBase = SlabRemaining.base();
|
|
|
|
uint64_t SlabRemainingSize = SlabRemaining.allocatedSize();
|
|
|
|
|
|
|
|
if (SegmentSize > SlabRemainingSize)
|
|
|
|
return make_error<StringError>("Slab allocator out of memory",
|
|
|
|
inconvertibleErrorCode());
|
|
|
|
|
|
|
|
sys::MemoryBlock SegMem(SlabBase, SegmentSize);
|
|
|
|
SlabRemaining =
|
|
|
|
sys::MemoryBlock(reinterpret_cast<char *>(SlabBase) + SegmentSize,
|
|
|
|
SlabRemainingSize - SegmentSize);
|
|
|
|
|
|
|
|
// Zero out the zero-fill memory.
|
|
|
|
memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
|
|
|
|
Seg.getZeroFillSize());
|
|
|
|
|
|
|
|
// Record the block for this segment.
|
|
|
|
Blocks[KV.first] = std::move(SegMem);
|
|
|
|
}
|
|
|
|
return std::unique_ptr<InProcessMemoryManager::Allocation>(
|
|
|
|
new IPMMAlloc(std::move(Blocks)));
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) {
|
|
|
|
ErrorAsOutParameter _(&Err);
|
|
|
|
|
|
|
|
PageSize = sys::Process::getPageSizeEstimate();
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sys::MemoryBlock SlabRemaining;
|
|
|
|
uint64_t PageSize = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
|
|
|
|
SizeString = SizeString.trim();
|
|
|
|
|
|
|
|
uint64_t Units = 1024;
|
|
|
|
|
|
|
|
if (SizeString.endswith_lower("kb"))
|
|
|
|
SizeString = SizeString.drop_back(2).rtrim();
|
|
|
|
else if (SizeString.endswith_lower("mb")) {
|
|
|
|
Units = 1024 * 1024;
|
|
|
|
SizeString = SizeString.drop_back(2).rtrim();
|
|
|
|
} else if (SizeString.endswith_lower("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<jitlink::JITLinkMemoryManager> createMemoryManager() {
|
|
|
|
if (!SlabAllocateSizeString.empty()) {
|
|
|
|
auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
|
|
|
|
return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize));
|
|
|
|
}
|
|
|
|
return std::make_unique<jitlink::InProcessMemoryManager>();
|
|
|
|
}
|
|
|
|
|
|
|
|
Session::Session(Triple TT)
|
|
|
|
: MemMgr(createMemoryManager()), ObjLayer(ES, *MemMgr), TT(std::move(TT)) {
|
2019-04-27 06:58:39 +08:00
|
|
|
|
|
|
|
/// 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, const Triple &TT,
|
|
|
|
PassConfiguration &PassConfig) {
|
|
|
|
S.modifyPassConfig(TT, PassConfig);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Session &S;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!NoExec && !TT.isOSWindows())
|
2019-08-15 23:54:37 +08:00
|
|
|
ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
|
2019-07-04 08:05:12 +08:00
|
|
|
InProcessEHFrameRegistrar::getInstance()));
|
2019-04-27 06:58:39 +08:00
|
|
|
|
2019-08-15 23:54:37 +08:00
|
|
|
ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
|
2019-04-27 06:58:39 +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
|
|
|
|
|
|
|
void Session::dumpSessionInfo(raw_ostream &OS) {
|
|
|
|
OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Session::modifyPassConfig(const Triple &FTT,
|
|
|
|
PassConfiguration &PassConfig) {
|
|
|
|
if (!CheckFiles.empty())
|
2019-10-04 11:55:26 +08:00
|
|
|
PassConfig.PostFixupPasses.push_back([this](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
|
|
|
if (TT.getObjectFormat() == Triple::MachO)
|
|
|
|
return registerMachOStubsAndGOT(*this, G);
|
|
|
|
return make_error<StringError>("Unsupported object format for GOT/stub "
|
|
|
|
"registration",
|
|
|
|
inconvertibleErrorCode());
|
|
|
|
});
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
if (ShowLinkGraph)
|
|
|
|
PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
|
|
|
|
outs() << "Link graph 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();
|
|
|
|
});
|
|
|
|
|
|
|
|
if (ShowSizes) {
|
2019-10-04 11:55:26 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-04-22 04:34:19 +08:00
|
|
|
if (ShowRelocatedSectionContents)
|
2019-10-04 11:55:26 +08:00
|
|
|
PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
|
2019-04-22 04:34:19 +08:00
|
|
|
outs() << "Relocated section contents for " << G.getName() << ":\n";
|
|
|
|
dumpSectionContents(outs(), 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
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-04-24 23:15:55 +08:00
|
|
|
Triple getFirstFileTriple() {
|
|
|
|
assert(!InputFiles.empty() && "InputFiles can not be empty");
|
|
|
|
auto ObjBuffer =
|
|
|
|
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
|
|
|
|
auto Obj = ExitOnErr(
|
|
|
|
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
|
|
|
|
return Obj->makeTriple();
|
|
|
|
}
|
|
|
|
|
2019-04-25 01:23:05 +08:00
|
|
|
Error sanitizeArguments(const Session &S) {
|
2019-04-24 23:15:55 +08:00
|
|
|
if (EntryPointName.empty()) {
|
|
|
|
if (S.TT.getObjectFormat() == Triple::MachO)
|
|
|
|
EntryPointName = "_main";
|
|
|
|
else
|
|
|
|
EntryPointName = "main";
|
|
|
|
}
|
2019-04-25 01:23:05 +08:00
|
|
|
|
|
|
|
if (NoExec && !InputArgv.empty())
|
|
|
|
outs() << "Warning: --args passed to -noexec run will be ignored.\n";
|
|
|
|
|
|
|
|
return Error::success();
|
2019-04-24 23:15:55 +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
|
|
|
Error loadProcessSymbols(Session &S) {
|
|
|
|
std::string ErrMsg;
|
|
|
|
if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg))
|
|
|
|
return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
|
|
|
|
|
|
|
|
char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0';
|
2019-04-24 23:15:55 +08:00
|
|
|
auto InternedEntryPointName = S.ES.intern(EntryPointName);
|
|
|
|
auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) {
|
|
|
|
return Name != InternedEntryPointName;
|
|
|
|
};
|
2019-08-14 00:05:18 +08:00
|
|
|
S.ES.getMainJITDylib().addGenerator(
|
2019-04-24 23:15:55 +08:00
|
|
|
ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
|
|
|
|
GlobalPrefix, FilterMainEntryPoint)));
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
Error loadDylibs() {
|
|
|
|
// FIXME: This should all be handled inside DynamicLibrary.
|
|
|
|
for (const auto &Dylib : Dylibs) {
|
|
|
|
if (!sys::fs::is_regular_file(Dylib))
|
|
|
|
return make_error<StringError>("\"" + Dylib + "\" is not a regular file",
|
|
|
|
inconvertibleErrorCode());
|
|
|
|
std::string ErrMsg;
|
|
|
|
if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
|
|
|
|
return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
|
|
|
|
}
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
Error loadObjects(Session &S) {
|
|
|
|
|
|
|
|
std::map<unsigned, JITDylib *> IdxToJLD;
|
|
|
|
|
|
|
|
// First, set up JITDylibs.
|
|
|
|
LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
|
|
|
|
{
|
|
|
|
// Create a "main" JITLinkDylib.
|
|
|
|
auto &MainJD = S.ES.getMainJITDylib();
|
|
|
|
IdxToJLD[0] = &MainJD;
|
|
|
|
S.JDSearchOrder.push_back(&MainJD);
|
|
|
|
LLVM_DEBUG(dbgs() << " 0: " << MainJD.getName() << "\n");
|
|
|
|
|
|
|
|
// Add any extra JITLinkDylibs from the command line.
|
|
|
|
std::string JDNamePrefix("lib");
|
|
|
|
for (auto JLDItr = JITLinkDylibs.begin(), JLDEnd = JITLinkDylibs.end();
|
|
|
|
JLDItr != JLDEnd; ++JLDItr) {
|
|
|
|
auto &JD = S.ES.createJITDylib(JDNamePrefix + *JLDItr);
|
|
|
|
unsigned JDIdx =
|
|
|
|
JITLinkDylibs.getPosition(JLDItr - JITLinkDylibs.begin());
|
|
|
|
IdxToJLD[JDIdx] = &JD;
|
|
|
|
S.JDSearchOrder.push_back(&JD);
|
|
|
|
LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD.getName() << "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set every dylib to link against every other, in command line order.
|
|
|
|
for (auto *JD : S.JDSearchOrder) {
|
|
|
|
JITDylibSearchList O;
|
|
|
|
for (auto *JD2 : S.JDSearchOrder) {
|
|
|
|
if (JD2 == JD)
|
|
|
|
continue;
|
|
|
|
O.push_back(std::make_pair(JD2, false));
|
|
|
|
}
|
|
|
|
JD->setSearchOrder(std::move(O));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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());
|
|
|
|
StringRef InputFile = *InputFileItr;
|
|
|
|
auto &JD = *std::prev(IdxToJLD.lower_bound(InputFileArgIdx))->second;
|
|
|
|
LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile
|
|
|
|
<< "\" to " << JD.getName() << "\n";);
|
|
|
|
auto ObjBuffer =
|
|
|
|
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile)));
|
|
|
|
ExitOnErr(S.ObjLayer.add(JD, std::move(ObjBuffer)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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(IdxToJLD.lower_bound(AbsDefArgIdx))->second;
|
|
|
|
|
|
|
|
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 define \"" + AbsDefStmt +
|
|
|
|
"\"",
|
|
|
|
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] = { StringRef(), Addr };
|
|
|
|
}
|
|
|
|
|
|
|
|
LLVM_DEBUG({
|
|
|
|
dbgs() << "Dylib search order is [ ";
|
|
|
|
for (auto *JD : S.JDSearchOrder)
|
|
|
|
dbgs() << JD->getName() << " ";
|
|
|
|
dbgs() << "]\n";
|
|
|
|
});
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
Error runChecks(Session &S) {
|
|
|
|
|
|
|
|
auto TripleName = S.TT.str();
|
|
|
|
std::string ErrorStr;
|
|
|
|
const Target *TheTarget = TargetRegistry::lookupTarget("", S.TT, ErrorStr);
|
|
|
|
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()));
|
|
|
|
|
|
|
|
std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
|
|
|
|
if (!MAI)
|
|
|
|
ExitOnErr(make_error<StringError>("Unable to create target asm info " +
|
|
|
|
TripleName,
|
|
|
|
inconvertibleErrorCode()));
|
|
|
|
|
|
|
|
MCContext Ctx(MAI.get(), MRI.get(), nullptr);
|
|
|
|
|
|
|
|
std::unique_ptr<MCDisassembler> Disassembler(
|
|
|
|
TheTarget->createMCDisassembler(*STI, Ctx));
|
|
|
|
if (!Disassembler)
|
|
|
|
ExitOnErr(make_error<StringError>("Unable to create disassembler for " +
|
|
|
|
TripleName,
|
|
|
|
inconvertibleErrorCode()));
|
|
|
|
|
|
|
|
std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
|
|
|
|
|
|
|
|
std::unique_ptr<MCInstPrinter> InstPrinter(
|
|
|
|
TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
|
|
|
|
|
|
|
|
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,
|
|
|
|
S.TT.isLittleEndian() ? support::little : support::big,
|
|
|
|
Disassembler.get(), InstPrinter.get(), dbgs());
|
|
|
|
|
|
|
|
for (auto &CheckFile : CheckFiles) {
|
|
|
|
auto CheckerFileBuf =
|
|
|
|
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile)));
|
|
|
|
if (!Checker.checkAllRulesInBuffer("# jitlink-check:", &*CheckerFileBuf))
|
|
|
|
ExitOnErr(make_error<StringError>(
|
|
|
|
"Some checks in " + CheckFile + " failed", inconvertibleErrorCode()));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dumpSessionStats(Session &S) {
|
|
|
|
if (ShowSizes)
|
2019-10-04 11:55:26 +08:00
|
|
|
outs() << "Total size of all blocks before pruning: " << S.SizeBeforePruning
|
|
|
|
<< "\nTotal 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, EntryPointName);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) {
|
|
|
|
assert(EntryPoint.getAddress() && "Entry point address should not be null");
|
|
|
|
|
|
|
|
constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>";
|
2019-08-15 23:54:37 +08:00
|
|
|
auto PNStorage = std::make_unique<char[]>(strlen(JITProgramName) + 1);
|
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
|
|
|
strcpy(PNStorage.get(), JITProgramName);
|
|
|
|
|
|
|
|
std::vector<const char *> EntryPointArgs;
|
|
|
|
EntryPointArgs.push_back(PNStorage.get());
|
2019-04-25 01:23:05 +08:00
|
|
|
for (auto &InputArg : InputArgv)
|
|
|
|
EntryPointArgs.push_back(InputArg.data());
|
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
|
|
|
EntryPointArgs.push_back(nullptr);
|
|
|
|
|
|
|
|
using MainTy = int (*)(int, const char *[]);
|
|
|
|
MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress());
|
|
|
|
|
|
|
|
return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data());
|
|
|
|
}
|
|
|
|
|
2019-09-05 02:38:29 +08:00
|
|
|
struct JITLinkTimers {
|
2019-09-05 04:26:26 +08:00
|
|
|
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};
|
2019-09-05 02:38:29 +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
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
InitLLVM X(argc, argv);
|
|
|
|
|
|
|
|
InitializeAllTargetInfos();
|
|
|
|
InitializeAllTargetMCs();
|
|
|
|
InitializeAllDisassemblers();
|
|
|
|
|
|
|
|
cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool");
|
|
|
|
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
|
|
|
|
|
2019-09-05 02:38:29 +08:00
|
|
|
/// If timers are enabled, create a JITLinkTimers instance.
|
|
|
|
std::unique_ptr<JITLinkTimers> Timers =
|
|
|
|
ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
|
|
|
|
|
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
|
|
|
Session S(getFirstFileTriple());
|
|
|
|
|
2019-04-25 01:23:05 +08:00
|
|
|
ExitOnErr(sanitizeArguments(S));
|
2019-04-24 23:15:55 +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
|
|
|
if (!NoProcessSymbols)
|
|
|
|
ExitOnErr(loadProcessSymbols(S));
|
|
|
|
ExitOnErr(loadDylibs());
|
|
|
|
|
|
|
|
|
2019-08-27 23:51:19 +08:00
|
|
|
{
|
2019-09-05 02:38:29 +08:00
|
|
|
TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
|
2019-08-27 23:51:19 +08:00
|
|
|
ExitOnErr(loadObjects(S));
|
|
|
|
}
|
|
|
|
|
|
|
|
JITEvaluatedSymbol EntryPoint = 0;
|
|
|
|
{
|
2019-09-05 02:38:29 +08:00
|
|
|
TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);
|
2019-08-27 23:51:19 +08:00
|
|
|
EntryPoint = ExitOnErr(getMainEntryPoint(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 (ShowAddrs)
|
|
|
|
S.dumpSessionInfo(outs());
|
|
|
|
|
|
|
|
ExitOnErr(runChecks(S));
|
|
|
|
|
|
|
|
dumpSessionStats(S);
|
|
|
|
|
|
|
|
if (NoExec)
|
|
|
|
return 0;
|
|
|
|
|
2019-08-27 23:51:19 +08:00
|
|
|
int Result = 0;
|
|
|
|
{
|
2019-09-05 02:38:29 +08:00
|
|
|
TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
|
2019-08-27 23:51:19 +08:00
|
|
|
Result = ExitOnErr(runEntryPoint(S, EntryPoint));
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|