25#define DEBUG_TYPE "jitlink"
29enum JITLinkErrorCode { GenericJITLinkError = 1 };
34class JITLinkerErrorCategory :
public std::error_category {
36 const char *
name()
const noexcept override {
return "runtimedyld"; }
38 std::string message(
int Condition)
const override {
39 switch (
static_cast<JITLinkErrorCode
>(Condition)) {
40 case GenericJITLinkError:
41 return "Generic JITLink error";
57 static JITLinkerErrorCategory TheJITLinkerErrorCategory;
58 return std::error_code(GenericJITLinkError, TheJITLinkerErrorCategory);
64 return "INVALID RELOCATION";
68 return "<Unrecognized edge kind>";
89 return "side-effects-only";
102 return B.getSize() == 1;
104 for (
size_t I = 0;
I !=
B.getSize() - 1; ++
I)
105 if (
B.getContent()[
I] ==
'\0')
108 return B.getContent()[
B.getSize() - 1] ==
'\0';
112 return OS <<
B.getAddress() <<
" -- " << (
B.getAddress() +
B.getSize())
114 <<
"size = " <<
formatv(
"{0:x8}",
B.getSize()) <<
", "
115 << (
B.isZeroFill() ?
"zero-fill" :
"content")
116 <<
", align = " <<
B.getAlignment()
117 <<
", align-ofs = " <<
B.getAlignmentOffset()
118 <<
", section = " <<
B.getSection().getName();
127 << (
Sym.
isLive() ?
"live" :
"dead") <<
" - "
134 OS <<
"edge@" <<
B.getAddress() + E.
getOffset() <<
": " <<
B.getAddress()
139 if (TargetSym.hasName())
140 OS << TargetSym.getName();
142 auto &TargetBlock = TargetSym.getBlock();
143 auto &TargetSec = TargetBlock.getSection();
145 for (
auto *
B : TargetSec.blocks())
146 if (
B->getAddress() < SecAddress)
147 SecAddress =
B->getAddress();
150 OS << TargetSym.getAddress() <<
" (section " << TargetSec.getName();
152 OS <<
" + " <<
formatv(
"{0:x}", SecDelta);
153 OS <<
" / block " << TargetBlock.getAddress();
154 if (TargetSym.getOffset())
155 OS <<
" + " <<
formatv(
"{0:x}", TargetSym.getOffset());
164 for (
auto *
Sym : Symbols)
166 for (
auto *
B : Blocks)
171 for (
auto *
Sym : AbsoluteSymbols) {
177 ExternalSymbols.
clear();
180std::vector<Block *> LinkGraph::splitBlockImpl(std::vector<Block *>
Blocks,
181 SplitBlockCache *Cache) {
182 assert(!
Blocks.empty() &&
"Blocks must at least contain the original block");
186 for (
size_t I = 0;
I !=
Blocks.size() - 1; ++
I) {
191 Blocks.back()->setContent(
193 bool IsMutable =
Blocks[0]->ContentMutable;
195 B->ContentMutable = IsMutable;
201 Cache = &LocalBlockSymbolsCache;
204 if (*Cache == std::nullopt) {
205 *Cache = SplitBlockCache::value_type();
209 (*Cache)->push_back(
Sym);
210 llvm::sort(**Cache, [](
const Symbol *LHS,
const Symbol *RHS) {
211 return LHS->getAddress() >
RHS->getAddress();
216 Sym.setOffset(
Sym.getAddress() -
B.getAddress());
218 if (
Sym.getSize() >
B.getSize())
219 Sym.setSize(
B.getSize() -
Sym.getOffset());
223 for (
size_t I = 0;
I !=
Blocks.size() - 1; ++
I) {
224 if ((*Cache)->empty())
226 while (!(*Cache)->empty() &&
227 (*Cache)->back()->getAddress() <
Blocks[
I + 1]->getAddress()) {
228 TransferSymbol(*(*Cache)->back(), *
Blocks[
I]);
229 (*Cache)->pop_back();
233 while (!(*Cache)->empty()) {
234 auto &
Sym = *(*Cache)->back();
235 (*Cache)->pop_back();
237 "Symbol address preceeds block");
239 "Symbol address starts past end of block");
245 auto &Edges =
Blocks[0]->Edges;
246 llvm::sort(Edges, [](
const Edge &LHS,
const Edge &RHS) {
247 return LHS.getOffset() <
RHS.getOffset();
250 for (
size_t I =
Blocks.size() - 1;
I != 0; --
I) {
259 if (Edges.back().getOffset() < Delta)
262 size_t EI = Edges.size() - 1;
263 while (EI != 0 && Edges[EI - 1].
getOffset() >= Delta)
266 for (
size_t J = EI; J != Edges.size(); ++J) {
267 Blocks[
I]->Edges.push_back(std::move(Edges[J]));
268 Blocks[
I]->Edges.back().setOffset(
Blocks[
I]->Edges.back().getOffset() -
272 while (Edges.size() > EI)
284 BlockSymbols[&
Sym->getBlock()].push_back(
Sym);
288 for (
auto &KV : BlockSymbols)
290 if (LHS->getOffset() != RHS->getOffset())
291 return LHS->getOffset() < RHS->getOffset();
292 if (LHS->getLinkage() != RHS->getLinkage())
293 return LHS->getLinkage() < RHS->getLinkage();
294 if (LHS->getScope() != RHS->getScope())
295 return LHS->getScope() < RHS->getScope();
296 if (LHS->hasName()) {
299 return LHS->getName() < RHS->getName();
304 std::vector<Section *> SortedSections;
306 SortedSections.push_back(&Sec);
311 for (
auto *Sec : SortedSections) {
312 OS <<
"section " << Sec->getName() <<
":\n\n";
314 std::vector<Block *> SortedBlocks;
315 llvm::copy(Sec->blocks(), std::back_inserter(SortedBlocks));
316 llvm::sort(SortedBlocks, [](
const Block *LHS,
const Block *RHS) {
317 return LHS->getAddress() <
RHS->getAddress();
320 for (
auto *
B : SortedBlocks) {
321 OS <<
" block " <<
B->getAddress()
322 <<
" size = " <<
formatv(
"{0:x8}",
B->getSize())
323 <<
", align = " <<
B->getAlignment()
324 <<
", alignment-offset = " <<
B->getAlignmentOffset();
329 auto BlockSymsI = BlockSymbols.find(
B);
330 if (BlockSymsI != BlockSymbols.end()) {
332 auto &Syms = BlockSymsI->second;
333 for (
auto *
Sym : Syms)
334 OS <<
" " << *
Sym <<
"\n";
336 OS <<
" no symbols\n";
338 if (!
B->edges_empty()) {
340 std::vector<Edge> SortedEdges;
341 llvm::copy(
B->edges(), std::back_inserter(SortedEdges));
342 llvm::sort(SortedEdges, [](
const Edge &LHS,
const Edge &RHS) {
343 return LHS.getOffset() <
RHS.getOffset();
345 for (
auto &E : SortedEdges) {
346 OS <<
" " <<
B->getFixupAddress(E) <<
" (block + "
347 <<
formatv(
"{0:x8}", E.getOffset()) <<
"), addend = ";
348 if (E.getAddend() >= 0)
351 OS <<
formatv(
"-{0:x8}", -E.getAddend());
353 if (E.getTarget().hasName())
354 OS << E.getTarget().getName();
357 <<
formatv(
"{0:x16}", E.getTarget().getAddress()) <<
"+"
358 <<
formatv(
"{0:x8}", E.getTarget().getOffset());
367 OS <<
"Absolute symbols:\n";
368 if (!absolute_symbols().empty()) {
369 for (
auto *
Sym : absolute_symbols())
374 OS <<
"\nExternal symbols:\n";
375 if (!external_symbols().empty()) {
376 for (
auto *
Sym : external_symbols())
385 case SymbolLookupFlags::RequiredSymbol:
386 return OS <<
"RequiredSymbol";
387 case SymbolLookupFlags::WeaklyReferencedSymbol:
388 return OS <<
"WeaklyReferencedSymbol";
393void JITLinkAsyncLookupContinuation::anchor() {}
395JITLinkContext::~JITLinkContext() =
default;
397bool JITLinkContext::shouldAddDefaultTargetPasses(
const Triple &TT)
const {
411 for (
auto *
Sym :
G.defined_symbols())
422 ErrStream <<
"In graph " <<
G.getName() <<
", section " << Sec.
getName()
423 <<
": relocation target ";
430 <<
" is out of range of " <<
G.getEdgeKindName(E.
getKind())
431 <<
" fixup at " <<
formatv(
"{0:x}",
B.getFixupAddress(E)) <<
" (";
433 Symbol *BestSymbolForBlock =
nullptr;
435 if (&
Sym->getBlock() == &
B &&
Sym->hasName() &&
Sym->getOffset() == 0 &&
436 (!BestSymbolForBlock ||
437 Sym->getScope() < BestSymbolForBlock->
getScope() ||
439 BestSymbolForBlock =
Sym;
441 if (BestSymbolForBlock)
442 ErrStream << BestSymbolForBlock->
getName() <<
", ";
444 ErrStream <<
"<anonymous block> @ ";
446 ErrStream <<
formatv(
"{0:x}",
B.getAddress()) <<
" + "
449 return make_error<JITLinkError>(std::move(ErrMsg));
454 return make_error<JITLinkError>(
"0x" + llvm::utohexstr(Loc.
getValue()) +
455 " improper alignment for relocation " +
457 llvm::utohexstr(
Value) +
458 " is not aligned to " +
Twine(
N) +
" bytes");
462 switch (TT.getArch()) {
464 return aarch64::createAnonymousPointer;
466 return x86_64::createAnonymousPointer;
468 return i386::createAnonymousPointer;
471 return loongarch::createAnonymousPointer;
478 switch (TT.getArch()) {
480 return aarch64::createAnonymousPointerJumpStub;
482 return x86_64::createAnonymousPointerJumpStub;
484 return i386::createAnonymousPointerJumpStub;
487 return loongarch::createAnonymousPointerJumpStub;
495 std::shared_ptr<orc::SymbolStringPool> SSP) {
505 return make_error<JITLinkError>(
"Unsupported file format");
509std::unique_ptr<LinkGraph>
511 std::shared_ptr<orc::SymbolStringPool> SSP,
513 unsigned PointerSize;
516 switch (TT.getArch()) {
531 static std::atomic<uint64_t> Counter = {0};
532 auto Index = Counter.fetch_add(1, std::memory_order_relaxed);
533 auto G = std::make_unique<LinkGraph>(
534 "<Absolute Symbols " + std::to_string(Index) +
">", std::move(SSP), TT,
535 PointerSize, Endianness,
nullptr);
536 for (
auto &[
Name, Def] : Symbols) {
538 G->addAbsoluteSymbol(*
Name, Def.getAddress(), 0,
539 Linkage::Strong, Scope::Default,
true);
540 Sym.setCallable(Def.getFlags().isCallable());
546void link(std::unique_ptr<LinkGraph>
G, std::unique_ptr<JITLinkContext> Ctx) {
547 switch (
G->getTargetTriple().getObjectFormat()) {
551 return link_ELF(std::move(
G), std::move(Ctx));
553 return link_COFF(std::move(
G), std::move(Ctx));
555 Ctx->notifyFailed(make_error<JITLinkError>(
"Unsupported object format"));
bbsections Prepares for basic block sections
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
DenseMap< Block *, BlockRelaxAux > Blocks
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
StringRef getBuffer() const
StringRef - Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
An Addressable with content and edges.
Section & getSection() const
Return the parent section for this block.
Represents fixups and constraints in the LinkGraph.
Symbol & getTarget() const
AddendT getAddend() const
OffsetT getOffset() const
std::error_code convertToErrorCode() const override
Convert this error to a std::error_code.
void log(raw_ostream &OS) const override
Print an error message to an output stream.
std::optional< SmallVector< Symbol *, 8 > > SplitBlockCache
Cache type for the splitBlock function.
void dump(raw_ostream &OS)
Dump the graph.
iterator_range< external_symbol_iterator > external_symbols()
iterator_range< defined_symbol_iterator > defined_symbols()
Represents an object file section.
iterator_range< symbol_iterator > symbols()
Returns an iterator over the symbols defined in this section.
StringRef getName() const
Returns the name of this section.
bool isLive() const
Returns true if this symbol is live (i.e.
const orc::SymbolStringPtr & getName() const
Returns the name of this symbol (empty if the symbol is anonymous).
bool isDefined() const
Returns true if this Symbol has content (potentially) defined within this object file (i....
Scope getScope() const
Get the visibility for this Symbol.
Linkage getLinkage() const
Get the linkage for this Symbol.
orc::ExecutorAddr getAddress() const
Returns the address of this symbol.
Block & getBlock()
Return the Block for this Symbol (Symbol must be defined).
orc::ExecutorAddrDiff getSize() const
Returns the size of this symbol.
orc::ExecutorAddrDiff getOffset() const
Returns the offset for this symbol within the underlying addressable.
bool isWeaklyReferenced() const
Returns true if this is a weakly referenced external symbol.
bool hasName() const
Returns true if this symbol has a name.
Represents an address in the executor process.
uint64_t getValue() const
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
unique_function is a type-erasing functor similar to std::function.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const char * getEdgeKindName(Edge::Kind K)
Get a human-readable name for the given AArch32 edge kind.
Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B, const Edge &E)
Create an out of range error for the given edge in the given block.
const char * getGenericEdgeKindName(Edge::Kind K)
Returns the string name of the given generic edge kind, or "unknown" otherwise.
const char * getLinkageName(Linkage L)
For errors and debugging output.
SymbolLookupFlags
Flags for symbol lookup.
Expected< std::unique_ptr< LinkGraph > > createLinkGraphFromCOFFObject(MemoryBufferRef ObjectBuffer, std::shared_ptr< orc::SymbolStringPool > SSP)
Create a LinkGraph from an COFF relocatable object.
Expected< std::unique_ptr< LinkGraph > > createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer, std::shared_ptr< orc::SymbolStringPool > SSP)
Create a LinkGraph from an ELF relocatable object.
Error makeAlignmentError(llvm::orc::ExecutorAddr Loc, uint64_t Value, int N, const Edge &E)
raw_ostream & operator<<(raw_ostream &OS, const Block &B)
PointerJumpStubCreator getPointerJumpStubCreator(const Triple &TT)
Get target-specific PointerJumpStubCreator.
void link(std::unique_ptr< LinkGraph > G, std::unique_ptr< JITLinkContext > Ctx)
Link the given graph.
Expected< std::unique_ptr< LinkGraph > > createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer, std::shared_ptr< orc::SymbolStringPool > SSP)
Create a LinkGraph from a MachO relocatable object.
Error markAllSymbolsLive(LinkGraph &G)
Marks all symbols in a graph live.
void link_COFF(std::unique_ptr< LinkGraph > G, std::unique_ptr< JITLinkContext > Ctx)
Link the given graph.
void link_ELF(std::unique_ptr< LinkGraph > G, std::unique_ptr< JITLinkContext > Ctx)
Link the given graph.
const char * getScopeName(Scope S)
For debugging output.
Expected< std::unique_ptr< LinkGraph > > createLinkGraphFromObject(MemoryBufferRef ObjectBuffer, std::shared_ptr< orc::SymbolStringPool > SSP)
Create a LinkGraph from the given object buffer.
Linkage
Describes symbol linkage. This can be used to resolve definition clashes.
void printEdge(raw_ostream &OS, const Block &B, const Edge &E, StringRef EdgeKindName)
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
bool isCStringBlock(Block &B)
void link_MachO(std::unique_ptr< LinkGraph > G, std::unique_ptr< JITLinkContext > Ctx)
jit-link the given ObjBuffer, which must be a MachO object file.
std::unique_ptr< LinkGraph > absoluteSymbolsLinkGraph(const Triple &TT, std::shared_ptr< orc::SymbolStringPool > SSP, orc::SymbolMap Symbols)
Create a LinkGraph defining the given absolute symbols.
AnonymousPointerCreator getAnonymousPointerCreator(const Triple &TT)
Get target-specific AnonymousPointerCreator.
Expected< const typename ELFT::Shdr * > getSection(typename ELFT::ShdrRange Sections, uint32_t Index)
NodeAddr< BlockNode * > Block
This is an optimization pass for GlobalISel generic memory operations.
file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
OutputIt copy(R &&Range, OutputIt Out)
@ elf_relocatable
ELF Relocatable object file.
@ macho_object
Mach-O Object file.
@ coff_object
COFF object file.
An LinkGraph pass configuration, consisting of a list of pre-prune, post-prune, and post-fixup passes...