[yaml2obj/obj2yaml] - Add support for .stack_sizes sections.
[llvm-complete.git] / include / llvm / ExecutionEngine / JITLink / JITLink.h
blobbe80d44ccf51cfb8b4a2c50c987091e5ac8be088
1 //===------------ JITLink.h - JIT linker functionality ----------*- 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 generic JIT-linker types.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINK_H
14 #define LLVM_EXECUTIONENGINE_JITLINK_JITLINK_H
16 #include "JITLinkMemoryManager.h"
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/DenseSet.h"
19 #include "llvm/ADT/Optional.h"
20 #include "llvm/ADT/Triple.h"
21 #include "llvm/ExecutionEngine/JITSymbol.h"
22 #include "llvm/Support/Allocator.h"
23 #include "llvm/Support/Endian.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/FormatVariadic.h"
26 #include "llvm/Support/MathExtras.h"
27 #include "llvm/Support/Memory.h"
28 #include "llvm/Support/MemoryBuffer.h"
30 #include <map>
31 #include <string>
32 #include <system_error>
34 namespace llvm {
35 namespace jitlink {
37 /// Base class for errors originating in JIT linker, e.g. missing relocation
38 /// support.
39 class JITLinkError : public ErrorInfo<JITLinkError> {
40 public:
41 static char ID;
43 JITLinkError(Twine ErrMsg) : ErrMsg(ErrMsg.str()) {}
45 void log(raw_ostream &OS) const override;
46 const std::string &getErrorMessage() const { return ErrMsg; }
47 std::error_code convertToErrorCode() const override;
49 private:
50 std::string ErrMsg;
53 // Forward declare the Atom class.
54 class Atom;
56 /// Edge class. Represents both object file relocations, as well as layout and
57 /// keep-alive constraints.
58 class Edge {
59 public:
60 using Kind = uint8_t;
62 using GenericEdgeKind = enum : Kind {
63 Invalid, // Invalid edge value.
64 FirstKeepAlive, // Keeps target alive. Offset/addend zero.
65 KeepAlive = FirstKeepAlive, // Tag first edge kind that preserves liveness.
66 LayoutNext, // Layout constraint. Offset/Addend zero.
67 FirstRelocation // First architecture specific relocation.
70 using OffsetT = uint32_t;
71 using AddendT = int64_t;
73 Edge(Kind K, OffsetT Offset, Atom &Target, AddendT Addend)
74 : Target(&Target), Offset(Offset), Addend(Addend), K(K) {}
76 OffsetT getOffset() const { return Offset; }
77 Kind getKind() const { return K; }
78 void setKind(Kind K) { this->K = K; }
79 bool isRelocation() const { return K >= FirstRelocation; }
80 Kind getRelocation() const {
81 assert(isRelocation() && "Not a relocation edge");
82 return K - FirstRelocation;
84 bool isKeepAlive() const { return K >= FirstKeepAlive; }
85 Atom &getTarget() const { return *Target; }
86 void setTarget(Atom &Target) { this->Target = &Target; }
87 AddendT getAddend() const { return Addend; }
88 void setAddend(AddendT Addend) { this->Addend = Addend; }
90 private:
91 Atom *Target;
92 OffsetT Offset;
93 AddendT Addend;
94 Kind K = 0;
97 using EdgeVector = std::vector<Edge>;
99 const StringRef getGenericEdgeKindName(Edge::Kind K);
101 /// Base Atom class. Used by absolute and undefined atoms.
102 class Atom {
103 friend class AtomGraph;
105 protected:
106 /// Create a named (as yet unresolved) atom.
107 Atom(StringRef Name)
108 : Name(Name), IsDefined(false), IsLive(false), ShouldDiscard(false),
109 IsGlobal(false), IsAbsolute(false), IsCallable(false),
110 IsExported(false), IsWeak(false), HasLayoutNext(false),
111 IsCommon(false) {}
113 /// Create an absolute symbol atom.
114 Atom(StringRef Name, JITTargetAddress Address)
115 : Name(Name), Address(Address), IsDefined(true), IsLive(false),
116 ShouldDiscard(false), IsGlobal(false), IsAbsolute(false),
117 IsCallable(false), IsExported(false), IsWeak(false),
118 HasLayoutNext(false), IsCommon(false) {}
120 public:
121 /// Returns true if this atom has a name.
122 bool hasName() const { return Name != StringRef(); }
124 /// Returns the name of this atom.
125 StringRef getName() const { return Name; }
127 /// Returns the current target address of this atom.
128 /// The initial target address (for atoms that have one) will be taken from
129 /// the input object file's virtual address space. During the layout phase
130 /// of JIT linking the atom's address will be updated to point to its final
131 /// address in the JIT'd process.
132 JITTargetAddress getAddress() const { return Address; }
134 /// Set the current target address of this atom.
135 void setAddress(JITTargetAddress Address) { this->Address = Address; }
137 /// Returns true if this is a defined atom.
138 bool isDefined() const { return IsDefined; }
140 /// Returns true if this atom is marked as live.
141 bool isLive() const { return IsLive; }
143 /// Mark this atom as live.
145 /// Note: Only defined and absolute atoms can be marked live.
146 void setLive(bool IsLive) {
147 assert((IsDefined || IsAbsolute || !IsLive) &&
148 "Only defined and absolute atoms can be marked live");
149 this->IsLive = IsLive;
152 /// Returns true if this atom should be discarded during pruning.
153 bool shouldDiscard() const { return ShouldDiscard; }
155 /// Mark this atom to be discarded.
157 /// Note: Only defined and absolute atoms can be marked live.
158 void setShouldDiscard(bool ShouldDiscard) {
159 assert((IsDefined || IsAbsolute || !ShouldDiscard) &&
160 "Only defined and absolute atoms can be marked live");
161 this->ShouldDiscard = ShouldDiscard;
164 /// Returns true if this definition is global (i.e. visible outside this
165 /// linkage unit).
167 /// Note: This is distict from Exported, which means visibile outside the
168 /// JITDylib that this graph is being linked in to.
169 bool isGlobal() const { return IsGlobal; }
171 /// Mark this atom as global.
172 void setGlobal(bool IsGlobal) { this->IsGlobal = IsGlobal; }
174 /// Returns true if this atom represents an absolute symbol.
175 bool isAbsolute() const { return IsAbsolute; }
177 /// Returns true if this atom is known to be callable.
179 /// Primarily provided for easy interoperability with ORC, which uses the
180 /// JITSymbolFlags::Common flag to identify symbols that can be interposed
181 /// with stubs.
182 bool isCallable() const { return IsCallable; }
184 /// Mark this atom as callable.
185 void setCallable(bool IsCallable) {
186 assert((IsDefined || IsAbsolute || !IsCallable) &&
187 "Callable atoms must be defined or absolute");
188 this->IsCallable = IsCallable;
191 /// Returns true if this atom should appear in the symbol table of a final
192 /// linked image.
193 bool isExported() const { return IsExported; }
195 /// Mark this atom as exported.
196 void setExported(bool IsExported) {
197 assert((!IsExported || ((IsDefined || IsAbsolute) && hasName())) &&
198 "Exported atoms must have names");
199 this->IsExported = IsExported;
202 /// Returns true if this is a weak symbol.
203 bool isWeak() const { return IsWeak; }
205 /// Mark this atom as weak.
206 void setWeak(bool IsWeak) { this->IsWeak = IsWeak; }
208 private:
209 StringRef Name;
210 JITTargetAddress Address = 0;
212 bool IsDefined : 1;
213 bool IsLive : 1;
214 bool ShouldDiscard : 1;
216 bool IsGlobal : 1;
217 bool IsAbsolute : 1;
218 bool IsCallable : 1;
219 bool IsExported : 1;
220 bool IsWeak : 1;
222 protected:
223 // These flags only make sense for DefinedAtom, but we can minimize the size
224 // of DefinedAtom by defining them here.
225 bool HasLayoutNext : 1;
226 bool IsCommon : 1;
229 // Forward declare DefinedAtom.
230 class DefinedAtom;
232 raw_ostream &operator<<(raw_ostream &OS, const Atom &A);
233 void printEdge(raw_ostream &OS, const Atom &FixupAtom, const Edge &E,
234 StringRef EdgeKindName);
236 /// Represents a section address range via a pair of DefinedAtom pointers to
237 /// the first and last atoms in the section.
238 class SectionRange {
239 public:
240 SectionRange() = default;
241 SectionRange(DefinedAtom *First, DefinedAtom *Last)
242 : First(First), Last(Last) {}
243 DefinedAtom *getFirstAtom() const {
244 assert((!Last || First) && "First can not be null if end is non-null");
245 return First;
247 DefinedAtom *getLastAtom() const {
248 assert((First || !Last) && "Last can not be null if start is non-null");
249 return Last;
251 bool isEmpty() const {
252 assert((First || !Last) && "Last can not be null if start is non-null");
253 return !First;
255 JITTargetAddress getStart() const;
256 JITTargetAddress getEnd() const;
257 uint64_t getSize() const;
259 private:
260 DefinedAtom *First = nullptr;
261 DefinedAtom *Last = nullptr;
264 /// Represents an object file section.
265 class Section {
266 friend class AtomGraph;
268 private:
269 Section(StringRef Name, uint32_t Alignment, sys::Memory::ProtectionFlags Prot,
270 unsigned Ordinal, bool IsZeroFill)
271 : Name(Name), Alignment(Alignment), Prot(Prot), Ordinal(Ordinal),
272 IsZeroFill(IsZeroFill) {
273 assert(isPowerOf2_32(Alignment) && "Alignments must be a power of 2");
276 using DefinedAtomSet = DenseSet<DefinedAtom *>;
278 public:
279 using atom_iterator = DefinedAtomSet::iterator;
280 using const_atom_iterator = DefinedAtomSet::const_iterator;
282 ~Section();
283 StringRef getName() const { return Name; }
284 uint32_t getAlignment() const { return Alignment; }
285 sys::Memory::ProtectionFlags getProtectionFlags() const { return Prot; }
286 unsigned getSectionOrdinal() const { return Ordinal; }
287 size_t getNextAtomOrdinal() { return ++NextAtomOrdinal; }
289 bool isZeroFill() const { return IsZeroFill; }
291 /// Returns an iterator over the atoms in the section (in no particular
292 /// order).
293 iterator_range<atom_iterator> atoms() {
294 return make_range(DefinedAtoms.begin(), DefinedAtoms.end());
297 /// Returns an iterator over the atoms in the section (in no particular
298 /// order).
299 iterator_range<const_atom_iterator> atoms() const {
300 return make_range(DefinedAtoms.begin(), DefinedAtoms.end());
303 /// Return the number of atoms in this section.
304 DefinedAtomSet::size_type atoms_size() { return DefinedAtoms.size(); }
306 /// Return true if this section contains no atoms.
307 bool atoms_empty() const { return DefinedAtoms.empty(); }
309 /// Returns the range of this section as the pair of atoms with the lowest
310 /// and highest target address. This operation is expensive, as it
311 /// must traverse all atoms in the section.
313 /// Note: If the section is empty, both values will be null. The section
314 /// address will evaluate to null, and the size to zero. If the section
315 /// contains a single atom both values will point to it, the address will
316 /// evaluate to the address of that atom, and the size will be the size of
317 /// that atom.
318 SectionRange getRange() const;
320 private:
321 void addAtom(DefinedAtom &DA) {
322 assert(!DefinedAtoms.count(&DA) && "Atom is already in this section");
323 DefinedAtoms.insert(&DA);
326 void removeAtom(DefinedAtom &DA) {
327 assert(DefinedAtoms.count(&DA) && "Atom is not in this section");
328 DefinedAtoms.erase(&DA);
331 StringRef Name;
332 uint32_t Alignment = 0;
333 sys::Memory::ProtectionFlags Prot;
334 unsigned Ordinal = 0;
335 unsigned NextAtomOrdinal = 0;
336 bool IsZeroFill = false;
337 DefinedAtomSet DefinedAtoms;
340 /// Defined atom class. Suitable for use by defined named and anonymous
341 /// atoms.
342 class DefinedAtom : public Atom {
343 friend class AtomGraph;
345 private:
346 DefinedAtom(Section &Parent, JITTargetAddress Address, uint32_t Alignment)
347 : Atom("", Address), Parent(Parent), Ordinal(Parent.getNextAtomOrdinal()),
348 Alignment(Alignment) {
349 assert(isPowerOf2_32(Alignment) && "Alignments must be a power of two");
352 DefinedAtom(Section &Parent, StringRef Name, JITTargetAddress Address,
353 uint32_t Alignment)
354 : Atom(Name, Address), Parent(Parent),
355 Ordinal(Parent.getNextAtomOrdinal()), Alignment(Alignment) {
356 assert(isPowerOf2_32(Alignment) && "Alignments must be a power of two");
359 public:
360 using edge_iterator = EdgeVector::iterator;
362 Section &getSection() const { return Parent; }
364 uint64_t getSize() const { return Size; }
366 StringRef getContent() const {
367 assert(!Parent.isZeroFill() && "Trying to get content for zero-fill atom");
368 assert(Size <= std::numeric_limits<size_t>::max() &&
369 "Content size too large");
370 return {ContentPtr, static_cast<size_t>(Size)};
372 void setContent(StringRef Content) {
373 assert(!Parent.isZeroFill() && "Calling setContent on zero-fill atom?");
374 ContentPtr = Content.data();
375 Size = Content.size();
378 bool isZeroFill() const { return Parent.isZeroFill(); }
380 void setZeroFill(uint64_t Size) {
381 assert(Parent.isZeroFill() && !ContentPtr &&
382 "Can't set zero-fill length of a non zero-fill atom");
383 this->Size = Size;
386 uint64_t getZeroFillSize() const {
387 assert(Parent.isZeroFill() &&
388 "Can't get zero-fill length of a non zero-fill atom");
389 return Size;
392 uint32_t getAlignment() const { return Alignment; }
394 bool hasLayoutNext() const { return HasLayoutNext; }
395 void setLayoutNext(DefinedAtom &Next) {
396 assert(!HasLayoutNext && "Atom already has layout-next constraint");
397 HasLayoutNext = true;
398 Edges.push_back(Edge(Edge::LayoutNext, 0, Next, 0));
400 DefinedAtom &getLayoutNext() {
401 assert(HasLayoutNext && "Atom does not have a layout-next constraint");
402 DefinedAtom *Next = nullptr;
403 for (auto &E : edges())
404 if (E.getKind() == Edge::LayoutNext) {
405 assert(E.getTarget().isDefined() &&
406 "layout-next target atom must be a defined atom");
407 Next = static_cast<DefinedAtom *>(&E.getTarget());
408 break;
410 assert(Next && "Missing LayoutNext edge");
411 return *Next;
414 bool isCommon() const { return IsCommon; }
416 void addEdge(Edge::Kind K, Edge::OffsetT Offset, Atom &Target,
417 Edge::AddendT Addend) {
418 assert(K != Edge::LayoutNext &&
419 "Layout edges should be added via setLayoutNext");
420 Edges.push_back(Edge(K, Offset, Target, Addend));
423 iterator_range<edge_iterator> edges() {
424 return make_range(Edges.begin(), Edges.end());
426 size_t edges_size() const { return Edges.size(); }
427 bool edges_empty() const { return Edges.empty(); }
429 unsigned getOrdinal() const { return Ordinal; }
431 private:
432 void setCommon(uint64_t Size) {
433 assert(ContentPtr == 0 && "Atom already has content?");
434 IsCommon = true;
435 setZeroFill(Size);
438 EdgeVector Edges;
439 uint64_t Size = 0;
440 Section &Parent;
441 const char *ContentPtr = nullptr;
442 unsigned Ordinal = 0;
443 uint32_t Alignment = 0;
446 inline JITTargetAddress SectionRange::getStart() const {
447 return First ? First->getAddress() : 0;
450 inline JITTargetAddress SectionRange::getEnd() const {
451 return Last ? Last->getAddress() + Last->getSize() : 0;
454 inline uint64_t SectionRange::getSize() const { return getEnd() - getStart(); }
456 inline SectionRange Section::getRange() const {
457 if (atoms_empty())
458 return SectionRange();
459 DefinedAtom *First = *DefinedAtoms.begin(), *Last = *DefinedAtoms.begin();
460 for (auto *DA : atoms()) {
461 if (DA->getAddress() < First->getAddress())
462 First = DA;
463 if (DA->getAddress() > Last->getAddress())
464 Last = DA;
466 return SectionRange(First, Last);
469 class AtomGraph {
470 private:
471 using SectionList = std::vector<std::unique_ptr<Section>>;
472 using AddressToAtomMap = std::map<JITTargetAddress, DefinedAtom *>;
473 using NamedAtomMap = DenseMap<StringRef, Atom *>;
474 using ExternalAtomSet = DenseSet<Atom *>;
476 public:
477 using external_atom_iterator = ExternalAtomSet::iterator;
479 using section_iterator = pointee_iterator<SectionList::iterator>;
480 using const_section_iterator = pointee_iterator<SectionList::const_iterator>;
482 template <typename SecItrT, typename AtomItrT, typename T>
483 class defined_atom_iterator_impl
484 : public iterator_facade_base<
485 defined_atom_iterator_impl<SecItrT, AtomItrT, T>,
486 std::forward_iterator_tag, T> {
487 public:
488 defined_atom_iterator_impl() = default;
490 defined_atom_iterator_impl(SecItrT SI, SecItrT SE)
491 : SI(SI), SE(SE),
492 AI(SI != SE ? SI->atoms().begin() : Section::atom_iterator()) {
493 moveToNextAtomOrEnd();
496 bool operator==(const defined_atom_iterator_impl &RHS) const {
497 return (SI == RHS.SI) && (AI == RHS.AI);
500 T operator*() const {
501 assert(AI != SI->atoms().end() && "Dereferencing end?");
502 return *AI;
505 defined_atom_iterator_impl operator++() {
506 ++AI;
507 moveToNextAtomOrEnd();
508 return *this;
511 private:
512 void moveToNextAtomOrEnd() {
513 while (SI != SE && AI == SI->atoms().end()) {
514 ++SI;
515 if (SI == SE)
516 AI = Section::atom_iterator();
517 else
518 AI = SI->atoms().begin();
522 SecItrT SI, SE;
523 AtomItrT AI;
526 using defined_atom_iterator =
527 defined_atom_iterator_impl<section_iterator, Section::atom_iterator,
528 DefinedAtom *>;
530 using const_defined_atom_iterator =
531 defined_atom_iterator_impl<const_section_iterator,
532 Section::const_atom_iterator,
533 const DefinedAtom *>;
535 AtomGraph(std::string Name, unsigned PointerSize,
536 support::endianness Endianness)
537 : Name(std::move(Name)), PointerSize(PointerSize),
538 Endianness(Endianness) {}
540 /// Returns the name of this graph (usually the name of the original
541 /// underlying MemoryBuffer).
542 const std::string &getName() { return Name; }
544 /// Returns the pointer size for use in this graph.
545 unsigned getPointerSize() const { return PointerSize; }
547 /// Returns the endianness of atom-content in this graph.
548 support::endianness getEndianness() const { return Endianness; }
550 /// Create a section with the given name, protection flags, and alignment.
551 Section &createSection(StringRef Name, uint32_t Alignment,
552 sys::Memory::ProtectionFlags Prot, bool IsZeroFill) {
553 std::unique_ptr<Section> Sec(
554 new Section(Name, Alignment, Prot, Sections.size(), IsZeroFill));
555 Sections.push_back(std::move(Sec));
556 return *Sections.back();
559 /// Add an external atom representing an undefined symbol in this graph.
560 Atom &addExternalAtom(StringRef Name) {
561 assert(!NamedAtoms.count(Name) && "Duplicate named atom inserted");
562 Atom *A = reinterpret_cast<Atom *>(
563 AtomAllocator.Allocate(sizeof(Atom), alignof(Atom)));
564 new (A) Atom(Name);
565 ExternalAtoms.insert(A);
566 NamedAtoms[Name] = A;
567 return *A;
570 /// Add an external atom representing an absolute symbol.
571 Atom &addAbsoluteAtom(StringRef Name, JITTargetAddress Addr) {
572 assert(!NamedAtoms.count(Name) && "Duplicate named atom inserted");
573 Atom *A = reinterpret_cast<Atom *>(
574 AtomAllocator.Allocate(sizeof(Atom), alignof(Atom)));
575 new (A) Atom(Name, Addr);
576 AbsoluteAtoms.insert(A);
577 NamedAtoms[Name] = A;
578 return *A;
581 /// Add an anonymous defined atom to the graph.
583 /// Anonymous atoms have content but no name. They must have an address.
584 DefinedAtom &addAnonymousAtom(Section &Parent, JITTargetAddress Address,
585 uint32_t Alignment) {
586 DefinedAtom *A = reinterpret_cast<DefinedAtom *>(
587 AtomAllocator.Allocate(sizeof(DefinedAtom), alignof(DefinedAtom)));
588 new (A) DefinedAtom(Parent, Address, Alignment);
589 Parent.addAtom(*A);
590 getAddrToAtomMap()[A->getAddress()] = A;
591 return *A;
594 /// Add a defined atom to the graph.
596 /// Allocates and constructs a DefinedAtom instance with the given parent,
597 /// name, address, and alignment.
598 DefinedAtom &addDefinedAtom(Section &Parent, StringRef Name,
599 JITTargetAddress Address, uint32_t Alignment) {
600 assert(!NamedAtoms.count(Name) && "Duplicate named atom inserted");
601 DefinedAtom *A = reinterpret_cast<DefinedAtom *>(
602 AtomAllocator.Allocate(sizeof(DefinedAtom), alignof(DefinedAtom)));
603 new (A) DefinedAtom(Parent, Name, Address, Alignment);
604 Parent.addAtom(*A);
605 getAddrToAtomMap()[A->getAddress()] = A;
606 NamedAtoms[Name] = A;
607 return *A;
610 /// Add a common symbol atom to the graph.
612 /// Adds a common-symbol atom to the graph with the given parent, name,
613 /// address, alignment and size.
614 DefinedAtom &addCommonAtom(Section &Parent, StringRef Name,
615 JITTargetAddress Address, uint32_t Alignment,
616 uint64_t Size) {
617 assert(!NamedAtoms.count(Name) && "Duplicate named atom inserted");
618 DefinedAtom *A = reinterpret_cast<DefinedAtom *>(
619 AtomAllocator.Allocate(sizeof(DefinedAtom), alignof(DefinedAtom)));
620 new (A) DefinedAtom(Parent, Name, Address, Alignment);
621 A->setCommon(Size);
622 Parent.addAtom(*A);
623 NamedAtoms[Name] = A;
624 return *A;
627 iterator_range<section_iterator> sections() {
628 return make_range(section_iterator(Sections.begin()),
629 section_iterator(Sections.end()));
632 /// Returns the section with the given name if it exists, otherwise returns
633 /// null.
634 Section *findSectionByName(StringRef Name) {
635 for (auto &S : sections())
636 if (S.getName() == Name)
637 return &S;
638 return nullptr;
641 iterator_range<external_atom_iterator> external_atoms() {
642 return make_range(ExternalAtoms.begin(), ExternalAtoms.end());
645 iterator_range<external_atom_iterator> absolute_atoms() {
646 return make_range(AbsoluteAtoms.begin(), AbsoluteAtoms.end());
649 iterator_range<defined_atom_iterator> defined_atoms() {
650 return make_range(defined_atom_iterator(Sections.begin(), Sections.end()),
651 defined_atom_iterator(Sections.end(), Sections.end()));
654 iterator_range<const_defined_atom_iterator> defined_atoms() const {
655 return make_range(
656 const_defined_atom_iterator(Sections.begin(), Sections.end()),
657 const_defined_atom_iterator(Sections.end(), Sections.end()));
660 /// Returns the atom with the given name, which must exist in this graph.
661 Atom &getAtomByName(StringRef Name) {
662 auto I = NamedAtoms.find(Name);
663 assert(I != NamedAtoms.end() && "Name not in NamedAtoms map");
664 return *I->second;
667 /// Returns the atom with the given name, which must exist in this graph and
668 /// be a DefinedAtom.
669 DefinedAtom &getDefinedAtomByName(StringRef Name) {
670 auto &A = getAtomByName(Name);
671 assert(A.isDefined() && "Atom is not a defined atom");
672 return static_cast<DefinedAtom &>(A);
675 /// Search for the given atom by name.
676 /// Returns the atom (if found) or an error (if no atom with this name
677 /// exists).
678 Expected<Atom &> findAtomByName(StringRef Name) {
679 auto I = NamedAtoms.find(Name);
680 if (I == NamedAtoms.end())
681 return make_error<JITLinkError>("No atom named " + Name);
682 return *I->second;
685 /// Search for the given defined atom by name.
686 /// Returns the defined atom (if found) or an error (if no atom with this
687 /// name exists, or if one exists but is not a defined atom).
688 Expected<DefinedAtom &> findDefinedAtomByName(StringRef Name) {
689 auto I = NamedAtoms.find(Name);
690 if (I == NamedAtoms.end())
691 return make_error<JITLinkError>("No atom named " + Name);
692 if (!I->second->isDefined())
693 return make_error<JITLinkError>("Atom " + Name +
694 " exists but is not a "
695 "defined atom");
696 return static_cast<DefinedAtom &>(*I->second);
699 /// Returns the atom covering the given address, or an error if no such atom
700 /// exists.
702 /// Returns null if no atom exists at the given address.
703 DefinedAtom *getAtomByAddress(JITTargetAddress Address) {
704 refreshAddrToAtomCache();
706 // If there are no defined atoms, bail out early.
707 if (AddrToAtomCache->empty())
708 return nullptr;
710 // Find the atom *after* the given address.
711 auto I = AddrToAtomCache->upper_bound(Address);
713 // If this address falls before any known atom, bail out.
714 if (I == AddrToAtomCache->begin())
715 return nullptr;
717 // The atom we're looking for is the one before the atom we found.
718 --I;
720 // Otherwise range check the atom that was found.
721 assert(!I->second->getContent().empty() && "Atom content not set");
722 if (Address >= I->second->getAddress() + I->second->getContent().size())
723 return nullptr;
725 return I->second;
728 /// Like getAtomByAddress, but returns an Error if the given address is not
729 /// covered by an atom, rather than a null pointer.
730 Expected<DefinedAtom &> findAtomByAddress(JITTargetAddress Address) {
731 if (auto *DA = getAtomByAddress(Address))
732 return *DA;
733 return make_error<JITLinkError>("No atom at address " +
734 formatv("{0:x16}", Address));
737 // Remove the given external atom from the graph.
738 void removeExternalAtom(Atom &A) {
739 assert(!A.isDefined() && !A.isAbsolute() && "A is not an external atom");
740 assert(ExternalAtoms.count(&A) && "A is not in the external atoms set");
741 ExternalAtoms.erase(&A);
742 A.~Atom();
745 /// Remove the given absolute atom from the graph.
746 void removeAbsoluteAtom(Atom &A) {
747 assert(A.isAbsolute() && "A is not an absolute atom");
748 assert(AbsoluteAtoms.count(&A) && "A is not in the absolute atoms set");
749 AbsoluteAtoms.erase(&A);
750 A.~Atom();
753 /// Remove the given defined atom from the graph.
754 void removeDefinedAtom(DefinedAtom &DA) {
755 if (AddrToAtomCache) {
756 assert(AddrToAtomCache->count(DA.getAddress()) &&
757 "Cache exists, but does not contain atom");
758 AddrToAtomCache->erase(DA.getAddress());
760 if (DA.hasName()) {
761 assert(NamedAtoms.count(DA.getName()) && "Named atom not in map");
762 NamedAtoms.erase(DA.getName());
764 DA.getSection().removeAtom(DA);
765 DA.~DefinedAtom();
768 /// Invalidate the atom-to-address map.
769 void invalidateAddrToAtomMap() { AddrToAtomCache = None; }
771 /// Dump the graph.
773 /// If supplied, the EdgeKindToName function will be used to name edge
774 /// kinds in the debug output. Otherwise raw edge kind numbers will be
775 /// displayed.
776 void dump(raw_ostream &OS,
777 std::function<StringRef(Edge::Kind)> EdegKindToName =
778 std::function<StringRef(Edge::Kind)>());
780 private:
781 AddressToAtomMap &getAddrToAtomMap() {
782 refreshAddrToAtomCache();
783 return *AddrToAtomCache;
786 const AddressToAtomMap &getAddrToAtomMap() const {
787 refreshAddrToAtomCache();
788 return *AddrToAtomCache;
791 void refreshAddrToAtomCache() const {
792 if (!AddrToAtomCache) {
793 AddrToAtomCache = AddressToAtomMap();
794 for (auto *DA : defined_atoms())
795 (*AddrToAtomCache)[DA->getAddress()] = const_cast<DefinedAtom *>(DA);
799 // Put the BumpPtrAllocator first so that we don't free any of the atoms in
800 // it until all of their destructors have been run.
801 BumpPtrAllocator AtomAllocator;
803 std::string Name;
804 unsigned PointerSize;
805 support::endianness Endianness;
806 SectionList Sections;
807 NamedAtomMap NamedAtoms;
808 ExternalAtomSet ExternalAtoms;
809 ExternalAtomSet AbsoluteAtoms;
810 mutable Optional<AddressToAtomMap> AddrToAtomCache;
813 /// A function for mutating AtomGraphs.
814 using AtomGraphPassFunction = std::function<Error(AtomGraph &)>;
816 /// A list of atom graph passes.
817 using AtomGraphPassList = std::vector<AtomGraphPassFunction>;
819 /// An atom graph pass configuration, consisting of a list of pre-prune,
820 /// post-prune, and post-fixup passes.
821 struct PassConfiguration {
823 /// Pre-prune passes.
825 /// These passes are called on the graph after it is built, and before any
826 /// atoms have been pruned.
828 /// Notable use cases: Marking atoms live or should-discard.
829 AtomGraphPassList PrePrunePasses;
831 /// Post-prune passes.
833 /// These passes are called on the graph after dead and should-discard atoms
834 /// have been removed, but before fixups are applied.
836 /// Notable use cases: Building GOT, stub, and TLV atoms.
837 AtomGraphPassList PostPrunePasses;
839 /// Post-fixup passes.
841 /// These passes are called on the graph after atom contents has been copied
842 /// to working memory, and fixups applied.
844 /// Notable use cases: Testing and validation.
845 AtomGraphPassList PostFixupPasses;
848 /// A map of symbol names to resolved addresses.
849 using AsyncLookupResult = DenseMap<StringRef, JITEvaluatedSymbol>;
851 /// A function to call with a resolved symbol map (See AsyncLookupResult) or an
852 /// error if resolution failed.
853 using JITLinkAsyncLookupContinuation =
854 std::function<void(Expected<AsyncLookupResult> LR)>;
856 /// An asynchronous symbol lookup. Performs a search (possibly asynchronously)
857 /// for the given symbols, calling the given continuation with either the result
858 /// (if the lookup succeeds), or an error (if the lookup fails).
859 using JITLinkAsyncLookupFunction =
860 std::function<void(const DenseSet<StringRef> &Symbols,
861 JITLinkAsyncLookupContinuation LookupContinuation)>;
863 /// Holds context for a single jitLink invocation.
864 class JITLinkContext {
865 public:
866 /// Destroy a JITLinkContext.
867 virtual ~JITLinkContext();
869 /// Return the MemoryManager to be used for this link.
870 virtual JITLinkMemoryManager &getMemoryManager() = 0;
872 /// Returns a StringRef for the object buffer.
873 /// This method can not be called once takeObjectBuffer has been called.
874 virtual MemoryBufferRef getObjectBuffer() const = 0;
876 /// Notify this context that linking failed.
877 /// Called by JITLink if linking cannot be completed.
878 virtual void notifyFailed(Error Err) = 0;
880 /// Called by JITLink to resolve external symbols. This method is passed a
881 /// lookup continutation which it must call with a result to continue the
882 /// linking process.
883 virtual void lookup(const DenseSet<StringRef> &Symbols,
884 JITLinkAsyncLookupContinuation LookupContinuation) = 0;
886 /// Called by JITLink once all defined atoms in the graph have been assigned
887 /// their final memory locations in the target process. At this point he
888 /// atom graph can be, inspected to build a symbol table however the atom
889 /// content will not generally have been copied to the target location yet.
890 virtual void notifyResolved(AtomGraph &G) = 0;
892 /// Called by JITLink to notify the context that the object has been
893 /// finalized (i.e. emitted to memory and memory permissions set). If all of
894 /// this objects dependencies have also been finalized then the code is ready
895 /// to run.
896 virtual void
897 notifyFinalized(std::unique_ptr<JITLinkMemoryManager::Allocation> A) = 0;
899 /// Called by JITLink prior to linking to determine whether default passes for
900 /// the target should be added. The default implementation returns true.
901 /// If subclasses override this method to return false for any target then
902 /// they are required to fully configure the pass pipeline for that target.
903 virtual bool shouldAddDefaultTargetPasses(const Triple &TT) const;
905 /// Returns the mark-live pass to be used for this link. If no pass is
906 /// returned (the default) then the target-specific linker implementation will
907 /// choose a conservative default (usually marking all atoms live).
908 /// This function is only called if shouldAddDefaultTargetPasses returns true,
909 /// otherwise the JITContext is responsible for adding a mark-live pass in
910 /// modifyPassConfig.
911 virtual AtomGraphPassFunction getMarkLivePass(const Triple &TT) const;
913 /// Called by JITLink to modify the pass pipeline prior to linking.
914 /// The default version performs no modification.
915 virtual Error modifyPassConfig(const Triple &TT, PassConfiguration &Config);
918 /// Marks all atoms in a graph live. This can be used as a default, conservative
919 /// mark-live implementation.
920 Error markAllAtomsLive(AtomGraph &G);
922 /// Basic JITLink implementation.
924 /// This function will use sensible defaults for GOT and Stub handling.
925 void jitLink(std::unique_ptr<JITLinkContext> Ctx);
927 } // end namespace jitlink
928 } // end namespace llvm
930 #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_H