Skip to content

Commit 11c8dfa

Browse files
committed
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
1 parent 3980d1c commit 11c8dfa

40 files changed

+6035
-78
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h

Lines changed: 919 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----- JITLink_EHFrameSupport.h - JITLink eh-frame utils ----*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// EHFrame registration support for JITLink.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORT_H
14+
#define LLVM_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORT_H
15+
16+
#include "llvm/ADT/Triple.h"
17+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
18+
#include "llvm/ExecutionEngine/JITSymbol.h"
19+
#include "llvm/Support/Error.h"
20+
21+
namespace llvm {
22+
namespace jitlink {
23+
24+
/// Registers all FDEs in the given eh-frame section with the current process.
25+
Error registerEHFrameSection(const void *EHFrameSectionAddr);
26+
27+
/// Deregisters all FDEs in the given eh-frame section with the current process.
28+
Error deregisterEHFrameSection(const void *EHFrameSectionAddr);
29+
30+
/// Creates a pass that records the address of the EH frame section. If no
31+
/// eh-frame section is found, it will set EHFrameAddr to zero.
32+
///
33+
/// Authors of JITLinkContexts can use this function to register a post-fixup
34+
/// pass that records the address of the eh-frame section. This address can
35+
/// be used after finalization to register and deregister the frame.
36+
AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
37+
JITTargetAddress &EHFrameAddr);
38+
39+
} // end namespace jitlink
40+
} // end namespace llvm
41+
42+
#endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORT_H
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===--- JITLink_MachO.h - Generic JIT link function for MachO --*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Generic jit-link functions for MachO.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_H
14+
#define LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_H
15+
16+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
17+
18+
namespace llvm {
19+
namespace jitlink {
20+
21+
/// jit-link the given ObjBuffer, which must be a MachO object file.
22+
///
23+
/// Uses conservative defaults for GOT and stub handling based on the target
24+
/// platform.
25+
void jitLink_MachO(std::unique_ptr<JITLinkContext> Ctx);
26+
27+
} // end namespace jitlink
28+
} // end namespace llvm
29+
30+
#endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_X86_64_H
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===--- JITLink_MachO_x86_64.h - JIT link functions for MachO --*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// jit-link functions for MachO/x86-64.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_X86_64_H
14+
#define LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_X86_64_H
15+
16+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
17+
18+
namespace llvm {
19+
namespace jitlink {
20+
21+
namespace MachO_x86_64_Edges {
22+
23+
enum MachOX86RelocationKind : Edge::Kind {
24+
Branch32 = Edge::FirstRelocation,
25+
Pointer64,
26+
Pointer64Anon,
27+
PCRel32,
28+
PCRel32Minus1,
29+
PCRel32Minus2,
30+
PCRel32Minus4,
31+
PCRel32Anon,
32+
PCRel32Minus1Anon,
33+
PCRel32Minus2Anon,
34+
PCRel32Minus4Anon,
35+
PCRel32GOTLoad,
36+
PCRel32GOT,
37+
PCRel32TLV,
38+
Delta32,
39+
Delta64,
40+
NegDelta32,
41+
NegDelta64,
42+
};
43+
44+
} // namespace MachO_x86_64_Edges
45+
46+
/// jit-link the given object buffer, which must be a MachO x86-64 object file.
47+
///
48+
/// If PrePrunePasses is empty then a default mark-live pass will be inserted
49+
/// that will mark all exported atoms live. If PrePrunePasses is not empty, the
50+
/// caller is responsible for including a pass to mark atoms as live.
51+
///
52+
/// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
53+
/// be inserted. If PostPrunePasses is not empty then the caller is responsible
54+
/// for including a pass to insert GOT and stub edges.
55+
void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx);
56+
57+
/// Return the string name of the given MachO x86-64 edge kind.
58+
StringRef getMachOX86RelocationKindName(Edge::Kind R);
59+
60+
} // end namespace jitlink
61+
} // end namespace llvm
62+
63+
#endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_X86_64_H

llvm/include/llvm/ExecutionEngine/JITSymbol.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ template <typename T> JITTargetAddress pointerToJITTargetAddress(T *Ptr) {
5555
class JITSymbolFlags {
5656
public:
5757
using UnderlyingType = uint8_t;
58-
using TargetFlagsType = uint64_t;
58+
using TargetFlagsType = uint8_t;
5959

6060
enum FlagNames : UnderlyingType {
6161
None = 0,
@@ -83,7 +83,7 @@ class JITSymbolFlags {
8383
/// Construct a JITSymbolFlags instance from the given flags and target
8484
/// flags.
8585
JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
86-
: Flags(Flags), TargetFlags(TargetFlags) {}
86+
: TargetFlags(TargetFlags), Flags(Flags) {}
8787

8888
/// Implicitly convert to bool. Returs true if any flag is set.
8989
explicit operator bool() const { return Flags != None || TargetFlags != 0; }
@@ -167,8 +167,8 @@ class JITSymbolFlags {
167167
fromObjectSymbol(const object::SymbolRef &Symbol);
168168

169169
private:
170-
FlagNames Flags = None;
171170
TargetFlagsType TargetFlags = 0;
171+
FlagNames Flags = None;
172172
};
173173

174174
inline JITSymbolFlags operator&(const JITSymbolFlags &LHS,

llvm/include/llvm/ExecutionEngine/Orc/Core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class MaterializationResponsibility {
174174
/// Note: The returned flags may have transient flags (Lazy, Materializing)
175175
/// set. These should be stripped with JITSymbolFlags::stripTransientFlags
176176
/// before using.
177-
const SymbolFlagsMap &getSymbols() { return SymbolFlags; }
177+
const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
178178

179179
/// Returns the names of any symbols covered by this
180180
/// MaterializationResponsibility object that have queries pending. This

llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,25 +217,26 @@ class DynamicLibrarySearchGenerator {
217217

218218
/// Create a DynamicLibrarySearchGenerator that searches for symbols in the
219219
/// given sys::DynamicLibrary.
220+
///
220221
/// If the Allow predicate is given then only symbols matching the predicate
221-
/// will be searched for in the DynamicLibrary. If the predicate is not given
222-
/// then all symbols will be searched for.
223-
DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, const DataLayout &DL,
222+
/// will be searched for. If the predicate is not given then all symbols will
223+
/// be searched for.
224+
DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, char GlobalPrefix,
224225
SymbolPredicate Allow = SymbolPredicate());
225226

226227
/// Permanently loads the library at the given path and, on success, returns
227228
/// a DynamicLibrarySearchGenerator that will search it for symbol definitions
228229
/// in the library. On failure returns the reason the library failed to load.
229230
static Expected<DynamicLibrarySearchGenerator>
230-
Load(const char *FileName, const DataLayout &DL,
231+
Load(const char *FileName, char GlobalPrefix,
231232
SymbolPredicate Allow = SymbolPredicate());
232233

233234
/// Creates a DynamicLibrarySearchGenerator that searches for symbols in
234235
/// the current process.
235236
static Expected<DynamicLibrarySearchGenerator>
236-
GetForCurrentProcess(const DataLayout &DL,
237+
GetForCurrentProcess(char GlobalPrefix,
237238
SymbolPredicate Allow = SymbolPredicate()) {
238-
return Load(nullptr, DL, std::move(Allow));
239+
return Load(nullptr, GlobalPrefix, std::move(Allow));
239240
}
240241

241242
SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names);
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//===-- ObjectLinkingLayer.h - JITLink-based jit linking layer --*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Contains the definition for an JITLink-based, in-process object linking
10+
// layer.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
15+
#define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
16+
17+
#include "llvm/ADT/STLExtras.h"
18+
#include "llvm/ADT/StringMap.h"
19+
#include "llvm/ADT/StringRef.h"
20+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
21+
#include "llvm/ExecutionEngine/JITSymbol.h"
22+
#include "llvm/ExecutionEngine/Orc/Core.h"
23+
#include "llvm/ExecutionEngine/Orc/Layer.h"
24+
#include "llvm/Support/Error.h"
25+
#include <algorithm>
26+
#include <cassert>
27+
#include <functional>
28+
#include <list>
29+
#include <memory>
30+
#include <string>
31+
#include <utility>
32+
#include <vector>
33+
34+
namespace llvm {
35+
36+
namespace object {
37+
class ObjectFile;
38+
} // namespace object
39+
40+
namespace orc {
41+
42+
class ObjectLinkingLayerJITLinkContext;
43+
44+
class ObjectLinkingLayer : public ObjectLayer {
45+
friend class ObjectLinkingLayerJITLinkContext;
46+
47+
public:
48+
/// Function object for receiving object-loaded notifications.
49+
using NotifyLoadedFunction = std::function<void(VModuleKey)>;
50+
51+
/// Function object for receiving finalization notifications.
52+
using NotifyEmittedFunction = std::function<void(VModuleKey)>;
53+
54+
/// Function object for modifying PassConfiguration objects.
55+
using ModifyPassConfigFunction =
56+
std::function<void(const Triple &TT, jitlink::PassConfiguration &Config)>;
57+
58+
/// Construct an ObjectLinkingLayer with the given NotifyLoaded,
59+
/// and NotifyEmitted functors.
60+
ObjectLinkingLayer(
61+
ExecutionSession &ES, jitlink::JITLinkMemoryManager &MemMgr,
62+
NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(),
63+
NotifyEmittedFunction NotifyEmitted = NotifyEmittedFunction(),
64+
ModifyPassConfigFunction ModifyPassConfig = ModifyPassConfigFunction());
65+
66+
/// Emit the object.
67+
void emit(MaterializationResponsibility R,
68+
std::unique_ptr<MemoryBuffer> O) override;
69+
70+
/// Instructs this ObjectLinkingLayer instance to override the symbol flags
71+
/// found in the AtomGraph with the flags supplied by the
72+
/// MaterializationResponsibility instance. This is a workaround to support
73+
/// symbol visibility in COFF, which does not use the libObject's
74+
/// SF_Exported flag. Use only when generating / adding COFF object files.
75+
///
76+
/// FIXME: We should be able to remove this if/when COFF properly tracks
77+
/// exported symbols.
78+
ObjectLinkingLayer &
79+
setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) {
80+
this->OverrideObjectFlags = OverrideObjectFlags;
81+
return *this;
82+
}
83+
84+
/// If set, this ObjectLinkingLayer instance will claim responsibility
85+
/// for any symbols provided by a given object file that were not already in
86+
/// the MaterializationResponsibility instance. Setting this flag allows
87+
/// higher-level program representations (e.g. LLVM IR) to be added based on
88+
/// only a subset of the symbols they provide, without having to write
89+
/// intervening layers to scan and add the additional symbols. This trades
90+
/// diagnostic quality for convenience however: If all symbols are enumerated
91+
/// up-front then clashes can be detected and reported early (and usually
92+
/// deterministically). If this option is set, clashes for the additional
93+
/// symbols may not be detected until late, and detection may depend on
94+
/// the flow of control through JIT'd code. Use with care.
95+
ObjectLinkingLayer &
96+
setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) {
97+
this->AutoClaimObjectSymbols = AutoClaimObjectSymbols;
98+
return *this;
99+
}
100+
101+
private:
102+
using AllocPtr = std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>;
103+
104+
class ObjectResources {
105+
public:
106+
ObjectResources() = default;
107+
ObjectResources(AllocPtr Alloc, JITTargetAddress EHFrameAddr);
108+
ObjectResources(ObjectResources &&Other);
109+
ObjectResources &operator=(ObjectResources &&Other);
110+
~ObjectResources();
111+
112+
private:
113+
AllocPtr Alloc;
114+
JITTargetAddress EHFrameAddr = 0;
115+
};
116+
117+
void notifyFinalized(ObjectResources OR) {
118+
ObjResources.push_back(std::move(OR));
119+
}
120+
121+
mutable std::mutex LayerMutex;
122+
jitlink::JITLinkMemoryManager &MemMgr;
123+
NotifyLoadedFunction NotifyLoaded;
124+
NotifyEmittedFunction NotifyEmitted;
125+
ModifyPassConfigFunction ModifyPassConfig;
126+
bool OverrideObjectFlags = false;
127+
bool AutoClaimObjectSymbols = false;
128+
std::vector<ObjectResources> ObjResources;
129+
};
130+
131+
} // end namespace orc
132+
} // end namespace llvm
133+
134+
#endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H

llvm/include/llvm/Support/Memory.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#include <system_error>
1919

2020
namespace llvm {
21+
22+
// Forward declare raw_ostream: it is used for debug dumping below.
23+
class raw_ostream;
24+
2125
namespace sys {
2226

2327
/// This class encapsulates the notion of a memory block which has an address
@@ -141,7 +145,14 @@ namespace sys {
141145
MemoryBlock M;
142146
};
143147

144-
}
145-
}
148+
#ifndef NDEBUG
149+
/// Debugging output for Memory::ProtectionFlags.
150+
raw_ostream &operator<<(raw_ostream &OS, const Memory::ProtectionFlags &PF);
151+
152+
/// Debugging output for MemoryBlock.
153+
raw_ostream &operator<<(raw_ostream &OS, const MemoryBlock &MB);
154+
#endif // ifndef NDEBUG
155+
} // end namespace sys
156+
} // end namespace llvm
146157

147158
#endif

llvm/lib/ExecutionEngine/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ if(BUILD_SHARED_LIBS)
1919
endif()
2020

2121
add_subdirectory(Interpreter)
22+
add_subdirectory(JITLink)
2223
add_subdirectory(MCJIT)
2324
add_subdirectory(Orc)
2425
add_subdirectory(RuntimeDyld)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
add_llvm_library(LLVMJITLink
2+
JITLink.cpp
3+
JITLinkGeneric.cpp
4+
JITLink_EHFrameSupport.cpp
5+
JITLink_MachO.cpp
6+
JITLink_MachO_x86_64.cpp
7+
MachOAtomGraphBuilder.cpp
8+
9+
DEPENDS
10+
intrinsics_gen
11+
)

0 commit comments

Comments
 (0)