diff options
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld')
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp | 13 | ||||
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h | 21 | ||||
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | 97 | ||||
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 107 | ||||
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h | 8 | ||||
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h | 27 | ||||
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp | 483 | ||||
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h | 60 |
8 files changed, 567 insertions, 249 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp index 1d0e9b3..8546571 100644 --- a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp @@ -45,7 +45,7 @@ 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() { @@ -108,10 +108,10 @@ void NotifyDebugger(jit_code_entry* JITCodeEntry) { __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; @@ -142,11 +142,10 @@ void GDBJITRegistrar::registerObject(const ObjectBuffer &Object) { "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; @@ -198,7 +197,7 @@ void GDBJITRegistrar::deregisterObjectInternal( } delete JITCodeEntry; - JITCodeEntry = NULL; + JITCodeEntry = nullptr; } llvm::ManagedStatic<GDBJITRegistrar> TheRegistrar; diff --git a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h index 3693c69..4917b93 100644 --- a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h +++ b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h @@ -18,6 +18,8 @@ #include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/Object/ObjectFile.h" +#include <memory> + namespace llvm { namespace object { @@ -30,13 +32,13 @@ class ObjectImageCommon : public ObjectImage { 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)) { } @@ -44,12 +46,13 @@ public: ObjectImageCommon(ObjectBuffer* Input) : ObjectImage(Input) // saves Input as Buffer and takes ownership { - ObjFile = - object::ObjectFile::createObjectFile(Buffer->getMemBuffer()).get(); + // FIXME: error checking? createObjectFile returns an ErrorOr<ObjectFile*> + // and should probably be checked for failure. + ObjFile.reset(object::ObjectFile::createObjectFile(Buffer->getMemBuffer()).get()); } - ObjectImageCommon(object::ObjectFile* Input) - : ObjectImage(NULL), ObjFile(Input) {} - virtual ~ObjectImageCommon() { delete ObjFile; } + ObjectImageCommon(std::unique_ptr<object::ObjectFile> Input) + : ObjectImage(nullptr), ObjFile(std::move(Input)) {} + virtual ~ObjectImageCommon() { } object::symbol_iterator begin_symbols() const override { return ObjFile->symbol_begin(); } @@ -66,7 +69,7 @@ public: StringRef getData() const override { return ObjFile->getData(); } - object::ObjectFile* getObjectFile() const override { 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 diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 986d3a0..c1eb0fd 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "JITRegistrar.h" #include "ObjectImageCommon.h" @@ -25,6 +24,8 @@ using namespace llvm; using namespace llvm::object; +#define DEBUG_TYPE "dyld" + // Empty out-of-line virtual destructor as the key function. RuntimeDyldImpl::~RuntimeDyldImpl() {} @@ -72,12 +73,40 @@ void RuntimeDyldImpl::mapSectionAddress(const void *LocalAddress, llvm_unreachable("Attempting to remap address of unknown section!"); } +static error_code getOffset(const SymbolRef &Sym, uint64_t &Result) { + uint64_t Address; + if (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 (error_code EC = Sym.getSection(SecI)) + return EC; + + if (SecI == Obj->section_end()) { + Result = UnknownAddressOrSize; + return object_error::success; + } + + uint64_t SectionAddress; + if (error_code EC = SecI->getAddress(SectionAddress)) + return EC; + + Result = Address - SectionAddress; + return object_error::success; +} + ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { MutexGuard locked(lock); std::unique_ptr<ObjectImage> Obj(InputObject); if (!Obj) - return NULL; + return nullptr; // Save information about our target Arch = (Triple::ArchType)Obj->getArch(); @@ -115,36 +144,33 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { 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(getOffset(*I, SectOffset)); 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 *)Obj->getData().data() + (uintptr_t)FileOffset; - uintptr_t SectOffset = - (uintptr_t)(SymPtr - (const uint8_t *)SectionData.begin()); 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); } } @@ -153,7 +179,7 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { // 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"); @@ -163,7 +189,10 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { StubMap Stubs; section_iterator RelocatedSection = SI->getRelocatedSection(); - if (SI->relocation_empty() && !ProcessAllSections) + relocation_iterator I = SI->relocation_begin(); + relocation_iterator E = SI->relocation_end(); + + if (I == E && !ProcessAllSections) continue; bool IsCode = false; @@ -172,14 +201,13 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { findOrEmitSection(*Obj, *RelocatedSection, IsCode, LocalSections); DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n"); - for (relocation_iterator I = SI->relocation_begin(), - E = SI->relocation_end(); I != E;) + for (; I != E;) I = processRelocationRef(SectionID, I, *Obj, LocalSections, LocalSymbols, Stubs); } // Give the subclasses a chance to tie-up any loose ends. - finalizeLoad(LocalSections); + finalizeLoad(*Obj, LocalSections); return Obj.release(); } @@ -400,7 +428,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, 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. @@ -441,7 +469,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, // to handle later processing (and by 'handle' I mean don't do anything // with these sections). Allocate = 0; - Addr = 0; + Addr = nullptr; DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name << " obj addr: " << format("%p", data.data()) << " new addr: 0" << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize @@ -490,7 +518,8 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, } uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { - if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) { + 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. @@ -560,6 +589,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; } @@ -586,7 +617,7 @@ 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); } @@ -651,7 +682,7 @@ 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; } @@ -672,21 +703,23 @@ createRuntimeDyldMachO(RTDyldMemoryManager *MM, bool ProcessAllSections) { return Dyld; } -ObjectImage *RuntimeDyld::loadObject(ObjectFile *InputObject) { +ObjectImage *RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) { std::unique_ptr<ObjectImage> InputImage; + ObjectFile &Obj = *InputObject; + if (InputObject->isELF()) { - InputImage.reset(RuntimeDyldELF::createObjectImageFromFile(InputObject)); + InputImage.reset(RuntimeDyldELF::createObjectImageFromFile(std::move(InputObject))); if (!Dyld) Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release(); } else if (InputObject->isMachO()) { - InputImage.reset(RuntimeDyldMachO::createObjectImageFromFile(InputObject)); + InputImage.reset(RuntimeDyldMachO::createObjectImageFromFile(std::move(InputObject))); if (!Dyld) Dyld = createRuntimeDyldMachO(MM, ProcessAllSections).release(); } else report_fatal_error("Incompatible object format!"); - if (!Dyld->isCompatibleFile(InputObject)) + if (!Dyld->isCompatibleFile(&Obj)) report_fatal_error("Incompatible object format!"); Dyld->loadObject(InputImage.get()); @@ -740,7 +773,7 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) { void *RuntimeDyld::getSymbolAddress(StringRef Name) { if (!Dyld) - return NULL; + return nullptr; return Dyld->getSymbolAddress(Name); } diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 3204b81..6ba24b9 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" #include "RuntimeDyldELF.h" #include "JITRegistrar.h" #include "ObjectImageCommon.h" @@ -29,6 +28,8 @@ using namespace llvm; using namespace llvm::object; +#define DEBUG_TYPE "dyld" + namespace { static inline error_code check(error_code Err) { @@ -50,7 +51,12 @@ template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { typedef typename ELFDataTypeTypedefHelper<ELFT>::value_type addr_type; + std::unique_ptr<ObjectFile> UnderlyingFile; + public: + DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, + MemoryBuffer *Wrapper, error_code &ec); + DyldELFObject(MemoryBuffer *Wrapper, error_code &ec); void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); @@ -67,13 +73,11 @@ public: }; template <class ELFT> class ELFObjectImage : public ObjectImageCommon { -protected: - DyldELFObject<ELFT> *DyldObj; bool Registered; public: - ELFObjectImage(ObjectBuffer *Input, DyldELFObject<ELFT> *Obj) - : ObjectImageCommon(Input, Obj), DyldObj(Obj), Registered(false) {} + ELFObjectImage(ObjectBuffer *Input, std::unique_ptr<DyldELFObject<ELFT>> Obj) + : ObjectImageCommon(Input, std::move(Obj)), Registered(false) {} virtual ~ELFObjectImage() { if (Registered) @@ -83,11 +87,13 @@ public: // 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 { - DyldObj->updateSectionAddress(Sec, Addr); + static_cast<DyldELFObject<ELFT>*>(getObjectFile()) + ->updateSectionAddress(Sec, Addr); } void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) override { - DyldObj->updateSymbolAddress(Sym, Addr); + static_cast<DyldELFObject<ELFT>*>(getObjectFile()) + ->updateSymbolAddress(Sym, Addr); } void registerWithDebugger() override { @@ -109,6 +115,14 @@ DyldELFObject<ELFT>::DyldELFObject(MemoryBuffer *Wrapper, error_code &ec) } template <class ELFT> +DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, + MemoryBuffer *Wrapper, error_code &ec) + : ELFObjectFile<ELFT>(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(); @@ -164,30 +178,36 @@ void RuntimeDyldELF::deregisterEHFrames() { } ObjectImage * -RuntimeDyldELF::createObjectImageFromFile(object::ObjectFile *ObjFile) { +RuntimeDyldELF::createObjectImageFromFile(std::unique_ptr<object::ObjectFile> ObjFile) { if (!ObjFile) - return NULL; + return nullptr; error_code ec; MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(ObjFile->getData(), "", false); if (ObjFile->getBytesInAddress() == 4 && ObjFile->isLittleEndian()) { - DyldELFObject<ELFType<support::little, 2, false>> *Obj = - new DyldELFObject<ELFType<support::little, 2, false>>(Buffer, ec); - return new ELFObjectImage<ELFType<support::little, 2, false>>(NULL, Obj); + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 2, false>>>( + std::move(ObjFile), Buffer, ec); + return new ELFObjectImage<ELFType<support::little, 2, false>>( + nullptr, std::move(Obj)); } else if (ObjFile->getBytesInAddress() == 4 && !ObjFile->isLittleEndian()) { - DyldELFObject<ELFType<support::big, 2, false>> *Obj = - new DyldELFObject<ELFType<support::big, 2, false>>(Buffer, ec); - return new ELFObjectImage<ELFType<support::big, 2, false>>(NULL, Obj); + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::big, 2, false>>>( + std::move(ObjFile), Buffer, ec); + return new ELFObjectImage<ELFType<support::big, 2, false>>(nullptr, std::move(Obj)); } else if (ObjFile->getBytesInAddress() == 8 && !ObjFile->isLittleEndian()) { - DyldELFObject<ELFType<support::big, 2, true>> *Obj = - new DyldELFObject<ELFType<support::big, 2, true>>(Buffer, ec); - return new ELFObjectImage<ELFType<support::big, 2, true>>(NULL, Obj); + auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 2, true>>>( + std::move(ObjFile), Buffer, ec); + return new ELFObjectImage<ELFType<support::big, 2, true>>(nullptr, + std::move(Obj)); } else if (ObjFile->getBytesInAddress() == 8 && ObjFile->isLittleEndian()) { - DyldELFObject<ELFType<support::little, 2, true>> *Obj = - new DyldELFObject<ELFType<support::little, 2, true>>(Buffer, ec); - return new ELFObjectImage<ELFType<support::little, 2, true>>(NULL, Obj); + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 2, true>>>( + std::move(ObjFile), Buffer, ec); + return new ELFObjectImage<ELFType<support::little, 2, true>>( + nullptr, std::move(Obj)); } else llvm_unreachable("Unexpected ELF format"); } @@ -201,28 +221,29 @@ ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) { error_code ec; if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { - DyldELFObject<ELFType<support::little, 4, false>> *Obj = - new DyldELFObject<ELFType<support::little, 4, false>>( + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 4, false>>>( Buffer->getMemBuffer(), ec); - return new ELFObjectImage<ELFType<support::little, 4, false>>(Buffer, Obj); + return new ELFObjectImage<ELFType<support::little, 4, false>>( + Buffer, std::move(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>>( + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::big, 4, false>>>( Buffer->getMemBuffer(), ec); - return new ELFObjectImage<ELFType<support::big, 4, false>>(Buffer, Obj); + return new ELFObjectImage<ELFType<support::big, 4, false>>(Buffer, + std::move(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); + auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 8, true>>>( + Buffer->getMemBuffer(), ec); + return new ELFObjectImage<ELFType<support::big, 8, true>>(Buffer, std::move(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>>( + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 8, true>>>( Buffer->getMemBuffer(), ec); - return new ELFObjectImage<ELFType<support::little, 8, true>>(Buffer, Obj); + return new ELFObjectImage<ELFType<support::little, 8, true>>(Buffer, std::move(Obj)); } else llvm_unreachable("Unexpected ELF format"); } @@ -845,6 +866,8 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, 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. @@ -950,7 +973,8 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset << "\n"); - if (Arch == Triple::aarch64 && + 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."); @@ -1151,7 +1175,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( // Extra check to avoid relocation againt empty symbols (usually // the R_PPC64_TOC). if (SymType != SymbolRef::ST_Unknown && TargetName.empty()) - Value.SymbolName = NULL; + Value.SymbolName = nullptr; if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); @@ -1283,7 +1307,8 @@ void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) { 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; } } @@ -1297,6 +1322,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: @@ -1331,7 +1359,7 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, uint64_t Offset) { // 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; @@ -1369,7 +1397,8 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, uint64_t Offset) { 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 diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index 27db5cd..a526073 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -59,7 +59,8 @@ class RuntimeDyldELF : public RuntimeDyldImpl { uint64_t Value, uint32_t Type, int64_t Addend); unsigned getMaxStubSize() override { - if (Arch == Triple::aarch64) + 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 @@ -115,11 +116,12 @@ public: bool isCompatibleFile(const object::ObjectFile *Buffer) const override; void registerEHFrames() override; void deregisterEHFrames() override; - void finalizeLoad(ObjSectionToIDMap &SectionMap) override; + void finalizeLoad(ObjectImage &ObjImg, + ObjSectionToIDMap &SectionMap) override; virtual ~RuntimeDyldELF(); static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); - static ObjectImage *createObjectImageFromFile(object::ObjectFile *Obj); + 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 c153ee1..412cf20 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -90,9 +90,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; @@ -113,6 +121,16 @@ public: bool IsPCRel, unsigned 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 { @@ -121,7 +139,8 @@ public: 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 && @@ -335,7 +354,7 @@ public: // 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; } @@ -372,7 +391,7 @@ public: virtual void deregisterEHFrames(); - virtual void finalizeLoad(ObjSectionToIDMap &SectionMap) {} + virtual void finalizeLoad(ObjectImage &ObjImg, ObjSectionToIDMap &SectionMap) {} }; } // end namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index 7eae9c2..2b425fb 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -11,17 +11,20 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" #include "RuntimeDyldMachO.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.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) { + 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; @@ -66,7 +69,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]; @@ -87,7 +90,8 @@ void RuntimeDyldMachO::registerEHFrames() { UnregisteredEHFrameSections.clear(); } -void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) { +void RuntimeDyldMachO::finalizeLoad(ObjectImage &ObjImg, + ObjSectionToIDMap &SectionMap) { unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID; unsigned TextSID = RTDYLD_INVALID_SECTION_ID; unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID; @@ -102,6 +106,12 @@ void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) { TextSID = i->second; else if (Name == "__gcc_except_tab") ExceptTabSID = i->second; + else if (Name == "__jump_table") + populateJumpTable(cast<MachOObjectFile>(*ObjImg.getObjectFile()), + Section, i->second); + else if (Name == "__pointers") + populatePointersSection(cast<MachOObjectFile>(*ObjImg.getObjectFile()), + Section, i->second); } UnregisteredEHFrameSections.push_back( EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID)); @@ -129,91 +139,87 @@ void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) { // 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"); + DEBUG ( + 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"; + ); // This just dispatches to the proper target specific routine. switch (Arch) { default: llvm_unreachable("Unsupported CPU type!"); case Triple::x86_64: - resolveX86_64Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, - isPCRel, MachoType, Size, Addend); + resolveX86_64Relocation(RE, Value); break; case Triple::x86: - resolveI386Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, isPCRel, - MachoType, Size, Addend); + resolveI386Relocation(RE, Value); break; case Triple::arm: // Fall through. case Triple::thumb: - resolveARMRelocation(LocalAddress, FinalAddress, (uintptr_t)Value, isPCRel, - MachoType, Size, Addend); + resolveARMRelocation(RE, Value); break; + case Triple::aarch64: case Triple::arm64: - resolveARM64Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, - isPCRel, MachoType, Size, Addend); + resolveAArch64Relocation(RE, Value); 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 +bool RuntimeDyldMachO::resolveI386Relocation(const RelocationEntry &RE, + uint64_t Value) { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t* LocalAddress = Section.Address + RE.Offset; - 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; + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation. } - 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!"); + + switch (RE.RelType) { + default: + llvm_unreachable("Invalid relocation type!"); + case MachO::GENERIC_RELOC_VANILLA: + return applyRelocationValue(LocalAddress, Value + RE.Addend, + 1 << RE.Size); + 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; + return applyRelocationValue(LocalAddress, Value, 1 << RE.Size); + } + 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) { +bool RuntimeDyldMachO::resolveX86_64Relocation(const RelocationEntry &RE, + uint64_t 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 (isPCRel) + 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? - Value -= FinalAddress + 4; + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation. + } - switch (Type) { + switch (RE.RelType) { default: llvm_unreachable("Invalid relocation type!"); case MachO::X86_64_RELOC_SIGNED_1: @@ -221,17 +227,8 @@ bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 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_BRANCH: + return applyRelocationValue(LocalAddress, Value + RE.Addend, 1 << RE.Size); case MachO::X86_64_RELOC_GOT_LOAD: case MachO::X86_64_RELOC_GOT: case MachO::X86_64_RELOC_SUBTRACTOR: @@ -240,14 +237,15 @@ bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, } } -bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, bool isPCRel, - unsigned Type, unsigned Size, - int64_t Addend) { +bool RuntimeDyldMachO::resolveARMRelocation(const RelocationEntry &RE, + uint64_t 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 (isPCRel) { + 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). @@ -255,19 +253,11 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, Value -= 8; } - switch (Type) { + switch (RE.RelType) { 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; - } - break; - } + case MachO::ARM_RELOC_VANILLA: + return applyRelocationValue(LocalAddress, Value, 1 << RE.Size); 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. @@ -275,13 +265,16 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, // The low two bits of the value are not encoded. Value >>= 2; // Mask the value to 24 bits. - Value &= 0xffffff; + uint64_t FinalValue = Value & 0xffffff; + // Check for overflow. + if (Value != FinalValue) + return Error("ARM BR24 relocation out of range."); // 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; + *p = (*p & ~0xffffff) | FinalValue; break; } case MachO::ARM_THUMB_RELOC_BR22: @@ -297,29 +290,23 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, return false; } -bool RuntimeDyldMachO::resolveARM64Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, bool isPCRel, - unsigned Type, unsigned Size, - int64_t Addend) { +bool RuntimeDyldMachO::resolveAArch64Relocation(const RelocationEntry &RE, + uint64_t 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 (isPCRel) + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; Value -= FinalAddress; + } - switch (Type) { + switch (RE.RelType) { default: llvm_unreachable("Invalid relocation type!"); - case MachO::ARM64_RELOC_UNSIGNED: { - // 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; - } - break; - } + case MachO::ARM64_RELOC_UNSIGNED: + return applyRelocationValue(LocalAddress, Value, 1 << RE.Size); case MachO::ARM64_RELOC_BRANCH26: { // Mask the value into the target address. We know instructions are // 32-bit aligned, so we can do it all at once. @@ -327,9 +314,12 @@ bool RuntimeDyldMachO::resolveARM64Relocation(uint8_t *LocalAddress, // The low two bits of the value are not encoded. Value >>= 2; // Mask the value to 26 bits. - Value &= 0x3ffffff; + uint64_t FinalValue = Value & 0x3ffffff; + // Check for overflow. + if (FinalValue != Value) + return Error("ARM64 BRANCH26 relocation out of range."); // Insert the value into the instruction. - *p = (*p & ~0x3ffffff) | Value; + *p = (*p & ~0x3ffffff) | FinalValue; break; } case MachO::ARM64_RELOC_SUBTRACTOR: @@ -346,6 +336,198 @@ bool RuntimeDyldMachO::resolveARM64Relocation(uint8_t *LocalAddress, return false; } +void RuntimeDyldMachO::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; + } +} + +void RuntimeDyldMachO::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; + } +} + + +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; +} + +relocation_iterator RuntimeDyldMachO::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 RuntimeDyldMachO::processI386ScatteredVANILLA( + 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); + + 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; +} + relocation_iterator RuntimeDyldMachO::processRelocationRef( unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj, ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols, @@ -358,18 +540,28 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef( 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 ++RelI; + // Special case the couple of scattered relocations that we know how + // to handle: SECTDIFF relocations, and scattered VANILLA relocations + // on I386. + // For all other scattered relocations, just bail out and hope for the + // best, since the offsets computed by scattered relocations have often + // been optimisticaly filled in by the compiler. This will fail + // horribly where the relocations *do* need to be applied, but that was + // already the case. + if (MachO->isRelocationScattered(RE)) { + if (RelType == MachO::GENERIC_RELOC_SECTDIFF || + RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) + return processSECTDIFFRelocation(SectionID, RelI, Obj, ObjSectionToID); + else if (Arch == Triple::x86 && RelType == MachO::GENERIC_RELOC_VANILLA) + return processI386ScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID); + else + return ++RelI; + } RelocationValueRef Value; SectionEntry &Section = Sections[SectionID]; - bool isExtern = MachO->getPlainRelocationExternal(RE); + bool IsExtern = MachO->getPlainRelocationExternal(RE); bool IsPCRel = MachO->getAnyRelocationPCRel(RE); unsigned Size = MachO->getAnyRelocationLength(RE); uint64_t Offset; @@ -379,7 +571,7 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef( uint64_t Addend = 0; memcpy(&Addend, LocalAddress, NumBytes); - if (isExtern) { + if (IsExtern) { // Obtain the symbol name which is referenced in the relocation symbol_iterator Symbol = RelI->getSymbol(); StringRef TargetName; @@ -401,6 +593,17 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef( Value.Addend = Addend; } } + + // 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. + if (Arch == Triple::x86 && IsPCRel) { + uint64_t RelocAddr = 0; + RelI->getAddress(RelocAddr); + Value.Addend += RelocAddr + 4; + } + } else { SectionRef Sec = MachO->getRelocationSection(RE); bool IsCode = false; @@ -417,6 +620,10 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef( RelType == MachO::X86_64_RELOC_GOT_LOAD)) { assert(IsPCRel); assert(Size == 2); + + // FIXME: Teach the generic code above not to prematurely conflate + // relocation addends and symbol offsets. + Value.Addend -= Addend; StubMap::const_iterator i = Stubs.find(Value); uint8_t *Addr; if (i != Stubs.end()) { @@ -424,41 +631,45 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef( } 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); + RelocationEntry GOTRE(SectionID, Section.StubOffset, + MachO::X86_64_RELOC_UNSIGNED, Value.Addend, false, + 3); if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); + addRelocationForSymbol(GOTRE, Value.SymbolName); else - addRelocationForSection(RE, Value.SectionID); + addRelocationForSection(GOTRE, Value.SectionID); Section.StubOffset += 8; Addr = GOTEntry; } - resolveRelocation(Section, Offset, (uint64_t)Addr, - MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, 2); + RelocationEntry TargetRE(SectionID, Offset, + MachO::X86_64_RELOC_UNSIGNED, Addend, true, + 2); + resolveRelocation(TargetRE, (uint64_t)Addr); } 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 { + 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 RE(SectionID, StubTargetAddr - Section.Address, - MachO::GENERIC_RELOC_VANILLA, Value.Addend); + RelocationEntry StubRE(SectionID, StubTargetAddr - Section.Address, + MachO::GENERIC_RELOC_VANILLA, Value.Addend); if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); + addRelocationForSymbol(StubRE, Value.SymbolName); else - addRelocationForSection(RE, Value.SectionID); - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, RelType, - 0, IsPCRel, Size); + addRelocationForSection(StubRE, Value.SectionID); + Addr = Section.Address + Section.StubOffset; Section.StubOffset += getMaxStubSize(); } + RelocationEntry TargetRE(Value.SectionID, Offset, RelType, 0, IsPCRel, + Size); + resolveRelocation(TargetRE, (uint64_t)Addr); } else { RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, IsPCRel, Size); if (Value.SymbolName) diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index 1006176..060eb8c 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -25,22 +25,31 @@ 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); - bool resolveARM64Relocation(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); +private: + + /// Write the least significant 'Size' bytes in 'Value' out at the address + /// pointed to by Addr. + bool applyRelocationValue(uint8_t *Addr, uint64_t Value, unsigned Size) { + for (unsigned i = 0; i < Size; ++i) { + *Addr++ = (uint8_t)Value; + Value >>= 8; + } + + return false; + } + + bool resolveI386Relocation(const RelocationEntry &RE, uint64_t Value); + bool resolveX86_64Relocation(const RelocationEntry &RE, uint64_t Value); + bool resolveARMRelocation(const RelocationEntry &RE, uint64_t Value); + bool resolveAArch64Relocation(const RelocationEntry &RE, uint64_t Value); + + // Populate stubs in __jump_table section. + void populateJumpTable(MachOObjectFile &Obj, const SectionRef &JTSection, + unsigned JTSectionID); + + // Populate __pointers section. + void populatePointersSection(MachOObjectFile &Obj, const SectionRef &PTSection, + unsigned PTSectionID); unsigned getMaxStubSize() override { if (Arch == Triple::arm || Arch == Triple::thumb) @@ -53,6 +62,18 @@ class RuntimeDyldMachO : public RuntimeDyldImpl { unsigned getStubAlignment() override { return 1; } + relocation_iterator processSECTDIFFRelocation( + unsigned SectionID, + relocation_iterator RelI, + ObjectImage &ObjImg, + ObjSectionToIDMap &ObjSectionToID); + + relocation_iterator processI386ScatteredVANILLA( + unsigned SectionID, + relocation_iterator RelI, + ObjectImage &ObjImg, + ObjSectionToIDMap &ObjSectionToID); + struct EHFrameRelatedSections { EHFrameRelatedSections() : EHFrameSID(RTDYLD_INVALID_SECTION_ID), @@ -81,15 +102,16 @@ public: bool isCompatibleFormat(const ObjectBuffer *Buffer) const override; bool isCompatibleFile(const object::ObjectFile *Obj) const override; void registerEHFrames() override; - void finalizeLoad(ObjSectionToIDMap &SectionMap) override; + void finalizeLoad(ObjectImage &ObjImg, + ObjSectionToIDMap &SectionMap) override; static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer) { return new ObjectImageCommon(InputBuffer); } static ObjectImage * - createObjectImageFromFile(object::ObjectFile *InputObject) { - return new ObjectImageCommon(InputObject); + createObjectImageFromFile(std::unique_ptr<object::ObjectFile> InputObject) { + return new ObjectImageCommon(std::move(InputObject)); } }; |