brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.1 KiB · 89b2097 Raw
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