600 lines · c
1//===-- RuntimeDyldImpl.h - Run-time dynamic linker for MC-JIT --*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// Interface for the implementations of runtime dynamic linker facilities.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H14#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H15 16#include "llvm/ADT/SmallVector.h"17#include "llvm/ADT/StringMap.h"18#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"19#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"20#include "llvm/ExecutionEngine/RuntimeDyld.h"21#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"22#include "llvm/Object/ObjectFile.h"23#include "llvm/Support/Debug.h"24#include "llvm/Support/ErrorHandling.h"25#include "llvm/Support/Format.h"26#include "llvm/Support/Mutex.h"27#include "llvm/Support/SwapByteOrder.h"28#include "llvm/TargetParser/Host.h"29#include "llvm/TargetParser/Triple.h"30#include <deque>31#include <map>32#include <system_error>33#include <unordered_map>34 35using namespace llvm;36using namespace llvm::object;37 38namespace llvm {39 40#define UNIMPLEMENTED_RELOC(RelType) \41 case RelType: \42 return make_error<RuntimeDyldError>("Unimplemented relocation: " #RelType)43 44/// SectionEntry - represents a section emitted into memory by the dynamic45/// linker.46class SectionEntry {47 /// Name - section name.48 std::string Name;49 50 /// Address - address in the linker's memory where the section resides.51 uint8_t *Address;52 53 /// Size - section size. Doesn't include the stubs.54 size_t Size;55 56 /// LoadAddress - the address of the section in the target process's memory.57 /// Used for situations in which JIT-ed code is being executed in the address58 /// space of a separate process. If the code executes in the same address59 /// space where it was JIT-ed, this just equals Address.60 uint64_t LoadAddress;61 62 /// StubOffset - used for architectures with stub functions for far63 /// relocations (like ARM).64 uintptr_t StubOffset;65 66 /// The total amount of space allocated for this section. This includes the67 /// section size and the maximum amount of space that the stubs can occupy.68 size_t AllocationSize;69 70 /// ObjAddress - address of the section in the in-memory object file. Used71 /// for calculating relocations in some object formats (like MachO).72 uintptr_t ObjAddress;73 74public:75 SectionEntry(StringRef name, uint8_t *address, size_t size,76 size_t allocationSize, uintptr_t objAddress)77 : Name(std::string(name)), Address(address), Size(size),78 LoadAddress(reinterpret_cast<uintptr_t>(address)), StubOffset(size),79 AllocationSize(allocationSize), ObjAddress(objAddress) {80 // AllocationSize is used only in asserts, prevent an "unused private field"81 // warning:82 (void)AllocationSize;83 }84 85 StringRef getName() const { return Name; }86 87 uint8_t *getAddress() const { return Address; }88 89 /// Return the address of this section with an offset.90 uint8_t *getAddressWithOffset(unsigned OffsetBytes) const {91 assert(OffsetBytes <= AllocationSize && "Offset out of bounds!");92 return Address + OffsetBytes;93 }94 95 size_t getSize() const { return Size; }96 97 uint64_t getLoadAddress() const { return LoadAddress; }98 void setLoadAddress(uint64_t LA) { LoadAddress = LA; }99 100 /// Return the load address of this section with an offset.101 uint64_t getLoadAddressWithOffset(unsigned OffsetBytes) const {102 assert(OffsetBytes <= AllocationSize && "Offset out of bounds!");103 return LoadAddress + OffsetBytes;104 }105 106 uintptr_t getStubOffset() const { return StubOffset; }107 108 void advanceStubOffset(unsigned StubSize) {109 StubOffset += StubSize;110 assert(StubOffset <= AllocationSize && "Not enough space allocated!");111 }112 113 uintptr_t getObjAddress() const { return ObjAddress; }114};115 116/// RelocationEntry - used to represent relocations internally in the dynamic117/// linker.118class RelocationEntry {119public:120 /// Offset - offset into the section.121 uint64_t Offset;122 123 /// Addend - the relocation addend encoded in the instruction itself. Also124 /// used to make a relocation section relative instead of symbol relative.125 int64_t Addend;126 127 /// SectionID - the section this relocation points to.128 unsigned SectionID;129 130 /// RelType - relocation type.131 uint32_t RelType;132 133 struct SectionPair {134 uint32_t SectionA;135 uint32_t SectionB;136 };137 138 /// SymOffset - Section offset of the relocation entry's symbol (used for GOT139 /// lookup).140 union {141 uint64_t SymOffset;142 SectionPair Sections;143 };144 145 /// The size of this relocation (MachO specific).146 unsigned Size;147 148 /// True if this is a PCRel relocation (MachO specific).149 bool IsPCRel : 1;150 151 // ARM (MachO and COFF) specific.152 bool IsTargetThumbFunc : 1;153 154 RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend)155 : Offset(offset), Addend(addend), SectionID(id), RelType(type),156 SymOffset(0), Size(0), IsPCRel(false), IsTargetThumbFunc(false) {}157 158 RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,159 uint64_t symoffset)160 : Offset(offset), Addend(addend), SectionID(id), RelType(type),161 SymOffset(symoffset), Size(0), IsPCRel(false),162 IsTargetThumbFunc(false) {}163 164 RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,165 bool IsPCRel, unsigned Size)166 : Offset(offset), Addend(addend), SectionID(id), RelType(type),167 SymOffset(0), Size(Size), IsPCRel(IsPCRel), IsTargetThumbFunc(false) {}168 169 RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,170 unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB,171 uint64_t SectionBOffset, bool IsPCRel, unsigned Size)172 : Offset(offset), Addend(SectionAOffset - SectionBOffset + addend),173 SectionID(id), RelType(type), Size(Size), IsPCRel(IsPCRel),174 IsTargetThumbFunc(false) {175 Sections.SectionA = SectionA;176 Sections.SectionB = SectionB;177 }178 179 RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,180 unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB,181 uint64_t SectionBOffset, bool IsPCRel, unsigned Size,182 bool IsTargetThumbFunc)183 : Offset(offset), Addend(SectionAOffset - SectionBOffset + addend),184 SectionID(id), RelType(type), Size(Size), IsPCRel(IsPCRel),185 IsTargetThumbFunc(IsTargetThumbFunc) {186 Sections.SectionA = SectionA;187 Sections.SectionB = SectionB;188 }189};190 191class RelocationValueRef {192public:193 unsigned SectionID = 0;194 uint64_t Offset = 0;195 int64_t Addend = 0;196 const char *SymbolName = nullptr;197 bool IsStubThumb = false;198 199 inline bool operator==(const RelocationValueRef &Other) const {200 return SectionID == Other.SectionID && Offset == Other.Offset &&201 Addend == Other.Addend && SymbolName == Other.SymbolName &&202 IsStubThumb == Other.IsStubThumb;203 }204 inline bool operator<(const RelocationValueRef &Other) const {205 return std::tie(SectionID, Offset, Addend, IsStubThumb, SymbolName) <206 std::tie(Other.SectionID, Other.Offset, Other.Addend,207 Other.IsStubThumb, Other.SymbolName);208 }209};210 211/// Symbol info for RuntimeDyld.212class SymbolTableEntry {213public:214 SymbolTableEntry() = default;215 216 SymbolTableEntry(unsigned SectionID, uint64_t Offset, JITSymbolFlags Flags)217 : Offset(Offset), SectionID(SectionID), Flags(Flags) {}218 219 unsigned getSectionID() const { return SectionID; }220 uint64_t getOffset() const { return Offset; }221 void setOffset(uint64_t NewOffset) { Offset = NewOffset; }222 223 JITSymbolFlags getFlags() const { return Flags; }224 225private:226 uint64_t Offset = 0;227 unsigned SectionID = 0;228 JITSymbolFlags Flags = JITSymbolFlags::None;229};230 231typedef StringMap<SymbolTableEntry> RTDyldSymbolTable;232 233class RuntimeDyldImpl {234 friend class RuntimeDyld::LoadedObjectInfo;235protected:236 static const unsigned AbsoluteSymbolSection = ~0U;237 238 // The MemoryManager to load objects into.239 RuntimeDyld::MemoryManager &MemMgr;240 241 // The symbol resolver to use for external symbols.242 JITSymbolResolver &Resolver;243 244 // A list of all sections emitted by the dynamic linker. These sections are245 // referenced in the code by means of their index in this list - SectionID.246 // Because references may be kept while the list grows, use a container that247 // guarantees reference stability.248 typedef std::deque<SectionEntry> SectionList;249 SectionList Sections;250 251 typedef unsigned SID; // Type for SectionIDs252#define RTDYLD_INVALID_SECTION_ID ((RuntimeDyldImpl::SID)(-1))253 254 // Keep a map of sections from object file to the SectionID which255 // references it.256 typedef std::map<SectionRef, unsigned> ObjSectionToIDMap;257 258 // A global symbol table for symbols from all loaded modules.259 RTDyldSymbolTable GlobalSymbolTable;260 261 // Keep a map of common symbols to their info pairs262 typedef std::vector<SymbolRef> CommonSymbolList;263 264 // For each symbol, keep a list of relocations based on it. Anytime265 // its address is reassigned (the JIT re-compiled the function, e.g.),266 // the relocations get re-resolved.267 // The symbol (or section) the relocation is sourced from is the Key268 // in the relocation list where it's stored.269 typedef SmallVector<RelocationEntry, 64> RelocationList;270 // Relocations to sections already loaded. Indexed by SectionID which is the271 // source of the address. The target where the address will be written is272 // SectionID/Offset in the relocation itself.273 std::unordered_map<unsigned, RelocationList> Relocations;274 275 // Relocations to external symbols that are not yet resolved. Symbols are276 // external when they aren't found in the global symbol table of all loaded277 // modules. This map is indexed by symbol name.278 StringMap<RelocationList> ExternalSymbolRelocations;279 280 281 typedef std::map<RelocationValueRef, uintptr_t> StubMap;282 283 Triple::ArchType Arch;284 bool IsTargetLittleEndian;285 bool IsMipsO32ABI;286 bool IsMipsN32ABI;287 bool IsMipsN64ABI;288 289 // True if all sections should be passed to the memory manager, false if only290 // sections containing relocations should be. Defaults to 'false'.291 bool ProcessAllSections;292 293 // This mutex prevents simultaneously loading objects from two different294 // threads. This keeps us from having to protect individual data structures295 // and guarantees that section allocation requests to the memory manager296 // won't be interleaved between modules. It is also used in mapSectionAddress297 // and resolveRelocations to protect write access to internal data structures.298 //299 // loadObject may be called on the same thread during the handling of300 // processRelocations, and that's OK. The handling of the relocation lists301 // is written in such a way as to work correctly if new elements are added to302 // the end of the list while the list is being processed.303 sys::Mutex lock;304 305 using NotifyStubEmittedFunction =306 RuntimeDyld::NotifyStubEmittedFunction;307 NotifyStubEmittedFunction NotifyStubEmitted;308 309 virtual unsigned getMaxStubSize() const = 0;310 virtual Align getStubAlignment() = 0;311 312 bool HasError;313 std::string ErrorStr;314 315 void writeInt16BE(uint8_t *Addr, uint16_t Value) {316 llvm::support::endian::write<uint16_t>(Addr, Value,317 IsTargetLittleEndian318 ? llvm::endianness::little319 : llvm::endianness::big);320 }321 322 void writeInt32BE(uint8_t *Addr, uint32_t Value) {323 llvm::support::endian::write<uint32_t>(Addr, Value,324 IsTargetLittleEndian325 ? llvm::endianness::little326 : llvm::endianness::big);327 }328 329 void writeInt64BE(uint8_t *Addr, uint64_t Value) {330 llvm::support::endian::write<uint64_t>(Addr, Value,331 IsTargetLittleEndian332 ? llvm::endianness::little333 : llvm::endianness::big);334 }335 336 virtual void setMipsABI(const ObjectFile &Obj) {337 IsMipsO32ABI = false;338 IsMipsN32ABI = false;339 IsMipsN64ABI = false;340 }341 342 /// Endian-aware read Read the least significant Size bytes from Src.343 uint64_t readBytesUnaligned(uint8_t *Src, unsigned Size) const;344 345 /// Endian-aware write. Write the least significant Size bytes from Value to346 /// Dst.347 void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const;348 349 /// Generate JITSymbolFlags from a libObject symbol.350 virtual Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &Sym);351 352 /// Modify the given target address based on the given symbol flags.353 /// This can be used by subclasses to tweak addresses based on symbol flags,354 /// For example: the MachO/ARM target uses it to set the low bit if the target355 /// is a thumb symbol.356 virtual uint64_t modifyAddressBasedOnFlags(uint64_t Addr,357 JITSymbolFlags Flags) const {358 return Addr;359 }360 361 /// Given the common symbols discovered in the object file, emit a362 /// new section for them and update the symbol mappings in the object and363 /// symbol table.364 Error emitCommonSymbols(const ObjectFile &Obj,365 CommonSymbolList &CommonSymbols, uint64_t CommonSize,366 uint32_t CommonAlign);367 368 /// Emits section data from the object file to the MemoryManager.369 /// \param IsCode if it's true then allocateCodeSection() will be370 /// used for emits, else allocateDataSection() will be used.371 /// \return SectionID.372 Expected<unsigned> emitSection(const ObjectFile &Obj,373 const SectionRef &Section,374 bool IsCode);375 376 /// Find Section in LocalSections. If the secton is not found - emit377 /// it and store in LocalSections.378 /// \param IsCode if it's true then allocateCodeSection() will be379 /// used for emmits, else allocateDataSection() will be used.380 /// \return SectionID.381 Expected<unsigned> findOrEmitSection(const ObjectFile &Obj,382 const SectionRef &Section, bool IsCode,383 ObjSectionToIDMap &LocalSections);384 385 // Add a relocation entry that uses the given section.386 void addRelocationForSection(const RelocationEntry &RE, unsigned SectionID);387 388 // Add a relocation entry that uses the given symbol. This symbol may389 // be found in the global symbol table, or it may be external.390 void addRelocationForSymbol(const RelocationEntry &RE, StringRef SymbolName);391 392 /// Emits long jump instruction to Addr.393 /// \return Pointer to the memory area for emitting target address.394 uint8_t *createStubFunction(uint8_t *Addr, unsigned AbiVariant = 0);395 396 /// Resolves relocations from Relocs list with address from Value.397 void resolveRelocationList(const RelocationList &Relocs, uint64_t Value);398 399 /// A object file specific relocation resolver400 /// \param RE The relocation to be resolved401 /// \param Value Target symbol address to apply the relocation action402 virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value) = 0;403 404 /// Parses one or more object file relocations (some object files use405 /// relocation pairs) and stores it to Relocations or SymbolRelocations406 /// (this depends on the object file type).407 /// \return Iterator to the next relocation that needs to be parsed.408 virtual Expected<relocation_iterator>409 processRelocationRef(unsigned SectionID, relocation_iterator RelI,410 const ObjectFile &Obj, ObjSectionToIDMap &ObjSectionToID,411 StubMap &Stubs) = 0;412 413 void applyExternalSymbolRelocations(414 const StringMap<JITEvaluatedSymbol> ExternalSymbolMap);415 416 /// Resolve relocations to external symbols.417 Error resolveExternalSymbols();418 419 // Compute an upper bound of the memory that is required to load all420 // sections421 Error computeTotalAllocSize(const ObjectFile &Obj, uint64_t &CodeSize,422 Align &CodeAlign, uint64_t &RODataSize,423 Align &RODataAlign, uint64_t &RWDataSize,424 Align &RWDataAlign);425 426 // Compute GOT size427 unsigned computeGOTSize(const ObjectFile &Obj);428 429 // Compute the stub buffer size required for a section430 unsigned computeSectionStubBufSize(const ObjectFile &Obj,431 const SectionRef &Section);432 433 // Implementation of the generic part of the loadObject algorithm.434 Expected<ObjSectionToIDMap> loadObjectImpl(const object::ObjectFile &Obj);435 436 // Return size of Global Offset Table (GOT) entry437 virtual size_t getGOTEntrySize() { return 0; }438 439 // Hook for the subclasses to do further processing when a symbol is added to440 // the global symbol table. This function may modify the symbol table entry.441 virtual void processNewSymbol(const SymbolRef &ObjSymbol, SymbolTableEntry& Entry) {}442 443 // Return true if the relocation R may require allocating a GOT entry.444 virtual bool relocationNeedsGot(const RelocationRef &R) const {445 return false;446 }447 448 // Return true if the relocation R may require allocating a stub.449 virtual bool relocationNeedsStub(const RelocationRef &R) const {450 return true; // Conservative answer451 }452 453 // Return true if the relocation R may require allocating a DLL import stub.454 virtual bool relocationNeedsDLLImportStub(const RelocationRef &R) const {455 return false;456 }457 458 // Add the size of a DLL import stub to the buffer size459 virtual unsigned sizeAfterAddingDLLImportStub(unsigned Size) const {460 return Size;461 }462 463public:464 RuntimeDyldImpl(RuntimeDyld::MemoryManager &MemMgr,465 JITSymbolResolver &Resolver)466 : MemMgr(MemMgr), Resolver(Resolver),467 ProcessAllSections(false), HasError(false) {468 }469 470 virtual ~RuntimeDyldImpl();471 472 void setProcessAllSections(bool ProcessAllSections) {473 this->ProcessAllSections = ProcessAllSections;474 }475 476 virtual std::unique_ptr<RuntimeDyld::LoadedObjectInfo>477 loadObject(const object::ObjectFile &Obj) = 0;478 479 uint64_t getSectionLoadAddress(unsigned SectionID) const {480 if (SectionID == AbsoluteSymbolSection)481 return 0;482 else483 return Sections[SectionID].getLoadAddress();484 }485 486 uint8_t *getSectionAddress(unsigned SectionID) const {487 if (SectionID == AbsoluteSymbolSection)488 return nullptr;489 else490 return Sections[SectionID].getAddress();491 }492 493 StringRef getSectionContent(unsigned SectionID) const {494 if (SectionID == AbsoluteSymbolSection)495 return {};496 else497 return StringRef(498 reinterpret_cast<char *>(Sections[SectionID].getAddress()),499 Sections[SectionID].getStubOffset() + getMaxStubSize());500 }501 502 uint8_t* getSymbolLocalAddress(StringRef Name) const {503 // FIXME: Just look up as a function for now. Overly simple of course.504 // Work in progress.505 RTDyldSymbolTable::const_iterator pos = GlobalSymbolTable.find(Name);506 if (pos == GlobalSymbolTable.end())507 return nullptr;508 const auto &SymInfo = pos->second;509 // Absolute symbols do not have a local address.510 if (SymInfo.getSectionID() == AbsoluteSymbolSection)511 return nullptr;512 return getSectionAddress(SymInfo.getSectionID()) + SymInfo.getOffset();513 }514 515 unsigned getSymbolSectionID(StringRef Name) const {516 auto GSTItr = GlobalSymbolTable.find(Name);517 if (GSTItr == GlobalSymbolTable.end())518 return ~0U;519 return GSTItr->second.getSectionID();520 }521 522 JITEvaluatedSymbol getSymbol(StringRef Name) const {523 // FIXME: Just look up as a function for now. Overly simple of course.524 // Work in progress.525 RTDyldSymbolTable::const_iterator pos = GlobalSymbolTable.find(Name);526 if (pos == GlobalSymbolTable.end())527 return nullptr;528 const auto &SymEntry = pos->second;529 uint64_t SectionAddr = 0;530 if (SymEntry.getSectionID() != AbsoluteSymbolSection)531 SectionAddr = getSectionLoadAddress(SymEntry.getSectionID());532 uint64_t TargetAddr = SectionAddr + SymEntry.getOffset();533 534 // FIXME: Have getSymbol should return the actual address and the client535 // modify it based on the flags. This will require clients to be536 // aware of the target architecture, which we should build537 // infrastructure for.538 TargetAddr = modifyAddressBasedOnFlags(TargetAddr, SymEntry.getFlags());539 return JITEvaluatedSymbol(TargetAddr, SymEntry.getFlags());540 }541 542 std::map<StringRef, JITEvaluatedSymbol> getSymbolTable() const {543 std::map<StringRef, JITEvaluatedSymbol> Result;544 545 for (const auto &KV : GlobalSymbolTable) {546 auto SectionID = KV.second.getSectionID();547 uint64_t SectionAddr = getSectionLoadAddress(SectionID);548 Result[KV.first()] =549 JITEvaluatedSymbol(SectionAddr + KV.second.getOffset(), KV.second.getFlags());550 }551 552 return Result;553 }554 555 void resolveRelocations();556 557 void resolveLocalRelocations();558 559 static void finalizeAsync(560 std::unique_ptr<RuntimeDyldImpl> This,561 unique_function<void(object::OwningBinary<object::ObjectFile>,562 std::unique_ptr<RuntimeDyld::LoadedObjectInfo>,563 Error)>564 OnEmitted,565 object::OwningBinary<object::ObjectFile> O,566 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info);567 568 void reassignSectionAddress(unsigned SectionID, uint64_t Addr);569 570 void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress);571 572 // Is the linker in an error state?573 bool hasError() { return HasError; }574 575 // Mark the error condition as handled and continue.576 void clearError() { HasError = false; }577 578 // Get the error message.579 StringRef getErrorString() { return ErrorStr; }580 581 virtual bool isCompatibleFile(const ObjectFile &Obj) const = 0;582 583 void setNotifyStubEmitted(NotifyStubEmittedFunction NotifyStubEmitted) {584 this->NotifyStubEmitted = std::move(NotifyStubEmitted);585 }586 587 virtual void registerEHFrames();588 589 void deregisterEHFrames();590 591 virtual Error finalizeLoad(const ObjectFile &ObjImg,592 ObjSectionToIDMap &SectionMap) {593 return Error::success();594 }595};596 597} // end namespace llvm598 599#endif600