diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2014-11-24 09:08:18 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2014-11-24 09:08:18 +0000 |
| commit | 5ca98fd98791947eba83a1ed3f2c8191ef7afa6c (patch) | |
| tree | f5944309621cee4fe0976be6f9ac619b7ebfc4c2 /lib/ExecutionEngine/RuntimeDyld | |
| parent | 68bcb7db193e4bc81430063148253d30a791023e (diff) | |
Notes
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld')
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp | 51 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/LLVMBuild.txt | 2 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h | 62 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | 619 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp | 656 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 987 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h | 117 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h | 164 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp | 517 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h | 194 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h | 255 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h | 154 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h | 315 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h | 132 |
15 files changed, 2968 insertions, 1258 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt b/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt index cbf7cf14d4915..eb1a60b60d08e 100644 --- a/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt +++ b/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_library(LLVMRuntimeDyld GDBRegistrar.cpp RuntimeDyld.cpp + RuntimeDyldChecker.cpp RuntimeDyldELF.cpp RuntimeDyldMachO.cpp ) diff --git a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp index 603c526d06e3c..85465715873fb 100644 --- a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" +#include "llvm/Support/ManagedStatic.h" using namespace llvm; @@ -44,10 +45,16 @@ extern "C" { // We put information about the JITed function in this global, which the // debugger reads. Make sure to specify the version statically, because the // debugger checks the version before we can set it during runtime. - struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; + struct jit_descriptor __jit_debug_descriptor = { 1, 0, nullptr, nullptr }; // Debuggers puts a breakpoint in this function. - LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { } + LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { + // The noinline and the asm prevent calls to this function from being + // optimized out. +#if !defined(_MSC_VER) + asm volatile("":::"memory"); +#endif + } } @@ -78,12 +85,12 @@ public: /// Creates an entry in the JIT registry for the buffer @p Object, /// which must contain an object file in executable memory with any /// debug information for the debugger. - void registerObject(const ObjectBuffer &Object); + void registerObject(const ObjectBuffer &Object) override; /// Removes the internal registration of @p Object, and /// frees associated resources. /// Returns true if @p Object was found in ObjectBufferMap. - bool deregisterObject(const ObjectBuffer &Object); + bool deregisterObject(const ObjectBuffer &Object) override; private: /// Deregister the debug info for the given object file from the debugger @@ -96,16 +103,15 @@ private: /// modify global variables. llvm::sys::Mutex JITDebugLock; -/// Acquire the lock and do the registration. +/// Do the registration. void NotifyDebugger(jit_code_entry* JITCodeEntry) { - llvm::MutexGuard locked(JITDebugLock); __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; // Insert this entry at the head of the list. - JITCodeEntry->prev_entry = NULL; + JITCodeEntry->prev_entry = nullptr; jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry; JITCodeEntry->next_entry = NextEntry; - if (NextEntry != NULL) { + if (NextEntry) { NextEntry->prev_entry = JITCodeEntry; } __jit_debug_descriptor.first_entry = JITCodeEntry; @@ -115,7 +121,8 @@ void NotifyDebugger(jit_code_entry* JITCodeEntry) { GDBJITRegistrar::~GDBJITRegistrar() { // Free all registered object files. - for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end(); + llvm::MutexGuard locked(JITDebugLock); + for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end(); I != E; ++I) { // Call the private method that doesn't update the map so our iterator // doesn't break. @@ -130,15 +137,15 @@ void GDBJITRegistrar::registerObject(const ObjectBuffer &Object) { size_t Size = Object.getBufferSize(); assert(Buffer && "Attempt to register a null object with a debugger."); + llvm::MutexGuard locked(JITDebugLock); assert(ObjectBufferMap.find(Buffer) == ObjectBufferMap.end() && "Second attempt to perform debug registration."); jit_code_entry* JITCodeEntry = new jit_code_entry(); - if (JITCodeEntry == 0) { + if (!JITCodeEntry) { llvm::report_fatal_error( "Allocation failed when registering a JIT entry!\n"); - } - else { + } else { JITCodeEntry->symfile_addr = Buffer; JITCodeEntry->symfile_size = Size; @@ -149,6 +156,7 @@ void GDBJITRegistrar::registerObject(const ObjectBuffer &Object) { bool GDBJITRegistrar::deregisterObject(const ObjectBuffer& Object) { const char *Buffer = Object.getBufferStart(); + llvm::MutexGuard locked(JITDebugLock); RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Buffer); if (I != ObjectBufferMap.end()) { @@ -164,9 +172,8 @@ void GDBJITRegistrar::deregisterObjectInternal( jit_code_entry*& JITCodeEntry = I->second.second; - // Acquire the lock and do the unregistration. + // Do the unregistration. { - llvm::MutexGuard locked(JITDebugLock); __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; // Remove the jit_code_entry from the linked list. @@ -190,25 +197,17 @@ void GDBJITRegistrar::deregisterObjectInternal( } delete JITCodeEntry; - JITCodeEntry = NULL; + JITCodeEntry = nullptr; } +llvm::ManagedStatic<GDBJITRegistrar> TheRegistrar; + } // end namespace namespace llvm { JITRegistrar& JITRegistrar::getGDBRegistrar() { - static GDBJITRegistrar* sRegistrar = NULL; - if (sRegistrar == NULL) { - // The mutex is here so that it won't slow down access once the registrar - // is instantiated - llvm::MutexGuard locked(JITDebugLock); - // Check again to be sure another thread didn't create this while we waited - if (sRegistrar == NULL) { - sRegistrar = new GDBJITRegistrar; - } - } - return *sRegistrar; + return *TheRegistrar; } } // namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/LLVMBuild.txt b/lib/ExecutionEngine/RuntimeDyld/LLVMBuild.txt index 97dc86129a33f..8bd5621918916 100644 --- a/lib/ExecutionEngine/RuntimeDyld/LLVMBuild.txt +++ b/lib/ExecutionEngine/RuntimeDyld/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = RuntimeDyld parent = ExecutionEngine -required_libraries = Object Support +required_libraries = MC Object Support diff --git a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h index 9cbde5daede5e..c3a21823bbc84 100644 --- a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h +++ b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h @@ -1,6 +1,6 @@ //===-- ObjectImageCommon.h - Format independent executuable object image -===// // -// The LLVM Compiler Infrastructure +// The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. @@ -18,21 +18,27 @@ #include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/Object/ObjectFile.h" +#include <memory> + namespace llvm { +namespace object { + class ObjectFile; +} + class ObjectImageCommon : public ObjectImage { ObjectImageCommon(); // = delete ObjectImageCommon(const ObjectImageCommon &other); // = delete - virtual void anchor(); + void anchor() override; protected: - object::ObjectFile *ObjFile; + std::unique_ptr<object::ObjectFile> ObjFile; // This form of the constructor allows subclasses to use // format-specific subclasses of ObjectFile directly - ObjectImageCommon(ObjectBuffer *Input, object::ObjectFile *Obj) + ObjectImageCommon(ObjectBuffer *Input, std::unique_ptr<object::ObjectFile> Obj) : ObjectImage(Input), // saves Input as Buffer and takes ownership - ObjFile(Obj) + ObjFile(std::move(Obj)) { } @@ -40,40 +46,44 @@ public: ObjectImageCommon(ObjectBuffer* Input) : ObjectImage(Input) // saves Input as Buffer and takes ownership { - ObjFile = object::ObjectFile::createObjectFile(Buffer->getMemBuffer()); + // FIXME: error checking? createObjectFile returns an ErrorOr<ObjectFile*> + // and should probably be checked for failure. + std::unique_ptr<MemoryBuffer> Buf(Buffer->getMemBuffer()); + ObjFile.reset(object::ObjectFile::createObjectFile(Buf).get()); } - virtual ~ObjectImageCommon() { delete ObjFile; } + ObjectImageCommon(std::unique_ptr<object::ObjectFile> Input) + : ObjectImage(nullptr), ObjFile(std::move(Input)) {} + virtual ~ObjectImageCommon() { } - virtual object::symbol_iterator begin_symbols() const - { return ObjFile->begin_symbols(); } - virtual object::symbol_iterator end_symbols() const - { return ObjFile->end_symbols(); } + object::symbol_iterator begin_symbols() const override + { return ObjFile->symbol_begin(); } + object::symbol_iterator end_symbols() const override + { return ObjFile->symbol_end(); } - virtual object::section_iterator begin_sections() const - { return ObjFile->begin_sections(); } - virtual object::section_iterator end_sections() const - { return ObjFile->end_sections(); } + object::section_iterator begin_sections() const override + { return ObjFile->section_begin(); } + object::section_iterator end_sections() const override + { return ObjFile->section_end(); } - virtual /* Triple::ArchType */ unsigned getArch() const - { return ObjFile->getArch(); } + /* Triple::ArchType */ unsigned getArch() const override + { return ObjFile->getArch(); } - virtual StringRef getData() const { return ObjFile->getData(); } + StringRef getData() const override { return ObjFile->getData(); } - virtual object::ObjectFile* getObjectFile() const { return ObjFile; } + object::ObjectFile* getObjectFile() const override { return ObjFile.get(); } // Subclasses can override these methods to update the image with loaded // addresses for sections and common symbols - virtual void updateSectionAddress(const object::SectionRef &Sec, - uint64_t Addr) {} - virtual void updateSymbolAddress(const object::SymbolRef &Sym, uint64_t Addr) - {} + void updateSectionAddress(const object::SectionRef &Sec, + uint64_t Addr) override {} + void updateSymbolAddress(const object::SymbolRef &Sym, + uint64_t Addr) override {} // Subclasses can override these methods to provide JIT debugging support - virtual void registerWithDebugger() {} - virtual void deregisterWithDebugger() {} + void registerWithDebugger() override {} + void deregisterWithDebugger() override {} }; } // end namespace llvm #endif // LLVM_RUNTIMEDYLD_OBJECT_IMAGE_H - diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 161135a4f8c0f..d86a751306850 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -11,21 +11,21 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "JITRegistrar.h" #include "ObjectImageCommon.h" #include "RuntimeDyldELF.h" #include "RuntimeDyldImpl.h" #include "RuntimeDyldMachO.h" -#include "llvm/Support/FileSystem.h" +#include "llvm/Object/ELF.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MutexGuard.h" -#include "llvm/Object/ELF.h" using namespace llvm; using namespace llvm::object; +#define DEBUG_TYPE "dyld" + // Empty out-of-line virtual destructor as the key function. RuntimeDyldImpl::~RuntimeDyldImpl() {} @@ -36,11 +36,9 @@ void ObjectImageCommon::anchor() {} namespace llvm { -void RuntimeDyldImpl::registerEHFrames() { -} +void RuntimeDyldImpl::registerEHFrames() {} -void RuntimeDyldImpl::deregisterEHFrames() { -} +void RuntimeDyldImpl::deregisterEHFrames() {} // Resolve the relocations for all symbols we currently know about. void RuntimeDyldImpl::resolveRelocations() { @@ -56,9 +54,8 @@ void RuntimeDyldImpl::resolveRelocations() { // symbol for the relocation is located. The SectionID in the relocation // entry provides the section to which the relocation will be applied. uint64_t Addr = Sections[i].LoadAddress; - DEBUG(dbgs() << "Resolving relocations Section #" << i - << "\t" << format("%p", (uint8_t *)Addr) - << "\n"); + DEBUG(dbgs() << "Resolving relocations Section #" << i << "\t" + << format("%p", (uint8_t *)Addr) << "\n"); resolveRelocationList(Relocations[i], Addr); Relocations.erase(i); } @@ -76,22 +73,52 @@ void RuntimeDyldImpl::mapSectionAddress(const void *LocalAddress, llvm_unreachable("Attempting to remap address of unknown section!"); } -// Subclasses can implement this method to create specialized image instances. -// The caller owns the pointer that is returned. -ObjectImage *RuntimeDyldImpl::createObjectImage(ObjectBuffer *InputBuffer) { - return new ObjectImageCommon(InputBuffer); +static std::error_code getOffset(const SymbolRef &Sym, uint64_t &Result) { + uint64_t Address; + if (std::error_code EC = Sym.getAddress(Address)) + return EC; + + if (Address == UnknownAddressOrSize) { + Result = UnknownAddressOrSize; + return object_error::success; + } + + const ObjectFile *Obj = Sym.getObject(); + section_iterator SecI(Obj->section_begin()); + if (std::error_code EC = Sym.getSection(SecI)) + return EC; + + if (SecI == Obj->section_end()) { + Result = UnknownAddressOrSize; + return object_error::success; + } + + uint64_t SectionAddress; + if (std::error_code EC = SecI->getAddress(SectionAddress)) + return EC; + + Result = Address - SectionAddress; + return object_error::success; } -ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) { +ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { MutexGuard locked(lock); - OwningPtr<ObjectImage> obj(createObjectImage(InputBuffer)); - if (!obj) - report_fatal_error("Unable to create object image from memory buffer!"); + std::unique_ptr<ObjectImage> Obj(InputObject); + if (!Obj) + return nullptr; // Save information about our target - Arch = (Triple::ArchType)obj->getArch(); - IsTargetLittleEndian = obj->getObjectFile()->isLittleEndian(); + Arch = (Triple::ArchType)Obj->getArch(); + IsTargetLittleEndian = Obj->getObjectFile()->isLittleEndian(); + + // Compute the memory size required to load all sections to be loaded + // and pass this information to the memory manager + if (MemMgr->needsToReserveAllocationSpace()) { + uint64_t CodeSize = 0, DataSizeRO = 0, DataSizeRW = 0; + computeTotalAllocSize(*Obj, CodeSize, DataSizeRO, DataSizeRW); + MemMgr->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW); + } // Symbols found in this object StringMap<SymbolLoc> LocalSymbols; @@ -103,52 +130,47 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) { // Maximum required total memory to allocate all common symbols uint64_t CommonSize = 0; - error_code err; // Parse symbols DEBUG(dbgs() << "Parse symbols:\n"); - for (symbol_iterator i = obj->begin_symbols(), e = obj->end_symbols(); - i != e; i.increment(err)) { - Check(err); + for (symbol_iterator I = Obj->begin_symbols(), E = Obj->end_symbols(); I != E; + ++I) { object::SymbolRef::Type SymType; StringRef Name; - Check(i->getType(SymType)); - Check(i->getName(Name)); + Check(I->getType(SymType)); + Check(I->getName(Name)); - uint32_t flags; - Check(i->getFlags(flags)); + uint32_t Flags = I->getFlags(); - bool isCommon = flags & SymbolRef::SF_Common; - if (isCommon) { + bool IsCommon = Flags & SymbolRef::SF_Common; + if (IsCommon) { // Add the common symbols to a list. We'll allocate them all below. - uint32_t Align; - Check(i->getAlignment(Align)); - uint64_t Size = 0; - Check(i->getSize(Size)); - CommonSize += Size + Align; - CommonSymbols[*i] = CommonSymbolInfo(Size, Align); + if (!GlobalSymbolTable.count(Name)) { + uint32_t Align; + Check(I->getAlignment(Align)); + uint64_t Size = 0; + Check(I->getSize(Size)); + CommonSize += Size + Align; + CommonSymbols[*I] = CommonSymbolInfo(Size, Align); + } } else { if (SymType == object::SymbolRef::ST_Function || SymType == object::SymbolRef::ST_Data || SymType == object::SymbolRef::ST_Unknown) { - uint64_t FileOffset; + uint64_t SectOffset; StringRef SectionData; bool IsCode; - section_iterator si = obj->end_sections(); - Check(i->getFileOffset(FileOffset)); - Check(i->getSection(si)); - if (si == obj->end_sections()) continue; - Check(si->getContents(SectionData)); - Check(si->isText(IsCode)); - const uint8_t* SymPtr = (const uint8_t*)InputBuffer->getBufferStart() + - (uintptr_t)FileOffset; - uintptr_t SectOffset = (uintptr_t)(SymPtr - - (const uint8_t*)SectionData.begin()); - unsigned SectionID = findOrEmitSection(*obj, *si, IsCode, LocalSections); + section_iterator SI = Obj->end_sections(); + Check(getOffset(*I, SectOffset)); + Check(I->getSection(SI)); + if (SI == Obj->end_sections()) + continue; + Check(SI->getContents(SectionData)); + Check(SI->isText(IsCode)); + unsigned SectionID = + findOrEmitSection(*Obj, *SI, IsCode, LocalSections); LocalSymbols[Name.data()] = SymbolLoc(SectionID, SectOffset); - DEBUG(dbgs() << "\tFileOffset: " << format("%p", (uintptr_t)FileOffset) - << " flags: " << flags - << " SID: " << SectionID - << " Offset: " << format("%p", SectOffset)); + DEBUG(dbgs() << "\tOffset: " << format("%p", (uintptr_t)SectOffset) + << " flags: " << Flags << " SID: " << SectionID); GlobalSymbolTable[Name] = SymbolLoc(SectionID, SectOffset); } } @@ -157,39 +179,179 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) { // Allocate common symbols if (CommonSize != 0) - emitCommonSymbols(*obj, CommonSymbols, CommonSize, LocalSymbols); + emitCommonSymbols(*Obj, CommonSymbols, CommonSize, GlobalSymbolTable); // Parse and process relocations DEBUG(dbgs() << "Parse relocations:\n"); - for (section_iterator si = obj->begin_sections(), - se = obj->end_sections(); si != se; si.increment(err)) { - Check(err); - bool isFirstRelocation = true; + for (section_iterator SI = Obj->begin_sections(), SE = Obj->end_sections(); + SI != SE; ++SI) { unsigned SectionID = 0; StubMap Stubs; - section_iterator RelocatedSection = si->getRelocatedSection(); + section_iterator RelocatedSection = SI->getRelocatedSection(); + + relocation_iterator I = SI->relocation_begin(); + relocation_iterator E = SI->relocation_end(); + + if (I == E && !ProcessAllSections) + continue; + + bool IsCode = false; + Check(RelocatedSection->isText(IsCode)); + SectionID = + findOrEmitSection(*Obj, *RelocatedSection, IsCode, LocalSections); + DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n"); + + for (; I != E;) + I = processRelocationRef(SectionID, I, *Obj, LocalSections, LocalSymbols, + Stubs); + } - for (relocation_iterator i = si->begin_relocations(), - e = si->end_relocations(); i != e; i.increment(err)) { - Check(err); + // Give the subclasses a chance to tie-up any loose ends. + finalizeLoad(*Obj, LocalSections); + + return Obj.release(); +} + +// A helper method for computeTotalAllocSize. +// Computes the memory size required to allocate sections with the given sizes, +// assuming that all sections are allocated with the given alignment +static uint64_t +computeAllocationSizeForSections(std::vector<uint64_t> &SectionSizes, + uint64_t Alignment) { + uint64_t TotalSize = 0; + for (size_t Idx = 0, Cnt = SectionSizes.size(); Idx < Cnt; Idx++) { + uint64_t AlignedSize = + (SectionSizes[Idx] + Alignment - 1) / Alignment * Alignment; + TotalSize += AlignedSize; + } + return TotalSize; +} + +// Compute an upper bound of the memory size that is required to load all +// sections +void RuntimeDyldImpl::computeTotalAllocSize(ObjectImage &Obj, + uint64_t &CodeSize, + uint64_t &DataSizeRO, + uint64_t &DataSizeRW) { + // Compute the size of all sections required for execution + std::vector<uint64_t> CodeSectionSizes; + std::vector<uint64_t> ROSectionSizes; + std::vector<uint64_t> RWSectionSizes; + uint64_t MaxAlignment = sizeof(void *); + + // Collect sizes of all sections to be loaded; + // also determine the max alignment of all sections + for (section_iterator SI = Obj.begin_sections(), SE = Obj.end_sections(); + SI != SE; ++SI) { + const SectionRef &Section = *SI; + + bool IsRequired; + Check(Section.isRequiredForExecution(IsRequired)); + + // Consider only the sections that are required to be loaded for execution + if (IsRequired) { + uint64_t DataSize = 0; + uint64_t Alignment64 = 0; + bool IsCode = false; + bool IsReadOnly = false; + StringRef Name; + Check(Section.getSize(DataSize)); + Check(Section.getAlignment(Alignment64)); + Check(Section.isText(IsCode)); + Check(Section.isReadOnlyData(IsReadOnly)); + Check(Section.getName(Name)); + unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; + + uint64_t StubBufSize = computeSectionStubBufSize(Obj, Section); + uint64_t SectionSize = DataSize + StubBufSize; + + // The .eh_frame section (at least on Linux) needs an extra four bytes + // padded + // with zeroes added at the end. For MachO objects, this section has a + // slightly different name, so this won't have any effect for MachO + // objects. + if (Name == ".eh_frame") + SectionSize += 4; - // If it's the first relocation in this section, find its SectionID - if (isFirstRelocation) { - SectionID = - findOrEmitSection(*obj, *RelocatedSection, true, LocalSections); - DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n"); - isFirstRelocation = false; + if (SectionSize > 0) { + // save the total size of the section + if (IsCode) { + CodeSectionSizes.push_back(SectionSize); + } else if (IsReadOnly) { + ROSectionSizes.push_back(SectionSize); + } else { + RWSectionSizes.push_back(SectionSize); + } + // update the max alignment + if (Alignment > MaxAlignment) { + MaxAlignment = Alignment; + } } + } + } - processRelocationRef(SectionID, *i, *obj, LocalSections, LocalSymbols, - Stubs); + // Compute the size of all common symbols + uint64_t CommonSize = 0; + for (symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E; + ++I) { + uint32_t Flags = I->getFlags(); + if (Flags & SymbolRef::SF_Common) { + // Add the common symbols to a list. We'll allocate them all below. + uint64_t Size = 0; + Check(I->getSize(Size)); + CommonSize += Size; } } + if (CommonSize != 0) { + RWSectionSizes.push_back(CommonSize); + } - // Give the subclasses a chance to tie-up any loose ends. - finalizeLoad(LocalSections); + // Compute the required allocation space for each different type of sections + // (code, read-only data, read-write data) assuming that all sections are + // allocated with the max alignment. Note that we cannot compute with the + // individual alignments of the sections, because then the required size + // depends on the order, in which the sections are allocated. + CodeSize = computeAllocationSizeForSections(CodeSectionSizes, MaxAlignment); + DataSizeRO = computeAllocationSizeForSections(ROSectionSizes, MaxAlignment); + DataSizeRW = computeAllocationSizeForSections(RWSectionSizes, MaxAlignment); +} + +// compute stub buffer size for the given section +unsigned RuntimeDyldImpl::computeSectionStubBufSize(ObjectImage &Obj, + const SectionRef &Section) { + unsigned StubSize = getMaxStubSize(); + if (StubSize == 0) { + return 0; + } + // FIXME: this is an inefficient way to handle this. We should computed the + // necessary section allocation size in loadObject by walking all the sections + // once. + unsigned StubBufSize = 0; + for (section_iterator SI = Obj.begin_sections(), SE = Obj.end_sections(); + SI != SE; ++SI) { + section_iterator RelSecI = SI->getRelocatedSection(); + if (!(RelSecI == Section)) + continue; + + for (const RelocationRef &Reloc : SI->relocations()) { + (void)Reloc; + StubBufSize += StubSize; + } + } + + // Get section data size and alignment + uint64_t Alignment64; + uint64_t DataSize; + Check(Section.getSize(DataSize)); + Check(Section.getAlignment(Alignment64)); - return obj.take(); + // Add stubbuf size alignment + unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; + unsigned StubAlignment = getStubAlignment(); + unsigned EndAlignment = (DataSize | Alignment) & -(DataSize | Alignment); + if (StubAlignment > EndAlignment) + StubBufSize += StubAlignment - EndAlignment; + return StubBufSize; } void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, @@ -198,22 +360,20 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, SymbolTableMap &SymbolTable) { // Allocate memory for the section unsigned SectionID = Sections.size(); - uint8_t *Addr = MemMgr->allocateDataSection( - TotalSize, sizeof(void*), SectionID, StringRef(), false); + uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, sizeof(void *), + SectionID, StringRef(), false); if (!Addr) report_fatal_error("Unable to allocate memory for common symbols!"); uint64_t Offset = 0; Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize, 0)); memset(Addr, 0, TotalSize); - DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID - << " new addr: " << format("%p", Addr) - << " DataSize: " << TotalSize - << "\n"); + DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID << " new addr: " + << format("%p", Addr) << " DataSize: " << TotalSize << "\n"); // Assign the address of each symbol for (CommonSymbolMap::const_iterator it = CommonSymbols.begin(), - itEnd = CommonSymbols.end(); it != itEnd; it++) { + itEnd = CommonSymbols.end(); it != itEnd; ++it) { uint64_t Size = it->second.first; uint64_t Align = it->second.second; StringRef Name; @@ -223,8 +383,8 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, uint64_t AlignOffset = OffsetToAlignment((uint64_t)Addr, Align); Addr += AlignOffset; Offset += AlignOffset; - DEBUG(dbgs() << "Allocating common symbol " << Name << " address " << - format("%p\n", Addr)); + DEBUG(dbgs() << "Allocating common symbol " << Name << " address " + << format("%p\n", Addr)); } Obj.updateSymbolAddress(it->first, (uint64_t)Addr); SymbolTable[Name.data()] = SymbolLoc(SectionID, Offset); @@ -234,30 +394,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, } unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, - const SectionRef &Section, - bool IsCode) { - - unsigned StubBufSize = 0, - StubSize = getMaxStubSize(); - error_code err; - const ObjectFile *ObjFile = Obj.getObjectFile(); - // FIXME: this is an inefficient way to handle this. We should computed the - // necessary section allocation size in loadObject by walking all the sections - // once. - if (StubSize > 0) { - for (section_iterator SI = ObjFile->begin_sections(), - SE = ObjFile->end_sections(); - SI != SE; SI.increment(err), Check(err)) { - section_iterator RelSecI = SI->getRelocatedSection(); - if (!(RelSecI == Section)) - continue; - - for (relocation_iterator I = SI->begin_relocations(), - E = SI->end_relocations(); I != E; I.increment(err), Check(err)) { - StubBufSize += StubSize; - } - } - } + const SectionRef &Section, bool IsCode) { StringRef data; uint64_t Alignment64; @@ -271,6 +408,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, bool IsReadOnly; uint64_t DataSize; unsigned PaddingSize = 0; + unsigned StubBufSize = 0; StringRef Name; Check(Section.isRequiredForExecution(IsRequired)); Check(Section.isVirtual(IsVirtual)); @@ -278,12 +416,8 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, Check(Section.isReadOnlyData(IsReadOnly)); Check(Section.getSize(DataSize)); Check(Section.getName(Name)); - if (StubSize > 0) { - unsigned StubAlignment = getStubAlignment(); - unsigned EndAlignment = (DataSize | Alignment) & -(DataSize | Alignment); - if (StubAlignment > EndAlignment) - StubBufSize += StubAlignment - EndAlignment; - } + + StubBufSize = computeSectionStubBufSize(Obj, Section); // The .eh_frame section (at least on Linux) needs an extra four bytes padded // with zeroes added at the end. For MachO objects, this section has a @@ -291,19 +425,19 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, if (Name == ".eh_frame") PaddingSize = 4; - unsigned Allocate; + uintptr_t Allocate; unsigned SectionID = Sections.size(); uint8_t *Addr; - const char *pData = 0; + const char *pData = nullptr; // Some sections, such as debug info, don't need to be loaded for execution. // Leave those where they are. if (IsRequired) { Allocate = DataSize + PaddingSize + StubBufSize; - Addr = IsCode - ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID, Name) - : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, Name, - IsReadOnly); + Addr = IsCode ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID, + Name) + : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, + Name, IsReadOnly); if (!Addr) report_fatal_error("Unable to allocate section memory!"); @@ -324,30 +458,22 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, DataSize += PaddingSize; } - DEBUG(dbgs() << "emitSection SectionID: " << SectionID - << " Name: " << Name + DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name << " obj addr: " << format("%p", pData) << " new addr: " << format("%p", Addr) - << " DataSize: " << DataSize - << " StubBufSize: " << StubBufSize - << " Allocate: " << Allocate - << "\n"); + << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize + << " Allocate: " << Allocate << "\n"); Obj.updateSectionAddress(Section, (uint64_t)Addr); - } - else { + } else { // Even if we didn't load the section, we need to record an entry for it // to handle later processing (and by 'handle' I mean don't do anything // with these sections). Allocate = 0; - Addr = 0; - DEBUG(dbgs() << "emitSection SectionID: " << SectionID - << " Name: " << Name - << " obj addr: " << format("%p", data.data()) - << " new addr: 0" - << " DataSize: " << DataSize - << " StubBufSize: " << StubBufSize - << " Allocate: " << Allocate - << "\n"); + Addr = nullptr; + DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name + << " obj addr: " << format("%p", data.data()) << " new addr: 0" + << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize + << " Allocate: " << Allocate << "\n"); } Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData)); @@ -380,8 +506,7 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, // Relocation by symbol. If the symbol is found in the global symbol table, // create an appropriate section relocation. Otherwise, add it to // ExternalSymbolRelocations. - SymbolTableMap::const_iterator Loc = - GlobalSymbolTable.find(SymbolName); + SymbolTableMap::const_iterator Loc = GlobalSymbolTable.find(SymbolName); if (Loc == GlobalSymbolTable.end()) { ExternalSymbolRelocations[SymbolName].push_back(RE); } else { @@ -392,12 +517,14 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, } } -uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { - if (Arch == Triple::aarch64) { +uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr, + unsigned AbiVariant) { + if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be || + Arch == Triple::arm64 || Arch == Triple::arm64_be) { // This stub has to be able to access the full address space, // since symbol lookup won't necessarily find a handy, in-range, // PLT stub for functions which could be anywhere. - uint32_t *StubAddr = (uint32_t*)Addr; + uint32_t *StubAddr = (uint32_t *)Addr; // Stub can use ip0 (== x16) to calculate address *StubAddr = 0xd2e00010; // movz ip0, #:abs_g3:<addr> @@ -411,14 +538,14 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { *StubAddr = 0xd61f0200; // br ip0 return Addr; - } else if (Arch == Triple::arm) { + } else if (Arch == Triple::arm || Arch == Triple::armeb) { // TODO: There is only ARM far stub now. We should add the Thumb stub, // and stubs for branches Thumb - ARM and ARM - Thumb. - uint32_t *StubAddr = (uint32_t*)Addr; + uint32_t *StubAddr = (uint32_t *)Addr; *StubAddr = 0xe51ff004; // ldr pc,<label> - return (uint8_t*)++StubAddr; + return (uint8_t *)++StubAddr; } else if (Arch == Triple::mipsel || Arch == Triple::mips) { - uint32_t *StubAddr = (uint32_t*)Addr; + uint32_t *StubAddr = (uint32_t *)Addr; // 0: 3c190000 lui t9,%hi(addr). // 4: 27390000 addiu t9,t9,%lo(addr). // 8: 03200008 jr t9. @@ -435,22 +562,31 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { *StubAddr = NopInstr; return Addr; } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { - // PowerPC64 stub: the address points to a function descriptor - // instead of the function itself. Load the function address - // on r11 and sets it to control register. Also loads the function - // TOC in r2 and environment pointer to r11. + // Depending on which version of the ELF ABI is in use, we need to + // generate one of two variants of the stub. They both start with + // the same sequence to load the target address into r12. writeInt32BE(Addr, 0x3D800000); // lis r12, highest(addr) writeInt32BE(Addr+4, 0x618C0000); // ori r12, higher(addr) writeInt32BE(Addr+8, 0x798C07C6); // sldi r12, r12, 32 writeInt32BE(Addr+12, 0x658C0000); // oris r12, r12, h(addr) writeInt32BE(Addr+16, 0x618C0000); // ori r12, r12, l(addr) - writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1) - writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12) - writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12) - writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11 - writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2) - writeInt32BE(Addr+40, 0x4E800420); // bctr - + if (AbiVariant == 2) { + // PowerPC64 stub ELFv2 ABI: The address points to the function itself. + // The address is already in r12 as required by the ABI. Branch to it. + writeInt32BE(Addr+20, 0xF8410018); // std r2, 24(r1) + writeInt32BE(Addr+24, 0x7D8903A6); // mtctr r12 + writeInt32BE(Addr+28, 0x4E800420); // bctr + } else { + // PowerPC64 stub ELFv1 ABI: The address points to a function descriptor. + // Load the function address on r11 and sets it to control register. Also + // loads the function TOC in r2 and environment pointer to r11. + writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1) + writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12) + writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12) + writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11 + writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2) + writeInt32BE(Addr+40, 0x4E800420); // bctr + } return Addr; } else if (Arch == Triple::systemz) { writeInt16BE(Addr, 0xC418); // lgrl %r1,.+8 @@ -463,6 +599,8 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { *Addr = 0xFF; // jmp *(Addr+1) = 0x25; // rip // 32-bit PC-relative address of the GOT entry will be stored at Addr+2 + } else if (Arch == Triple::x86) { + *Addr = 0xE9; // 32-bit pc-relative jump. } return Addr; } @@ -489,36 +627,37 @@ void RuntimeDyldImpl::resolveRelocationList(const RelocationList &Relocs, for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { const RelocationEntry &RE = Relocs[i]; // Ignore relocations for sections that were not loaded - if (Sections[RE.SectionID].Address == 0) + if (Sections[RE.SectionID].Address == nullptr) continue; resolveRelocation(RE, Value); } } void RuntimeDyldImpl::resolveExternalSymbols() { - while(!ExternalSymbolRelocations.empty()) { + while (!ExternalSymbolRelocations.empty()) { StringMap<RelocationList>::iterator i = ExternalSymbolRelocations.begin(); StringRef Name = i->first(); if (Name.size() == 0) { // This is an absolute symbol, use an address of zero. - DEBUG(dbgs() << "Resolving absolute relocations." << "\n"); + DEBUG(dbgs() << "Resolving absolute relocations." + << "\n"); RelocationList &Relocs = i->second; resolveRelocationList(Relocs, 0); } else { uint64_t Addr = 0; SymbolTableMap::const_iterator Loc = GlobalSymbolTable.find(Name); if (Loc == GlobalSymbolTable.end()) { - // This is an external symbol, try to get its address from - // MemoryManager. - Addr = MemMgr->getSymbolAddress(Name.data()); - // The call to getSymbolAddress may have caused additional modules to - // be loaded, which may have added new entries to the - // ExternalSymbolRelocations map. Consquently, we need to update our - // iterator. This is also why retrieval of the relocation list - // associated with this symbol is deferred until below this point. - // New entries may have been added to the relocation list. - i = ExternalSymbolRelocations.find(Name); + // This is an external symbol, try to get its address from + // MemoryManager. + Addr = MemMgr->getSymbolAddress(Name.data()); + // The call to getSymbolAddress may have caused additional modules to + // be loaded, which may have added new entries to the + // ExternalSymbolRelocations map. Consquently, we need to update our + // iterator. This is also why retrieval of the relocation list + // associated with this symbol is deferred until below this point. + // New entries may have been added to the relocation list. + i = ExternalSymbolRelocations.find(Name); } else { // We found the symbol in our global table. It was probably in a // Module that we loaded previously. @@ -529,12 +668,11 @@ void RuntimeDyldImpl::resolveExternalSymbols() { // FIXME: Implement error handling that doesn't kill the host program! if (!Addr) report_fatal_error("Program used external function '" + Name + - "' which could not be resolved!"); + "' which could not be resolved!"); updateGOTEntries(Name, Addr); - DEBUG(dbgs() << "Resolving relocations Name: " << Name - << "\t" << format("0x%lx", Addr) - << "\n"); + DEBUG(dbgs() << "Resolving relocations Name: " << Name << "\t" + << format("0x%lx", Addr) << "\n"); // This list may have been updated when we called getSymbolAddress, so // don't change this code to get the list earlier. RelocationList &Relocs = i->second; @@ -545,7 +683,6 @@ void RuntimeDyldImpl::resolveExternalSymbols() { } } - //===----------------------------------------------------------------------===// // RuntimeDyld class implementation RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) { @@ -555,58 +692,103 @@ RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) { // though the public class spawns a new 'impl' instance for each load, // they share a single memory manager. This can become a problem when page // permissions are applied. - Dyld = 0; + Dyld = nullptr; MM = mm; + ProcessAllSections = false; +} + +RuntimeDyld::~RuntimeDyld() { delete Dyld; } + +static std::unique_ptr<RuntimeDyldELF> +createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections) { + std::unique_ptr<RuntimeDyldELF> Dyld(new RuntimeDyldELF(MM)); + Dyld->setProcessAllSections(ProcessAllSections); + return Dyld; } -RuntimeDyld::~RuntimeDyld() { - delete Dyld; +static std::unique_ptr<RuntimeDyldMachO> +createRuntimeDyldMachO(Triple::ArchType Arch, RTDyldMemoryManager *MM, + bool ProcessAllSections) { + std::unique_ptr<RuntimeDyldMachO> Dyld(RuntimeDyldMachO::create(Arch, MM)); + Dyld->setProcessAllSections(ProcessAllSections); + return Dyld; +} + +ObjectImage *RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) { + std::unique_ptr<ObjectImage> InputImage; + + ObjectFile &Obj = *InputObject; + + if (InputObject->isELF()) { + InputImage.reset(RuntimeDyldELF::createObjectImageFromFile(std::move(InputObject))); + if (!Dyld) + Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release(); + } else if (InputObject->isMachO()) { + InputImage.reset(RuntimeDyldMachO::createObjectImageFromFile(std::move(InputObject))); + if (!Dyld) + Dyld = createRuntimeDyldMachO( + static_cast<Triple::ArchType>(InputImage->getArch()), + MM, ProcessAllSections).release(); + } else + report_fatal_error("Incompatible object format!"); + + if (!Dyld->isCompatibleFile(&Obj)) + report_fatal_error("Incompatible object format!"); + + Dyld->loadObject(InputImage.get()); + return InputImage.release(); } ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) { - if (!Dyld) { - sys::fs::file_magic Type = - sys::fs::identify_magic(InputBuffer->getBuffer()); - switch (Type) { - case sys::fs::file_magic::elf_relocatable: - case sys::fs::file_magic::elf_executable: - case sys::fs::file_magic::elf_shared_object: - case sys::fs::file_magic::elf_core: - Dyld = new RuntimeDyldELF(MM); - break; - case sys::fs::file_magic::macho_object: - case sys::fs::file_magic::macho_executable: - case sys::fs::file_magic::macho_fixed_virtual_memory_shared_lib: - case sys::fs::file_magic::macho_core: - case sys::fs::file_magic::macho_preload_executable: - case sys::fs::file_magic::macho_dynamically_linked_shared_lib: - case sys::fs::file_magic::macho_dynamic_linker: - case sys::fs::file_magic::macho_bundle: - case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: - case sys::fs::file_magic::macho_dsym_companion: - Dyld = new RuntimeDyldMachO(MM); - break; - case sys::fs::file_magic::unknown: - case sys::fs::file_magic::bitcode: - case sys::fs::file_magic::archive: - case sys::fs::file_magic::coff_object: - case sys::fs::file_magic::coff_import_library: - case sys::fs::file_magic::pecoff_executable: - case sys::fs::file_magic::macho_universal_binary: - case sys::fs::file_magic::windows_resource: - report_fatal_error("Incompatible object format!"); - } - } else { - if (!Dyld->isCompatibleFormat(InputBuffer)) - report_fatal_error("Incompatible object format!"); + std::unique_ptr<ObjectImage> InputImage; + sys::fs::file_magic Type = sys::fs::identify_magic(InputBuffer->getBuffer()); + + switch (Type) { + case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::elf_executable: + case sys::fs::file_magic::elf_shared_object: + case sys::fs::file_magic::elf_core: + InputImage.reset(RuntimeDyldELF::createObjectImage(InputBuffer)); + if (!Dyld) + Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release(); + break; + case sys::fs::file_magic::macho_object: + case sys::fs::file_magic::macho_executable: + case sys::fs::file_magic::macho_fixed_virtual_memory_shared_lib: + case sys::fs::file_magic::macho_core: + case sys::fs::file_magic::macho_preload_executable: + case sys::fs::file_magic::macho_dynamically_linked_shared_lib: + case sys::fs::file_magic::macho_dynamic_linker: + case sys::fs::file_magic::macho_bundle: + case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: + case sys::fs::file_magic::macho_dsym_companion: + InputImage.reset(RuntimeDyldMachO::createObjectImage(InputBuffer)); + if (!Dyld) + Dyld = createRuntimeDyldMachO( + static_cast<Triple::ArchType>(InputImage->getArch()), + MM, ProcessAllSections).release(); + break; + case sys::fs::file_magic::unknown: + case sys::fs::file_magic::bitcode: + case sys::fs::file_magic::archive: + case sys::fs::file_magic::coff_object: + case sys::fs::file_magic::coff_import_library: + case sys::fs::file_magic::pecoff_executable: + case sys::fs::file_magic::macho_universal_binary: + case sys::fs::file_magic::windows_resource: + report_fatal_error("Incompatible object format!"); } - return Dyld->loadObject(InputBuffer); + if (!Dyld->isCompatibleFormat(InputBuffer)) + report_fatal_error("Incompatible object format!"); + + Dyld->loadObject(InputImage.get()); + return InputImage.release(); } void *RuntimeDyld::getSymbolAddress(StringRef Name) { if (!Dyld) - return NULL; + return nullptr; return Dyld->getSymbolAddress(Name); } @@ -616,12 +798,9 @@ uint64_t RuntimeDyld::getSymbolLoadAddress(StringRef Name) { return Dyld->getSymbolLoadAddress(Name); } -void RuntimeDyld::resolveRelocations() { - Dyld->resolveRelocations(); -} +void RuntimeDyld::resolveRelocations() { Dyld->resolveRelocations(); } -void RuntimeDyld::reassignSectionAddress(unsigned SectionID, - uint64_t Addr) { +void RuntimeDyld::reassignSectionAddress(unsigned SectionID, uint64_t Addr) { Dyld->reassignSectionAddress(SectionID, Addr); } @@ -630,9 +809,9 @@ void RuntimeDyld::mapSectionAddress(const void *LocalAddress, Dyld->mapSectionAddress(LocalAddress, TargetAddress); } -StringRef RuntimeDyld::getErrorString() { - return Dyld->getErrorString(); -} +bool RuntimeDyld::hasError() { return Dyld->hasError(); } + +StringRef RuntimeDyld::getErrorString() { return Dyld->getErrorString(); } void RuntimeDyld::registerEHFrames() { if (Dyld) diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp new file mode 100644 index 0000000000000..1e63d9207f73f --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -0,0 +1,656 @@ +//===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/RuntimeDyldChecker.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/StringRefMemoryObject.h" +#include "RuntimeDyldImpl.h" +#include <cctype> +#include <memory> + +#define DEBUG_TYPE "rtdyld" + +using namespace llvm; + +namespace llvm { + + // Helper class that implements the language evaluated by RuntimeDyldChecker. + class RuntimeDyldCheckerExprEval { + public: + + RuntimeDyldCheckerExprEval(const RuntimeDyldChecker &Checker, + llvm::raw_ostream &ErrStream) + : Checker(Checker), ErrStream(ErrStream) {} + + bool evaluate(StringRef Expr) const { + // Expect equality expression of the form 'LHS = RHS'. + Expr = Expr.trim(); + size_t EQIdx = Expr.find('='); + + // Evaluate LHS. + StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim(); + StringRef RemainingExpr; + EvalResult LHSResult; + std::tie(LHSResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(LHSExpr)); + if (LHSResult.hasError()) + return handleError(Expr, LHSResult); + if (RemainingExpr != "") + return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, "")); + + // Evaluate RHS. + StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim(); + EvalResult RHSResult; + std::tie(RHSResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(RHSExpr)); + if (RHSResult.hasError()) + return handleError(Expr, RHSResult); + if (RemainingExpr != "") + return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, "")); + + if (LHSResult.getValue() != RHSResult.getValue()) { + ErrStream << "Expression '" << Expr << "' is false: " + << format("0x%lx", LHSResult.getValue()) << " != " + << format("0x%lx", RHSResult.getValue()) << "\n"; + return false; + } + return true; + } + + private: + const RuntimeDyldChecker &Checker; + llvm::raw_ostream &ErrStream; + + enum class BinOpToken : unsigned { Invalid, Add, Sub, BitwiseAnd, + BitwiseOr, ShiftLeft, ShiftRight }; + + class EvalResult { + public: + EvalResult() + : Value(0), ErrorMsg("") {} + EvalResult(uint64_t Value) + : Value(Value), ErrorMsg("") {} + EvalResult(std::string ErrorMsg) + : Value(0), ErrorMsg(ErrorMsg) {} + uint64_t getValue() const { return Value; } + bool hasError() const { return ErrorMsg != ""; } + const std::string& getErrorMsg() const { return ErrorMsg; } + private: + uint64_t Value; + std::string ErrorMsg; + }; + + StringRef getTokenForError(StringRef Expr) const { + if (Expr.empty()) + return ""; + + StringRef Token, Remaining; + if (isalpha(Expr[0])) + std::tie(Token, Remaining) = parseSymbol(Expr); + else if (isdigit(Expr[0])) + std::tie(Token, Remaining) = parseNumberString(Expr); + else { + unsigned TokLen = 1; + if (Expr.startswith("<<") || Expr.startswith(">>")) + TokLen = 2; + Token = Expr.substr(0, TokLen); + } + return Token; + } + + EvalResult unexpectedToken(StringRef TokenStart, + StringRef SubExpr, + StringRef ErrText) const { + std::string ErrorMsg("Encountered unexpected token '"); + ErrorMsg += getTokenForError(TokenStart); + if (SubExpr != "") { + ErrorMsg += "' while parsing subexpression '"; + ErrorMsg += SubExpr; + } + ErrorMsg += "'"; + if (ErrText != "") { + ErrorMsg += " "; + ErrorMsg += ErrText; + } + return EvalResult(std::move(ErrorMsg)); + } + + bool handleError(StringRef Expr, const EvalResult &R) const { + assert(R.hasError() && "Not an error result."); + ErrStream << "Error evaluating expression '" << Expr << "': " + << R.getErrorMsg() << "\n"; + return false; + } + + std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const { + if (Expr.empty()) + return std::make_pair(BinOpToken::Invalid, ""); + + // Handle the two 2-character tokens. + if (Expr.startswith("<<")) + return std::make_pair(BinOpToken::ShiftLeft, + Expr.substr(2).ltrim()); + if (Expr.startswith(">>")) + return std::make_pair(BinOpToken::ShiftRight, + Expr.substr(2).ltrim()); + + // Handle one-character tokens. + BinOpToken Op; + switch (Expr[0]) { + default: return std::make_pair(BinOpToken::Invalid, Expr); + case '+': Op = BinOpToken::Add; break; + case '-': Op = BinOpToken::Sub; break; + case '&': Op = BinOpToken::BitwiseAnd; break; + case '|': Op = BinOpToken::BitwiseOr; break; + } + + return std::make_pair(Op, Expr.substr(1).ltrim()); + } + + EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult, + const EvalResult &RHSResult) const { + switch (Op) { + default: llvm_unreachable("Tried to evaluate unrecognized operation."); + case BinOpToken::Add: + return EvalResult(LHSResult.getValue() + RHSResult.getValue()); + case BinOpToken::Sub: + return EvalResult(LHSResult.getValue() - RHSResult.getValue()); + case BinOpToken::BitwiseAnd: + return EvalResult(LHSResult.getValue() & RHSResult.getValue()); + case BinOpToken::BitwiseOr: + return EvalResult(LHSResult.getValue() | RHSResult.getValue()); + case BinOpToken::ShiftLeft: + return EvalResult(LHSResult.getValue() << RHSResult.getValue()); + case BinOpToken::ShiftRight: + return EvalResult(LHSResult.getValue() >> RHSResult.getValue()); + } + } + + // Parse a symbol and return a (string, string) pair representing the symbol + // name and expression remaining to be parsed. + std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const { + size_t FirstNonSymbol = + Expr.find_first_not_of("0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + ":_"); + return std::make_pair(Expr.substr(0, FirstNonSymbol), + Expr.substr(FirstNonSymbol).ltrim()); + } + + // Evaluate a call to decode_operand. Decode the instruction operand at the + // given symbol and get the value of the requested operand. + // Returns an error if the instruction cannot be decoded, or the requested + // operand is not an immediate. + // On success, retuns a pair containing the value of the operand, plus + // the expression remaining to be evaluated. + std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const { + if (!Expr.startswith("(")) + return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + StringRef Symbol; + std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); + + if (!Checker.isSymbolValid(Symbol)) + return std::make_pair(EvalResult(("Cannot decode unknown symbol '" + + Symbol + "'").str()), + ""); + + if (!RemainingExpr.startswith(",")) + return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr, + "expected ','"), + ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + EvalResult OpIdxExpr; + std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + if (OpIdxExpr.hasError()) + return std::make_pair(OpIdxExpr, ""); + + if (!RemainingExpr.startswith(")")) + return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr, + "expected ')'"), + ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + MCInst Inst; + uint64_t Size; + if (!decodeInst(Symbol, Inst, Size)) + return std::make_pair(EvalResult(("Couldn't decode instruction at '" + + Symbol + "'").str()), + ""); + + unsigned OpIdx = OpIdxExpr.getValue(); + if (OpIdx >= Inst.getNumOperands()) { + std::string ErrMsg; + raw_string_ostream ErrMsgStream(ErrMsg); + ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx) + << "' for instruction '" << Symbol + << "'. Instruction has only " + << format("%i", Inst.getNumOperands()) + << " operands.\nInstruction is:\n "; + Inst.dump_pretty(ErrMsgStream, + Checker.Disassembler->getContext().getAsmInfo(), + Checker.InstPrinter); + return std::make_pair(EvalResult(ErrMsgStream.str()), ""); + } + + const MCOperand &Op = Inst.getOperand(OpIdx); + if (!Op.isImm()) { + std::string ErrMsg; + raw_string_ostream ErrMsgStream(ErrMsg); + ErrMsgStream << "Operand '" << format("%i", OpIdx) + << "' of instruction '" << Symbol + << "' is not an immediate.\nInstruction is:\n "; + Inst.dump_pretty(ErrMsgStream, + Checker.Disassembler->getContext().getAsmInfo(), + Checker.InstPrinter); + + return std::make_pair(EvalResult(ErrMsgStream.str()), ""); + } + + return std::make_pair(EvalResult(Op.getImm()), RemainingExpr); + } + + // Evaluate a call to next_pc. Decode the instruction at the given + // symbol and return the following program counter.. + // Returns an error if the instruction cannot be decoded. + // On success, returns a pair containing the next PC, plus the length of the + // expression remaining to be evaluated. + std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr) const { + if (!Expr.startswith("(")) + return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + StringRef Symbol; + std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); + + if (!Checker.isSymbolValid(Symbol)) + return std::make_pair(EvalResult(("Cannot decode unknown symbol '" + + Symbol + "'").str()), + ""); + + if (!RemainingExpr.startswith(")")) + return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr, + "expected ')'"), + ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + MCInst Inst; + uint64_t Size; + if (!decodeInst(Symbol, Inst, Size)) + return std::make_pair(EvalResult(("Couldn't decode instruction at '" + + Symbol + "'").str()), + ""); + uint64_t NextPC = Checker.getSymbolAddress(Symbol) + Size; + + return std::make_pair(EvalResult(NextPC), RemainingExpr); + } + + // Evaluate an identiefer expr, which may be a symbol, or a call to + // one of the builtin functions: get_insn_opcode or get_insn_length. + // Return the result, plus the expression remaining to be parsed. + std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr) const { + StringRef Symbol; + StringRef RemainingExpr; + std::tie(Symbol, RemainingExpr) = parseSymbol(Expr); + + // Check for builtin function calls. + if (Symbol == "decode_operand") + return evalDecodeOperand(RemainingExpr); + else if (Symbol == "next_pc") + return evalNextPC(RemainingExpr); + + if (!Checker.isSymbolValid(Symbol)) { + std::string ErrMsg("No known address for symbol '"); + ErrMsg += Symbol; + ErrMsg += "'"; + if (Symbol.startswith("L")) + ErrMsg += " (this appears to be an assembler local label - " + " perhaps drop the 'L'?)"; + + return std::make_pair(EvalResult(ErrMsg), ""); + } + + // Looks like a plain symbol reference. + return std::make_pair(EvalResult(Checker.getSymbolAddress(Symbol)), + RemainingExpr); + } + + // Parse a number (hexadecimal or decimal) and return a (string, string) + // pair representing the number and the expression remaining to be parsed. + std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const { + size_t FirstNonDigit = StringRef::npos; + if (Expr.startswith("0x")) { + FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2); + if (FirstNonDigit == StringRef::npos) + FirstNonDigit = Expr.size(); + } else { + FirstNonDigit = Expr.find_first_not_of("0123456789"); + if (FirstNonDigit == StringRef::npos) + FirstNonDigit = Expr.size(); + } + return std::make_pair(Expr.substr(0, FirstNonDigit), + Expr.substr(FirstNonDigit)); + } + + // Evaluate a constant numeric expression (hexidecimal or decimal) and + // return a pair containing the result, and the expression remaining to be + // evaluated. + std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const { + StringRef ValueStr; + StringRef RemainingExpr; + std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr); + + if (ValueStr.empty() || !isdigit(ValueStr[0])) + return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr, + "expected number"), + ""); + uint64_t Value; + ValueStr.getAsInteger(0, Value); + return std::make_pair(EvalResult(Value), RemainingExpr); + } + + // Evaluate an expression of the form "(<expr>)" and return a pair + // containing the result of evaluating <expr>, plus the expression + // remaining to be parsed. + std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr) const { + assert(Expr.startswith("(") && "Not a parenthesized expression"); + EvalResult SubExprResult; + StringRef RemainingExpr; + std::tie(SubExprResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim())); + if (SubExprResult.hasError()) + return std::make_pair(SubExprResult, ""); + if (!RemainingExpr.startswith(")")) + return std::make_pair(unexpectedToken(RemainingExpr, Expr, + "expected ')'"), + ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + return std::make_pair(SubExprResult, RemainingExpr); + } + + // Evaluate an expression in one of the following forms: + // *{<number>}<symbol> + // *{<number>}(<symbol> + <number>) + // *{<number>}(<symbol> - <number>) + // Return a pair containing the result, plus the expression remaining to be + // parsed. + std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const { + assert(Expr.startswith("*") && "Not a load expression"); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + // Parse read size. + if (!RemainingExpr.startswith("{")) + return std::make_pair(EvalResult("Expected '{' following '*'."), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + EvalResult ReadSizeExpr; + std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + if (ReadSizeExpr.hasError()) + return std::make_pair(ReadSizeExpr, RemainingExpr); + uint64_t ReadSize = ReadSizeExpr.getValue(); + if (ReadSize < 1 || ReadSize > 8) + return std::make_pair(EvalResult("Invalid size for dereference."), ""); + if (!RemainingExpr.startswith("}")) + return std::make_pair(EvalResult("Missing '}' for dereference."), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + // Check for '(symbol +/- constant)' form. + bool SymbolPlusConstant = false; + if (RemainingExpr.startswith("(")) { + SymbolPlusConstant = true; + RemainingExpr = RemainingExpr.substr(1).ltrim(); + } + + // Read symbol. + StringRef Symbol; + std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); + + if (!Checker.isSymbolValid(Symbol)) + return std::make_pair(EvalResult(("Cannot dereference unknown symbol '" + + Symbol + "'").str()), + ""); + + // Set up defaut offset. + int64_t Offset = 0; + + // Handle "+/- constant)" portion if necessary. + if (SymbolPlusConstant) { + char OpChar = RemainingExpr[0]; + if (OpChar != '+' && OpChar != '-') + return std::make_pair(EvalResult("Invalid operator in load address."), + ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + EvalResult OffsetExpr; + std::tie(OffsetExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + + Offset = (OpChar == '+') ? + OffsetExpr.getValue() : -1 * OffsetExpr.getValue(); + + if (!RemainingExpr.startswith(")")) + return std::make_pair(EvalResult("Missing ')' in load address."), + ""); + + RemainingExpr = RemainingExpr.substr(1).ltrim(); + } + + return std::make_pair( + EvalResult(Checker.readMemoryAtSymbol(Symbol, Offset, ReadSize)), + RemainingExpr); + } + + // Evaluate a "simple" expression. This is any expression that _isn't_ an + // un-parenthesized binary expression. + // + // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr. + // + // Returns a pair containing the result of the evaluation, plus the + // expression remaining to be parsed. + std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr) const { + EvalResult SubExprResult; + StringRef RemainingExpr; + + if (Expr.empty()) + return std::make_pair(EvalResult("Unexpected end of expression"), ""); + + if (Expr[0] == '(') + std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr); + else if (Expr[0] == '*') + std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr); + else if (isalpha(Expr[0])) + std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr); + else if (isdigit(Expr[0])) + std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr); + + if (SubExprResult.hasError()) + return std::make_pair(SubExprResult, RemainingExpr); + + // Evaluate bit-slice if present. + if (RemainingExpr.startswith("[")) + std::tie(SubExprResult, RemainingExpr) = + evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr)); + + return std::make_pair(SubExprResult, RemainingExpr); + } + + // Evaluate a bit-slice of an expression. + // A bit-slice has the form "<expr>[high:low]". The result of evaluating a + // slice is the bits between high and low (inclusive) in the original + // expression, right shifted so that the "low" bit is in position 0 in the + // result. + // Returns a pair containing the result of the slice operation, plus the + // expression remaining to be parsed. + std::pair<EvalResult, StringRef> evalSliceExpr( + std::pair<EvalResult, StringRef> Ctx) const{ + EvalResult SubExprResult; + StringRef RemainingExpr; + std::tie(SubExprResult, RemainingExpr) = Ctx; + + assert(RemainingExpr.startswith("[") && "Not a slice expr."); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + EvalResult HighBitExpr; + std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + + if (HighBitExpr.hasError()) + return std::make_pair(HighBitExpr, RemainingExpr); + + if (!RemainingExpr.startswith(":")) + return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr, + "expected ':'"), + ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + EvalResult LowBitExpr; + std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + + if (LowBitExpr.hasError()) + return std::make_pair(LowBitExpr, RemainingExpr); + + if (!RemainingExpr.startswith("]")) + return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr, + "expected ']'"), + ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + unsigned HighBit = HighBitExpr.getValue(); + unsigned LowBit = LowBitExpr.getValue(); + uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1; + uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask; + return std::make_pair(EvalResult(SlicedValue), RemainingExpr); + } + + // Evaluate a "complex" expression. + // Takes an already evaluated subexpression and checks for the presence of a + // binary operator, computing the result of the binary operation if one is + // found. Used to make arithmetic expressions left-associative. + // Returns a pair containing the ultimate result of evaluating the + // expression, plus the expression remaining to be evaluated. + std::pair<EvalResult, StringRef> evalComplexExpr( + std::pair<EvalResult, StringRef> Ctx) const { + EvalResult LHSResult; + StringRef RemainingExpr; + std::tie(LHSResult, RemainingExpr) = Ctx; + + // If there was an error, or there's nothing left to evaluate, return the + // result. + if (LHSResult.hasError() || RemainingExpr == "") + return std::make_pair(LHSResult, RemainingExpr); + + // Otherwise check if this is a binary expressioan. + BinOpToken BinOp; + std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr); + + // If this isn't a recognized expression just return. + if (BinOp == BinOpToken::Invalid) + return std::make_pair(LHSResult, RemainingExpr); + + // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop. + EvalResult RHSResult; + std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr); + + // If there was an error evaluating the RHS, return it. + if (RHSResult.hasError()) + return std::make_pair(RHSResult, RemainingExpr); + + // This is a binary expression - evaluate and try to continue as a + // complex expr. + EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult)); + + return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr)); + } + + bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { + MCDisassembler *Dis = Checker.Disassembler; + StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol); + StringRefMemoryObject SectionBytes(SectionMem, 0); + + MCDisassembler::DecodeStatus S = + Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls()); + + return (S == MCDisassembler::Success); + } + + }; + +} + +bool RuntimeDyldChecker::check(StringRef CheckExpr) const { + CheckExpr = CheckExpr.trim(); + DEBUG(llvm::dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr + << "'...\n"); + RuntimeDyldCheckerExprEval P(*this, ErrStream); + bool Result = P.evaluate(CheckExpr); + (void)Result; + DEBUG(llvm::dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' " + << (Result ? "passed" : "FAILED") << ".\n"); + return Result; +} + +bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix, + MemoryBuffer* MemBuf) const { + bool DidAllTestsPass = true; + unsigned NumRules = 0; + + const char *LineStart = MemBuf->getBufferStart(); + + // Eat whitespace. + while (LineStart != MemBuf->getBufferEnd() && + std::isspace(*LineStart)) + ++LineStart; + + while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') { + const char *LineEnd = LineStart; + while (LineEnd != MemBuf->getBufferEnd() && + *LineEnd != '\r' && *LineEnd != '\n') + ++LineEnd; + + StringRef Line(LineStart, LineEnd - LineStart); + if (Line.startswith(RulePrefix)) { + DidAllTestsPass &= check(Line.substr(RulePrefix.size())); + ++NumRules; + } + + // Eat whitespace. + LineStart = LineEnd; + while (LineStart != MemBuf->getBufferEnd() && + std::isspace(*LineStart)) + ++LineStart; + } + return DidAllTestsPass && (NumRules != 0); +} + +bool RuntimeDyldChecker::isSymbolValid(StringRef Symbol) const { + return RTDyld.getSymbolAddress(Symbol) != nullptr; +} + +uint64_t RuntimeDyldChecker::getSymbolAddress(StringRef Symbol) const { + return RTDyld.getAnySymbolRemoteAddress(Symbol); +} + +uint64_t RuntimeDyldChecker::readMemoryAtSymbol(StringRef Symbol, + int64_t Offset, + unsigned Size) const { + uint8_t *Src = RTDyld.getSymbolAddress(Symbol); + uint64_t Result = 0; + memcpy(&Result, Src + Offset, Size); + return Result; +} + +StringRef RuntimeDyldChecker::getSubsectionStartingAt(StringRef Name) const { + RuntimeDyldImpl::SymbolTableMap::const_iterator pos = + RTDyld.GlobalSymbolTable.find(Name); + if (pos == RTDyld.GlobalSymbolTable.end()) + return StringRef(); + RuntimeDyldImpl::SymbolLoc Loc = pos->second; + uint8_t *SectionAddr = RTDyld.getSectionAddress(Loc.first); + return StringRef(reinterpret_cast<const char*>(SectionAddr) + Loc.second, + RTDyld.Sections[Loc.first].Size - Loc.second); +} diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index f2c69fc99cecd..728138ed8c162 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -11,12 +11,10 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" #include "RuntimeDyldELF.h" #include "JITRegistrar.h" #include "ObjectImageCommon.h" #include "llvm/ADT/IntervalMap.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" @@ -25,122 +23,125 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ELF.h" +#include "llvm/Support/MemoryBuffer.h" + using namespace llvm; using namespace llvm::object; +#define DEBUG_TYPE "dyld" + namespace { -static inline -error_code check(error_code Err) { +static inline std::error_code check(std::error_code Err) { if (Err) { report_fatal_error(Err.message()); } return Err; } -template<class ELFT> -class DyldELFObject - : public ELFObjectFile<ELFT> { +template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) typedef Elf_Shdr_Impl<ELFT> Elf_Shdr; typedef Elf_Sym_Impl<ELFT> Elf_Sym; - typedef - Elf_Rel_Impl<ELFT, false> Elf_Rel; - typedef - Elf_Rel_Impl<ELFT, true> Elf_Rela; + typedef Elf_Rel_Impl<ELFT, false> Elf_Rel; + typedef Elf_Rel_Impl<ELFT, true> Elf_Rela; typedef Elf_Ehdr_Impl<ELFT> Elf_Ehdr; - typedef typename ELFDataTypeTypedefHelper< - ELFT>::value_type addr_type; + typedef typename ELFDataTypeTypedefHelper<ELFT>::value_type addr_type; + + std::unique_ptr<ObjectFile> UnderlyingFile; public: - DyldELFObject(MemoryBuffer *Wrapper, error_code &ec); + DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, + std::unique_ptr<MemoryBuffer> Wrapper, std::error_code &ec); + + DyldELFObject(std::unique_ptr<MemoryBuffer> Wrapper, std::error_code &ec); void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr); // Methods for type inquiry through isa, cast and dyn_cast static inline bool classof(const Binary *v) { - return (isa<ELFObjectFile<ELFT> >(v) - && classof(cast<ELFObjectFile - <ELFT> >(v))); + return (isa<ELFObjectFile<ELFT>>(v) && + classof(cast<ELFObjectFile<ELFT>>(v))); } - static inline bool classof( - const ELFObjectFile<ELFT> *v) { + static inline bool classof(const ELFObjectFile<ELFT> *v) { return v->isDyldType(); } }; -template<class ELFT> -class ELFObjectImage : public ObjectImageCommon { - protected: - DyldELFObject<ELFT> *DyldObj; - bool Registered; +template <class ELFT> class ELFObjectImage : public ObjectImageCommon { + bool Registered; - public: - ELFObjectImage(ObjectBuffer *Input, - DyldELFObject<ELFT> *Obj) - : ObjectImageCommon(Input, Obj), - DyldObj(Obj), - Registered(false) {} +public: + ELFObjectImage(ObjectBuffer *Input, std::unique_ptr<DyldELFObject<ELFT>> Obj) + : ObjectImageCommon(Input, std::move(Obj)), Registered(false) {} - virtual ~ELFObjectImage() { - if (Registered) - deregisterWithDebugger(); - } + virtual ~ELFObjectImage() { + if (Registered) + deregisterWithDebugger(); + } - // Subclasses can override these methods to update the image with loaded - // addresses for sections and common symbols - virtual void updateSectionAddress(const SectionRef &Sec, uint64_t Addr) - { - DyldObj->updateSectionAddress(Sec, Addr); - } + // Subclasses can override these methods to update the image with loaded + // addresses for sections and common symbols + void updateSectionAddress(const SectionRef &Sec, uint64_t Addr) override { + static_cast<DyldELFObject<ELFT>*>(getObjectFile()) + ->updateSectionAddress(Sec, Addr); + } - virtual void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) - { - DyldObj->updateSymbolAddress(Sym, Addr); - } + void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) override { + static_cast<DyldELFObject<ELFT>*>(getObjectFile()) + ->updateSymbolAddress(Sym, Addr); + } - virtual void registerWithDebugger() - { - JITRegistrar::getGDBRegistrar().registerObject(*Buffer); - Registered = true; - } - virtual void deregisterWithDebugger() - { - JITRegistrar::getGDBRegistrar().deregisterObject(*Buffer); - } + void registerWithDebugger() override { + JITRegistrar::getGDBRegistrar().registerObject(*Buffer); + Registered = true; + } + void deregisterWithDebugger() override { + JITRegistrar::getGDBRegistrar().deregisterObject(*Buffer); + } }; // The MemoryBuffer passed into this constructor is just a wrapper around the // actual memory. Ultimately, the Binary parent class will take ownership of // this MemoryBuffer object but not the underlying memory. -template<class ELFT> -DyldELFObject<ELFT>::DyldELFObject(MemoryBuffer *Wrapper, error_code &ec) - : ELFObjectFile<ELFT>(Wrapper, ec) { +template <class ELFT> +DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<MemoryBuffer> Wrapper, + std::error_code &EC) + : ELFObjectFile<ELFT>(std::move(Wrapper), EC) { this->isDyldELFObject = true; } -template<class ELFT> +template <class ELFT> +DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, + std::unique_ptr<MemoryBuffer> Wrapper, + std::error_code &EC) + : ELFObjectFile<ELFT>(std::move(Wrapper), EC), + UnderlyingFile(std::move(UnderlyingFile)) { + this->isDyldELFObject = true; +} + +template <class ELFT> void DyldELFObject<ELFT>::updateSectionAddress(const SectionRef &Sec, uint64_t Addr) { DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); - Elf_Shdr *shdr = const_cast<Elf_Shdr*>( - reinterpret_cast<const Elf_Shdr *>(ShdrRef.p)); + Elf_Shdr *shdr = + const_cast<Elf_Shdr *>(reinterpret_cast<const Elf_Shdr *>(ShdrRef.p)); // This assumes the address passed in matches the target address bitness // The template-based type cast handles everything else. shdr->sh_addr = static_cast<addr_type>(Addr); } -template<class ELFT> +template <class ELFT> void DyldELFObject<ELFT>::updateSymbolAddress(const SymbolRef &SymRef, uint64_t Addr) { - Elf_Sym *sym = const_cast<Elf_Sym*>( - ELFObjectFile<ELFT>::getSymbol(SymRef.getRawDataRefImpl())); + Elf_Sym *sym = const_cast<Elf_Sym *>( + ELFObjectFile<ELFT>::getSymbol(SymRef.getRawDataRefImpl())); // This assumes the address passed in matches the target address bitness // The template-based type cast handles everything else. @@ -178,60 +179,94 @@ void RuntimeDyldELF::deregisterEHFrames() { RegisteredEHFrameSections.clear(); } +ObjectImage * +RuntimeDyldELF::createObjectImageFromFile(std::unique_ptr<object::ObjectFile> ObjFile) { + if (!ObjFile) + return nullptr; + + std::error_code ec; + std::unique_ptr<MemoryBuffer> Buffer( + MemoryBuffer::getMemBuffer(ObjFile->getData(), "", false)); + + if (ObjFile->getBytesInAddress() == 4 && ObjFile->isLittleEndian()) { + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 2, false>>>( + std::move(ObjFile), std::move(Buffer), ec); + return new ELFObjectImage<ELFType<support::little, 2, false>>( + nullptr, std::move(Obj)); + } else if (ObjFile->getBytesInAddress() == 4 && !ObjFile->isLittleEndian()) { + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::big, 2, false>>>( + std::move(ObjFile), std::move(Buffer), ec); + return new ELFObjectImage<ELFType<support::big, 2, false>>(nullptr, std::move(Obj)); + } else if (ObjFile->getBytesInAddress() == 8 && !ObjFile->isLittleEndian()) { + auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 2, true>>>( + std::move(ObjFile), std::move(Buffer), ec); + return new ELFObjectImage<ELFType<support::big, 2, true>>(nullptr, + std::move(Obj)); + } else if (ObjFile->getBytesInAddress() == 8 && ObjFile->isLittleEndian()) { + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 2, true>>>( + std::move(ObjFile), std::move(Buffer), ec); + return new ELFObjectImage<ELFType<support::little, 2, true>>( + nullptr, std::move(Obj)); + } else + llvm_unreachable("Unexpected ELF format"); +} + ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) { if (Buffer->getBufferSize() < ELF::EI_NIDENT) llvm_unreachable("Unexpected ELF object size"); - std::pair<unsigned char, unsigned char> Ident = std::make_pair( - (uint8_t)Buffer->getBufferStart()[ELF::EI_CLASS], - (uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]); - error_code ec; + std::pair<unsigned char, unsigned char> Ident = + std::make_pair((uint8_t)Buffer->getBufferStart()[ELF::EI_CLASS], + (uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]); + std::error_code ec; + + std::unique_ptr<MemoryBuffer> Buf(Buffer->getMemBuffer()); if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { - DyldELFObject<ELFType<support::little, 4, false> > *Obj = - new DyldELFObject<ELFType<support::little, 4, false> >( - Buffer->getMemBuffer(), ec); - return new ELFObjectImage<ELFType<support::little, 4, false> >(Buffer, Obj); - } - else if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) { - DyldELFObject<ELFType<support::big, 4, false> > *Obj = - new DyldELFObject<ELFType<support::big, 4, false> >( - Buffer->getMemBuffer(), ec); - return new ELFObjectImage<ELFType<support::big, 4, false> >(Buffer, Obj); - } - else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) { - DyldELFObject<ELFType<support::big, 8, true> > *Obj = - new DyldELFObject<ELFType<support::big, 8, true> >( - Buffer->getMemBuffer(), ec); - return new ELFObjectImage<ELFType<support::big, 8, true> >(Buffer, Obj); - } - else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB) { - DyldELFObject<ELFType<support::little, 8, true> > *Obj = - new DyldELFObject<ELFType<support::little, 8, true> >( - Buffer->getMemBuffer(), ec); - return new ELFObjectImage<ELFType<support::little, 8, true> >(Buffer, Obj); - } - else + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 4, false>>>( + std::move(Buf), ec); + return new ELFObjectImage<ELFType<support::little, 4, false>>( + Buffer, std::move(Obj)); + } else if (Ident.first == ELF::ELFCLASS32 && + Ident.second == ELF::ELFDATA2MSB) { + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::big, 4, false>>>( + std::move(Buf), ec); + return new ELFObjectImage<ELFType<support::big, 4, false>>(Buffer, + std::move(Obj)); + } else if (Ident.first == ELF::ELFCLASS64 && + Ident.second == ELF::ELFDATA2MSB) { + auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 8, true>>>( + std::move(Buf), ec); + return new ELFObjectImage<ELFType<support::big, 8, true>>(Buffer, std::move(Obj)); + } else if (Ident.first == ELF::ELFCLASS64 && + Ident.second == ELF::ELFDATA2LSB) { + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 8, true>>>( + std::move(Buf), ec); + return new ELFObjectImage<ELFType<support::little, 8, true>>(Buffer, std::move(Obj)); + } else llvm_unreachable("Unexpected ELF format"); } -RuntimeDyldELF::~RuntimeDyldELF() { -} +RuntimeDyldELF::~RuntimeDyldELF() {} void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, uint64_t SymOffset) { switch (Type) { default: llvm_unreachable("Relocation type not implemented yet!"); - break; + break; case ELF::R_X86_64_64: { - uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + Offset); + uint64_t *Target = reinterpret_cast<uint64_t *>(Section.Address + Offset); *Target = Value + Addend; - DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) - << " at " << format("%p\n",Target)); + DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " + << format("%p\n", Target)); break; } case ELF::R_X86_64_32: @@ -239,20 +274,20 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, Value += Addend; assert((Type == ELF::R_X86_64_32 && (Value <= UINT32_MAX)) || (Type == ELF::R_X86_64_32S && - ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); + ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); - uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); + uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); *Target = TruncatedAddr; - DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) - << " at " << format("%p\n",Target)); + DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at " + << format("%p\n", Target)); break; } case ELF::R_X86_64_GOTPCREL: { // findGOTEntry returns the 'G + GOT' part of the relocation calculation // based on the load/target address of the GOT (not the current/local addr). uint64_t GOTAddr = findGOTEntry(Value, SymOffset); - uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); - uint64_t FinalAddress = Section.LoadAddress + Offset; + uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); + uint64_t FinalAddress = Section.LoadAddress + Offset; // The processRelocationRef method combines the symbol offset and the addend // and in most cases that's what we want. For this relocation type, we need // the raw addend, so we subtract the symbol offset to get it. @@ -265,10 +300,10 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, case ELF::R_X86_64_PC32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress - + Offset); - uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); - uint64_t FinalAddress = Section.LoadAddress + Offset; + uint32_t *Placeholder = + reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); + uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); + uint64_t FinalAddress = Section.LoadAddress + Offset; int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress; assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); @@ -278,10 +313,10 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, case ELF::R_X86_64_PC64: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint64_t *Placeholder = reinterpret_cast<uint64_t*>(Section.ObjAddress - + Offset); - uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + Offset); - uint64_t FinalAddress = Section.LoadAddress + Offset; + uint64_t *Placeholder = + reinterpret_cast<uint64_t *>(Section.ObjAddress + Offset); + uint64_t *Target = reinterpret_cast<uint64_t *>(Section.Address + Offset); + uint64_t FinalAddress = Section.LoadAddress + Offset; *Target = *Placeholder + Value + Addend - FinalAddress; break; } @@ -289,53 +324,48 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, } void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend) { + uint64_t Offset, uint32_t Value, + uint32_t Type, int32_t Addend) { switch (Type) { case ELF::R_386_32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress - + Offset); - uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); + uint32_t *Placeholder = + reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); + uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); *Target = *Placeholder + Value + Addend; break; } case ELF::R_386_PC32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress - + Offset); - uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); - uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); + uint32_t *Placeholder = + reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); + uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); + uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; *Target = RealOffset; break; - } - default: - // There are other relocation types, but it appears these are the - // only ones currently used by the LLVM ELF object writer - llvm_unreachable("Relocation type not implemented yet!"); - break; + } + default: + // There are other relocation types, but it appears these are the + // only ones currently used by the LLVM ELF object writer + llvm_unreachable("Relocation type not implemented yet!"); + break; } } void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend) { - uint32_t *TargetPtr = reinterpret_cast<uint32_t*>(Section.Address + Offset); + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + uint32_t *TargetPtr = reinterpret_cast<uint32_t *>(Section.Address + Offset); uint64_t FinalAddress = Section.LoadAddress + Offset; DEBUG(dbgs() << "resolveAArch64Relocation, LocalAddress: 0x" << format("%llx", Section.Address + Offset) - << " FinalAddress: 0x" << format("%llx",FinalAddress) - << " Value: 0x" << format("%llx",Value) - << " Type: 0x" << format("%x",Type) - << " Addend: 0x" << format("%llx",Addend) + << " FinalAddress: 0x" << format("%llx", FinalAddress) + << " Value: 0x" << format("%llx", Value) << " Type: 0x" + << format("%x", Type) << " Addend: 0x" << format("%llx", Addend) << "\n"); switch (Type) { @@ -343,7 +373,8 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, llvm_unreachable("Relocation type not implemented yet!"); break; case ELF::R_AARCH64_ABS64: { - uint64_t *TargetPtr = reinterpret_cast<uint64_t*>(Section.Address + Offset); + uint64_t *TargetPtr = + reinterpret_cast<uint64_t *>(Section.Address + Offset); *TargetPtr = Value + Addend; break; } @@ -419,35 +450,77 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, assert((*TargetPtr >> 21 & 0x3) == 0 && "invalid shift for relocation"); break; } + case ELF::R_AARCH64_ADR_PREL_PG_HI21: { + // Operation: Page(S+A) - Page(P) + uint64_t Result = + ((Value + Addend) & ~0xfffULL) - (FinalAddress & ~0xfffULL); + + // Check that -2^32 <= X < 2^32 + assert(static_cast<int64_t>(Result) >= (-1LL << 32) && + static_cast<int64_t>(Result) < (1LL << 32) && + "overflow check failed for relocation"); + + // AArch64 code is emitted with .rela relocations. The data already in any + // bits affected by the relocation on entry is garbage. + *TargetPtr &= 0x9f00001fU; + // Immediate goes in bits 30:29 + 5:23 of ADRP instruction, taken + // from bits 32:12 of X. + *TargetPtr |= ((Result & 0x3000U) << (29 - 12)); + *TargetPtr |= ((Result & 0x1ffffc000ULL) >> (14 - 5)); + break; + } + case ELF::R_AARCH64_LDST32_ABS_LO12_NC: { + // Operation: S + A + uint64_t Result = Value + Addend; + + // AArch64 code is emitted with .rela relocations. The data already in any + // bits affected by the relocation on entry is garbage. + *TargetPtr &= 0xffc003ffU; + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:2 of X + *TargetPtr |= ((Result & 0xffc) << (10 - 2)); + break; + } + case ELF::R_AARCH64_LDST64_ABS_LO12_NC: { + // Operation: S + A + uint64_t Result = Value + Addend; + + // AArch64 code is emitted with .rela relocations. The data already in any + // bits affected by the relocation on entry is garbage. + *TargetPtr &= 0xffc003ffU; + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:3 of X + *TargetPtr |= ((Result & 0xff8) << (10 - 3)); + break; + } } } void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend) { + uint64_t Offset, uint32_t Value, + uint32_t Type, int32_t Addend) { // TODO: Add Thumb relocations. - uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress + - Offset); - uint32_t* TargetPtr = (uint32_t*)(Section.Address + Offset); + uint32_t *Placeholder = + reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); + uint32_t *TargetPtr = (uint32_t *)(Section.Address + Offset); uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); Value += Addend; DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " << Section.Address + Offset - << " FinalAddress: " << format("%p",FinalAddress) - << " Value: " << format("%x",Value) - << " Type: " << format("%x",Type) - << " Addend: " << format("%x",Addend) - << "\n"); + << " FinalAddress: " << format("%p", FinalAddress) << " Value: " + << format("%x", Value) << " Type: " << format("%x", Type) + << " Addend: " << format("%x", Addend) << "\n"); - switch(Type) { + switch (Type) { default: llvm_unreachable("Not implemented relocation type!"); + case ELF::R_ARM_NONE: + break; // Write a 32bit value to relocation address, taking into account the // implicit addend encoded in the target. + case ELF::R_ARM_PREL31: case ELF::R_ARM_TARGET1: case ELF::R_ARM_ABS32: *TargetPtr = *Placeholder + Value; @@ -475,8 +548,8 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, *TargetPtr |= ((Value >> 12) & 0xF) << 16; break; // Write 24 bit relative value to the branch instruction. - case ELF::R_ARM_PC24 : // Fall through. - case ELF::R_ARM_CALL : // Fall through. + case ELF::R_ARM_PC24: // Fall through. + case ELF::R_ARM_CALL: // Fall through. case ELF::R_ARM_JUMP24: { int32_t RelValue = static_cast<int32_t>(Value - FinalAddress - 8); RelValue = (RelValue & 0x03FFFFFC) >> 2; @@ -496,25 +569,20 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, } void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend) { - uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress + - Offset); - uint32_t* TargetPtr = (uint32_t*)(Section.Address + Offset); + uint64_t Offset, uint32_t Value, + uint32_t Type, int32_t Addend) { + uint32_t *Placeholder = + reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); + uint32_t *TargetPtr = (uint32_t *)(Section.Address + Offset); Value += Addend; DEBUG(dbgs() << "resolveMipselocation, LocalAddress: " - << Section.Address + Offset - << " FinalAddress: " - << format("%p",Section.LoadAddress + Offset) - << " Value: " << format("%x",Value) - << " Type: " << format("%x",Type) - << " Addend: " << format("%x",Addend) - << "\n"); + << Section.Address + Offset << " FinalAddress: " + << format("%p", Section.LoadAddress + Offset) << " Value: " + << format("%x", Value) << " Type: " << format("%x", Type) + << " Addend: " << format("%x", Addend) << "\n"); - switch(Type) { + switch (Type) { default: llvm_unreachable("Not implemented relocation type!"); break; @@ -522,13 +590,13 @@ void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, *TargetPtr = Value + (*Placeholder); break; case ELF::R_MIPS_26: - *TargetPtr = ((*Placeholder) & 0xfc000000) | (( Value & 0x0fffffff) >> 2); + *TargetPtr = ((*Placeholder) & 0xfc000000) | ((Value & 0x0fffffff) >> 2); break; case ELF::R_MIPS_HI16: // Get the higher 16-bits. Also add 1 if bit 15 is 1. Value += ((*Placeholder) & 0x0000ffff) << 16; - *TargetPtr = ((*Placeholder) & 0xffff0000) | - (((Value + 0x8000) >> 16) & 0xffff); + *TargetPtr = + ((*Placeholder) & 0xffff0000) | (((Value + 0x8000) >> 16) & 0xffff); break; case ELF::R_MIPS_LO16: Value += ((*Placeholder) & 0x0000ffff); @@ -539,41 +607,47 @@ void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, // are used for internal JIT purpose. These relocations are similar to // R_MIPS_HI16 and R_MIPS_LO16, but they do not take any addend into // account. - *TargetPtr = ((*TargetPtr) & 0xffff0000) | - (((Value + 0x8000) >> 16) & 0xffff); + *TargetPtr = + ((*TargetPtr) & 0xffff0000) | (((Value + 0x8000) >> 16) & 0xffff); break; case ELF::R_MIPS_UNUSED2: *TargetPtr = ((*TargetPtr) & 0xffff0000) | (Value & 0xffff); break; - } + } } -// Return the .TOC. section address to R_PPC64_TOC relocations. -uint64_t RuntimeDyldELF::findPPC64TOC() const { +// Return the .TOC. section and offset. +void RuntimeDyldELF::findPPC64TOCSection(ObjectImage &Obj, + ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel) { + // Set a default SectionID in case we do not find a TOC section below. + // This may happen for references to TOC base base (sym@toc, .odp + // relocation) without a .toc directive. In this case just use the + // first section (which is usually the .odp) since the code won't + // reference the .toc base directly. + Rel.SymbolName = NULL; + Rel.SectionID = 0; + // The TOC consists of sections .got, .toc, .tocbss, .plt in that // order. The TOC starts where the first of these sections starts. - SectionList::const_iterator it = Sections.begin(); - SectionList::const_iterator ite = Sections.end(); - for (; it != ite; ++it) { - if (it->Name == ".got" || - it->Name == ".toc" || - it->Name == ".tocbss" || - it->Name == ".plt") + for (section_iterator si = Obj.begin_sections(), se = Obj.end_sections(); + si != se; ++si) { + + StringRef SectionName; + check(si->getName(SectionName)); + + if (SectionName == ".got" + || SectionName == ".toc" + || SectionName == ".tocbss" + || SectionName == ".plt") { + Rel.SectionID = findOrEmitSection(Obj, *si, false, LocalSections); break; + } } - if (it == ite) { - // This may happen for - // * references to TOC base base (sym@toc, .odp relocation) without - // a .toc directive. - // In this case just use the first section (which is usually - // the .odp) since the code won't reference the .toc base - // directly. - it = Sections.begin(); - } - assert (it != ite); + // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. - return it->LoadAddress + 0x8000; + Rel.Addend = 0x8000; } // Returns the sections and offset associated with the ODP entry referenced @@ -583,10 +657,8 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, RelocationValueRef &Rel) { // Get the ELF symbol value (st_value) to compare with Relocation offset in // .opd entries - - error_code err; - for (section_iterator si = Obj.begin_sections(), - se = Obj.end_sections(); si != se; si.increment(err)) { + for (section_iterator si = Obj.begin_sections(), se = Obj.end_sections(); + si != se; ++si) { section_iterator RelSecI = si->getRelocatedSection(); if (RelSecI == Obj.end_sections()) continue; @@ -596,16 +668,15 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, if (RelSectionName != ".opd") continue; - for (relocation_iterator i = si->begin_relocations(), - e = si->end_relocations(); i != e;) { - check(err); - + for (relocation_iterator i = si->relocation_begin(), + e = si->relocation_end(); + i != e;) { // The R_PPC64_ADDR64 relocation indicates the first field // of a .opd entry uint64_t TypeFunc; check(i->getType(TypeFunc)); if (TypeFunc != ELF::R_PPC64_ADDR64) { - i.increment(err); + ++i; continue; } @@ -615,10 +686,9 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, int64_t Addend; check(getELFRelocationAddend(*i, Addend)); - i = i.increment(err); + ++i; if (i == e) break; - check(err); // Just check if following relocation is a R_PPC64_TOC uint64_t TypeTOC; @@ -634,7 +704,9 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, section_iterator tsi(Obj.end_sections()); check(TargetSymbol->getSection(tsi)); - Rel.SectionID = findOrEmitSection(Obj, (*tsi), true, LocalSections); + bool IsCode = false; + tsi->isText(IsCode); + Rel.SectionID = findOrEmitSection(Obj, (*tsi), IsCode, LocalSections); Rel.Addend = (intptr_t)Addend; return; } @@ -642,69 +714,103 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, llvm_unreachable("Attempting to get address of ODP entry!"); } -// Relocation masks following the #lo(value), #hi(value), #higher(value), -// and #highest(value) macros defined in section 4.5.1. Relocation Types -// in PPC-elf64abi document. -// -static inline -uint16_t applyPPClo (uint64_t value) -{ - return value & 0xffff; -} +// Relocation masks following the #lo(value), #hi(value), #ha(value), +// #higher(value), #highera(value), #highest(value), and #highesta(value) +// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi +// document. + +static inline uint16_t applyPPClo(uint64_t value) { return value & 0xffff; } -static inline -uint16_t applyPPChi (uint64_t value) -{ +static inline uint16_t applyPPChi(uint64_t value) { return (value >> 16) & 0xffff; } -static inline -uint16_t applyPPChigher (uint64_t value) -{ +static inline uint16_t applyPPCha (uint64_t value) { + return ((value + 0x8000) >> 16) & 0xffff; +} + +static inline uint16_t applyPPChigher(uint64_t value) { return (value >> 32) & 0xffff; } -static inline -uint16_t applyPPChighest (uint64_t value) -{ +static inline uint16_t applyPPChighera (uint64_t value) { + return ((value + 0x8000) >> 32) & 0xffff; +} + +static inline uint16_t applyPPChighest(uint64_t value) { return (value >> 48) & 0xffff; } +static inline uint16_t applyPPChighesta (uint64_t value) { + return ((value + 0x8000) >> 48) & 0xffff; +} + void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend) { - uint8_t* LocalAddress = Section.Address + Offset; + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + uint8_t *LocalAddress = Section.Address + Offset; switch (Type) { default: llvm_unreachable("Relocation type not implemented yet!"); - break; - case ELF::R_PPC64_ADDR16_LO : - writeInt16BE(LocalAddress, applyPPClo (Value + Addend)); break; - case ELF::R_PPC64_ADDR16_HI : - writeInt16BE(LocalAddress, applyPPChi (Value + Addend)); + case ELF::R_PPC64_ADDR16: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_DS: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); break; - case ELF::R_PPC64_ADDR16_HIGHER : - writeInt16BE(LocalAddress, applyPPChigher (Value + Addend)); + case ELF::R_PPC64_ADDR16_LO: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); break; - case ELF::R_PPC64_ADDR16_HIGHEST : - writeInt16BE(LocalAddress, applyPPChighest (Value + Addend)); + case ELF::R_PPC64_ADDR16_LO_DS: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); break; - case ELF::R_PPC64_ADDR14 : { + case ELF::R_PPC64_ADDR16_HI: + writeInt16BE(LocalAddress, applyPPChi(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HA: + writeInt16BE(LocalAddress, applyPPCha(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHER: + writeInt16BE(LocalAddress, applyPPChigher(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHERA: + writeInt16BE(LocalAddress, applyPPChighera(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHEST: + writeInt16BE(LocalAddress, applyPPChighest(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHESTA: + writeInt16BE(LocalAddress, applyPPChighesta(Value + Addend)); + break; + case ELF::R_PPC64_ADDR14: { assert(((Value + Addend) & 3) == 0); // Preserve the AA/LK bits in the branch instruction - uint8_t aalk = *(LocalAddress+3); + uint8_t aalk = *(LocalAddress + 3); writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc)); } break; - case ELF::R_PPC64_ADDR32 : { + case ELF::R_PPC64_REL16_LO: { + uint64_t FinalAddress = (Section.LoadAddress + Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPClo(Delta)); + } break; + case ELF::R_PPC64_REL16_HI: { + uint64_t FinalAddress = (Section.LoadAddress + Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPChi(Delta)); + } break; + case ELF::R_PPC64_REL16_HA: { + uint64_t FinalAddress = (Section.LoadAddress + Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPCha(Delta)); + } break; + case ELF::R_PPC64_ADDR32: { int32_t Result = static_cast<int32_t>(Value + Addend); if (SignExtend32<32>(Result) != Result) llvm_unreachable("Relocation R_PPC64_ADDR32 overflow"); writeInt32BE(LocalAddress, Result); } break; - case ELF::R_PPC64_REL24 : { + case ELF::R_PPC64_REL24: { uint64_t FinalAddress = (Section.LoadAddress + Offset); int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend); if (SignExtend32<24>(delta) != delta) @@ -712,7 +818,7 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, // Generates a 'bl <address>' instruction writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC)); } break; - case ELF::R_PPC64_REL32 : { + case ELF::R_PPC64_REL32: { uint64_t FinalAddress = (Section.LoadAddress + Offset); int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend); if (SignExtend32<32>(delta) != delta) @@ -724,30 +830,15 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, uint64_t Delta = Value - FinalAddress + Addend; writeInt64BE(LocalAddress, Delta); } break; - case ELF::R_PPC64_ADDR64 : + case ELF::R_PPC64_ADDR64: writeInt64BE(LocalAddress, Value + Addend); break; - case ELF::R_PPC64_TOC : - writeInt64BE(LocalAddress, findPPC64TOC()); - break; - case ELF::R_PPC64_TOC16 : { - uint64_t TOCStart = findPPC64TOC(); - Value = applyPPClo((Value + Addend) - TOCStart); - writeInt16BE(LocalAddress, applyPPClo(Value)); - } break; - case ELF::R_PPC64_TOC16_DS : { - uint64_t TOCStart = findPPC64TOC(); - Value = ((Value + Addend) - TOCStart); - writeInt16BE(LocalAddress, applyPPClo(Value)); - } break; } } void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend) { + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { uint8_t *LocalAddress = Section.Address + Offset; switch (Type) { default: @@ -807,66 +898,63 @@ void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, } void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, uint64_t SymOffset) { switch (Arch) { case Triple::x86_64: resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset); break; case Triple::x86: - resolveX86Relocation(Section, Offset, - (uint32_t)(Value & 0xffffffffL), Type, + resolveX86Relocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; case Triple::aarch64: + case Triple::aarch64_be: + case Triple::arm64: + case Triple::arm64_be: resolveAArch64Relocation(Section, Offset, Value, Type, Addend); break; - case Triple::arm: // Fall through. + case Triple::arm: // Fall through. + case Triple::armeb: case Triple::thumb: - resolveARMRelocation(Section, Offset, - (uint32_t)(Value & 0xffffffffL), Type, + case Triple::thumbeb: + resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; - case Triple::mips: // Fall through. + case Triple::mips: // Fall through. case Triple::mipsel: - resolveMIPSRelocation(Section, Offset, - (uint32_t)(Value & 0xffffffffL), Type, - (uint32_t)(Addend & 0xffffffffL)); + resolveMIPSRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), + Type, (uint32_t)(Addend & 0xffffffffL)); break; - case Triple::ppc64: // Fall through. + case Triple::ppc64: // Fall through. case Triple::ppc64le: resolvePPC64Relocation(Section, Offset, Value, Type, Addend); break; case Triple::systemz: resolveSystemZRelocation(Section, Offset, Value, Type, Addend); break; - default: llvm_unreachable("Unsupported CPU type!"); + default: + llvm_unreachable("Unsupported CPU type!"); } } -void RuntimeDyldELF::processRelocationRef(unsigned SectionID, - RelocationRef RelI, - ObjectImage &Obj, - ObjSectionToIDMap &ObjSectionToID, - const SymbolTableMap &Symbols, - StubMap &Stubs) { +relocation_iterator RuntimeDyldELF::processRelocationRef( + unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj, + ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols, + StubMap &Stubs) { uint64_t RelType; - Check(RelI.getType(RelType)); + Check(RelI->getType(RelType)); int64_t Addend; - Check(getELFRelocationAddend(RelI, Addend)); - symbol_iterator Symbol = RelI.getSymbol(); + Check(getELFRelocationAddend(*RelI, Addend)); + symbol_iterator Symbol = RelI->getSymbol(); // Obtain the symbol name which is referenced in the relocation StringRef TargetName; if (Symbol != Obj.end_symbols()) Symbol->getName(TargetName); - DEBUG(dbgs() << "\t\tRelType: " << RelType - << " Addend: " << Addend - << " TargetName: " << TargetName - << "\n"); + DEBUG(dbgs() << "\t\tRelType: " << RelType << " Addend: " << Addend + << " TargetName: " << TargetName << "\n"); RelocationValueRef Value; // First search for the symbol in the local symbol table SymbolTableMap::const_iterator lsi = Symbols.end(); @@ -890,53 +978,49 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, Value.Addend = gsi->second.second + Addend; } else { switch (SymType) { - case SymbolRef::ST_Debug: { - // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously - // and can be changed by another developers. Maybe best way is add - // a new symbol type ST_Section to SymbolRef and use it. - section_iterator si(Obj.end_sections()); - Symbol->getSection(si); - if (si == Obj.end_sections()) - llvm_unreachable("Symbol section not found, bad object file format!"); - DEBUG(dbgs() << "\t\tThis is section symbol\n"); - // Default to 'true' in case isText fails (though it never does). - bool isCode = true; - si->isText(isCode); - Value.SectionID = findOrEmitSection(Obj, - (*si), - isCode, - ObjSectionToID); - Value.Addend = Addend; - break; - } - case SymbolRef::ST_Data: - case SymbolRef::ST_Unknown: { - Value.SymbolName = TargetName.data(); - Value.Addend = Addend; + case SymbolRef::ST_Debug: { + // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously + // and can be changed by another developers. Maybe best way is add + // a new symbol type ST_Section to SymbolRef and use it. + section_iterator si(Obj.end_sections()); + Symbol->getSection(si); + if (si == Obj.end_sections()) + llvm_unreachable("Symbol section not found, bad object file format!"); + DEBUG(dbgs() << "\t\tThis is section symbol\n"); + // Default to 'true' in case isText fails (though it never does). + bool isCode = true; + si->isText(isCode); + Value.SectionID = findOrEmitSection(Obj, (*si), isCode, ObjSectionToID); + Value.Addend = Addend; + break; + } + case SymbolRef::ST_Data: + case SymbolRef::ST_Unknown: { + Value.SymbolName = TargetName.data(); + Value.Addend = Addend; - // Absolute relocations will have a zero symbol ID (STN_UNDEF), which - // will manifest here as a NULL symbol name. - // We can set this as a valid (but empty) symbol name, and rely - // on addRelocationForSymbol to handle this. - if (!Value.SymbolName) - Value.SymbolName = ""; - break; - } - default: - llvm_unreachable("Unresolved symbol type!"); - break; + // Absolute relocations will have a zero symbol ID (STN_UNDEF), which + // will manifest here as a NULL symbol name. + // We can set this as a valid (but empty) symbol name, and rely + // on addRelocationForSymbol to handle this. + if (!Value.SymbolName) + Value.SymbolName = ""; + break; + } + default: + llvm_unreachable("Unresolved symbol type!"); + break; } } } uint64_t Offset; - Check(RelI.getOffset(Offset)); + Check(RelI->getOffset(Offset)); - DEBUG(dbgs() << "\t\tSectionID: " << SectionID - << " Offset: " << Offset + DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset << "\n"); - if (Arch == Triple::aarch64 && - (RelType == ELF::R_AARCH64_CALL26 || - RelType == ELF::R_AARCH64_JUMP26)) { + if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be || + Arch == Triple::arm64 || Arch == Triple::arm64_be) && + (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26)) { // This is an AArch64 branch relocation, need to use a stub function. DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation."); SectionEntry &Section = Sections[SectionID]; @@ -944,24 +1028,21 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // Look for an existing stub. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) { - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + i->second, RelType, 0); + resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, + RelType, 0); DEBUG(dbgs() << " Stub function found\n"); } else { // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset); - RelocationEntry REmovz_g3(SectionID, - StubTargetAddr - Section.Address, + RelocationEntry REmovz_g3(SectionID, StubTargetAddr - Section.Address, ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend); - RelocationEntry REmovk_g2(SectionID, - StubTargetAddr - Section.Address + 4, + RelocationEntry REmovk_g2(SectionID, StubTargetAddr - Section.Address + 4, ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend); - RelocationEntry REmovk_g1(SectionID, - StubTargetAddr - Section.Address + 8, + RelocationEntry REmovk_g1(SectionID, StubTargetAddr - Section.Address + 8, ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend); RelocationEntry REmovk_g0(SectionID, StubTargetAddr - Section.Address + 12, @@ -979,14 +1060,13 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, addRelocationForSection(REmovk_g0, Value.SectionID); } resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, - RelType, 0); + (uint64_t)Section.Address + Section.StubOffset, RelType, + 0); Section.StubOffset += getMaxStubSize(); } } else if (Arch == Triple::arm && - (RelType == ELF::R_ARM_PC24 || - RelType == ELF::R_ARM_CALL || - RelType == ELF::R_ARM_JUMP24)) { + (RelType == ELF::R_ARM_PC24 || RelType == ELF::R_ARM_CALL || + RelType == ELF::R_ARM_JUMP24)) { // This is an ARM branch relocation, need to use a stub function. DEBUG(dbgs() << "\t\tThis is an ARM branch relocation."); SectionEntry &Section = Sections[SectionID]; @@ -994,15 +1074,15 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // Look for an existing stub. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) { - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + i->second, RelType, 0); + resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, + RelType, 0); DEBUG(dbgs() << " Stub function found\n"); } else { // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, ELF::R_ARM_PRIVATE_0, Value.Addend); if (Value.SymbolName) @@ -1011,8 +1091,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, addRelocationForSection(RE, Value.SectionID); resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, - RelType, 0); + (uint64_t)Section.Address + Section.StubOffset, RelType, + 0); Section.StubOffset += getMaxStubSize(); } } else if ((Arch == Triple::mipsel || Arch == Triple::mips) && @@ -1038,15 +1118,13 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset); // Creating Hi and Lo relocations for the filled stub instructions. - RelocationEntry REHi(SectionID, - StubTargetAddr - Section.Address, + RelocationEntry REHi(SectionID, StubTargetAddr - Section.Address, ELF::R_MIPS_UNUSED1, Value.Addend); - RelocationEntry RELo(SectionID, - StubTargetAddr - Section.Address + 4, + RelocationEntry RELo(SectionID, StubTargetAddr - Section.Address + 4, ELF::R_MIPS_UNUSED2, Value.Addend); if (Value.SymbolName) { @@ -1063,6 +1141,10 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, } } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { if (RelType == ELF::R_PPC64_REL24) { + // Determine ABI variant in use for this object. + unsigned AbiVariant; + Obj.getObjectFile()->getPlatformFlags(AbiVariant); + AbiVariant &= ELF::EF_PPC64_ABI; // A PPC branch relocation will need a stub function if the target is // an external symbol (Symbol::ST_Unknown) or if the target address // is not within the signed 24-bits branch address. @@ -1070,9 +1152,18 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, uint8_t *Target = Section.Address + Offset; bool RangeOverflow = false; if (SymType != SymbolRef::ST_Unknown) { - // A function call may points to the .opd entry, so the final symbol value - // in calculated based in the relocation values in .opd section. - findOPDEntrySection(Obj, ObjSectionToID, Value); + if (AbiVariant != 2) { + // In the ELFv1 ABI, a function call may point to the .opd entry, + // so the final symbol value is calculated based on the relocation + // values in the .opd section. + findOPDEntrySection(Obj, ObjSectionToID, Value); + } else { + // In the ELFv2 ABI, a function symbol may provide a local entry + // point, which must be used for direct calls. + uint8_t SymOther; + Symbol->getOther(SymOther); + Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther); + } uint8_t *RelocTarget = Sections[Value.SectionID].Address + Value.Addend; int32_t delta = static_cast<int32_t>(Target - RelocTarget); // If it is within 24-bits branch range, just set the branch target @@ -1099,53 +1190,100 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset, + AbiVariant); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, ELF::R_PPC64_ADDR64, Value.Addend); // Generates the 64-bits address loads as exemplified in section - // 4.5.1 in PPC64 ELF ABI. - RelocationEntry REhst(SectionID, - StubTargetAddr - Section.Address + 2, + // 4.5.1 in PPC64 ELF ABI. Note that the relocations need to + // apply to the low part of the instructions, so we have to update + // the offset according to the target endianness. + uint64_t StubRelocOffset = StubTargetAddr - Section.Address; + if (!IsTargetLittleEndian) + StubRelocOffset += 2; + + RelocationEntry REhst(SectionID, StubRelocOffset + 0, ELF::R_PPC64_ADDR16_HIGHEST, Value.Addend); - RelocationEntry REhr(SectionID, - StubTargetAddr - Section.Address + 6, + RelocationEntry REhr(SectionID, StubRelocOffset + 4, ELF::R_PPC64_ADDR16_HIGHER, Value.Addend); - RelocationEntry REh(SectionID, - StubTargetAddr - Section.Address + 14, + RelocationEntry REh(SectionID, StubRelocOffset + 12, ELF::R_PPC64_ADDR16_HI, Value.Addend); - RelocationEntry REl(SectionID, - StubTargetAddr - Section.Address + 18, + RelocationEntry REl(SectionID, StubRelocOffset + 16, ELF::R_PPC64_ADDR16_LO, Value.Addend); if (Value.SymbolName) { addRelocationForSymbol(REhst, Value.SymbolName); - addRelocationForSymbol(REhr, Value.SymbolName); - addRelocationForSymbol(REh, Value.SymbolName); - addRelocationForSymbol(REl, Value.SymbolName); + addRelocationForSymbol(REhr, Value.SymbolName); + addRelocationForSymbol(REh, Value.SymbolName); + addRelocationForSymbol(REl, Value.SymbolName); } else { addRelocationForSection(REhst, Value.SectionID); - addRelocationForSection(REhr, Value.SectionID); - addRelocationForSection(REh, Value.SectionID); - addRelocationForSection(REl, Value.SectionID); + addRelocationForSection(REhr, Value.SectionID); + addRelocationForSection(REh, Value.SectionID); + addRelocationForSection(REl, Value.SectionID); } resolveRelocation(Section, Offset, (uint64_t)Section.Address + Section.StubOffset, RelType, 0); - if (SymType == SymbolRef::ST_Unknown) - // Restore the TOC for external calls - writeInt32BE(Target+4, 0xE8410028); // ld r2,40(r1) Section.StubOffset += getMaxStubSize(); } + if (SymType == SymbolRef::ST_Unknown) { + // Restore the TOC for external calls + if (AbiVariant == 2) + writeInt32BE(Target + 4, 0xE8410018); // ld r2,28(r1) + else + writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1) + } } + } else if (RelType == ELF::R_PPC64_TOC16 || + RelType == ELF::R_PPC64_TOC16_DS || + RelType == ELF::R_PPC64_TOC16_LO || + RelType == ELF::R_PPC64_TOC16_LO_DS || + RelType == ELF::R_PPC64_TOC16_HI || + RelType == ELF::R_PPC64_TOC16_HA) { + // These relocations are supposed to subtract the TOC address from + // the final value. This does not fit cleanly into the RuntimeDyld + // scheme, since there may be *two* sections involved in determining + // the relocation value (the section of the symbol refered to by the + // relocation, and the TOC section associated with the current module). + // + // Fortunately, these relocations are currently only ever generated + // refering to symbols that themselves reside in the TOC, which means + // that the two sections are actually the same. Thus they cancel out + // and we can immediately resolve the relocation right now. + switch (RelType) { + case ELF::R_PPC64_TOC16: RelType = ELF::R_PPC64_ADDR16; break; + case ELF::R_PPC64_TOC16_DS: RelType = ELF::R_PPC64_ADDR16_DS; break; + case ELF::R_PPC64_TOC16_LO: RelType = ELF::R_PPC64_ADDR16_LO; break; + case ELF::R_PPC64_TOC16_LO_DS: RelType = ELF::R_PPC64_ADDR16_LO_DS; break; + case ELF::R_PPC64_TOC16_HI: RelType = ELF::R_PPC64_ADDR16_HI; break; + case ELF::R_PPC64_TOC16_HA: RelType = ELF::R_PPC64_ADDR16_HA; break; + default: llvm_unreachable("Wrong relocation type."); + } + + RelocationValueRef TOCValue; + findPPC64TOCSection(Obj, ObjSectionToID, TOCValue); + if (Value.SymbolName || Value.SectionID != TOCValue.SectionID) + llvm_unreachable("Unsupported TOC relocation."); + Value.Addend -= TOCValue.Addend; + resolveRelocation(Sections[SectionID], Offset, Value.Addend, RelType, 0); } else { + // There are two ways to refer to the TOC address directly: either + // via a ELF::R_PPC64_TOC relocation (where both symbol and addend are + // ignored), or via any relocation that refers to the magic ".TOC." + // symbols (in which case the addend is respected). + if (RelType == ELF::R_PPC64_TOC) { + RelType = ELF::R_PPC64_ADDR64; + findPPC64TOCSection(Obj, ObjSectionToID, Value); + } else if (TargetName == ".TOC.") { + findPPC64TOCSection(Obj, ObjSectionToID, Value); + Value.Addend += Addend; + } + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); - // Extra check to avoid relocation againt empty symbols (usually - // the R_PPC64_TOC). - if (SymType != SymbolRef::ST_Unknown && TargetName.empty()) - Value.SymbolName = NULL; if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); @@ -1153,8 +1291,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, addRelocationForSection(RE, Value.SectionID); } } else if (Arch == Triple::systemz && - (RelType == ELF::R_390_PLT32DBL || - RelType == ELF::R_390_GOTENT)) { + (RelType == ELF::R_390_PLT32DBL || RelType == ELF::R_390_GOTENT)) { // Create function stubs for both PLT and GOT references, regardless of // whether the GOT reference is to data or code. The stub contains the // full address of the symbol, as needed by GOT references, and the @@ -1179,14 +1316,14 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, uintptr_t BaseAddress = uintptr_t(Section.Address); uintptr_t StubAlignment = getStubAlignment(); - StubAddress = (BaseAddress + Section.StubOffset + - StubAlignment - 1) & -StubAlignment; + StubAddress = (BaseAddress + Section.StubOffset + StubAlignment - 1) & + -StubAlignment; unsigned StubOffset = StubAddress - BaseAddress; Stubs[Value] = StubOffset; createStubFunction((uint8_t *)StubAddress); - RelocationEntry RE(SectionID, StubOffset + 8, - ELF::R_390_64, Value.Addend - Addend); + RelocationEntry RE(SectionID, StubOffset + 8, ELF::R_390_64, + Value.Addend - Addend); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else @@ -1195,15 +1332,17 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, } if (RelType == ELF::R_390_GOTENT) - resolveRelocation(Section, Offset, StubAddress + 8, - ELF::R_390_PC32DBL, Addend); + resolveRelocation(Section, Offset, StubAddress + 8, ELF::R_390_PC32DBL, + Addend); else resolveRelocation(Section, Offset, StubAddress, RelType, Addend); } else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) { - // The way the PLT relocations normally work is that the linker allocates the + // The way the PLT relocations normally work is that the linker allocates + // the // PLT and this relocation makes a PC-relative call into the PLT. The PLT - // entry will then jump to an address provided by the GOT. On first call, the - // GOT address will point back into PLT code that resolves the symbol. After + // entry will then jump to an address provided by the GOT. On first call, + // the + // GOT address will point back into PLT code that resolves the symbol. After // the first call, the GOT entry points to the actual function. // // For local functions we're ignoring all of that here and just replacing @@ -1229,8 +1368,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, uintptr_t BaseAddress = uintptr_t(Section.Address); uintptr_t StubAlignment = getStubAlignment(); - StubAddress = (BaseAddress + Section.StubOffset + - StubAlignment - 1) & -StubAlignment; + StubAddress = (BaseAddress + Section.StubOffset + StubAlignment - 1) & + -StubAlignment; unsigned StubOffset = StubAddress - BaseAddress; Stubs[Value] = StubOffset; createStubFunction((uint8_t *)StubAddress); @@ -1239,8 +1378,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, GOTEntries.push_back(Value); // Make our stub function a relative call to the GOT entry. - RelocationEntry RE(SectionID, StubOffset + 2, - ELF::R_X86_64_GOTPCREL, -4); + RelocationEntry RE(SectionID, StubOffset + 2, ELF::R_X86_64_GOTPCREL, + -4); addRelocationForSymbol(RE, Value.SymbolName); // Bump our stub offset counter @@ -1248,8 +1387,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, } // Make the target call a call into the stub table. - resolveRelocation(Section, Offset, StubAddress, - ELF::R_X86_64_PC32, Addend); + resolveRelocation(Section, Offset, StubAddress, ELF::R_X86_64_PC32, + Addend); } else { RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend, Value.Offset); @@ -1265,17 +1404,19 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, else addRelocationForSection(RE, Value.SectionID); } + return ++RelI; } void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) { - SmallVectorImpl<std::pair<SID, GOTRelocations> >::iterator it; - SmallVectorImpl<std::pair<SID, GOTRelocations> >::iterator end = GOTs.end(); + SmallVectorImpl<std::pair<SID, GOTRelocations>>::iterator it; + SmallVectorImpl<std::pair<SID, GOTRelocations>>::iterator end = GOTs.end(); for (it = GOTs.begin(); it != end; ++it) { GOTRelocations &GOTEntries = it->second; for (int i = 0, e = GOTEntries.size(); i != e; ++i) { - if (GOTEntries[i].SymbolName != 0 && GOTEntries[i].SymbolName == Name) { + if (GOTEntries[i].SymbolName != nullptr && + GOTEntries[i].SymbolName == Name) { GOTEntries[i].Offset = Addr; } } @@ -1289,6 +1430,9 @@ size_t RuntimeDyldELF::getGOTEntrySize() { switch (Arch) { case Triple::x86_64: case Triple::aarch64: + case Triple::aarch64_be: + case Triple::arm64: + case Triple::arm64_be: case Triple::ppc64: case Triple::ppc64le: case Triple::systemz: @@ -1301,18 +1445,19 @@ size_t RuntimeDyldELF::getGOTEntrySize() { case Triple::mipsel: Result = sizeof(uint32_t); break; - default: llvm_unreachable("Unsupported CPU type!"); + default: + llvm_unreachable("Unsupported CPU type!"); } return Result; } -uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, - uint64_t Offset) { +uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, uint64_t Offset) { const size_t GOTEntrySize = getGOTEntrySize(); - SmallVectorImpl<std::pair<SID, GOTRelocations> >::const_iterator it; - SmallVectorImpl<std::pair<SID, GOTRelocations> >::const_iterator end = GOTs.end(); + SmallVectorImpl<std::pair<SID, GOTRelocations>>::const_iterator it; + SmallVectorImpl<std::pair<SID, GOTRelocations>>::const_iterator end = + GOTs.end(); int GOTIndex = -1; for (it = GOTs.begin(); it != end; ++it) { @@ -1322,7 +1467,7 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, // Find the matching entry in our vector. uint64_t SymbolOffset = 0; for (int i = 0, e = GOTEntries.size(); i != e; ++i) { - if (GOTEntries[i].SymbolName == 0) { + if (!GOTEntries[i].SymbolName) { if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress && GOTEntries[i].Offset == Offset) { GOTIndex = i; @@ -1342,11 +1487,11 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, if (GOTIndex != -1) { if (GOTEntrySize == sizeof(uint64_t)) { - uint64_t *LocalGOTAddr = (uint64_t*)getSectionAddress(GOTSectionID); + uint64_t *LocalGOTAddr = (uint64_t *)getSectionAddress(GOTSectionID); // Fill in this entry with the address of the symbol being referenced. LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset; } else { - uint32_t *LocalGOTAddr = (uint32_t*)getSectionAddress(GOTSectionID); + uint32_t *LocalGOTAddr = (uint32_t *)getSectionAddress(GOTSectionID); // Fill in this entry with the address of the symbol being referenced. LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset); } @@ -1360,7 +1505,8 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, return 0; } -void RuntimeDyldELF::finalizeLoad(ObjSectionToIDMap &SectionMap) { +void RuntimeDyldELF::finalizeLoad(ObjectImage &ObjImg, + ObjSectionToIDMap &SectionMap) { // If necessary, allocate the global offset table if (MemMgr) { // Allocate the GOT if necessary @@ -1380,8 +1526,7 @@ void RuntimeDyldELF::finalizeLoad(ObjSectionToIDMap &SectionMap) { // needed when GOT-based relocations are applied. memset(Addr, 0, TotalSize); } - } - else { + } else { report_fatal_error("Unable to allocate memory for GOT!"); } @@ -1401,6 +1546,12 @@ void RuntimeDyldELF::finalizeLoad(ObjSectionToIDMap &SectionMap) { bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const { if (Buffer->getBufferSize() < strlen(ELF::ElfMagic)) return false; - return (memcmp(Buffer->getBufferStart(), ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0; + return (memcmp(Buffer->getBufferStart(), ELF::ElfMagic, + strlen(ELF::ElfMagic))) == 0; +} + +bool RuntimeDyldELF::isCompatibleFile(const object::ObjectFile *Obj) const { + return Obj->isELF(); } + } // namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index 3adf82706ad0e..59fdfbe325214 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -20,70 +20,46 @@ using namespace llvm; namespace llvm { - namespace { - // Helper for extensive error checking in debug builds. - error_code Check(error_code Err) { - if (Err) { - report_fatal_error(Err.message()); - } - return Err; +// Helper for extensive error checking in debug builds. +std::error_code Check(std::error_code Err) { + if (Err) { + report_fatal_error(Err.message()); } + return Err; +} } // end anonymous namespace class RuntimeDyldELF : public RuntimeDyldImpl { - void resolveRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, - uint64_t SymOffset=0); + void resolveRelocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + uint64_t SymOffset = 0); - void resolveX86_64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, + void resolveX86_64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, uint64_t SymOffset); - void resolveX86Relocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend); + void resolveX86Relocation(const SectionEntry &Section, uint64_t Offset, + uint32_t Value, uint32_t Type, int32_t Addend); - void resolveAArch64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend); + void resolveAArch64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend); - void resolveARMRelocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend); + void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset, + uint32_t Value, uint32_t Type, int32_t Addend); - void resolveMIPSRelocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend); + void resolveMIPSRelocation(const SectionEntry &Section, uint64_t Offset, + uint32_t Value, uint32_t Type, int32_t Addend); - void resolvePPC64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend); + void resolvePPC64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend); - void resolveSystemZRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend); + void resolveSystemZRelocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend); - unsigned getMaxStubSize() { - if (Arch == Triple::aarch64) + unsigned getMaxStubSize() override { + if (Arch == Triple::aarch64 || Arch == Triple::arm64 || + Arch == Triple::aarch64_be || Arch == Triple::arm64_be) return 20; // movz; movk; movk; movk; br if (Arch == Triple::arm || Arch == Triple::thumb) return 8; // 32-bit instruction and 32-bit address @@ -99,24 +75,24 @@ class RuntimeDyldELF : public RuntimeDyldImpl { return 0; } - unsigned getStubAlignment() { + unsigned getStubAlignment() override { if (Arch == Triple::systemz) return 8; else return 1; } - uint64_t findPPC64TOC() const; - void findOPDEntrySection(ObjectImage &Obj, - ObjSectionToIDMap &LocalSections, + void findPPC64TOCSection(ObjectImage &Obj, ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel); + void findOPDEntrySection(ObjectImage &Obj, ObjSectionToIDMap &LocalSections, RelocationValueRef &Rel); uint64_t findGOTEntry(uint64_t LoadAddr, uint64_t Offset); size_t getGOTEntrySize(); - virtual void updateGOTEntries(StringRef Name, uint64_t Addr); + void updateGOTEntries(StringRef Name, uint64_t Addr) override; - // Relocation entries for symbols whose position-independant offset is + // Relocation entries for symbols whose position-independent offset is // updated in a global offset table. typedef SmallVector<RelocationValueRef, 2> GOTRelocations; GOTRelocations GOTEntries; // List of entries requiring finalization. @@ -129,22 +105,23 @@ class RuntimeDyldELF : public RuntimeDyldImpl { SmallVector<SID, 2> RegisteredEHFrameSections; public: - RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) - {} + RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} - virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value); - virtual void processRelocationRef(unsigned SectionID, - RelocationRef RelI, - ObjectImage &Obj, - ObjSectionToIDMap &ObjSectionToID, - const SymbolTableMap &Symbols, - StubMap &Stubs); - virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const; - virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); - virtual void registerEHFrames(); - virtual void deregisterEHFrames(); - virtual void finalizeLoad(ObjSectionToIDMap &SectionMap); + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override; + relocation_iterator + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + ObjectImage &Obj, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols, StubMap &Stubs) override; + bool isCompatibleFormat(const ObjectBuffer *Buffer) const override; + bool isCompatibleFile(const object::ObjectFile *Buffer) const override; + void registerEHFrames() override; + void deregisterEHFrames() override; + void finalizeLoad(ObjectImage &ObjImg, + ObjSectionToIDMap &SectionMap) override; virtual ~RuntimeDyldELF(); + + static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); + static ObjectImage *createObjectImageFromFile(std::unique_ptr<object::ObjectFile> Obj); }; } // end namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index 3014b30773acc..0211d2bbbb052 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -20,6 +20,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/RuntimeDyldChecker.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -28,8 +29,8 @@ #include "llvm/Support/Mutex.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include <map> +#include <system_error> using namespace llvm; using namespace llvm::object; @@ -39,7 +40,6 @@ namespace llvm { class ObjectBuffer; class Twine; - /// SectionEntry - represents a section emitted into memory by the dynamic /// linker. class SectionEntry { @@ -69,8 +69,9 @@ public: SectionEntry(StringRef name, uint8_t *address, size_t size, uintptr_t objAddress) - : Name(name), Address(address), Size(size), LoadAddress((uintptr_t)address), - StubOffset(size), ObjAddress(objAddress) {} + : Name(name), Address(address), Size(size), + LoadAddress((uintptr_t)address), StubOffset(size), + ObjAddress(objAddress) {} }; /// RelocationEntry - used to represent relocations internally in the dynamic @@ -90,9 +91,17 @@ public: /// used to make a relocation section relative instead of symbol relative. int64_t Addend; + struct SectionPair { + uint32_t SectionA; + uint32_t SectionB; + }; + /// SymOffset - Section offset of the relocation entry's symbol (used for GOT /// lookup). - uint64_t SymOffset; + union { + uint64_t SymOffset; + SectionPair Sections; + }; /// True if this is a PCRel relocation (MachO specific). bool IsPCRel; @@ -101,33 +110,44 @@ public: unsigned Size; RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend) - : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(0), IsPCRel(false), Size(0) {} + : SectionID(id), Offset(offset), RelType(type), Addend(addend), + SymOffset(0), IsPCRel(false), Size(0) {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, uint64_t symoffset) - : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(symoffset), IsPCRel(false), Size(0) {} + : SectionID(id), Offset(offset), RelType(type), Addend(addend), + SymOffset(symoffset), IsPCRel(false), Size(0) {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, bool IsPCRel, unsigned Size) - : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(0), IsPCRel(IsPCRel), Size(Size) {} + : SectionID(id), Offset(offset), RelType(type), Addend(addend), + SymOffset(0), IsPCRel(IsPCRel), Size(Size) {} + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, + unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB, + uint64_t SectionBOffset, bool IsPCRel, unsigned Size) + : SectionID(id), Offset(offset), RelType(type), + Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), + Size(Size) { + Sections.SectionA = SectionA; + Sections.SectionB = SectionB; + } }; class RelocationValueRef { public: - unsigned SectionID; - uint64_t Offset; - int64_t Addend; + unsigned SectionID; + uint64_t Offset; + int64_t Addend; const char *SymbolName; - RelocationValueRef(): SectionID(0), Offset(0), Addend(0), SymbolName(0) {} + RelocationValueRef() : SectionID(0), Offset(0), Addend(0), + SymbolName(nullptr) {} inline bool operator==(const RelocationValueRef &Other) const { return SectionID == Other.SectionID && Offset == Other.Offset && Addend == Other.Addend && SymbolName == Other.SymbolName; } - inline bool operator <(const RelocationValueRef &Other) const { + inline bool operator<(const RelocationValueRef &Other) const { if (SectionID != Other.SectionID) return SectionID < Other.SectionID; if (Offset != Other.Offset) @@ -139,6 +159,15 @@ public: }; class RuntimeDyldImpl { + friend class RuntimeDyldChecker; +private: + + uint64_t getAnySymbolRemoteAddress(StringRef Symbol) { + if (uint64_t InternalSymbolAddr = getSymbolLoadAddress(Symbol)) + return InternalSymbolAddr; + return MemMgr->getSymbolAddress(Symbol); + } + protected: // The MemoryManager to load objects into. RTDyldMemoryManager *MemMgr; @@ -149,7 +178,7 @@ protected: SectionList Sections; typedef unsigned SID; // Type for SectionIDs - #define RTDYLD_INVALID_SECTION_ID ((SID)(-1)) +#define RTDYLD_INVALID_SECTION_ID ((SID)(-1)) // Keep a map of sections from object file to the SectionID which // references it. @@ -187,6 +216,10 @@ protected: Triple::ArchType Arch; bool IsTargetLittleEndian; + // True if all sections should be passed to the memory manager, false if only + // sections containing relocations should be. Defaults to 'false'. + bool ProcessAllSections; + // This mutex prevents simultaneously loading objects from two different // threads. This keeps us from having to protect individual data structures // and guarantees that section allocation requests to the memory manager @@ -217,52 +250,49 @@ protected: } uint8_t *getSectionAddress(unsigned SectionID) { - return (uint8_t*)Sections[SectionID].Address; + return (uint8_t *)Sections[SectionID].Address; } void writeInt16BE(uint8_t *Addr, uint16_t Value) { if (IsTargetLittleEndian) - Value = sys::SwapByteOrder(Value); - *Addr = (Value >> 8) & 0xFF; - *(Addr+1) = Value & 0xFF; + sys::swapByteOrder(Value); + *Addr = (Value >> 8) & 0xFF; + *(Addr + 1) = Value & 0xFF; } void writeInt32BE(uint8_t *Addr, uint32_t Value) { if (IsTargetLittleEndian) - Value = sys::SwapByteOrder(Value); - *Addr = (Value >> 24) & 0xFF; - *(Addr+1) = (Value >> 16) & 0xFF; - *(Addr+2) = (Value >> 8) & 0xFF; - *(Addr+3) = Value & 0xFF; + sys::swapByteOrder(Value); + *Addr = (Value >> 24) & 0xFF; + *(Addr + 1) = (Value >> 16) & 0xFF; + *(Addr + 2) = (Value >> 8) & 0xFF; + *(Addr + 3) = Value & 0xFF; } void writeInt64BE(uint8_t *Addr, uint64_t Value) { if (IsTargetLittleEndian) - Value = sys::SwapByteOrder(Value); - *Addr = (Value >> 56) & 0xFF; - *(Addr+1) = (Value >> 48) & 0xFF; - *(Addr+2) = (Value >> 40) & 0xFF; - *(Addr+3) = (Value >> 32) & 0xFF; - *(Addr+4) = (Value >> 24) & 0xFF; - *(Addr+5) = (Value >> 16) & 0xFF; - *(Addr+6) = (Value >> 8) & 0xFF; - *(Addr+7) = Value & 0xFF; + sys::swapByteOrder(Value); + *Addr = (Value >> 56) & 0xFF; + *(Addr + 1) = (Value >> 48) & 0xFF; + *(Addr + 2) = (Value >> 40) & 0xFF; + *(Addr + 3) = (Value >> 32) & 0xFF; + *(Addr + 4) = (Value >> 24) & 0xFF; + *(Addr + 5) = (Value >> 16) & 0xFF; + *(Addr + 6) = (Value >> 8) & 0xFF; + *(Addr + 7) = Value & 0xFF; } /// \brief Given the common symbols discovered in the object file, emit a /// new section for them and update the symbol mappings in the object and /// symbol table. - void emitCommonSymbols(ObjectImage &Obj, - const CommonSymbolMap &CommonSymbols, - uint64_t TotalSize, - SymbolTableMap &SymbolTable); + void emitCommonSymbols(ObjectImage &Obj, const CommonSymbolMap &CommonSymbols, + uint64_t TotalSize, SymbolTableMap &SymbolTable); /// \brief Emits section data from the object file to the MemoryManager. /// \param IsCode if it's true then allocateCodeSection() will be /// used for emits, else allocateDataSection() will be used. /// \return SectionID. - unsigned emitSection(ObjectImage &Obj, - const SectionRef &Section, + unsigned emitSection(ObjectImage &Obj, const SectionRef &Section, bool IsCode); /// \brief Find Section in LocalSections. If the secton is not found - emit @@ -270,10 +300,8 @@ protected: /// \param IsCode if it's true then allocateCodeSection() will be /// used for emmits, else allocateDataSection() will be used. /// \return SectionID. - unsigned findOrEmitSection(ObjectImage &Obj, - const SectionRef &Section, - bool IsCode, - ObjSectionToIDMap &LocalSections); + unsigned findOrEmitSection(ObjectImage &Obj, const SectionRef &Section, + bool IsCode, ObjSectionToIDMap &LocalSections); // \brief Add a relocation entry that uses the given section. void addRelocationForSection(const RelocationEntry &RE, unsigned SectionID); @@ -284,7 +312,7 @@ protected: /// \brief Emits long jump instruction to Addr. /// \return Pointer to the memory area for emitting target address. - uint8_t* createStubFunction(uint8_t *Addr); + uint8_t *createStubFunction(uint8_t *Addr, unsigned AbiVariant = 0); /// \brief Resolves relocations from Relocs list with address from Value. void resolveRelocationList(const RelocationList &Relocs, uint64_t Value); @@ -294,14 +322,14 @@ protected: /// \param Value Target symbol address to apply the relocation action virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value) = 0; - /// \brief Parses the object file relocation and stores it to Relocations - /// or SymbolRelocations (this depends on the object file type). - virtual void processRelocationRef(unsigned SectionID, - RelocationRef RelI, - ObjectImage &Obj, - ObjSectionToIDMap &ObjSectionToID, - const SymbolTableMap &Symbols, - StubMap &Stubs) = 0; + /// \brief Parses one or more object file relocations (some object files use + /// relocation pairs) and stores it to Relocations or SymbolRelocations + /// (this depends on the object file type). + /// \return Iterator to the next relocation that needs to be parsed. + virtual relocation_iterator + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + ObjectImage &Obj, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols, StubMap &Stubs) = 0; /// \brief Resolve relocations to external symbols. void resolveExternalSymbols(); @@ -310,20 +338,34 @@ protected: // The base class does nothing. ELF overrides this. virtual void updateGOTEntries(StringRef Name, uint64_t Addr) {} - virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); + // \brief Compute an upper bound of the memory that is required to load all + // sections + void computeTotalAllocSize(ObjectImage &Obj, uint64_t &CodeSize, + uint64_t &DataSizeRO, uint64_t &DataSizeRW); + + // \brief Compute the stub buffer size required for a section + unsigned computeSectionStubBufSize(ObjectImage &Obj, + const SectionRef &Section); + public: - RuntimeDyldImpl(RTDyldMemoryManager *mm) : MemMgr(mm), HasError(false) {} + RuntimeDyldImpl(RTDyldMemoryManager *mm) + : MemMgr(mm), ProcessAllSections(false), HasError(false) { + } virtual ~RuntimeDyldImpl(); - ObjectImage *loadObject(ObjectBuffer *InputBuffer); + void setProcessAllSections(bool ProcessAllSections) { + this->ProcessAllSections = ProcessAllSections; + } + + ObjectImage *loadObject(ObjectImage *InputObject); - void *getSymbolAddress(StringRef Name) { + uint8_t* getSymbolAddress(StringRef Name) { // FIXME: Just look up as a function for now. Overly simple of course. // Work in progress. SymbolTableMap::const_iterator pos = GlobalSymbolTable.find(Name); if (pos == GlobalSymbolTable.end()) - return 0; + return nullptr; SymbolLoc Loc = pos->second; return getSectionAddress(Loc.first) + Loc.second; } @@ -354,15 +396,15 @@ public: StringRef getErrorString() { return ErrorStr; } virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0; + virtual bool isCompatibleFile(const ObjectFile *Obj) const = 0; virtual void registerEHFrames(); virtual void deregisterEHFrames(); - virtual void finalizeLoad(ObjSectionToIDMap &SectionMap) {} + virtual void finalizeLoad(ObjectImage &ObjImg, ObjSectionToIDMap &SectionMap) {} }; } // end namespace llvm - #endif diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index 5b92867b4778b..58fb51557c93d 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -11,28 +11,148 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" #include "RuntimeDyldMachO.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" + +#include "Targets/RuntimeDyldMachOARM.h" +#include "Targets/RuntimeDyldMachOAArch64.h" +#include "Targets/RuntimeDyldMachOI386.h" +#include "Targets/RuntimeDyldMachOX86_64.h" + using namespace llvm; using namespace llvm::object; +#define DEBUG_TYPE "dyld" + namespace llvm { -static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, intptr_t DeltaForEH) { - uint32_t Length = *((uint32_t*)P); +uint64_t RuntimeDyldMachO::decodeAddend(uint8_t *LocalAddress, unsigned NumBytes, + uint32_t RelType) const { + uint64_t Addend = 0; + memcpy(&Addend, LocalAddress, NumBytes); + return Addend; +} + +RelocationValueRef RuntimeDyldMachO::getRelocationValueRef( + ObjectImage &ObjImg, const relocation_iterator &RI, + const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols) { + + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RI->getRawDataRefImpl()); + RelocationValueRef Value; + + bool IsExternal = Obj.getPlainRelocationExternal(RelInfo); + if (IsExternal) { + symbol_iterator Symbol = RI->getSymbol(); + StringRef TargetName; + Symbol->getName(TargetName); + SymbolTableMap::const_iterator SI = Symbols.find(TargetName.data()); + if (SI != Symbols.end()) { + Value.SectionID = SI->second.first; + Value.Addend = SI->second.second + RE.Addend; + } else { + SI = GlobalSymbolTable.find(TargetName.data()); + if (SI != GlobalSymbolTable.end()) { + Value.SectionID = SI->second.first; + Value.Addend = SI->second.second + RE.Addend; + } else { + Value.SymbolName = TargetName.data(); + Value.Addend = RE.Addend; + } + } + } else { + SectionRef Sec = Obj.getRelocationSection(RelInfo); + bool IsCode = false; + Sec.isText(IsCode); + Value.SectionID = findOrEmitSection(ObjImg, Sec, IsCode, ObjSectionToID); + uint64_t Addr; + Sec.getAddress(Addr); + Value.Addend = RE.Addend - Addr; + } + + return Value; +} + +void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef &Value, + ObjectImage &ObjImg, + const relocation_iterator &RI) { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RI->getRawDataRefImpl()); + + bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo); + if (IsPCRel) { + uint64_t RelocAddr = 0; + RI->getAddress(RelocAddr); + unsigned RelocSize = Obj.getAnyRelocationLength(RelInfo); + Value.Addend += RelocAddr + (1ULL << RelocSize); + } +} + +void RuntimeDyldMachO::dumpRelocationToResolve(const RelocationEntry &RE, + uint64_t Value) const { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.Address + RE.Offset; + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + + dbgs() << "resolveRelocation Section: " << RE.SectionID + << " LocalAddress: " << format("%p", LocalAddress) + << " FinalAddress: " << format("%p", FinalAddress) + << " Value: " << format("%p", Value) << " Addend: " << RE.Addend + << " isPCRel: " << RE.IsPCRel << " MachoType: " << RE.RelType + << " Size: " << (1 << RE.Size) << "\n"; +} + +bool RuntimeDyldMachO::writeBytesUnaligned(uint8_t *Addr, uint64_t Value, + unsigned Size) { + for (unsigned i = 0; i < Size; ++i) { + *Addr++ = (uint8_t)Value; + Value >>= 8; + } + + return false; +} + +bool +RuntimeDyldMachO::isCompatibleFormat(const ObjectBuffer *InputBuffer) const { + if (InputBuffer->getBufferSize() < 4) + return false; + StringRef Magic(InputBuffer->getBufferStart(), 4); + if (Magic == "\xFE\xED\xFA\xCE") + return true; + if (Magic == "\xCE\xFA\xED\xFE") + return true; + if (Magic == "\xFE\xED\xFA\xCF") + return true; + if (Magic == "\xCF\xFA\xED\xFE") + return true; + return false; +} + +bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const { + return Obj->isMachO(); +} + +static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, + intptr_t DeltaForEH) { + DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText + << ", Delta for EH: " << DeltaForEH << "\n"); + uint32_t Length = *((uint32_t *)P); P += 4; unsigned char *Ret = P + Length; - uint32_t Offset = *((uint32_t*)P); + uint32_t Offset = *((uint32_t *)P); if (Offset == 0) // is a CIE return Ret; P += 4; - intptr_t FDELocation = *((intptr_t*)P); + intptr_t FDELocation = *((intptr_t *)P); intptr_t NewLocation = FDELocation - DeltaForText; - *((intptr_t*)P) = NewLocation; + *((intptr_t *)P) = NewLocation; P += sizeof(intptr_t); // Skip the FDE address range @@ -41,16 +161,16 @@ static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, intptr uint8_t Augmentationsize = *P; P += 1; if (Augmentationsize != 0) { - intptr_t LSDA = *((intptr_t*)P); + intptr_t LSDA = *((intptr_t *)P); intptr_t NewLSDA = LSDA - DeltaForEH; - *((intptr_t*)P) = NewLSDA; + *((intptr_t *)P) = NewLSDA; } return Ret; } static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) { - intptr_t ObjDistance = A->ObjAddress - B->ObjAddress; + intptr_t ObjDistance = A->ObjAddress - B->ObjAddress; intptr_t MemDistance = A->LoadAddress - B->LoadAddress; return ObjDistance - MemDistance; } @@ -66,7 +186,7 @@ void RuntimeDyldMachO::registerEHFrames() { continue; SectionEntry *Text = &Sections[SectionInfo.TextSID]; SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID]; - SectionEntry *ExceptTab = NULL; + SectionEntry *ExceptTab = nullptr; if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID) ExceptTab = &Sections[SectionInfo.ExceptTabSID]; @@ -77,382 +197,27 @@ void RuntimeDyldMachO::registerEHFrames() { unsigned char *P = EHFrame->Address; unsigned char *End = P + EHFrame->Size; - do { + do { P = processFDE(P, DeltaForText, DeltaForEH); - } while(P != End); + } while (P != End); - MemMgr->registerEHFrames(EHFrame->Address, - EHFrame->LoadAddress, + MemMgr->registerEHFrames(EHFrame->Address, EHFrame->LoadAddress, EHFrame->Size); } UnregisteredEHFrameSections.clear(); } -void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) { - unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID; - unsigned TextSID = RTDYLD_INVALID_SECTION_ID; - unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID; - ObjSectionToIDMap::iterator i, e; - for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) { - const SectionRef &Section = i->first; - StringRef Name; - Section.getName(Name); - if (Name == "__eh_frame") - EHFrameSID = i->second; - else if (Name == "__text") - TextSID = i->second; - else if (Name == "__gcc_except_tab") - ExceptTabSID = i->second; - } - UnregisteredEHFrameSections.push_back(EHFrameRelatedSections(EHFrameSID, - TextSID, - ExceptTabSID)); -} - -// The target location for the relocation is described by RE.SectionID and -// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each -// SectionEntry has three members describing its location. -// SectionEntry::Address is the address at which the section has been loaded -// into memory in the current (host) process. SectionEntry::LoadAddress is the -// address that the section will have in the target process. -// SectionEntry::ObjAddress is the address of the bits for this section in the -// original emitted object image (also in the current address space). -// -// Relocations will be applied as if the section were loaded at -// SectionEntry::LoadAddress, but they will be applied at an address based -// on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer to -// Target memory contents if they are required for value calculations. -// -// The Value parameter here is the load address of the symbol for the -// relocation to be applied. For relocations which refer to symbols in the -// current object Value will be the LoadAddress of the section in which -// the symbol resides (RE.Addend provides additional information about the -// symbol location). For external symbols, Value will be the address of the -// symbol in the target address space. -void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE, - uint64_t Value) { - const SectionEntry &Section = Sections[RE.SectionID]; - return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, - RE.IsPCRel, RE.Size); -} - -void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, - bool isPCRel, - unsigned LogSize) { - uint8_t *LocalAddress = Section.Address + Offset; - uint64_t FinalAddress = Section.LoadAddress + Offset; - unsigned MachoType = Type; - unsigned Size = 1 << LogSize; - - DEBUG(dbgs() << "resolveRelocation LocalAddress: " - << format("%p", LocalAddress) - << " FinalAddress: " << format("%p", FinalAddress) - << " Value: " << format("%p", Value) - << " Addend: " << Addend - << " isPCRel: " << isPCRel - << " MachoType: " << MachoType - << " Size: " << Size - << "\n"); - - // This just dispatches to the proper target specific routine. +std::unique_ptr<RuntimeDyldMachO> +llvm::RuntimeDyldMachO::create(Triple::ArchType Arch, RTDyldMemoryManager *MM) { switch (Arch) { - default: llvm_unreachable("Unsupported CPU type!"); - case Triple::x86_64: - resolveX86_64Relocation(LocalAddress, - FinalAddress, - (uintptr_t)Value, - isPCRel, - MachoType, - Size, - Addend); - break; - case Triple::x86: - resolveI386Relocation(LocalAddress, - FinalAddress, - (uintptr_t)Value, - isPCRel, - MachoType, - Size, - Addend); - break; - case Triple::arm: // Fall through. - case Triple::thumb: - resolveARMRelocation(LocalAddress, - FinalAddress, - (uintptr_t)Value, - isPCRel, - MachoType, - Size, - Addend); - break; - } -} - -bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend) { - if (isPCRel) - Value -= FinalAddress + 4; // see resolveX86_64Relocation - - switch (Type) { - default: - llvm_unreachable("Invalid relocation type!"); - case MachO::GENERIC_RELOC_VANILLA: { - uint8_t *p = LocalAddress; - uint64_t ValueToWrite = Value + Addend; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)(ValueToWrite & 0xff); - ValueToWrite >>= 8; - } - return false; - } - case MachO::GENERIC_RELOC_SECTDIFF: - case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: - case MachO::GENERIC_RELOC_PB_LA_PTR: - return Error("Relocation type not implemented yet!"); - } -} - -bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend) { - // If the relocation is PC-relative, the value to be encoded is the - // pointer difference. - if (isPCRel) - // FIXME: It seems this value needs to be adjusted by 4 for an effective PC - // address. Is that expected? Only for branches, perhaps? - Value -= FinalAddress + 4; - - switch(Type) { default: - llvm_unreachable("Invalid relocation type!"); - case MachO::X86_64_RELOC_SIGNED_1: - case MachO::X86_64_RELOC_SIGNED_2: - case MachO::X86_64_RELOC_SIGNED_4: - case MachO::X86_64_RELOC_SIGNED: - case MachO::X86_64_RELOC_UNSIGNED: - case MachO::X86_64_RELOC_BRANCH: { - Value += Addend; - // Mask in the target value a byte at a time (we don't have an alignment - // guarantee for the target address, so this is safest). - uint8_t *p = (uint8_t*)LocalAddress; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)Value; - Value >>= 8; - } - return false; - } - case MachO::X86_64_RELOC_GOT_LOAD: - case MachO::X86_64_RELOC_GOT: - case MachO::X86_64_RELOC_SUBTRACTOR: - case MachO::X86_64_RELOC_TLV: - return Error("Relocation type not implemented yet!"); - } -} - -bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend) { - // If the relocation is PC-relative, the value to be encoded is the - // pointer difference. - if (isPCRel) { - Value -= FinalAddress; - // ARM PCRel relocations have an effective-PC offset of two instructions - // (four bytes in Thumb mode, 8 bytes in ARM mode). - // FIXME: For now, assume ARM mode. - Value -= 8; - } - - switch(Type) { - default: - llvm_unreachable("Invalid relocation type!"); - case MachO::ARM_RELOC_VANILLA: { - // Mask in the target value a byte at a time (we don't have an alignment - // guarantee for the target address, so this is safest). - uint8_t *p = (uint8_t*)LocalAddress; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)Value; - Value >>= 8; - } + llvm_unreachable("Unsupported target for RuntimeDyldMachO."); break; + case Triple::arm: return make_unique<RuntimeDyldMachOARM>(MM); + case Triple::arm64: return make_unique<RuntimeDyldMachOAArch64>(MM); + case Triple::x86: return make_unique<RuntimeDyldMachOI386>(MM); + case Triple::x86_64: return make_unique<RuntimeDyldMachOX86_64>(MM); } - case MachO::ARM_RELOC_BR24: { - // Mask the value into the target address. We know instructions are - // 32-bit aligned, so we can do it all at once. - uint32_t *p = (uint32_t*)LocalAddress; - // The low two bits of the value are not encoded. - Value >>= 2; - // Mask the value to 24 bits. - Value &= 0xffffff; - // FIXME: If the destination is a Thumb function (and the instruction - // is a non-predicated BL instruction), we need to change it to a BLX - // instruction instead. - - // Insert the value into the instruction. - *p = (*p & ~0xffffff) | Value; - break; - } - case MachO::ARM_THUMB_RELOC_BR22: - case MachO::ARM_THUMB_32BIT_BRANCH: - case MachO::ARM_RELOC_HALF: - case MachO::ARM_RELOC_HALF_SECTDIFF: - case MachO::ARM_RELOC_PAIR: - case MachO::ARM_RELOC_SECTDIFF: - case MachO::ARM_RELOC_LOCAL_SECTDIFF: - case MachO::ARM_RELOC_PB_LA_PTR: - return Error("Relocation type not implemented yet!"); - } - return false; -} - -void RuntimeDyldMachO::processRelocationRef(unsigned SectionID, - RelocationRef RelI, - ObjectImage &Obj, - ObjSectionToIDMap &ObjSectionToID, - const SymbolTableMap &Symbols, - StubMap &Stubs) { - const ObjectFile *OF = Obj.getObjectFile(); - const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF); - MachO::any_relocation_info RE= MachO->getRelocation(RelI.getRawDataRefImpl()); - - uint32_t RelType = MachO->getAnyRelocationType(RE); - - // FIXME: Properly handle scattered relocations. - // For now, optimistically skip these: they can often be ignored, as - // the static linker will already have applied the relocation, and it - // only needs to be reapplied if symbols move relative to one another. - // Note: This will fail horribly where the relocations *do* need to be - // applied, but that was already the case. - if (MachO->isRelocationScattered(RE)) - return; - - RelocationValueRef Value; - SectionEntry &Section = Sections[SectionID]; - - bool isExtern = MachO->getPlainRelocationExternal(RE); - bool IsPCRel = MachO->getAnyRelocationPCRel(RE); - unsigned Size = MachO->getAnyRelocationLength(RE); - uint64_t Offset; - RelI.getOffset(Offset); - uint8_t *LocalAddress = Section.Address + Offset; - unsigned NumBytes = 1 << Size; - uint64_t Addend = 0; - memcpy(&Addend, LocalAddress, NumBytes); - - if (isExtern) { - // Obtain the symbol name which is referenced in the relocation - symbol_iterator Symbol = RelI.getSymbol(); - StringRef TargetName; - Symbol->getName(TargetName); - // First search for the symbol in the local symbol table - SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); - if (lsi != Symbols.end()) { - Value.SectionID = lsi->second.first; - Value.Addend = lsi->second.second + Addend; - } else { - // Search for the symbol in the global symbol table - SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); - if (gsi != GlobalSymbolTable.end()) { - Value.SectionID = gsi->second.first; - Value.Addend = gsi->second.second + Addend; - } else { - Value.SymbolName = TargetName.data(); - Value.Addend = Addend; - } - } - } else { - SectionRef Sec = MachO->getRelocationSection(RE); - Value.SectionID = findOrEmitSection(Obj, Sec, true, ObjSectionToID); - uint64_t Addr; - Sec.getAddress(Addr); - Value.Addend = Addend - Addr; - } - - if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT || - RelType == MachO::X86_64_RELOC_GOT_LOAD)) { - assert(IsPCRel); - assert(Size == 2); - StubMap::const_iterator i = Stubs.find(Value); - uint8_t *Addr; - if (i != Stubs.end()) { - Addr = Section.Address + i->second; - } else { - Stubs[Value] = Section.StubOffset; - uint8_t *GOTEntry = Section.Address + Section.StubOffset; - RelocationEntry RE(SectionID, Section.StubOffset, - MachO::X86_64_RELOC_UNSIGNED, 0, false, 3); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - Section.StubOffset += 8; - Addr = GOTEntry; - } - resolveRelocation(Section, Offset, (uint64_t)Addr, - MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, 2); - } else if (Arch == Triple::arm && - (RelType & 0xf) == MachO::ARM_RELOC_BR24) { - // This is an ARM branch relocation, need to use a stub function. - - // Look up for existing stub. - StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + i->second, - RelType, 0, IsPCRel, Size); - else { - // Create a new stub function. - Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); - RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, - MachO::GENERIC_RELOC_VANILLA, Value.Addend); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, - RelType, 0, IsPCRel, Size); - Section.StubOffset += getMaxStubSize(); - } - } else { - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, - IsPCRel, Size); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } -} - - -bool RuntimeDyldMachO::isCompatibleFormat( - const ObjectBuffer *InputBuffer) const { - if (InputBuffer->getBufferSize() < 4) - return false; - StringRef Magic(InputBuffer->getBufferStart(), 4); - if (Magic == "\xFE\xED\xFA\xCE") return true; - if (Magic == "\xCE\xFA\xED\xFE") return true; - if (Magic == "\xFE\xED\xFA\xCF") return true; - if (Magic == "\xCF\xFA\xED\xFE") return true; - return false; } } // end namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index bbf6aa9f65061..7d1dc0263db02 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -14,66 +14,31 @@ #ifndef LLVM_RUNTIME_DYLD_MACHO_H #define LLVM_RUNTIME_DYLD_MACHO_H +#include "ObjectImageCommon.h" #include "RuntimeDyldImpl.h" -#include "llvm/ADT/IndexedMap.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Format.h" +#define DEBUG_TYPE "dyld" + using namespace llvm; using namespace llvm::object; - namespace llvm { class RuntimeDyldMachO : public RuntimeDyldImpl { - bool resolveI386Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend); - bool resolveX86_64Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend); - bool resolveARMRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend); - - void resolveRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, - bool isPCRel, - unsigned Size); - - unsigned getMaxStubSize() { - if (Arch == Triple::arm || Arch == Triple::thumb) - return 8; // 32-bit instruction and 32-bit address - else if (Arch == Triple::x86_64) - return 8; // GOT entry - else - return 0; - } - - unsigned getStubAlignment() { - return 1; - } +protected: + struct SectionOffsetPair { + unsigned SectionID; + uint64_t Offset; + }; struct EHFrameRelatedSections { - EHFrameRelatedSections() : EHFrameSID(RTDYLD_INVALID_SECTION_ID), - TextSID(RTDYLD_INVALID_SECTION_ID), - ExceptTabSID(RTDYLD_INVALID_SECTION_ID) {} - EHFrameRelatedSections(SID EH, SID T, SID Ex) - : EHFrameSID(EH), TextSID(T), ExceptTabSID(Ex) {} + EHFrameRelatedSections() + : EHFrameSID(RTDYLD_INVALID_SECTION_ID), + TextSID(RTDYLD_INVALID_SECTION_ID), + ExceptTabSID(RTDYLD_INVALID_SECTION_ID) {} + EHFrameRelatedSections(SID EH, SID T, SID Ex) + : EHFrameSID(EH), TextSID(T), ExceptTabSID(Ex) {} SID EHFrameSID; SID TextSID; SID ExceptTabSID; @@ -83,21 +48,130 @@ class RuntimeDyldMachO : public RuntimeDyldImpl { // in a table until we receive a request to register all unregistered // EH frame sections with the memory manager. SmallVector<EHFrameRelatedSections, 2> UnregisteredEHFrameSections; -public: + RuntimeDyldMachO(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} - virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value); - virtual void processRelocationRef(unsigned SectionID, - RelocationRef RelI, - ObjectImage &Obj, - ObjSectionToIDMap &ObjSectionToID, - const SymbolTableMap &Symbols, - StubMap &Stubs); - virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const; - virtual void registerEHFrames(); - virtual void finalizeLoad(ObjSectionToIDMap &SectionMap); + /// Extract the addend encoded in the instruction. + uint64_t decodeAddend(uint8_t *LocalAddress, unsigned NumBytes, + uint32_t RelType) const; + + /// Construct a RelocationValueRef representing the relocation target. + /// For Symbols in known sections, this will return a RelocationValueRef + /// representing a (SectionID, Offset) pair. + /// For Symbols whose section is not known, this will return a + /// (SymbolName, Offset) pair, where the Offset is taken from the instruction + /// immediate (held in RE.Addend). + /// In both cases the Addend field is *NOT* fixed up to be PC-relative. That + /// should be done by the caller where appropriate by calling makePCRel on + /// the RelocationValueRef. + RelocationValueRef getRelocationValueRef(ObjectImage &ObjImg, + const relocation_iterator &RI, + const RelocationEntry &RE, + ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols); + + /// Make the RelocationValueRef addend PC-relative. + void makeValueAddendPCRel(RelocationValueRef &Value, ObjectImage &ObjImg, + const relocation_iterator &RI); + + /// Dump information about the relocation entry (RE) and resolved value. + void dumpRelocationToResolve(const RelocationEntry &RE, uint64_t Value) const; + +public: + /// Create an ObjectImage from the given ObjectBuffer. + static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer) { + return new ObjectImageCommon(InputBuffer); + } + + /// Create an ObjectImage from the given ObjectFile. + static ObjectImage * + createObjectImageFromFile(std::unique_ptr<object::ObjectFile> InputObject) { + return new ObjectImageCommon(std::move(InputObject)); + } + + /// Create a RuntimeDyldMachO instance for the given target architecture. + static std::unique_ptr<RuntimeDyldMachO> create(Triple::ArchType Arch, + RTDyldMemoryManager *mm); + + /// Write the least significant 'Size' bytes in 'Value' out at the address + /// pointed to by Addr. Check for overflow. + bool writeBytesUnaligned(uint8_t *Addr, uint64_t Value, unsigned Size); + + SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; } + + bool isCompatibleFormat(const ObjectBuffer *Buffer) const override; + bool isCompatibleFile(const object::ObjectFile *Obj) const override; + void registerEHFrames() override; +}; + +/// RuntimeDyldMachOTarget - Templated base class for generic MachO linker +/// algorithms and data structures. +/// +/// Concrete, target specific sub-classes can be accessed via the impl() +/// methods. (i.e. the RuntimeDyldMachO hierarchy uses the Curiously +/// Recurring Template Idiom). Concrete subclasses for each target +/// can be found in ./Targets. +template <typename Impl> +class RuntimeDyldMachOCRTPBase : public RuntimeDyldMachO { +private: + Impl &impl() { return static_cast<Impl &>(*this); } + const Impl &impl() const { return static_cast<const Impl &>(*this); } + +protected: + + /// Parse the given relocation, which must be a non-scattered, and + /// return a RelocationEntry representing the information. The 'Addend' field + /// will contain the unmodified instruction immediate. + RelocationEntry getBasicRelocationEntry(unsigned SectionID, + ObjectImage &ObjImg, + const relocation_iterator &RI) const { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RI->getRawDataRefImpl()); + + const SectionEntry &Section = Sections[SectionID]; + bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo); + unsigned Size = Obj.getAnyRelocationLength(RelInfo); + uint64_t Offset; + RI->getOffset(Offset); + uint8_t *LocalAddress = Section.Address + Offset; + unsigned NumBytes = 1 << Size; + uint32_t RelType = Obj.getAnyRelocationType(RelInfo); + uint64_t Addend = impl().decodeAddend(LocalAddress, NumBytes, RelType); + + return RelocationEntry(SectionID, Offset, RelType, Addend, IsPCRel, Size); + } + +public: + RuntimeDyldMachOCRTPBase(RTDyldMemoryManager *mm) : RuntimeDyldMachO(mm) {} + + void finalizeLoad(ObjectImage &ObjImg, ObjSectionToIDMap &SectionMap) { + unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID; + unsigned TextSID = RTDYLD_INVALID_SECTION_ID; + unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID; + ObjSectionToIDMap::iterator i, e; + + for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) { + const SectionRef &Section = i->first; + StringRef Name; + Section.getName(Name); + if (Name == "__eh_frame") + EHFrameSID = i->second; + else if (Name == "__text") + TextSID = i->second; + else if (Name == "__gcc_except_tab") + ExceptTabSID = i->second; + else + impl().finalizeSection(ObjImg, i->second, Section); + } + UnregisteredEHFrameSections.push_back( + EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID)); + } }; } // end namespace llvm +#undef DEBUG_TYPE + #endif diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h new file mode 100644 index 0000000000000..775ed9ec36359 --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h @@ -0,0 +1,255 @@ +//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_RUNTIMEDYLDMACHOAARCH64_H +#define LLVM_RUNTIMEDYLDMACHOAARCH64_H + +#include "../RuntimeDyldMachO.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOAArch64 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> { +public: + RuntimeDyldMachOAArch64(RTDyldMemoryManager *MM) + : RuntimeDyldMachOCRTPBase(MM) {} + + unsigned getMaxStubSize() override { return 8; } + + unsigned getStubAlignment() override { return 8; } + + relocation_iterator + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols, StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + assert(!Obj.isRelocationScattered(RelInfo) && ""); + + // ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit + // addend for the following relocation. If found: (1) store the associated + // addend, (2) consume the next relocation, and (3) use the stored addend to + // override the addend. + bool HasExplicitAddend = false; + int64_t ExplicitAddend = 0; + if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) { + assert(!Obj.getPlainRelocationExternal(RelInfo)); + assert(!Obj.getAnyRelocationPCRel(RelInfo)); + assert(Obj.getAnyRelocationLength(RelInfo) == 2); + HasExplicitAddend = true; + int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo); + // Sign-extend the 24-bit to 64-bit. + ExplicitAddend = (RawAddend << 40) >> 40; + ++RelI; + RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl()); + } + + RelocationEntry RE(getBasicRelocationEntry(SectionID, ObjImg, RelI)); + RelocationValueRef Value( + getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols)); + + if (HasExplicitAddend) { + RE.Addend = ExplicitAddend; + Value.Addend = ExplicitAddend; + } + + bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + if (!IsExtern && RE.IsPCRel) + makeValueAddendPCRel(Value, ObjImg, RelI); + + RE.Addend = Value.Addend; + + if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 || + RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12) + processGOTRelocation(RE, Value, Stubs); + else { + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) { + DEBUG(dumpRelocationToResolve(RE, Value)); + + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.Address + RE.Offset; + + switch (RE.RelType) { + default: + llvm_unreachable("Invalid relocation type!"); + case MachO::ARM64_RELOC_UNSIGNED: { + assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported"); + // Mask in the target value a byte at a time (we don't have an alignment + // guarantee for the target address, so this is safest). + if (RE.Size < 2) + llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED"); + + writeBytesUnaligned(LocalAddress, Value + RE.Addend, 1 << RE.Size); + break; + } + case MachO::ARM64_RELOC_BRANCH26: { + assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported"); + // Mask the value into the target address. We know instructions are + // 32-bit aligned, so we can do it all at once. + uint32_t *p = (uint32_t *)LocalAddress; + // Check if the addend is encoded in the instruction. + uint32_t EncodedAddend = *p & 0x03FFFFFF; + if (EncodedAddend != 0) { + if (RE.Addend == 0) + llvm_unreachable("branch26 instruction has embedded addend."); + else + llvm_unreachable("branch26 instruction has embedded addend and" + "ARM64_RELOC_ADDEND."); + } + // Check if branch is in range. + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + uint64_t PCRelVal = Value - FinalAddress + RE.Addend; + assert(isInt<26>(PCRelVal) && "Branch target out of range!"); + // Insert the value into the instruction. + *p = (*p & 0xFC000000) | ((uint32_t)(PCRelVal >> 2) & 0x03FFFFFF); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_PAGE21: { + assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported"); + // Mask the value into the target address. We know instructions are + // 32-bit aligned, so we can do it all at once. + uint32_t *p = (uint32_t *)LocalAddress; + // Check if the addend is encoded in the instruction. + uint32_t EncodedAddend = + ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3); + if (EncodedAddend != 0) { + if (RE.Addend == 0) + llvm_unreachable("adrp instruction has embedded addend."); + else + llvm_unreachable("adrp instruction has embedded addend and" + "ARM64_RELOC_ADDEND."); + } + // Adjust for PC-relative relocation and offset. + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + uint64_t PCRelVal = + ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096)); + // Check that the value fits into 21 bits (+ 12 lower bits). + assert(isInt<33>(PCRelVal) && "Invalid page reloc value!"); + // Insert the value into the instruction. + uint32_t ImmLoValue = (uint32_t)(PCRelVal << 17) & 0x60000000; + uint32_t ImmHiValue = (uint32_t)(PCRelVal >> 9) & 0x00FFFFE0; + *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue; + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: + case MachO::ARM64_RELOC_PAGEOFF12: { + assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported"); + // Mask the value into the target address. We know instructions are + // 32-bit aligned, so we can do it all at once. + uint32_t *p = (uint32_t *)LocalAddress; + // Check if the addend is encoded in the instruction. + uint32_t EncodedAddend = *p & 0x003FFC00; + if (EncodedAddend != 0) { + if (RE.Addend == 0) + llvm_unreachable("adrp instruction has embedded addend."); + else + llvm_unreachable("adrp instruction has embedded addend and" + "ARM64_RELOC_ADDEND."); + } + // Add the offset from the symbol. + Value += RE.Addend; + // Mask out the page address and only use the lower 12 bits. + Value &= 0xFFF; + // Check which instruction we are updating to obtain the implicit shift + // factor from LDR/STR instructions. + if (*p & 0x08000000) { + uint32_t ImplicitShift = ((*p >> 30) & 0x3); + switch (ImplicitShift) { + case 0: + // Check if this a vector op. + if ((*p & 0x04800000) == 0x04800000) { + ImplicitShift = 4; + assert(((Value & 0xF) == 0) && + "128-bit LDR/STR not 16-byte aligned."); + } + break; + case 1: + assert(((Value & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned."); + case 2: + assert(((Value & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned."); + case 3: + assert(((Value & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned."); + } + // Compensate for implicit shift. + Value >>= ImplicitShift; + } + // Insert the value into the instruction. + *p = (*p & 0xFFC003FF) | ((uint32_t)(Value << 10) & 0x003FFC00); + break; + } + case MachO::ARM64_RELOC_SUBTRACTOR: + case MachO::ARM64_RELOC_POINTER_TO_GOT: + case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: + case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: + llvm_unreachable("Relocation type not implemented yet!"); + case MachO::ARM64_RELOC_ADDEND: + llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by " + "processRelocationRef!"); + } + } + + void finalizeSection(ObjectImage &ObjImg, unsigned SectionID, + const SectionRef &Section) {} + +private: + void processGOTRelocation(const RelocationEntry &RE, + RelocationValueRef &Value, StubMap &Stubs) { + assert(RE.Size == 2); + SectionEntry &Section = Sections[RE.SectionID]; + StubMap::const_iterator i = Stubs.find(Value); + uint8_t *Addr; + if (i != Stubs.end()) + Addr = Section.Address + i->second; + else { + // FIXME: There must be a better way to do this then to check and fix the + // alignment every time!!! + uintptr_t BaseAddress = uintptr_t(Section.Address); + uintptr_t StubAlignment = getStubAlignment(); + uintptr_t StubAddress = + (BaseAddress + Section.StubOffset + StubAlignment - 1) & + -StubAlignment; + unsigned StubOffset = StubAddress - BaseAddress; + Stubs[Value] = StubOffset; + assert(((StubAddress % getStubAlignment()) == 0) && + "GOT entry not aligned"); + RelocationEntry GOTRE(RE.SectionID, StubOffset, + MachO::ARM64_RELOC_UNSIGNED, Value.Addend, + /*IsPCRel=*/false, /*Size=*/3); + if (Value.SymbolName) + addRelocationForSymbol(GOTRE, Value.SymbolName); + else + addRelocationForSection(GOTRE, Value.SectionID); + Section.StubOffset = StubOffset + getMaxStubSize(); + Addr = (uint8_t *)StubAddress; + } + RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, /*Addend=*/0, + RE.IsPCRel, RE.Size); + resolveRelocation(TargetRE, (uint64_t)Addr); + } +}; +} + +#undef DEBUG_TYPE + +#endif // LLVM_RUNTIMEDYLDMACHOAARCH64_H diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h new file mode 100644 index 0000000000000..1de9942198249 --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h @@ -0,0 +1,154 @@ +//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_RUNTIMEDYLDMACHOARM_H +#define LLVM_RUNTIMEDYLDMACHOARM_H + +#include "../RuntimeDyldMachO.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOARM + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> { +public: + RuntimeDyldMachOARM(RTDyldMemoryManager *MM) : RuntimeDyldMachOCRTPBase(MM) {} + + unsigned getMaxStubSize() override { return 8; } + + unsigned getStubAlignment() override { return 4; } + + relocation_iterator + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols, StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + if (Obj.isRelocationScattered(RelInfo)) + return ++++RelI; + + RelocationEntry RE(getBasicRelocationEntry(SectionID, ObjImg, RelI)); + RelocationValueRef Value( + getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols)); + + bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + if (!IsExtern && RE.IsPCRel) + makeValueAddendPCRel(Value, ObjImg, RelI); + + if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24) + processBranchRelocation(RE, Value, Stubs); + else { + RE.Addend = Value.Addend; + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) { + DEBUG(dumpRelocationToResolve(RE, Value)); + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.Address + RE.Offset; + + // If the relocation is PC-relative, the value to be encoded is the + // pointer difference. + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + Value -= FinalAddress; + // ARM PCRel relocations have an effective-PC offset of two instructions + // (four bytes in Thumb mode, 8 bytes in ARM mode). + // FIXME: For now, assume ARM mode. + Value -= 8; + } + + switch (RE.RelType) { + default: + llvm_unreachable("Invalid relocation type!"); + case MachO::ARM_RELOC_VANILLA: + writeBytesUnaligned(LocalAddress, Value, 1 << RE.Size); + break; + case MachO::ARM_RELOC_BR24: { + // Mask the value into the target address. We know instructions are + // 32-bit aligned, so we can do it all at once. + uint32_t *p = (uint32_t *)LocalAddress; + // The low two bits of the value are not encoded. + Value >>= 2; + // Mask the value to 24 bits. + uint64_t FinalValue = Value & 0xffffff; + // Check for overflow. + if (Value != FinalValue) { + Error("ARM BR24 relocation out of range."); + return; + } + // FIXME: If the destination is a Thumb function (and the instruction + // is a non-predicated BL instruction), we need to change it to a BLX + // instruction instead. + + // Insert the value into the instruction. + *p = (*p & ~0xffffff) | FinalValue; + break; + } + case MachO::ARM_THUMB_RELOC_BR22: + case MachO::ARM_THUMB_32BIT_BRANCH: + case MachO::ARM_RELOC_HALF: + case MachO::ARM_RELOC_HALF_SECTDIFF: + case MachO::ARM_RELOC_PAIR: + case MachO::ARM_RELOC_SECTDIFF: + case MachO::ARM_RELOC_LOCAL_SECTDIFF: + case MachO::ARM_RELOC_PB_LA_PTR: + Error("Relocation type not implemented yet!"); + return; + } + } + + void finalizeSection(ObjectImage &ObjImg, unsigned SectionID, + const SectionRef &Section) {} + +private: + void processBranchRelocation(const RelocationEntry &RE, + const RelocationValueRef &Value, + StubMap &Stubs) { + // This is an ARM branch relocation, need to use a stub function. + // Look up for existing stub. + SectionEntry &Section = Sections[RE.SectionID]; + RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value); + uint8_t *Addr; + if (i != Stubs.end()) { + Addr = Section.Address + i->second; + } else { + // Create a new stub function. + Stubs[Value] = Section.StubOffset; + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset); + RelocationEntry StubRE(RE.SectionID, StubTargetAddr - Section.Address, + MachO::GENERIC_RELOC_VANILLA, Value.Addend); + if (Value.SymbolName) + addRelocationForSymbol(StubRE, Value.SymbolName); + else + addRelocationForSection(StubRE, Value.SectionID); + Addr = Section.Address + Section.StubOffset; + Section.StubOffset += getMaxStubSize(); + } + RelocationEntry TargetRE(Value.SectionID, RE.Offset, RE.RelType, 0, + RE.IsPCRel, RE.Size); + resolveRelocation(TargetRE, (uint64_t)Addr); + } +}; +} + +#undef DEBUG_TYPE + +#endif // LLVM_RUNTIMEDYLDMACHOARM_H diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h new file mode 100644 index 0000000000000..856c6ca3035c5 --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h @@ -0,0 +1,315 @@ +//===---- RuntimeDyldMachOI386.h ---- MachO/I386 specific code. ---*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_RUNTIMEDYLDMACHOI386_H +#define LLVM_RUNTIMEDYLDMACHOI386_H + +#include "../RuntimeDyldMachO.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOI386 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> { +public: + RuntimeDyldMachOI386(RTDyldMemoryManager *MM) + : RuntimeDyldMachOCRTPBase(MM) {} + + unsigned getMaxStubSize() override { return 0; } + + unsigned getStubAlignment() override { return 1; } + + relocation_iterator + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols, StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + uint32_t RelType = Obj.getAnyRelocationType(RelInfo); + + if (Obj.isRelocationScattered(RelInfo)) { + if (RelType == MachO::GENERIC_RELOC_SECTDIFF || + RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) + return processSECTDIFFRelocation(SectionID, RelI, ObjImg, + ObjSectionToID); + else if (Arch == Triple::x86 && RelType == MachO::GENERIC_RELOC_VANILLA) + return processI386ScatteredVANILLA(SectionID, RelI, ObjImg, + ObjSectionToID); + llvm_unreachable("Unhandled scattered relocation."); + } + + RelocationEntry RE(getBasicRelocationEntry(SectionID, ObjImg, RelI)); + RelocationValueRef Value( + getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols)); + + // Addends for external, PC-rel relocations on i386 point back to the zero + // offset. Calculate the final offset from the relocation target instead. + // This allows us to use the same logic for both external and internal + // relocations in resolveI386RelocationRef. + // bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + // if (IsExtern && RE.IsPCRel) { + // uint64_t RelocAddr = 0; + // RelI->getAddress(RelocAddr); + // Value.Addend += RelocAddr + 4; + // } + if (RE.IsPCRel) + makeValueAddendPCRel(Value, ObjImg, RelI); + + RE.Addend = Value.Addend; + + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) { + DEBUG(dumpRelocationToResolve(RE, Value)); + + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.Address + RE.Offset; + + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation. + } + + switch (RE.RelType) { + default: + llvm_unreachable("Invalid relocation type!"); + case MachO::GENERIC_RELOC_VANILLA: + writeBytesUnaligned(LocalAddress, Value + RE.Addend, 1 << RE.Size); + break; + case MachO::GENERIC_RELOC_SECTDIFF: + case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: { + uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress; + uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress; + assert((Value == SectionABase || Value == SectionBBase) && + "Unexpected SECTDIFF relocation value."); + Value = SectionABase - SectionBBase + RE.Addend; + writeBytesUnaligned(LocalAddress, Value, 1 << RE.Size); + break; + } + case MachO::GENERIC_RELOC_PB_LA_PTR: + Error("Relocation type not implemented yet!"); + } + } + + void finalizeSection(ObjectImage &ObjImg, unsigned SectionID, + const SectionRef &Section) { + StringRef Name; + Section.getName(Name); + + if (Name == "__jump_table") + populateJumpTable(cast<MachOObjectFile>(*ObjImg.getObjectFile()), Section, + SectionID); + else if (Name == "__pointers") + populatePointersSection(cast<MachOObjectFile>(*ObjImg.getObjectFile()), + Section, SectionID); + } + +private: + relocation_iterator + processSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI, + ObjectImage &Obj, + ObjSectionToIDMap &ObjSectionToID) { + const MachOObjectFile *MachO = + static_cast<const MachOObjectFile *>(Obj.getObjectFile()); + MachO::any_relocation_info RE = + MachO->getRelocation(RelI->getRawDataRefImpl()); + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = MachO->getAnyRelocationType(RE); + bool IsPCRel = MachO->getAnyRelocationPCRel(RE); + unsigned Size = MachO->getAnyRelocationLength(RE); + uint64_t Offset; + RelI->getOffset(Offset); + uint8_t *LocalAddress = Section.Address + Offset; + unsigned NumBytes = 1 << Size; + int64_t Addend = 0; + memcpy(&Addend, LocalAddress, NumBytes); + + ++RelI; + MachO::any_relocation_info RE2 = + MachO->getRelocation(RelI->getRawDataRefImpl()); + + uint32_t AddrA = MachO->getScatteredRelocationValue(RE); + section_iterator SAI = getSectionByAddress(*MachO, AddrA); + assert(SAI != MachO->section_end() && "Can't find section for address A"); + uint64_t SectionABase; + SAI->getAddress(SectionABase); + uint64_t SectionAOffset = AddrA - SectionABase; + SectionRef SectionA = *SAI; + bool IsCode; + SectionA.isText(IsCode); + uint32_t SectionAID = + findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID); + + uint32_t AddrB = MachO->getScatteredRelocationValue(RE2); + section_iterator SBI = getSectionByAddress(*MachO, AddrB); + assert(SBI != MachO->section_end() && "Can't find section for address B"); + uint64_t SectionBBase; + SBI->getAddress(SectionBBase); + uint64_t SectionBOffset = AddrB - SectionBBase; + SectionRef SectionB = *SBI; + uint32_t SectionBID = + findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID); + + if (Addend != AddrA - AddrB) + Error("Unexpected SECTDIFF relocation addend."); + + DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB + << ", Addend: " << Addend << ", SectionA ID: " << SectionAID + << ", SectionAOffset: " << SectionAOffset + << ", SectionB ID: " << SectionBID + << ", SectionBOffset: " << SectionBOffset << "\n"); + RelocationEntry R(SectionID, Offset, RelocType, 0, SectionAID, + SectionAOffset, SectionBID, SectionBOffset, IsPCRel, + Size); + + addRelocationForSection(R, SectionAID); + addRelocationForSection(R, SectionBID); + + return ++RelI; + } + + relocation_iterator processI386ScatteredVANILLA( + unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj, + RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID) { + const MachOObjectFile *MachO = + static_cast<const MachOObjectFile *>(Obj.getObjectFile()); + MachO::any_relocation_info RE = + MachO->getRelocation(RelI->getRawDataRefImpl()); + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = MachO->getAnyRelocationType(RE); + bool IsPCRel = MachO->getAnyRelocationPCRel(RE); + unsigned Size = MachO->getAnyRelocationLength(RE); + uint64_t Offset; + RelI->getOffset(Offset); + uint8_t *LocalAddress = Section.Address + Offset; + unsigned NumBytes = 1 << Size; + int64_t Addend = 0; + memcpy(&Addend, LocalAddress, NumBytes); + + unsigned SymbolBaseAddr = MachO->getScatteredRelocationValue(RE); + section_iterator TargetSI = getSectionByAddress(*MachO, SymbolBaseAddr); + assert(TargetSI != MachO->section_end() && "Can't find section for symbol"); + uint64_t SectionBaseAddr; + TargetSI->getAddress(SectionBaseAddr); + SectionRef TargetSection = *TargetSI; + bool IsCode; + TargetSection.isText(IsCode); + uint32_t TargetSectionID = + findOrEmitSection(Obj, TargetSection, IsCode, ObjSectionToID); + + Addend -= SectionBaseAddr; + RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size); + + addRelocationForSection(R, TargetSectionID); + + return ++RelI; + } + + // Populate stubs in __jump_table section. + void populateJumpTable(MachOObjectFile &Obj, const SectionRef &JTSection, + unsigned JTSectionID) { + assert(!Obj.is64Bit() && + "__jump_table section not supported in 64-bit MachO."); + + MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); + MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl()); + uint32_t JTSectionSize = Sec32.size; + unsigned FirstIndirectSymbol = Sec32.reserved1; + unsigned JTEntrySize = Sec32.reserved2; + unsigned NumJTEntries = JTSectionSize / JTEntrySize; + uint8_t *JTSectionAddr = getSectionAddress(JTSectionID); + unsigned JTEntryOffset = 0; + + assert((JTSectionSize % JTEntrySize) == 0 && + "Jump-table section does not contain a whole number of stubs?"); + + for (unsigned i = 0; i < NumJTEntries; ++i) { + unsigned SymbolIndex = + Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); + symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); + StringRef IndirectSymbolName; + SI->getName(IndirectSymbolName); + uint8_t *JTEntryAddr = JTSectionAddr + JTEntryOffset; + createStubFunction(JTEntryAddr); + RelocationEntry RE(JTSectionID, JTEntryOffset + 1, + MachO::GENERIC_RELOC_VANILLA, 0, true, 2); + addRelocationForSymbol(RE, IndirectSymbolName); + JTEntryOffset += JTEntrySize; + } + } + + // Populate __pointers section. + void populatePointersSection(MachOObjectFile &Obj, + const SectionRef &PTSection, + unsigned PTSectionID) { + assert(!Obj.is64Bit() && + "__pointers section not supported in 64-bit MachO."); + + MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); + MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl()); + uint32_t PTSectionSize = Sec32.size; + unsigned FirstIndirectSymbol = Sec32.reserved1; + const unsigned PTEntrySize = 4; + unsigned NumPTEntries = PTSectionSize / PTEntrySize; + unsigned PTEntryOffset = 0; + + assert((PTSectionSize % PTEntrySize) == 0 && + "Pointers section does not contain a whole number of stubs?"); + + DEBUG(dbgs() << "Populating __pointers, Section ID " << PTSectionID << ", " + << NumPTEntries << " entries, " << PTEntrySize + << " bytes each:\n"); + + for (unsigned i = 0; i < NumPTEntries; ++i) { + unsigned SymbolIndex = + Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); + symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); + StringRef IndirectSymbolName; + SI->getName(IndirectSymbolName); + DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex + << ", PT offset: " << PTEntryOffset << "\n"); + RelocationEntry RE(PTSectionID, PTEntryOffset, + MachO::GENERIC_RELOC_VANILLA, 0, false, 2); + addRelocationForSymbol(RE, IndirectSymbolName); + PTEntryOffset += PTEntrySize; + } + } + + static section_iterator getSectionByAddress(const MachOObjectFile &Obj, + uint64_t Addr) { + section_iterator SI = Obj.section_begin(); + section_iterator SE = Obj.section_end(); + + for (; SI != SE; ++SI) { + uint64_t SAddr, SSize; + SI->getAddress(SAddr); + SI->getSize(SSize); + if ((Addr >= SAddr) && (Addr < SAddr + SSize)) + return SI; + } + + return SE; + } +}; +} + +#undef DEBUG_TYPE + +#endif // LLVM_RUNTIMEDYLDMACHOI386_H diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h new file mode 100644 index 0000000000000..99efe9da44869 --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h @@ -0,0 +1,132 @@ +//===-- RuntimeDyldMachOX86_64.h ---- MachO/X86_64 specific code. -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_RUNTIMEDYLDMACHOX86_64_H +#define LLVM_RUNTIMEDYLDMACHOX86_64_H + +#include "../RuntimeDyldMachO.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOX86_64 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOX86_64> { +public: + RuntimeDyldMachOX86_64(RTDyldMemoryManager *MM) + : RuntimeDyldMachOCRTPBase(MM) {} + + unsigned getMaxStubSize() override { return 8; } + + unsigned getStubAlignment() override { return 1; } + + relocation_iterator + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols, StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + assert(!Obj.isRelocationScattered(RelInfo) && + "Scattered relocations not supported on X86_64"); + + RelocationEntry RE(getBasicRelocationEntry(SectionID, ObjImg, RelI)); + RelocationValueRef Value( + getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols)); + + bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + if (!IsExtern && RE.IsPCRel) + makeValueAddendPCRel(Value, ObjImg, RelI); + + if (RE.RelType == MachO::X86_64_RELOC_GOT || + RE.RelType == MachO::X86_64_RELOC_GOT_LOAD) + processGOTRelocation(RE, Value, Stubs); + else { + RE.Addend = Value.Addend; + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) { + DEBUG(dumpRelocationToResolve(RE, Value)); + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.Address + RE.Offset; + + // If the relocation is PC-relative, the value to be encoded is the + // pointer difference. + if (RE.IsPCRel) { + // FIXME: It seems this value needs to be adjusted by 4 for an effective + // PC address. Is that expected? Only for branches, perhaps? + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + Value -= FinalAddress + 4; + } + + switch (RE.RelType) { + default: + llvm_unreachable("Invalid relocation type!"); + case MachO::X86_64_RELOC_SIGNED_1: + case MachO::X86_64_RELOC_SIGNED_2: + case MachO::X86_64_RELOC_SIGNED_4: + case MachO::X86_64_RELOC_SIGNED: + case MachO::X86_64_RELOC_UNSIGNED: + case MachO::X86_64_RELOC_BRANCH: + writeBytesUnaligned(LocalAddress, Value + RE.Addend, 1 << RE.Size); + break; + case MachO::X86_64_RELOC_GOT_LOAD: + case MachO::X86_64_RELOC_GOT: + case MachO::X86_64_RELOC_SUBTRACTOR: + case MachO::X86_64_RELOC_TLV: + Error("Relocation type not implemented yet!"); + } + } + + void finalizeSection(ObjectImage &ObjImg, unsigned SectionID, + const SectionRef &Section) {} + +private: + void processGOTRelocation(const RelocationEntry &RE, + RelocationValueRef &Value, StubMap &Stubs) { + SectionEntry &Section = Sections[RE.SectionID]; + assert(RE.IsPCRel); + assert(RE.Size == 2); + Value.Addend -= RE.Addend; + RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value); + uint8_t *Addr; + if (i != Stubs.end()) { + Addr = Section.Address + i->second; + } else { + Stubs[Value] = Section.StubOffset; + uint8_t *GOTEntry = Section.Address + Section.StubOffset; + RelocationEntry GOTRE(RE.SectionID, Section.StubOffset, + MachO::X86_64_RELOC_UNSIGNED, Value.Addend, false, + 3); + if (Value.SymbolName) + addRelocationForSymbol(GOTRE, Value.SymbolName); + else + addRelocationForSection(GOTRE, Value.SectionID); + Section.StubOffset += 8; + Addr = GOTEntry; + } + RelocationEntry TargetRE(RE.SectionID, RE.Offset, + MachO::X86_64_RELOC_UNSIGNED, RE.Addend, true, 2); + resolveRelocation(TargetRE, (uint64_t)Addr); + } +}; +} + +#undef DEBUG_TYPE + +#endif // LLVM_RUNTIMEDYLDMACHOX86_64_H |
