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