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
|
|
|
//===------------- JITLink.cpp - Core Run-time JIT linker APIs ------------===//
|
|
|
|
//
|
2021-08-05 11:16:17 +08:00
|
|
|
// 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
|
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/JITLink/JITLink.h"
|
|
|
|
|
|
|
|
#include "llvm/BinaryFormat/Magic.h"
|
2020-05-22 12:44:00 +08:00
|
|
|
#include "llvm/ExecutionEngine/JITLink/ELF.h"
|
2019-04-22 11:03:09 +08:00
|
|
|
#include "llvm/ExecutionEngine/JITLink/MachO.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/Format.h"
|
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::object;
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "jitlink"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
enum JITLinkErrorCode { GenericJITLinkError = 1 };
|
|
|
|
|
|
|
|
// FIXME: This class is only here to support the transition to llvm::Error. It
|
|
|
|
// will be removed once this transition is complete. Clients should prefer to
|
|
|
|
// deal with the Error value directly, rather than converting to error_code.
|
|
|
|
class JITLinkerErrorCategory : public std::error_category {
|
|
|
|
public:
|
|
|
|
const char *name() const noexcept override { return "runtimedyld"; }
|
|
|
|
|
|
|
|
std::string message(int Condition) const override {
|
|
|
|
switch (static_cast<JITLinkErrorCode>(Condition)) {
|
|
|
|
case GenericJITLinkError:
|
|
|
|
return "Generic JITLink error";
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unrecognized JITLinkErrorCode");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static ManagedStatic<JITLinkerErrorCategory> JITLinkerErrorCategory;
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace jitlink {
|
|
|
|
|
|
|
|
char JITLinkError::ID = 0;
|
|
|
|
|
2021-03-18 12:19:13 +08:00
|
|
|
void JITLinkError::log(raw_ostream &OS) const { OS << ErrMsg; }
|
Initial implementation of JITLink - A replacement for RuntimeDyld.
Summary:
JITLink is a jit-linker that performs the same high-level task as RuntimeDyld:
it parses relocatable object files and makes their contents runnable in a target
process.
JITLink aims to improve on RuntimeDyld in several ways:
(1) A clear design intended to maximize code-sharing while minimizing coupling.
RuntimeDyld has been developed in an ad-hoc fashion for a number of years and
this had led to intermingling of code for multiple architectures (e.g. in
RuntimeDyldELF::processRelocationRef) in a way that makes the code more
difficult to read, reason about, extend. JITLink is designed to isolate
format and architecture specific code, while still sharing generic code.
(2) Support for native code models.
RuntimeDyld required the use of large code models (where calls to external
functions are made indirectly via registers) for many of platforms due to its
restrictive model for stub generation (one "stub" per symbol). JITLink allows
arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be
added naturally.
(3) Native support for asynchronous linking.
JITLink uses asynchronous calls for symbol resolution and finalization: these
callbacks are passed a continuation function that they must call to complete the
linker's work. This allows for cleaner interoperation with the new concurrent
ORC JIT APIs, while still being easily implementable in synchronous style if
asynchrony is not needed.
To maximise sharing, the design has a hierarchy of common code:
(1) Generic atom-graph data structure and algorithms (e.g. dead stripping and
| memory allocation) that are intended to be shared by all architectures.
|
+ -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to
| atom-graph parsing.
|
+ -- (3) Architecture specific code that uses (1) and (2). E.g.
JITLinkerMachO_x86_64, which adds x86-64 specific relocation
support to (2) to build and patch up the atom graph.
To support asynchronous symbol resolution and finalization, the callbacks for
these operations take continuations as arguments:
using JITLinkAsyncLookupContinuation =
std::function<void(Expected<AsyncLookupResult> LR)>;
using JITLinkAsyncLookupFunction =
std::function<void(const DenseSet<StringRef> &Symbols,
JITLinkAsyncLookupContinuation LookupContinuation)>;
using FinalizeContinuation = std::function<void(Error)>;
virtual void finalizeAsync(FinalizeContinuation OnFinalize);
In addition to its headline features, JITLink also makes other improvements:
- Dead stripping support: symbols that are not used (e.g. redundant ODR
definitions) are discarded, and take up no memory in the target process
(In contrast, RuntimeDyld supported pointer equality for weak definitions,
but the redundant definitions stayed resident in memory).
- Improved exception handling support. JITLink provides a much more extensive
eh-frame parser than RuntimeDyld, and is able to correctly fix up many
eh-frame sections that RuntimeDyld currently (silently) fails on.
- More extensive validation and error handling throughout.
This initial patch supports linking MachO/x86-64 only. Work on support for
other architectures and formats will happen in-tree.
Differential Revision: https://reviews.llvm.org/D58704
llvm-svn: 358818
2019-04-21 01:10:34 +08:00
|
|
|
|
|
|
|
std::error_code JITLinkError::convertToErrorCode() const {
|
|
|
|
return std::error_code(GenericJITLinkError, *JITLinkerErrorCategory);
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
const char *getGenericEdgeKindName(Edge::Kind K) {
|
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
|
|
|
switch (K) {
|
|
|
|
case Edge::Invalid:
|
|
|
|
return "INVALID RELOCATION";
|
|
|
|
case Edge::KeepAlive:
|
|
|
|
return "Keep-Alive";
|
|
|
|
default:
|
2021-01-22 17:04:18 +08:00
|
|
|
return "<Unrecognized edge kind>";
|
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-10-04 11:55:26 +08:00
|
|
|
const char *getLinkageName(Linkage L) {
|
|
|
|
switch (L) {
|
|
|
|
case Linkage::Strong:
|
|
|
|
return "strong";
|
|
|
|
case Linkage::Weak:
|
|
|
|
return "weak";
|
|
|
|
}
|
2019-10-04 19:24:51 +08:00
|
|
|
llvm_unreachable("Unrecognized llvm.jitlink.Linkage enum");
|
2019-10-04 11:55:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *getScopeName(Scope S) {
|
|
|
|
switch (S) {
|
|
|
|
case Scope::Default:
|
|
|
|
return "default";
|
|
|
|
case Scope::Hidden:
|
|
|
|
return "hidden";
|
|
|
|
case Scope::Local:
|
|
|
|
return "local";
|
|
|
|
}
|
2019-10-04 19:24:51 +08:00
|
|
|
llvm_unreachable("Unrecognized llvm.jitlink.Scope enum");
|
2019-10-04 11:55:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &operator<<(raw_ostream &OS, const Block &B) {
|
2022-01-06 13:03:06 +08:00
|
|
|
return OS << B.getAddress() << " -- " << (B.getAddress() + B.getSize())
|
|
|
|
<< ": "
|
2021-05-12 07:04:00 +08:00
|
|
|
<< "size = " << formatv("{0:x8}", B.getSize()) << ", "
|
2019-10-04 11:55:26 +08:00
|
|
|
<< (B.isZeroFill() ? "zero-fill" : "content")
|
|
|
|
<< ", align = " << B.getAlignment()
|
|
|
|
<< ", align-ofs = " << B.getAlignmentOffset()
|
|
|
|
<< ", section = " << B.getSection().getName();
|
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &operator<<(raw_ostream &OS, const Symbol &Sym) {
|
2022-01-06 13:03:06 +08:00
|
|
|
OS << Sym.getAddress() << " (" << (Sym.isDefined() ? "block" : "addressable")
|
|
|
|
<< " + " << formatv("{0:x8}", Sym.getOffset())
|
2021-05-12 05:09:49 +08:00
|
|
|
<< "): size: " << formatv("{0:x8}", Sym.getSize())
|
|
|
|
<< ", linkage: " << formatv("{0:6}", getLinkageName(Sym.getLinkage()))
|
|
|
|
<< ", scope: " << formatv("{0:8}", getScopeName(Sym.getScope())) << ", "
|
|
|
|
<< (Sym.isLive() ? "live" : "dead") << " - "
|
|
|
|
<< (Sym.hasName() ? Sym.getName() : "<anonymous symbol>");
|
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 OS;
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
void printEdge(raw_ostream &OS, const Block &B, const Edge &E,
|
Initial implementation of JITLink - A replacement for RuntimeDyld.
Summary:
JITLink is a jit-linker that performs the same high-level task as RuntimeDyld:
it parses relocatable object files and makes their contents runnable in a target
process.
JITLink aims to improve on RuntimeDyld in several ways:
(1) A clear design intended to maximize code-sharing while minimizing coupling.
RuntimeDyld has been developed in an ad-hoc fashion for a number of years and
this had led to intermingling of code for multiple architectures (e.g. in
RuntimeDyldELF::processRelocationRef) in a way that makes the code more
difficult to read, reason about, extend. JITLink is designed to isolate
format and architecture specific code, while still sharing generic code.
(2) Support for native code models.
RuntimeDyld required the use of large code models (where calls to external
functions are made indirectly via registers) for many of platforms due to its
restrictive model for stub generation (one "stub" per symbol). JITLink allows
arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be
added naturally.
(3) Native support for asynchronous linking.
JITLink uses asynchronous calls for symbol resolution and finalization: these
callbacks are passed a continuation function that they must call to complete the
linker's work. This allows for cleaner interoperation with the new concurrent
ORC JIT APIs, while still being easily implementable in synchronous style if
asynchrony is not needed.
To maximise sharing, the design has a hierarchy of common code:
(1) Generic atom-graph data structure and algorithms (e.g. dead stripping and
| memory allocation) that are intended to be shared by all architectures.
|
+ -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to
| atom-graph parsing.
|
+ -- (3) Architecture specific code that uses (1) and (2). E.g.
JITLinkerMachO_x86_64, which adds x86-64 specific relocation
support to (2) to build and patch up the atom graph.
To support asynchronous symbol resolution and finalization, the callbacks for
these operations take continuations as arguments:
using JITLinkAsyncLookupContinuation =
std::function<void(Expected<AsyncLookupResult> LR)>;
using JITLinkAsyncLookupFunction =
std::function<void(const DenseSet<StringRef> &Symbols,
JITLinkAsyncLookupContinuation LookupContinuation)>;
using FinalizeContinuation = std::function<void(Error)>;
virtual void finalizeAsync(FinalizeContinuation OnFinalize);
In addition to its headline features, JITLink also makes other improvements:
- Dead stripping support: symbols that are not used (e.g. redundant ODR
definitions) are discarded, and take up no memory in the target process
(In contrast, RuntimeDyld supported pointer equality for weak definitions,
but the redundant definitions stayed resident in memory).
- Improved exception handling support. JITLink provides a much more extensive
eh-frame parser than RuntimeDyld, and is able to correctly fix up many
eh-frame sections that RuntimeDyld currently (silently) fails on.
- More extensive validation and error handling throughout.
This initial patch supports linking MachO/x86-64 only. Work on support for
other architectures and formats will happen in-tree.
Differential Revision: https://reviews.llvm.org/D58704
llvm-svn: 358818
2019-04-21 01:10:34 +08:00
|
|
|
StringRef EdgeKindName) {
|
2022-01-06 13:03:06 +08:00
|
|
|
OS << "edge@" << B.getAddress() + E.getOffset() << ": " << B.getAddress()
|
|
|
|
<< " + " << formatv("{0:x}", E.getOffset()) << " -- " << EdgeKindName
|
|
|
|
<< " -> ";
|
2020-09-14 05:22:20 +08:00
|
|
|
|
|
|
|
auto &TargetSym = E.getTarget();
|
|
|
|
if (TargetSym.hasName())
|
|
|
|
OS << TargetSym.getName();
|
|
|
|
else {
|
|
|
|
auto &TargetBlock = TargetSym.getBlock();
|
|
|
|
auto &TargetSec = TargetBlock.getSection();
|
2022-01-06 13:03:06 +08:00
|
|
|
orc::ExecutorAddr SecAddress(~uint64_t(0));
|
2020-09-14 05:22:20 +08:00
|
|
|
for (auto *B : TargetSec.blocks())
|
|
|
|
if (B->getAddress() < SecAddress)
|
|
|
|
SecAddress = B->getAddress();
|
|
|
|
|
2022-01-06 13:03:06 +08:00
|
|
|
orc::ExecutorAddrDiff SecDelta = TargetSym.getAddress() - SecAddress;
|
|
|
|
OS << TargetSym.getAddress() << " (section " << TargetSec.getName();
|
2020-09-14 05:22:20 +08:00
|
|
|
if (SecDelta)
|
|
|
|
OS << " + " << formatv("{0:x}", SecDelta);
|
2022-01-06 13:03:06 +08:00
|
|
|
OS << " / block " << TargetBlock.getAddress();
|
2020-09-14 05:22:20 +08:00
|
|
|
if (TargetSym.getOffset())
|
|
|
|
OS << " + " << formatv("{0:x}", TargetSym.getOffset());
|
|
|
|
OS << ")";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (E.getAddend() != 0)
|
|
|
|
OS << " + " << E.getAddend();
|
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
|
|
|
}
|
|
|
|
|
|
|
|
Section::~Section() {
|
2019-10-04 11:55:26 +08:00
|
|
|
for (auto *Sym : Symbols)
|
|
|
|
Sym->~Symbol();
|
2019-10-04 13:24:40 +08:00
|
|
|
for (auto *B : Blocks)
|
|
|
|
B->~Block();
|
|
|
|
}
|
|
|
|
|
2019-10-31 03:26:15 +08:00
|
|
|
Block &LinkGraph::splitBlock(Block &B, size_t SplitIndex,
|
|
|
|
SplitBlockCache *Cache) {
|
|
|
|
|
|
|
|
assert(SplitIndex > 0 && "splitBlock can not be called with SplitIndex == 0");
|
|
|
|
|
|
|
|
// If the split point covers all of B then just return B.
|
|
|
|
if (SplitIndex == B.getSize())
|
|
|
|
return B;
|
|
|
|
|
|
|
|
assert(SplitIndex < B.getSize() && "SplitIndex out of range");
|
|
|
|
|
|
|
|
// Create the new block covering [ 0, SplitIndex ).
|
|
|
|
auto &NewBlock =
|
|
|
|
B.isZeroFill()
|
|
|
|
? createZeroFillBlock(B.getSection(), SplitIndex, B.getAddress(),
|
|
|
|
B.getAlignment(), B.getAlignmentOffset())
|
|
|
|
: createContentBlock(
|
2021-03-31 11:56:03 +08:00
|
|
|
B.getSection(), B.getContent().slice(0, SplitIndex),
|
2019-10-31 03:26:15 +08:00
|
|
|
B.getAddress(), B.getAlignment(), B.getAlignmentOffset());
|
|
|
|
|
|
|
|
// Modify B to cover [ SplitIndex, B.size() ).
|
|
|
|
B.setAddress(B.getAddress() + SplitIndex);
|
2021-03-31 11:56:03 +08:00
|
|
|
B.setContent(B.getContent().slice(SplitIndex));
|
2019-10-31 03:26:15 +08:00
|
|
|
B.setAlignmentOffset((B.getAlignmentOffset() + SplitIndex) %
|
|
|
|
B.getAlignment());
|
|
|
|
|
|
|
|
// Handle edge transfer/update.
|
|
|
|
{
|
|
|
|
// Copy edges to NewBlock (recording their iterators so that we can remove
|
|
|
|
// them from B), and update of Edges remaining on B.
|
|
|
|
std::vector<Block::edge_iterator> EdgesToRemove;
|
2020-04-23 01:18:44 +08:00
|
|
|
for (auto I = B.edges().begin(); I != B.edges().end();) {
|
2019-10-31 03:26:15 +08:00
|
|
|
if (I->getOffset() < SplitIndex) {
|
|
|
|
NewBlock.addEdge(*I);
|
2020-04-23 01:18:44 +08:00
|
|
|
I = B.removeEdge(I);
|
|
|
|
} else {
|
2019-10-31 03:26:15 +08:00
|
|
|
I->setOffset(I->getOffset() - SplitIndex);
|
2020-04-23 01:18:44 +08:00
|
|
|
++I;
|
|
|
|
}
|
2019-10-31 03:26:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle symbol transfer/update.
|
|
|
|
{
|
|
|
|
// Initialize the symbols cache if necessary.
|
|
|
|
SplitBlockCache LocalBlockSymbolsCache;
|
|
|
|
if (!Cache)
|
|
|
|
Cache = &LocalBlockSymbolsCache;
|
|
|
|
if (*Cache == None) {
|
|
|
|
*Cache = SplitBlockCache::value_type();
|
|
|
|
for (auto *Sym : B.getSection().symbols())
|
|
|
|
if (&Sym->getBlock() == &B)
|
|
|
|
(*Cache)->push_back(Sym);
|
|
|
|
|
|
|
|
llvm::sort(**Cache, [](const Symbol *LHS, const Symbol *RHS) {
|
|
|
|
return LHS->getOffset() > RHS->getOffset();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
auto &BlockSymbols = **Cache;
|
|
|
|
|
|
|
|
// Transfer all symbols with offset less than SplitIndex to NewBlock.
|
|
|
|
while (!BlockSymbols.empty() &&
|
|
|
|
BlockSymbols.back()->getOffset() < SplitIndex) {
|
2021-11-16 05:55:06 +08:00
|
|
|
auto *Sym = BlockSymbols.back();
|
|
|
|
// If the symbol extends beyond the split, update the size to be within
|
|
|
|
// the new block.
|
|
|
|
if (Sym->getOffset() + Sym->getSize() > SplitIndex)
|
|
|
|
Sym->setSize(SplitIndex - Sym->getOffset());
|
|
|
|
Sym->setBlock(NewBlock);
|
2019-10-31 03:26:15 +08:00
|
|
|
BlockSymbols.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update offsets for all remaining symbols in B.
|
|
|
|
for (auto *Sym : BlockSymbols)
|
|
|
|
Sym->setOffset(Sym->getOffset() - SplitIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewBlock;
|
|
|
|
}
|
|
|
|
|
2021-03-16 05:56:29 +08:00
|
|
|
void LinkGraph::dump(raw_ostream &OS) {
|
2021-05-12 05:09:49 +08:00
|
|
|
DenseMap<Block *, std::vector<Symbol *>> BlockSymbols;
|
|
|
|
|
|
|
|
// Map from blocks to the symbols pointing at them.
|
|
|
|
for (auto *Sym : defined_symbols())
|
|
|
|
BlockSymbols[&Sym->getBlock()].push_back(Sym);
|
|
|
|
|
|
|
|
// For each block, sort its symbols by something approximating
|
|
|
|
// relevance.
|
|
|
|
for (auto &KV : BlockSymbols)
|
|
|
|
llvm::sort(KV.second, [](const Symbol *LHS, const Symbol *RHS) {
|
2021-05-17 01:09:35 +08:00
|
|
|
if (LHS->getOffset() != RHS->getOffset())
|
|
|
|
return LHS->getOffset() < RHS->getOffset();
|
|
|
|
if (LHS->getLinkage() != RHS->getLinkage())
|
|
|
|
return LHS->getLinkage() < RHS->getLinkage();
|
|
|
|
if (LHS->getScope() != RHS->getScope())
|
|
|
|
return LHS->getScope() < RHS->getScope();
|
2021-05-12 05:09:49 +08:00
|
|
|
if (LHS->hasName()) {
|
|
|
|
if (!RHS->hasName())
|
|
|
|
return true;
|
|
|
|
return LHS->getName() < RHS->getName();
|
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
|
|
|
}
|
2021-05-12 05:09:49 +08:00
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
for (auto &Sec : sections()) {
|
|
|
|
OS << "section " << Sec.getName() << ":\n\n";
|
|
|
|
|
|
|
|
std::vector<Block *> SortedBlocks;
|
|
|
|
llvm::copy(Sec.blocks(), std::back_inserter(SortedBlocks));
|
|
|
|
llvm::sort(SortedBlocks, [](const Block *LHS, const Block *RHS) {
|
|
|
|
return LHS->getAddress() < RHS->getAddress();
|
|
|
|
});
|
|
|
|
|
|
|
|
for (auto *B : SortedBlocks) {
|
2022-01-06 13:03:06 +08:00
|
|
|
OS << " block " << B->getAddress()
|
2021-05-12 05:09:49 +08:00
|
|
|
<< " size = " << formatv("{0:x8}", B->getSize())
|
|
|
|
<< ", align = " << B->getAlignment()
|
2021-07-20 18:28:29 +08:00
|
|
|
<< ", alignment-offset = " << B->getAlignmentOffset();
|
|
|
|
if (B->isZeroFill())
|
|
|
|
OS << ", zero-fill";
|
|
|
|
OS << "\n";
|
2021-05-12 05:09:49 +08:00
|
|
|
|
|
|
|
auto BlockSymsI = BlockSymbols.find(B);
|
|
|
|
if (BlockSymsI != BlockSymbols.end()) {
|
|
|
|
OS << " symbols:\n";
|
|
|
|
auto &Syms = BlockSymsI->second;
|
|
|
|
for (auto *Sym : Syms)
|
|
|
|
OS << " " << *Sym << "\n";
|
|
|
|
} else
|
|
|
|
OS << " no symbols\n";
|
|
|
|
|
|
|
|
if (!B->edges_empty()) {
|
|
|
|
OS << " edges:\n";
|
|
|
|
std::vector<Edge> SortedEdges;
|
|
|
|
llvm::copy(B->edges(), std::back_inserter(SortedEdges));
|
|
|
|
llvm::sort(SortedEdges, [](const Edge &LHS, const Edge &RHS) {
|
|
|
|
return LHS.getOffset() < RHS.getOffset();
|
|
|
|
});
|
|
|
|
for (auto &E : SortedEdges) {
|
2022-01-06 13:03:06 +08:00
|
|
|
OS << " " << B->getFixupAddress(E) << " (block + "
|
|
|
|
<< formatv("{0:x8}", E.getOffset()) << "), addend = ";
|
2021-05-12 05:09:49 +08:00
|
|
|
if (E.getAddend() >= 0)
|
|
|
|
OS << formatv("+{0:x8}", E.getAddend());
|
|
|
|
else
|
|
|
|
OS << formatv("-{0:x8}", -E.getAddend());
|
|
|
|
OS << ", kind = " << getEdgeKindName(E.getKind()) << ", target = ";
|
|
|
|
if (E.getTarget().hasName())
|
|
|
|
OS << E.getTarget().getName();
|
|
|
|
else
|
|
|
|
OS << "addressable@"
|
|
|
|
<< formatv("{0:x16}", E.getTarget().getAddress()) << "+"
|
|
|
|
<< formatv("{0:x8}", E.getTarget().getOffset());
|
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
OS << " no edges\n";
|
|
|
|
OS << "\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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
OS << "Absolute symbols:\n";
|
2021-05-12 05:09:49 +08:00
|
|
|
if (!llvm::empty(absolute_symbols())) {
|
|
|
|
for (auto *Sym : absolute_symbols())
|
2022-01-06 13:03:06 +08:00
|
|
|
OS << " " << Sym->getAddress() << ": " << *Sym << "\n";
|
2021-05-12 05:09:49 +08:00
|
|
|
} else
|
|
|
|
OS << " none\n";
|
|
|
|
|
|
|
|
OS << "\nExternal symbols:\n";
|
|
|
|
if (!llvm::empty(external_symbols())) {
|
|
|
|
for (auto *Sym : external_symbols())
|
2022-01-06 13:03:06 +08:00
|
|
|
OS << " " << Sym->getAddress() << ": " << *Sym << "\n";
|
2021-05-12 05:09:49 +08:00
|
|
|
} else
|
|
|
|
OS << " none\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
|
|
|
}
|
|
|
|
|
2019-11-26 13:57:27 +08:00
|
|
|
raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupFlags &LF) {
|
|
|
|
switch (LF) {
|
|
|
|
case SymbolLookupFlags::RequiredSymbol:
|
|
|
|
return OS << "RequiredSymbol";
|
|
|
|
case SymbolLookupFlags::WeaklyReferencedSymbol:
|
|
|
|
return OS << "WeaklyReferencedSymbol";
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unrecognized lookup flags");
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
void JITLinkAsyncLookupContinuation::anchor() {}
|
|
|
|
|
2022-02-07 14:18:35 +08:00
|
|
|
JITLinkContext::~JITLinkContext() = default;
|
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
|
|
|
|
|
|
|
bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
LinkGraphPassFunction JITLinkContext::getMarkLivePass(const Triple &TT) const {
|
|
|
|
return LinkGraphPassFunction();
|
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
|
|
|
}
|
|
|
|
|
2021-03-13 09:02:01 +08:00
|
|
|
Error JITLinkContext::modifyPassConfig(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
|
|
|
PassConfiguration &Config) {
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2019-10-04 11:55:26 +08:00
|
|
|
Error markAllSymbolsLive(LinkGraph &G) {
|
|
|
|
for (auto *Sym : G.defined_symbols())
|
|
|
|
Sym->setLive(true);
|
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();
|
|
|
|
}
|
|
|
|
|
2021-03-18 12:19:13 +08:00
|
|
|
Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B,
|
|
|
|
const Edge &E) {
|
2021-03-16 05:56:29 +08:00
|
|
|
std::string ErrMsg;
|
|
|
|
{
|
|
|
|
raw_string_ostream ErrStream(ErrMsg);
|
2021-03-18 12:19:13 +08:00
|
|
|
Section &Sec = B.getSection();
|
|
|
|
ErrStream << "In graph " << G.getName() << ", section " << Sec.getName()
|
|
|
|
<< ": relocation target ";
|
2022-01-12 12:41:11 +08:00
|
|
|
if (E.getTarget().hasName()) {
|
|
|
|
ErrStream << "\"" << E.getTarget().getName() << "\"";
|
|
|
|
} else
|
|
|
|
ErrStream << E.getTarget().getBlock().getSection().getName() << " + "
|
|
|
|
<< formatv("{0:x}", E.getOffset());
|
|
|
|
ErrStream << " at address " << formatv("{0:x}", E.getTarget().getAddress())
|
|
|
|
<< " is out of range of " << G.getEdgeKindName(E.getKind())
|
2021-03-18 12:19:13 +08:00
|
|
|
<< " fixup at " << formatv("{0:x}", B.getFixupAddress(E)) << " (";
|
|
|
|
|
|
|
|
Symbol *BestSymbolForBlock = nullptr;
|
|
|
|
for (auto *Sym : Sec.symbols())
|
|
|
|
if (&Sym->getBlock() == &B && Sym->hasName() && Sym->getOffset() == 0 &&
|
|
|
|
(!BestSymbolForBlock ||
|
|
|
|
Sym->getScope() < BestSymbolForBlock->getScope() ||
|
|
|
|
Sym->getLinkage() < BestSymbolForBlock->getLinkage()))
|
|
|
|
BestSymbolForBlock = Sym;
|
|
|
|
|
|
|
|
if (BestSymbolForBlock)
|
|
|
|
ErrStream << BestSymbolForBlock->getName() << ", ";
|
|
|
|
else
|
|
|
|
ErrStream << "<anonymous block> @ ";
|
|
|
|
|
|
|
|
ErrStream << formatv("{0:x}", B.getAddress()) << " + "
|
|
|
|
<< formatv("{0:x}", E.getOffset()) << ")";
|
2021-03-16 05:56:29 +08:00
|
|
|
}
|
|
|
|
return make_error<JITLinkError>(std::move(ErrMsg));
|
|
|
|
}
|
|
|
|
|
2022-03-09 22:13:28 +08:00
|
|
|
Error makeAlignmentError(llvm::orc::ExecutorAddr Loc, uint64_t Value, int N,
|
|
|
|
const Edge &E) {
|
|
|
|
return make_error<JITLinkError>("0x" + llvm::utohexstr(Loc.getValue()) +
|
|
|
|
" improper alignment for relocation " +
|
|
|
|
formatv("{0:d}", E.getKind()) + ": 0x" +
|
|
|
|
llvm::utohexstr(Value) +
|
|
|
|
" is not aligned to " + Twine(N) + " bytes");
|
|
|
|
}
|
|
|
|
|
2020-12-16 09:18:30 +08:00
|
|
|
Expected<std::unique_ptr<LinkGraph>>
|
|
|
|
createLinkGraphFromObject(MemoryBufferRef ObjectBuffer) {
|
|
|
|
auto Magic = identify_magic(ObjectBuffer.getBuffer());
|
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
|
|
|
switch (Magic) {
|
|
|
|
case file_magic::macho_object:
|
2021-02-12 21:58:57 +08:00
|
|
|
return createLinkGraphFromMachOObject(ObjectBuffer);
|
2020-05-22 12:44:00 +08:00
|
|
|
case file_magic::elf_relocatable:
|
2021-02-12 21:58:57 +08:00
|
|
|
return createLinkGraphFromELFObject(ObjectBuffer);
|
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
|
|
|
default:
|
2020-12-16 09:18:30 +08:00
|
|
|
return make_error<JITLinkError>("Unsupported file format");
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx) {
|
|
|
|
switch (G->getTargetTriple().getObjectFormat()) {
|
|
|
|
case Triple::MachO:
|
|
|
|
return link_MachO(std::move(G), std::move(Ctx));
|
|
|
|
case Triple::ELF:
|
|
|
|
return link_ELF(std::move(G), std::move(Ctx));
|
|
|
|
default:
|
|
|
|
Ctx->notifyFailed(make_error<JITLinkError>("Unsupported object format"));
|
Initial implementation of JITLink - A replacement for RuntimeDyld.
Summary:
JITLink is a jit-linker that performs the same high-level task as RuntimeDyld:
it parses relocatable object files and makes their contents runnable in a target
process.
JITLink aims to improve on RuntimeDyld in several ways:
(1) A clear design intended to maximize code-sharing while minimizing coupling.
RuntimeDyld has been developed in an ad-hoc fashion for a number of years and
this had led to intermingling of code for multiple architectures (e.g. in
RuntimeDyldELF::processRelocationRef) in a way that makes the code more
difficult to read, reason about, extend. JITLink is designed to isolate
format and architecture specific code, while still sharing generic code.
(2) Support for native code models.
RuntimeDyld required the use of large code models (where calls to external
functions are made indirectly via registers) for many of platforms due to its
restrictive model for stub generation (one "stub" per symbol). JITLink allows
arbitrary mutation of the atom graph, allowing both GOT and PLT atoms to be
added naturally.
(3) Native support for asynchronous linking.
JITLink uses asynchronous calls for symbol resolution and finalization: these
callbacks are passed a continuation function that they must call to complete the
linker's work. This allows for cleaner interoperation with the new concurrent
ORC JIT APIs, while still being easily implementable in synchronous style if
asynchrony is not needed.
To maximise sharing, the design has a hierarchy of common code:
(1) Generic atom-graph data structure and algorithms (e.g. dead stripping and
| memory allocation) that are intended to be shared by all architectures.
|
+ -- (2) Shared per-format code that utilizes (1), e.g. Generic MachO to
| atom-graph parsing.
|
+ -- (3) Architecture specific code that uses (1) and (2). E.g.
JITLinkerMachO_x86_64, which adds x86-64 specific relocation
support to (2) to build and patch up the atom graph.
To support asynchronous symbol resolution and finalization, the callbacks for
these operations take continuations as arguments:
using JITLinkAsyncLookupContinuation =
std::function<void(Expected<AsyncLookupResult> LR)>;
using JITLinkAsyncLookupFunction =
std::function<void(const DenseSet<StringRef> &Symbols,
JITLinkAsyncLookupContinuation LookupContinuation)>;
using FinalizeContinuation = std::function<void(Error)>;
virtual void finalizeAsync(FinalizeContinuation OnFinalize);
In addition to its headline features, JITLink also makes other improvements:
- Dead stripping support: symbols that are not used (e.g. redundant ODR
definitions) are discarded, and take up no memory in the target process
(In contrast, RuntimeDyld supported pointer equality for weak definitions,
but the redundant definitions stayed resident in memory).
- Improved exception handling support. JITLink provides a much more extensive
eh-frame parser than RuntimeDyld, and is able to correctly fix up many
eh-frame sections that RuntimeDyld currently (silently) fails on.
- More extensive validation and error handling throughout.
This initial patch supports linking MachO/x86-64 only. Work on support for
other architectures and formats will happen in-tree.
Differential Revision: https://reviews.llvm.org/D58704
llvm-svn: 358818
2019-04-21 01:10:34 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace jitlink
|
|
|
|
} // end namespace llvm
|