Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
35271 views
//===------------- JITLink.cpp - Core Run-time JIT linker APIs ------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ExecutionEngine/JITLink/JITLink.h"910#include "llvm/ADT/StringExtras.h"11#include "llvm/BinaryFormat/Magic.h"12#include "llvm/ExecutionEngine/JITLink/COFF.h"13#include "llvm/ExecutionEngine/JITLink/ELF.h"14#include "llvm/ExecutionEngine/JITLink/MachO.h"15#include "llvm/ExecutionEngine/JITLink/aarch64.h"16#include "llvm/ExecutionEngine/JITLink/i386.h"17#include "llvm/ExecutionEngine/JITLink/loongarch.h"18#include "llvm/ExecutionEngine/JITLink/x86_64.h"19#include "llvm/Support/Format.h"20#include "llvm/Support/MemoryBuffer.h"21#include "llvm/Support/raw_ostream.h"2223using namespace llvm;24using namespace llvm::object;2526#define DEBUG_TYPE "jitlink"2728namespace {2930enum JITLinkErrorCode { GenericJITLinkError = 1 };3132// FIXME: This class is only here to support the transition to llvm::Error. It33// will be removed once this transition is complete. Clients should prefer to34// deal with the Error value directly, rather than converting to error_code.35class JITLinkerErrorCategory : public std::error_category {36public:37const char *name() const noexcept override { return "runtimedyld"; }3839std::string message(int Condition) const override {40switch (static_cast<JITLinkErrorCode>(Condition)) {41case GenericJITLinkError:42return "Generic JITLink error";43}44llvm_unreachable("Unrecognized JITLinkErrorCode");45}46};4748} // namespace4950namespace llvm {51namespace jitlink {5253char JITLinkError::ID = 0;5455void JITLinkError::log(raw_ostream &OS) const { OS << ErrMsg; }5657std::error_code JITLinkError::convertToErrorCode() const {58static JITLinkerErrorCategory TheJITLinkerErrorCategory;59return std::error_code(GenericJITLinkError, TheJITLinkerErrorCategory);60}6162const char *getGenericEdgeKindName(Edge::Kind K) {63switch (K) {64case Edge::Invalid:65return "INVALID RELOCATION";66case Edge::KeepAlive:67return "Keep-Alive";68default:69return "<Unrecognized edge kind>";70}71}7273const char *getLinkageName(Linkage L) {74switch (L) {75case Linkage::Strong:76return "strong";77case Linkage::Weak:78return "weak";79}80llvm_unreachable("Unrecognized llvm.jitlink.Linkage enum");81}8283const char *getScopeName(Scope S) {84switch (S) {85case Scope::Default:86return "default";87case Scope::Hidden:88return "hidden";89case Scope::Local:90return "local";91}92llvm_unreachable("Unrecognized llvm.jitlink.Scope enum");93}9495bool isCStringBlock(Block &B) {96if (B.getSize() == 0) // Empty blocks are not valid C-strings.97return false;9899// Zero-fill blocks of size one are valid empty strings.100if (B.isZeroFill())101return B.getSize() == 1;102103for (size_t I = 0; I != B.getSize() - 1; ++I)104if (B.getContent()[I] == '\0')105return false;106107return B.getContent()[B.getSize() - 1] == '\0';108}109110raw_ostream &operator<<(raw_ostream &OS, const Block &B) {111return OS << B.getAddress() << " -- " << (B.getAddress() + B.getSize())112<< ": "113<< "size = " << formatv("{0:x8}", B.getSize()) << ", "114<< (B.isZeroFill() ? "zero-fill" : "content")115<< ", align = " << B.getAlignment()116<< ", align-ofs = " << B.getAlignmentOffset()117<< ", section = " << B.getSection().getName();118}119120raw_ostream &operator<<(raw_ostream &OS, const Symbol &Sym) {121OS << Sym.getAddress() << " (" << (Sym.isDefined() ? "block" : "addressable")122<< " + " << formatv("{0:x8}", Sym.getOffset())123<< "): size: " << formatv("{0:x8}", Sym.getSize())124<< ", linkage: " << formatv("{0:6}", getLinkageName(Sym.getLinkage()))125<< ", scope: " << formatv("{0:8}", getScopeName(Sym.getScope())) << ", "126<< (Sym.isLive() ? "live" : "dead") << " - "127<< (Sym.hasName() ? Sym.getName() : "<anonymous symbol>");128return OS;129}130131void printEdge(raw_ostream &OS, const Block &B, const Edge &E,132StringRef EdgeKindName) {133OS << "edge@" << B.getAddress() + E.getOffset() << ": " << B.getAddress()134<< " + " << formatv("{0:x}", E.getOffset()) << " -- " << EdgeKindName135<< " -> ";136137auto &TargetSym = E.getTarget();138if (TargetSym.hasName())139OS << TargetSym.getName();140else {141auto &TargetBlock = TargetSym.getBlock();142auto &TargetSec = TargetBlock.getSection();143orc::ExecutorAddr SecAddress(~uint64_t(0));144for (auto *B : TargetSec.blocks())145if (B->getAddress() < SecAddress)146SecAddress = B->getAddress();147148orc::ExecutorAddrDiff SecDelta = TargetSym.getAddress() - SecAddress;149OS << TargetSym.getAddress() << " (section " << TargetSec.getName();150if (SecDelta)151OS << " + " << formatv("{0:x}", SecDelta);152OS << " / block " << TargetBlock.getAddress();153if (TargetSym.getOffset())154OS << " + " << formatv("{0:x}", TargetSym.getOffset());155OS << ")";156}157158if (E.getAddend() != 0)159OS << " + " << E.getAddend();160}161162Section::~Section() {163for (auto *Sym : Symbols)164Sym->~Symbol();165for (auto *B : Blocks)166B->~Block();167}168169Block &LinkGraph::splitBlock(Block &B, size_t SplitIndex,170SplitBlockCache *Cache) {171172assert(SplitIndex > 0 && "splitBlock can not be called with SplitIndex == 0");173174// If the split point covers all of B then just return B.175if (SplitIndex == B.getSize())176return B;177178assert(SplitIndex < B.getSize() && "SplitIndex out of range");179180// Create the new block covering [ 0, SplitIndex ).181auto &NewBlock =182B.isZeroFill()183? createZeroFillBlock(B.getSection(), SplitIndex, B.getAddress(),184B.getAlignment(), B.getAlignmentOffset())185: createContentBlock(186B.getSection(), B.getContent().slice(0, SplitIndex),187B.getAddress(), B.getAlignment(), B.getAlignmentOffset());188189// Modify B to cover [ SplitIndex, B.size() ).190B.setAddress(B.getAddress() + SplitIndex);191B.setContent(B.getContent().slice(SplitIndex));192B.setAlignmentOffset((B.getAlignmentOffset() + SplitIndex) %193B.getAlignment());194195// Handle edge transfer/update.196{197// Copy edges to NewBlock (recording their iterators so that we can remove198// them from B), and update of Edges remaining on B.199std::vector<Block::edge_iterator> EdgesToRemove;200for (auto I = B.edges().begin(); I != B.edges().end();) {201if (I->getOffset() < SplitIndex) {202NewBlock.addEdge(*I);203I = B.removeEdge(I);204} else {205I->setOffset(I->getOffset() - SplitIndex);206++I;207}208}209}210211// Handle symbol transfer/update.212{213// Initialize the symbols cache if necessary.214SplitBlockCache LocalBlockSymbolsCache;215if (!Cache)216Cache = &LocalBlockSymbolsCache;217if (*Cache == std::nullopt) {218*Cache = SplitBlockCache::value_type();219for (auto *Sym : B.getSection().symbols())220if (&Sym->getBlock() == &B)221(*Cache)->push_back(Sym);222223llvm::sort(**Cache, [](const Symbol *LHS, const Symbol *RHS) {224return LHS->getOffset() > RHS->getOffset();225});226}227auto &BlockSymbols = **Cache;228229// Transfer all symbols with offset less than SplitIndex to NewBlock.230while (!BlockSymbols.empty() &&231BlockSymbols.back()->getOffset() < SplitIndex) {232auto *Sym = BlockSymbols.back();233// If the symbol extends beyond the split, update the size to be within234// the new block.235if (Sym->getOffset() + Sym->getSize() > SplitIndex)236Sym->setSize(SplitIndex - Sym->getOffset());237Sym->setBlock(NewBlock);238BlockSymbols.pop_back();239}240241// Update offsets for all remaining symbols in B.242for (auto *Sym : BlockSymbols)243Sym->setOffset(Sym->getOffset() - SplitIndex);244}245246return NewBlock;247}248249void LinkGraph::dump(raw_ostream &OS) {250DenseMap<Block *, std::vector<Symbol *>> BlockSymbols;251252// Map from blocks to the symbols pointing at them.253for (auto *Sym : defined_symbols())254BlockSymbols[&Sym->getBlock()].push_back(Sym);255256// For each block, sort its symbols by something approximating257// relevance.258for (auto &KV : BlockSymbols)259llvm::sort(KV.second, [](const Symbol *LHS, const Symbol *RHS) {260if (LHS->getOffset() != RHS->getOffset())261return LHS->getOffset() < RHS->getOffset();262if (LHS->getLinkage() != RHS->getLinkage())263return LHS->getLinkage() < RHS->getLinkage();264if (LHS->getScope() != RHS->getScope())265return LHS->getScope() < RHS->getScope();266if (LHS->hasName()) {267if (!RHS->hasName())268return true;269return LHS->getName() < RHS->getName();270}271return false;272});273274for (auto &Sec : sections()) {275OS << "section " << Sec.getName() << ":\n\n";276277std::vector<Block *> SortedBlocks;278llvm::copy(Sec.blocks(), std::back_inserter(SortedBlocks));279llvm::sort(SortedBlocks, [](const Block *LHS, const Block *RHS) {280return LHS->getAddress() < RHS->getAddress();281});282283for (auto *B : SortedBlocks) {284OS << " block " << B->getAddress()285<< " size = " << formatv("{0:x8}", B->getSize())286<< ", align = " << B->getAlignment()287<< ", alignment-offset = " << B->getAlignmentOffset();288if (B->isZeroFill())289OS << ", zero-fill";290OS << "\n";291292auto BlockSymsI = BlockSymbols.find(B);293if (BlockSymsI != BlockSymbols.end()) {294OS << " symbols:\n";295auto &Syms = BlockSymsI->second;296for (auto *Sym : Syms)297OS << " " << *Sym << "\n";298} else299OS << " no symbols\n";300301if (!B->edges_empty()) {302OS << " edges:\n";303std::vector<Edge> SortedEdges;304llvm::copy(B->edges(), std::back_inserter(SortedEdges));305llvm::sort(SortedEdges, [](const Edge &LHS, const Edge &RHS) {306return LHS.getOffset() < RHS.getOffset();307});308for (auto &E : SortedEdges) {309OS << " " << B->getFixupAddress(E) << " (block + "310<< formatv("{0:x8}", E.getOffset()) << "), addend = ";311if (E.getAddend() >= 0)312OS << formatv("+{0:x8}", E.getAddend());313else314OS << formatv("-{0:x8}", -E.getAddend());315OS << ", kind = " << getEdgeKindName(E.getKind()) << ", target = ";316if (E.getTarget().hasName())317OS << E.getTarget().getName();318else319OS << "addressable@"320<< formatv("{0:x16}", E.getTarget().getAddress()) << "+"321<< formatv("{0:x8}", E.getTarget().getOffset());322OS << "\n";323}324} else325OS << " no edges\n";326OS << "\n";327}328}329330OS << "Absolute symbols:\n";331if (!absolute_symbols().empty()) {332for (auto *Sym : absolute_symbols())333OS << " " << Sym->getAddress() << ": " << *Sym << "\n";334} else335OS << " none\n";336337OS << "\nExternal symbols:\n";338if (!external_symbols().empty()) {339for (auto *Sym : external_symbols())340OS << " " << Sym->getAddress() << ": " << *Sym341<< (Sym->isWeaklyReferenced() ? " (weakly referenced)" : "") << "\n";342} else343OS << " none\n";344}345346raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupFlags &LF) {347switch (LF) {348case SymbolLookupFlags::RequiredSymbol:349return OS << "RequiredSymbol";350case SymbolLookupFlags::WeaklyReferencedSymbol:351return OS << "WeaklyReferencedSymbol";352}353llvm_unreachable("Unrecognized lookup flags");354}355356void JITLinkAsyncLookupContinuation::anchor() {}357358JITLinkContext::~JITLinkContext() = default;359360bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const {361return true;362}363364LinkGraphPassFunction JITLinkContext::getMarkLivePass(const Triple &TT) const {365return LinkGraphPassFunction();366}367368Error JITLinkContext::modifyPassConfig(LinkGraph &G,369PassConfiguration &Config) {370return Error::success();371}372373Error markAllSymbolsLive(LinkGraph &G) {374for (auto *Sym : G.defined_symbols())375Sym->setLive(true);376return Error::success();377}378379Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B,380const Edge &E) {381std::string ErrMsg;382{383raw_string_ostream ErrStream(ErrMsg);384Section &Sec = B.getSection();385ErrStream << "In graph " << G.getName() << ", section " << Sec.getName()386<< ": relocation target ";387if (E.getTarget().hasName()) {388ErrStream << "\"" << E.getTarget().getName() << "\"";389} else390ErrStream << E.getTarget().getBlock().getSection().getName() << " + "391<< formatv("{0:x}", E.getOffset());392ErrStream << " at address " << formatv("{0:x}", E.getTarget().getAddress())393<< " is out of range of " << G.getEdgeKindName(E.getKind())394<< " fixup at " << formatv("{0:x}", B.getFixupAddress(E)) << " (";395396Symbol *BestSymbolForBlock = nullptr;397for (auto *Sym : Sec.symbols())398if (&Sym->getBlock() == &B && Sym->hasName() && Sym->getOffset() == 0 &&399(!BestSymbolForBlock ||400Sym->getScope() < BestSymbolForBlock->getScope() ||401Sym->getLinkage() < BestSymbolForBlock->getLinkage()))402BestSymbolForBlock = Sym;403404if (BestSymbolForBlock)405ErrStream << BestSymbolForBlock->getName() << ", ";406else407ErrStream << "<anonymous block> @ ";408409ErrStream << formatv("{0:x}", B.getAddress()) << " + "410<< formatv("{0:x}", E.getOffset()) << ")";411}412return make_error<JITLinkError>(std::move(ErrMsg));413}414415Error makeAlignmentError(llvm::orc::ExecutorAddr Loc, uint64_t Value, int N,416const Edge &E) {417return make_error<JITLinkError>("0x" + llvm::utohexstr(Loc.getValue()) +418" improper alignment for relocation " +419formatv("{0:d}", E.getKind()) + ": 0x" +420llvm::utohexstr(Value) +421" is not aligned to " + Twine(N) + " bytes");422}423424AnonymousPointerCreator getAnonymousPointerCreator(const Triple &TT) {425switch (TT.getArch()) {426case Triple::aarch64:427return aarch64::createAnonymousPointer;428case Triple::x86_64:429return x86_64::createAnonymousPointer;430case Triple::x86:431return i386::createAnonymousPointer;432case Triple::loongarch32:433case Triple::loongarch64:434return loongarch::createAnonymousPointer;435default:436return nullptr;437}438}439440PointerJumpStubCreator getPointerJumpStubCreator(const Triple &TT) {441switch (TT.getArch()) {442case Triple::aarch64:443return aarch64::createAnonymousPointerJumpStub;444case Triple::x86_64:445return x86_64::createAnonymousPointerJumpStub;446case Triple::x86:447return i386::createAnonymousPointerJumpStub;448case Triple::loongarch32:449case Triple::loongarch64:450return loongarch::createAnonymousPointerJumpStub;451default:452return nullptr;453}454}455456Expected<std::unique_ptr<LinkGraph>>457createLinkGraphFromObject(MemoryBufferRef ObjectBuffer) {458auto Magic = identify_magic(ObjectBuffer.getBuffer());459switch (Magic) {460case file_magic::macho_object:461return createLinkGraphFromMachOObject(ObjectBuffer);462case file_magic::elf_relocatable:463return createLinkGraphFromELFObject(ObjectBuffer);464case file_magic::coff_object:465return createLinkGraphFromCOFFObject(ObjectBuffer);466default:467return make_error<JITLinkError>("Unsupported file format");468};469}470471std::unique_ptr<LinkGraph> absoluteSymbolsLinkGraph(const Triple &TT,472orc::SymbolMap Symbols) {473unsigned PointerSize;474endianness Endianness =475TT.isLittleEndian() ? endianness::little : endianness::big;476switch (TT.getArch()) {477case Triple::aarch64:478case llvm::Triple::riscv64:479case Triple::x86_64:480PointerSize = 8;481break;482case llvm::Triple::arm:483case llvm::Triple::riscv32:484case llvm::Triple::x86:485PointerSize = 4;486break;487default:488llvm::report_fatal_error("unhandled target architecture");489}490491static std::atomic<uint64_t> Counter = {0};492auto Index = Counter.fetch_add(1, std::memory_order_relaxed);493auto G = std::make_unique<LinkGraph>(494"<Absolute Symbols " + std::to_string(Index) + ">", TT, PointerSize,495Endianness, /*GetEdgeKindName=*/nullptr);496for (auto &[Name, Def] : Symbols) {497auto &Sym =498G->addAbsoluteSymbol(*Name, Def.getAddress(), /*Size=*/0,499Linkage::Strong, Scope::Default, /*IsLive=*/true);500Sym.setCallable(Def.getFlags().isCallable());501}502503return G;504}505506void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx) {507switch (G->getTargetTriple().getObjectFormat()) {508case Triple::MachO:509return link_MachO(std::move(G), std::move(Ctx));510case Triple::ELF:511return link_ELF(std::move(G), std::move(Ctx));512case Triple::COFF:513return link_COFF(std::move(G), std::move(Ctx));514default:515Ctx->notifyFailed(make_error<JITLinkError>("Unsupported object format"));516};517}518519} // end namespace jitlink520} // end namespace llvm521522523