Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
35266 views
//===-- RuntimeDyldImpl.h - Run-time dynamic linker for MC-JIT --*- C++ -*-===//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//===----------------------------------------------------------------------===//7//8// Interface for the implementations of runtime dynamic linker facilities.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H13#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H1415#include "llvm/ADT/SmallVector.h"16#include "llvm/ADT/StringMap.h"17#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"18#include "llvm/ExecutionEngine/RuntimeDyld.h"19#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"20#include "llvm/Object/ObjectFile.h"21#include "llvm/Support/Debug.h"22#include "llvm/Support/ErrorHandling.h"23#include "llvm/Support/Format.h"24#include "llvm/Support/Mutex.h"25#include "llvm/Support/SwapByteOrder.h"26#include "llvm/TargetParser/Host.h"27#include "llvm/TargetParser/Triple.h"28#include <deque>29#include <map>30#include <system_error>31#include <unordered_map>3233using namespace llvm;34using namespace llvm::object;3536namespace llvm {3738#define UNIMPLEMENTED_RELOC(RelType) \39case RelType: \40return make_error<RuntimeDyldError>("Unimplemented relocation: " #RelType)4142/// SectionEntry - represents a section emitted into memory by the dynamic43/// linker.44class SectionEntry {45/// Name - section name.46std::string Name;4748/// Address - address in the linker's memory where the section resides.49uint8_t *Address;5051/// Size - section size. Doesn't include the stubs.52size_t Size;5354/// LoadAddress - the address of the section in the target process's memory.55/// Used for situations in which JIT-ed code is being executed in the address56/// space of a separate process. If the code executes in the same address57/// space where it was JIT-ed, this just equals Address.58uint64_t LoadAddress;5960/// StubOffset - used for architectures with stub functions for far61/// relocations (like ARM).62uintptr_t StubOffset;6364/// The total amount of space allocated for this section. This includes the65/// section size and the maximum amount of space that the stubs can occupy.66size_t AllocationSize;6768/// ObjAddress - address of the section in the in-memory object file. Used69/// for calculating relocations in some object formats (like MachO).70uintptr_t ObjAddress;7172public:73SectionEntry(StringRef name, uint8_t *address, size_t size,74size_t allocationSize, uintptr_t objAddress)75: Name(std::string(name)), Address(address), Size(size),76LoadAddress(reinterpret_cast<uintptr_t>(address)), StubOffset(size),77AllocationSize(allocationSize), ObjAddress(objAddress) {78// AllocationSize is used only in asserts, prevent an "unused private field"79// warning:80(void)AllocationSize;81}8283StringRef getName() const { return Name; }8485uint8_t *getAddress() const { return Address; }8687/// Return the address of this section with an offset.88uint8_t *getAddressWithOffset(unsigned OffsetBytes) const {89assert(OffsetBytes <= AllocationSize && "Offset out of bounds!");90return Address + OffsetBytes;91}9293size_t getSize() const { return Size; }9495uint64_t getLoadAddress() const { return LoadAddress; }96void setLoadAddress(uint64_t LA) { LoadAddress = LA; }9798/// Return the load address of this section with an offset.99uint64_t getLoadAddressWithOffset(unsigned OffsetBytes) const {100assert(OffsetBytes <= AllocationSize && "Offset out of bounds!");101return LoadAddress + OffsetBytes;102}103104uintptr_t getStubOffset() const { return StubOffset; }105106void advanceStubOffset(unsigned StubSize) {107StubOffset += StubSize;108assert(StubOffset <= AllocationSize && "Not enough space allocated!");109}110111uintptr_t getObjAddress() const { return ObjAddress; }112};113114/// RelocationEntry - used to represent relocations internally in the dynamic115/// linker.116class RelocationEntry {117public:118/// Offset - offset into the section.119uint64_t Offset;120121/// Addend - the relocation addend encoded in the instruction itself. Also122/// used to make a relocation section relative instead of symbol relative.123int64_t Addend;124125/// SectionID - the section this relocation points to.126unsigned SectionID;127128/// RelType - relocation type.129uint32_t RelType;130131struct SectionPair {132uint32_t SectionA;133uint32_t SectionB;134};135136/// SymOffset - Section offset of the relocation entry's symbol (used for GOT137/// lookup).138union {139uint64_t SymOffset;140SectionPair Sections;141};142143/// The size of this relocation (MachO specific).144unsigned Size;145146/// True if this is a PCRel relocation (MachO specific).147bool IsPCRel : 1;148149// ARM (MachO and COFF) specific.150bool IsTargetThumbFunc : 1;151152RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend)153: Offset(offset), Addend(addend), SectionID(id), RelType(type),154SymOffset(0), Size(0), IsPCRel(false), IsTargetThumbFunc(false) {}155156RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,157uint64_t symoffset)158: Offset(offset), Addend(addend), SectionID(id), RelType(type),159SymOffset(symoffset), Size(0), IsPCRel(false),160IsTargetThumbFunc(false) {}161162RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,163bool IsPCRel, unsigned Size)164: Offset(offset), Addend(addend), SectionID(id), RelType(type),165SymOffset(0), Size(Size), IsPCRel(IsPCRel), IsTargetThumbFunc(false) {}166167RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,168unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB,169uint64_t SectionBOffset, bool IsPCRel, unsigned Size)170: Offset(offset), Addend(SectionAOffset - SectionBOffset + addend),171SectionID(id), RelType(type), Size(Size), IsPCRel(IsPCRel),172IsTargetThumbFunc(false) {173Sections.SectionA = SectionA;174Sections.SectionB = SectionB;175}176177RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,178unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB,179uint64_t SectionBOffset, bool IsPCRel, unsigned Size,180bool IsTargetThumbFunc)181: Offset(offset), Addend(SectionAOffset - SectionBOffset + addend),182SectionID(id), RelType(type), Size(Size), IsPCRel(IsPCRel),183IsTargetThumbFunc(IsTargetThumbFunc) {184Sections.SectionA = SectionA;185Sections.SectionB = SectionB;186}187};188189class RelocationValueRef {190public:191unsigned SectionID = 0;192uint64_t Offset = 0;193int64_t Addend = 0;194const char *SymbolName = nullptr;195bool IsStubThumb = false;196197inline bool operator==(const RelocationValueRef &Other) const {198return SectionID == Other.SectionID && Offset == Other.Offset &&199Addend == Other.Addend && SymbolName == Other.SymbolName &&200IsStubThumb == Other.IsStubThumb;201}202inline bool operator<(const RelocationValueRef &Other) const {203if (SectionID != Other.SectionID)204return SectionID < Other.SectionID;205if (Offset != Other.Offset)206return Offset < Other.Offset;207if (Addend != Other.Addend)208return Addend < Other.Addend;209if (IsStubThumb != Other.IsStubThumb)210return IsStubThumb < Other.IsStubThumb;211return SymbolName < Other.SymbolName;212}213};214215/// Symbol info for RuntimeDyld.216class SymbolTableEntry {217public:218SymbolTableEntry() = default;219220SymbolTableEntry(unsigned SectionID, uint64_t Offset, JITSymbolFlags Flags)221: Offset(Offset), SectionID(SectionID), Flags(Flags) {}222223unsigned getSectionID() const { return SectionID; }224uint64_t getOffset() const { return Offset; }225void setOffset(uint64_t NewOffset) { Offset = NewOffset; }226227JITSymbolFlags getFlags() const { return Flags; }228229private:230uint64_t Offset = 0;231unsigned SectionID = 0;232JITSymbolFlags Flags = JITSymbolFlags::None;233};234235typedef StringMap<SymbolTableEntry> RTDyldSymbolTable;236237class RuntimeDyldImpl {238friend class RuntimeDyld::LoadedObjectInfo;239protected:240static const unsigned AbsoluteSymbolSection = ~0U;241242// The MemoryManager to load objects into.243RuntimeDyld::MemoryManager &MemMgr;244245// The symbol resolver to use for external symbols.246JITSymbolResolver &Resolver;247248// A list of all sections emitted by the dynamic linker. These sections are249// referenced in the code by means of their index in this list - SectionID.250// Because references may be kept while the list grows, use a container that251// guarantees reference stability.252typedef std::deque<SectionEntry> SectionList;253SectionList Sections;254255typedef unsigned SID; // Type for SectionIDs256#define RTDYLD_INVALID_SECTION_ID ((RuntimeDyldImpl::SID)(-1))257258// Keep a map of sections from object file to the SectionID which259// references it.260typedef std::map<SectionRef, unsigned> ObjSectionToIDMap;261262// A global symbol table for symbols from all loaded modules.263RTDyldSymbolTable GlobalSymbolTable;264265// Keep a map of common symbols to their info pairs266typedef std::vector<SymbolRef> CommonSymbolList;267268// For each symbol, keep a list of relocations based on it. Anytime269// its address is reassigned (the JIT re-compiled the function, e.g.),270// the relocations get re-resolved.271// The symbol (or section) the relocation is sourced from is the Key272// in the relocation list where it's stored.273typedef SmallVector<RelocationEntry, 64> RelocationList;274// Relocations to sections already loaded. Indexed by SectionID which is the275// source of the address. The target where the address will be written is276// SectionID/Offset in the relocation itself.277std::unordered_map<unsigned, RelocationList> Relocations;278279// Relocations to external symbols that are not yet resolved. Symbols are280// external when they aren't found in the global symbol table of all loaded281// modules. This map is indexed by symbol name.282StringMap<RelocationList> ExternalSymbolRelocations;283284285typedef std::map<RelocationValueRef, uintptr_t> StubMap;286287Triple::ArchType Arch;288bool IsTargetLittleEndian;289bool IsMipsO32ABI;290bool IsMipsN32ABI;291bool IsMipsN64ABI;292293// True if all sections should be passed to the memory manager, false if only294// sections containing relocations should be. Defaults to 'false'.295bool ProcessAllSections;296297// This mutex prevents simultaneously loading objects from two different298// threads. This keeps us from having to protect individual data structures299// and guarantees that section allocation requests to the memory manager300// won't be interleaved between modules. It is also used in mapSectionAddress301// and resolveRelocations to protect write access to internal data structures.302//303// loadObject may be called on the same thread during the handling of304// processRelocations, and that's OK. The handling of the relocation lists305// is written in such a way as to work correctly if new elements are added to306// the end of the list while the list is being processed.307sys::Mutex lock;308309using NotifyStubEmittedFunction =310RuntimeDyld::NotifyStubEmittedFunction;311NotifyStubEmittedFunction NotifyStubEmitted;312313virtual unsigned getMaxStubSize() const = 0;314virtual Align getStubAlignment() = 0;315316bool HasError;317std::string ErrorStr;318319void writeInt16BE(uint8_t *Addr, uint16_t Value) {320llvm::support::endian::write<uint16_t>(Addr, Value,321IsTargetLittleEndian322? llvm::endianness::little323: llvm::endianness::big);324}325326void writeInt32BE(uint8_t *Addr, uint32_t Value) {327llvm::support::endian::write<uint32_t>(Addr, Value,328IsTargetLittleEndian329? llvm::endianness::little330: llvm::endianness::big);331}332333void writeInt64BE(uint8_t *Addr, uint64_t Value) {334llvm::support::endian::write<uint64_t>(Addr, Value,335IsTargetLittleEndian336? llvm::endianness::little337: llvm::endianness::big);338}339340virtual void setMipsABI(const ObjectFile &Obj) {341IsMipsO32ABI = false;342IsMipsN32ABI = false;343IsMipsN64ABI = false;344}345346/// Endian-aware read Read the least significant Size bytes from Src.347uint64_t readBytesUnaligned(uint8_t *Src, unsigned Size) const;348349/// Endian-aware write. Write the least significant Size bytes from Value to350/// Dst.351void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const;352353/// Generate JITSymbolFlags from a libObject symbol.354virtual Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &Sym);355356/// Modify the given target address based on the given symbol flags.357/// This can be used by subclasses to tweak addresses based on symbol flags,358/// For example: the MachO/ARM target uses it to set the low bit if the target359/// is a thumb symbol.360virtual uint64_t modifyAddressBasedOnFlags(uint64_t Addr,361JITSymbolFlags Flags) const {362return Addr;363}364365/// Given the common symbols discovered in the object file, emit a366/// new section for them and update the symbol mappings in the object and367/// symbol table.368Error emitCommonSymbols(const ObjectFile &Obj,369CommonSymbolList &CommonSymbols, uint64_t CommonSize,370uint32_t CommonAlign);371372/// Emits section data from the object file to the MemoryManager.373/// \param IsCode if it's true then allocateCodeSection() will be374/// used for emits, else allocateDataSection() will be used.375/// \return SectionID.376Expected<unsigned> emitSection(const ObjectFile &Obj,377const SectionRef &Section,378bool IsCode);379380/// Find Section in LocalSections. If the secton is not found - emit381/// it and store in LocalSections.382/// \param IsCode if it's true then allocateCodeSection() will be383/// used for emmits, else allocateDataSection() will be used.384/// \return SectionID.385Expected<unsigned> findOrEmitSection(const ObjectFile &Obj,386const SectionRef &Section, bool IsCode,387ObjSectionToIDMap &LocalSections);388389// Add a relocation entry that uses the given section.390void addRelocationForSection(const RelocationEntry &RE, unsigned SectionID);391392// Add a relocation entry that uses the given symbol. This symbol may393// be found in the global symbol table, or it may be external.394void addRelocationForSymbol(const RelocationEntry &RE, StringRef SymbolName);395396/// Emits long jump instruction to Addr.397/// \return Pointer to the memory area for emitting target address.398uint8_t *createStubFunction(uint8_t *Addr, unsigned AbiVariant = 0);399400/// Resolves relocations from Relocs list with address from Value.401void resolveRelocationList(const RelocationList &Relocs, uint64_t Value);402403/// A object file specific relocation resolver404/// \param RE The relocation to be resolved405/// \param Value Target symbol address to apply the relocation action406virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value) = 0;407408/// Parses one or more object file relocations (some object files use409/// relocation pairs) and stores it to Relocations or SymbolRelocations410/// (this depends on the object file type).411/// \return Iterator to the next relocation that needs to be parsed.412virtual Expected<relocation_iterator>413processRelocationRef(unsigned SectionID, relocation_iterator RelI,414const ObjectFile &Obj, ObjSectionToIDMap &ObjSectionToID,415StubMap &Stubs) = 0;416417void applyExternalSymbolRelocations(418const StringMap<JITEvaluatedSymbol> ExternalSymbolMap);419420/// Resolve relocations to external symbols.421Error resolveExternalSymbols();422423// Compute an upper bound of the memory that is required to load all424// sections425Error computeTotalAllocSize(const ObjectFile &Obj, uint64_t &CodeSize,426Align &CodeAlign, uint64_t &RODataSize,427Align &RODataAlign, uint64_t &RWDataSize,428Align &RWDataAlign);429430// Compute GOT size431unsigned computeGOTSize(const ObjectFile &Obj);432433// Compute the stub buffer size required for a section434unsigned computeSectionStubBufSize(const ObjectFile &Obj,435const SectionRef &Section);436437// Implementation of the generic part of the loadObject algorithm.438Expected<ObjSectionToIDMap> loadObjectImpl(const object::ObjectFile &Obj);439440// Return size of Global Offset Table (GOT) entry441virtual size_t getGOTEntrySize() { return 0; }442443// Hook for the subclasses to do further processing when a symbol is added to444// the global symbol table. This function may modify the symbol table entry.445virtual void processNewSymbol(const SymbolRef &ObjSymbol, SymbolTableEntry& Entry) {}446447// Return true if the relocation R may require allocating a GOT entry.448virtual bool relocationNeedsGot(const RelocationRef &R) const {449return false;450}451452// Return true if the relocation R may require allocating a stub.453virtual bool relocationNeedsStub(const RelocationRef &R) const {454return true; // Conservative answer455}456457public:458RuntimeDyldImpl(RuntimeDyld::MemoryManager &MemMgr,459JITSymbolResolver &Resolver)460: MemMgr(MemMgr), Resolver(Resolver),461ProcessAllSections(false), HasError(false) {462}463464virtual ~RuntimeDyldImpl();465466void setProcessAllSections(bool ProcessAllSections) {467this->ProcessAllSections = ProcessAllSections;468}469470virtual std::unique_ptr<RuntimeDyld::LoadedObjectInfo>471loadObject(const object::ObjectFile &Obj) = 0;472473uint64_t getSectionLoadAddress(unsigned SectionID) const {474if (SectionID == AbsoluteSymbolSection)475return 0;476else477return Sections[SectionID].getLoadAddress();478}479480uint8_t *getSectionAddress(unsigned SectionID) const {481if (SectionID == AbsoluteSymbolSection)482return nullptr;483else484return Sections[SectionID].getAddress();485}486487StringRef getSectionContent(unsigned SectionID) const {488if (SectionID == AbsoluteSymbolSection)489return {};490else491return StringRef(492reinterpret_cast<char *>(Sections[SectionID].getAddress()),493Sections[SectionID].getStubOffset() + getMaxStubSize());494}495496uint8_t* getSymbolLocalAddress(StringRef Name) const {497// FIXME: Just look up as a function for now. Overly simple of course.498// Work in progress.499RTDyldSymbolTable::const_iterator pos = GlobalSymbolTable.find(Name);500if (pos == GlobalSymbolTable.end())501return nullptr;502const auto &SymInfo = pos->second;503// Absolute symbols do not have a local address.504if (SymInfo.getSectionID() == AbsoluteSymbolSection)505return nullptr;506return getSectionAddress(SymInfo.getSectionID()) + SymInfo.getOffset();507}508509unsigned getSymbolSectionID(StringRef Name) const {510auto GSTItr = GlobalSymbolTable.find(Name);511if (GSTItr == GlobalSymbolTable.end())512return ~0U;513return GSTItr->second.getSectionID();514}515516JITEvaluatedSymbol getSymbol(StringRef Name) const {517// FIXME: Just look up as a function for now. Overly simple of course.518// Work in progress.519RTDyldSymbolTable::const_iterator pos = GlobalSymbolTable.find(Name);520if (pos == GlobalSymbolTable.end())521return nullptr;522const auto &SymEntry = pos->second;523uint64_t SectionAddr = 0;524if (SymEntry.getSectionID() != AbsoluteSymbolSection)525SectionAddr = getSectionLoadAddress(SymEntry.getSectionID());526uint64_t TargetAddr = SectionAddr + SymEntry.getOffset();527528// FIXME: Have getSymbol should return the actual address and the client529// modify it based on the flags. This will require clients to be530// aware of the target architecture, which we should build531// infrastructure for.532TargetAddr = modifyAddressBasedOnFlags(TargetAddr, SymEntry.getFlags());533return JITEvaluatedSymbol(TargetAddr, SymEntry.getFlags());534}535536std::map<StringRef, JITEvaluatedSymbol> getSymbolTable() const {537std::map<StringRef, JITEvaluatedSymbol> Result;538539for (const auto &KV : GlobalSymbolTable) {540auto SectionID = KV.second.getSectionID();541uint64_t SectionAddr = getSectionLoadAddress(SectionID);542Result[KV.first()] =543JITEvaluatedSymbol(SectionAddr + KV.second.getOffset(), KV.second.getFlags());544}545546return Result;547}548549void resolveRelocations();550551void resolveLocalRelocations();552553static void finalizeAsync(554std::unique_ptr<RuntimeDyldImpl> This,555unique_function<void(object::OwningBinary<object::ObjectFile>,556std::unique_ptr<RuntimeDyld::LoadedObjectInfo>,557Error)>558OnEmitted,559object::OwningBinary<object::ObjectFile> O,560std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info);561562void reassignSectionAddress(unsigned SectionID, uint64_t Addr);563564void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress);565566// Is the linker in an error state?567bool hasError() { return HasError; }568569// Mark the error condition as handled and continue.570void clearError() { HasError = false; }571572// Get the error message.573StringRef getErrorString() { return ErrorStr; }574575virtual bool isCompatibleFile(const ObjectFile &Obj) const = 0;576577void setNotifyStubEmitted(NotifyStubEmittedFunction NotifyStubEmitted) {578this->NotifyStubEmitted = std::move(NotifyStubEmitted);579}580581virtual void registerEHFrames();582583void deregisterEHFrames();584585virtual Error finalizeLoad(const ObjectFile &ObjImg,586ObjSectionToIDMap &SectionMap) {587return Error::success();588}589};590591} // end namespace llvm592593#endif594595596