diff options
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld')
15 files changed, 2596 insertions, 1531 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp index 8546571..dfa3a20 100644 --- a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp @@ -101,7 +101,7 @@ private: /// Lock used to serialize all jit registration events, since they /// modify global variables. -llvm::sys::Mutex JITDebugLock; +ManagedStatic<sys::Mutex> JITDebugLock; /// Do the registration. void NotifyDebugger(jit_code_entry* JITCodeEntry) { @@ -121,7 +121,7 @@ void NotifyDebugger(jit_code_entry* JITCodeEntry) { GDBJITRegistrar::~GDBJITRegistrar() { // Free all registered object files. - llvm::MutexGuard locked(JITDebugLock); + 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 @@ -137,7 +137,7 @@ 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); + llvm::MutexGuard locked(*JITDebugLock); assert(ObjectBufferMap.find(Buffer) == ObjectBufferMap.end() && "Second attempt to perform debug registration."); jit_code_entry* JITCodeEntry = new jit_code_entry(); @@ -156,7 +156,7 @@ void GDBJITRegistrar::registerObject(const ObjectBuffer &Object) { bool GDBJITRegistrar::deregisterObject(const ObjectBuffer& Object) { const char *Buffer = Object.getBufferStart(); - llvm::MutexGuard locked(JITDebugLock); + llvm::MutexGuard locked(*JITDebugLock); RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Buffer); if (I != ObjectBufferMap.end()) { diff --git a/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h b/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h index 6a514ea..636011f 100644 --- a/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h +++ b/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_EXECUTION_ENGINE_JIT_REGISTRAR_H -#define LLVM_EXECUTION_ENGINE_JIT_REGISTRAR_H +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_JITREGISTRAR_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_JITREGISTRAR_H #include "llvm/ExecutionEngine/ObjectBuffer.h" @@ -41,4 +41,4 @@ public: } // end namespace llvm -#endif // LLVM_EXECUTION_ENGINE_JIT_REGISTRAR_H +#endif diff --git a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h index c3a2182..9bbf6a0d 100644 --- a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h +++ b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_RUNTIMEDYLD_OBJECTIMAGECOMMON_H -#define LLVM_RUNTIMEDYLD_OBJECTIMAGECOMMON_H +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_OBJECTIMAGECOMMON_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_OBJECTIMAGECOMMON_H #include "llvm/ExecutionEngine/ObjectBuffer.h" #include "llvm/ExecutionEngine/ObjectImage.h" @@ -36,20 +36,17 @@ protected: // This form of the constructor allows subclasses to use // format-specific subclasses of ObjectFile directly - ObjectImageCommon(ObjectBuffer *Input, std::unique_ptr<object::ObjectFile> Obj) - : ObjectImage(Input), // saves Input as Buffer and takes ownership - ObjFile(std::move(Obj)) - { - } + ObjectImageCommon(std::unique_ptr<ObjectBuffer> Input, + std::unique_ptr<object::ObjectFile> Obj) + : ObjectImage(std::move(Input)), ObjFile(std::move(Obj)) {} public: - ObjectImageCommon(ObjectBuffer* Input) - : ObjectImage(Input) // saves Input as Buffer and takes ownership - { + ObjectImageCommon(std::unique_ptr<ObjectBuffer> Input) + : ObjectImage(std::move(Input)) { // 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()); + MemoryBufferRef Buf = Buffer->getMemBuffer(); + ObjFile = std::move(object::ObjectFile::createObjectFile(Buf).get()); } ObjectImageCommon(std::unique_ptr<object::ObjectFile> Input) : ObjectImage(nullptr), ObjFile(std::move(Input)) {} @@ -86,4 +83,4 @@ public: } // end namespace llvm -#endif // LLVM_RUNTIMEDYLD_OBJECT_IMAGE_H +#endif diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 9dfd167..c7c67f6 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -14,6 +14,7 @@ #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "JITRegistrar.h" #include "ObjectImageCommon.h" +#include "RuntimeDyldCheckerImpl.h" #include "RuntimeDyldELF.h" #include "RuntimeDyldImpl.h" #include "RuntimeDyldMachO.h" @@ -40,6 +41,44 @@ void RuntimeDyldImpl::registerEHFrames() {} void RuntimeDyldImpl::deregisterEHFrames() {} +#ifndef NDEBUG +static void dumpSectionMemory(const SectionEntry &S, StringRef State) { + dbgs() << "----- Contents of section " << S.Name << " " << State << " -----"; + + if (S.Address == nullptr) { + dbgs() << "\n <section not emitted>\n"; + return; + } + + const unsigned ColsPerRow = 16; + + uint8_t *DataAddr = S.Address; + uint64_t LoadAddr = S.LoadAddress; + + unsigned StartPadding = LoadAddr & (ColsPerRow - 1); + unsigned BytesRemaining = S.Size; + + if (StartPadding) { + dbgs() << "\n" << format("0x%016" PRIx64, LoadAddr & ~(ColsPerRow - 1)) << ":"; + while (StartPadding--) + dbgs() << " "; + } + + while (BytesRemaining > 0) { + if ((LoadAddr & (ColsPerRow - 1)) == 0) + dbgs() << "\n" << format("0x%016" PRIx64, LoadAddr) << ":"; + + dbgs() << " " << format("%02x", *DataAddr); + + ++DataAddr; + ++LoadAddr; + --BytesRemaining; + } + + dbgs() << "\n"; +} +#endif + // Resolve the relocations for all symbols we currently know about. void RuntimeDyldImpl::resolveRelocations() { MutexGuard locked(lock); @@ -55,8 +94,10 @@ void RuntimeDyldImpl::resolveRelocations() { // 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"); + << format("0x%x", Addr) << "\n"); + DEBUG(dumpSectionMemory(Sections[i], "before relocations")); resolveRelocationList(Relocations[i], Addr); + DEBUG(dumpSectionMemory(Sections[i], "after relocations")); Relocations.erase(i); } } @@ -88,23 +129,20 @@ static std::error_code getOffset(const SymbolRef &Sym, uint64_t &Result) { 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; + if (SecI == Obj->section_end()) { + Result = UnknownAddressOrSize; + return object_error::success; + } + uint64_t SectionAddress = SecI->getAddress(); Result = Address - SectionAddress; return object_error::success; } -ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { +std::unique_ptr<ObjectImage> +RuntimeDyldImpl::loadObject(std::unique_ptr<ObjectImage> Obj) { MutexGuard locked(lock); - std::unique_ptr<ObjectImage> Obj(InputObject); if (!Obj) return nullptr; @@ -158,14 +196,13 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { SymType == object::SymbolRef::ST_Unknown) { uint64_t SectOffset; StringRef SectionData; - bool IsCode; 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)); + bool IsCode = SI->isText(); unsigned SectionID = findOrEmitSection(*Obj, *SI, IsCode, LocalSections); LocalSymbols[Name.data()] = SymbolLoc(SectionID, SectOffset); @@ -195,8 +232,7 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { if (I == E && !ProcessAllSections) continue; - bool IsCode = false; - Check(RelocatedSection->isText(IsCode)); + bool IsCode = RelocatedSection->isText(); SectionID = findOrEmitSection(*Obj, *RelocatedSection, IsCode, LocalSections); DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n"); @@ -204,12 +240,17 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { for (; I != E;) I = processRelocationRef(SectionID, I, *Obj, LocalSections, LocalSymbols, Stubs); + + // If there is an attached checker, notify it about the stubs for this + // section so that they can be verified. + if (Checker) + Checker->registerStubMap(Obj->getImageName(), SectionID, Stubs); } // Give the subclasses a chance to tie-up any loose ends. finalizeLoad(*Obj, LocalSections); - return Obj.release(); + return Obj; } // A helper method for computeTotalAllocSize. @@ -245,20 +286,15 @@ void RuntimeDyldImpl::computeTotalAllocSize(ObjectImage &Obj, SI != SE; ++SI) { const SectionRef &Section = *SI; - bool IsRequired; - Check(Section.isRequiredForExecution(IsRequired)); + bool IsRequired = Section.isRequiredForExecution(); // 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)); + uint64_t DataSize = Section.getSize(); + uint64_t Alignment64 = Section.getAlignment(); + bool IsCode = Section.isText(); + bool IsReadOnly = Section.isReadOnlyData(); Check(Section.getName(Name)); unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; @@ -340,10 +376,8 @@ unsigned RuntimeDyldImpl::computeSectionStubBufSize(ObjectImage &Obj, } // Get section data size and alignment - uint64_t Alignment64; - uint64_t DataSize; - Check(Section.getSize(DataSize)); - Check(Section.getAlignment(Alignment64)); + uint64_t DataSize = Section.getSize(); + uint64_t Alignment64 = Section.getAlignment(); // Add stubbuf size alignment unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; @@ -354,6 +388,36 @@ unsigned RuntimeDyldImpl::computeSectionStubBufSize(ObjectImage &Obj, return StubBufSize; } +uint64_t RuntimeDyldImpl::readBytesUnaligned(uint8_t *Src, + unsigned Size) const { + uint64_t Result = 0; + if (IsTargetLittleEndian) { + Src += Size - 1; + while (Size--) + Result = (Result << 8) | *Src--; + } else + while (Size--) + Result = (Result << 8) | *Src++; + + return Result; +} + +void RuntimeDyldImpl::writeBytesUnaligned(uint64_t Value, uint8_t *Dst, + unsigned Size) const { + if (IsTargetLittleEndian) { + while (Size--) { + *Dst++ = Value & 0xFF; + Value >>= 8; + } + } else { + Dst += Size - 1; + while (Size--) { + *Dst-- = Value & 0xFF; + Value >>= 8; + } + } +} + void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, const CommonSymbolMap &CommonSymbols, uint64_t TotalSize, @@ -365,7 +429,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, if (!Addr) report_fatal_error("Unable to allocate memory for common symbols!"); uint64_t Offset = 0; - Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize, 0)); + Sections.push_back(SectionEntry("<common symbols>", Addr, TotalSize, 0)); memset(Addr, 0, TotalSize); DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID << " new addr: " @@ -397,24 +461,18 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, const SectionRef &Section, bool IsCode) { StringRef data; - uint64_t Alignment64; Check(Section.getContents(data)); - Check(Section.getAlignment(Alignment64)); + uint64_t Alignment64 = Section.getAlignment(); unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; - bool IsRequired; - bool IsVirtual; - bool IsZeroInit; - bool IsReadOnly; - uint64_t DataSize; unsigned PaddingSize = 0; unsigned StubBufSize = 0; StringRef Name; - Check(Section.isRequiredForExecution(IsRequired)); - Check(Section.isVirtual(IsVirtual)); - Check(Section.isZeroInit(IsZeroInit)); - Check(Section.isReadOnlyData(IsReadOnly)); - Check(Section.getSize(DataSize)); + bool IsRequired = Section.isRequiredForExecution(); + bool IsVirtual = Section.isVirtual(); + bool IsZeroInit = Section.isZeroInit(); + bool IsReadOnly = Section.isReadOnlyData(); + uint64_t DataSize = Section.getSize(); Check(Section.getName(Name)); StubBufSize = computeSectionStubBufSize(Obj, Section); @@ -477,6 +535,10 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, } Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData)); + + if (Checker) + Checker->registerSection(Obj.getImageName(), SectionID); + return SectionID; } @@ -517,34 +579,26 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, } } -uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { - if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be || - Arch == Triple::arm64 || Arch == Triple::arm64_be) { +uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr, + unsigned AbiVariant) { + if (Arch == Triple::aarch64 || Arch == Triple::aarch64_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; - // Stub can use ip0 (== x16) to calculate address - *StubAddr = 0xd2e00010; // movz ip0, #:abs_g3:<addr> - StubAddr++; - *StubAddr = 0xf2c00010; // movk ip0, #:abs_g2_nc:<addr> - StubAddr++; - *StubAddr = 0xf2a00010; // movk ip0, #:abs_g1_nc:<addr> - StubAddr++; - *StubAddr = 0xf2800010; // movk ip0, #:abs_g0_nc:<addr> - StubAddr++; - *StubAddr = 0xd61f0200; // br ip0 + writeBytesUnaligned(0xd2e00010, Addr, 4); // movz ip0, #:abs_g3:<addr> + writeBytesUnaligned(0xf2c00010, Addr+4, 4); // movk ip0, #:abs_g2_nc:<addr> + writeBytesUnaligned(0xf2a00010, Addr+8, 4); // movk ip0, #:abs_g1_nc:<addr> + writeBytesUnaligned(0xf2800010, Addr+12, 4); // movk ip0, #:abs_g0_nc:<addr> + writeBytesUnaligned(0xd61f0200, Addr+16, 4); // br ip0 return Addr; } 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; - *StubAddr = 0xe51ff004; // ldr pc,<label> - return (uint8_t *)++StubAddr; + writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc,<label> + return Addr + 4; } else if (Arch == Triple::mipsel || Arch == Triple::mips) { - uint32_t *StubAddr = (uint32_t *)Addr; // 0: 3c190000 lui t9,%hi(addr). // 4: 27390000 addiu t9,t9,%lo(addr). // 8: 03200008 jr t9. @@ -552,31 +606,37 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { const unsigned LuiT9Instr = 0x3c190000, AdduiT9Instr = 0x27390000; const unsigned JrT9Instr = 0x03200008, NopInstr = 0x0; - *StubAddr = LuiT9Instr; - StubAddr++; - *StubAddr = AdduiT9Instr; - StubAddr++; - *StubAddr = JrT9Instr; - StubAddr++; - *StubAddr = NopInstr; + writeBytesUnaligned(LuiT9Instr, Addr, 4); + writeBytesUnaligned(AdduiT9Instr, Addr+4, 4); + writeBytesUnaligned(JrT9Instr, Addr+8, 4); + writeBytesUnaligned(NopInstr, Addr+12, 4); 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 @@ -609,6 +669,10 @@ void RuntimeDyldImpl::reassignSectionAddress(unsigned SectionID, // Addr is a uint64_t because we can't assume the pointer width // of the target is the same as that of the host. Just use a generic // "big enough" type. + DEBUG(dbgs() << "Reassigning address for section " + << SectionID << " (" << Sections[SectionID].Name << "): " + << format("0x%016" PRIx64, Sections[SectionID].LoadAddress) << " -> " + << format("0x%016" PRIx64, Addr) << "\n"); Sections[SectionID].LoadAddress = Addr; } @@ -685,25 +749,31 @@ RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) { Dyld = nullptr; MM = mm; ProcessAllSections = false; + Checker = nullptr; } -RuntimeDyld::~RuntimeDyld() { delete Dyld; } +RuntimeDyld::~RuntimeDyld() {} static std::unique_ptr<RuntimeDyldELF> -createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections) { +createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections, + RuntimeDyldCheckerImpl *Checker) { std::unique_ptr<RuntimeDyldELF> Dyld(new RuntimeDyldELF(MM)); Dyld->setProcessAllSections(ProcessAllSections); + Dyld->setRuntimeDyldChecker(Checker); return Dyld; } static std::unique_ptr<RuntimeDyldMachO> -createRuntimeDyldMachO(RTDyldMemoryManager *MM, bool ProcessAllSections) { - std::unique_ptr<RuntimeDyldMachO> Dyld(new RuntimeDyldMachO(MM)); +createRuntimeDyldMachO(Triple::ArchType Arch, RTDyldMemoryManager *MM, + bool ProcessAllSections, RuntimeDyldCheckerImpl *Checker) { + std::unique_ptr<RuntimeDyldMachO> Dyld(RuntimeDyldMachO::create(Arch, MM)); Dyld->setProcessAllSections(ProcessAllSections); + Dyld->setRuntimeDyldChecker(Checker); return Dyld; } -ObjectImage *RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) { +std::unique_ptr<ObjectImage> +RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) { std::unique_ptr<ObjectImage> InputImage; ObjectFile &Obj = *InputObject; @@ -711,33 +781,37 @@ ObjectImage *RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) { if (InputObject->isELF()) { InputImage.reset(RuntimeDyldELF::createObjectImageFromFile(std::move(InputObject))); if (!Dyld) - Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release(); + Dyld = createRuntimeDyldELF(MM, ProcessAllSections, Checker); } else if (InputObject->isMachO()) { InputImage.reset(RuntimeDyldMachO::createObjectImageFromFile(std::move(InputObject))); if (!Dyld) - Dyld = createRuntimeDyldMachO(MM, ProcessAllSections).release(); + Dyld = createRuntimeDyldMachO( + static_cast<Triple::ArchType>(InputImage->getArch()), MM, + ProcessAllSections, Checker); } else report_fatal_error("Incompatible object format!"); if (!Dyld->isCompatibleFile(&Obj)) report_fatal_error("Incompatible object format!"); - Dyld->loadObject(InputImage.get()); - return InputImage.release(); + return Dyld->loadObject(std::move(InputImage)); } -ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) { +std::unique_ptr<ObjectImage> +RuntimeDyld::loadObject(std::unique_ptr<ObjectBuffer> InputBuffer) { std::unique_ptr<ObjectImage> InputImage; sys::fs::file_magic Type = sys::fs::identify_magic(InputBuffer->getBuffer()); + auto *InputBufferPtr = InputBuffer.get(); switch (Type) { + case sys::fs::file_magic::elf: 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)); + InputImage = RuntimeDyldELF::createObjectImage(std::move(InputBuffer)); if (!Dyld) - Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release(); + Dyld = createRuntimeDyldELF(MM, ProcessAllSections, Checker); break; case sys::fs::file_magic::macho_object: case sys::fs::file_magic::macho_executable: @@ -749,9 +823,11 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) { 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)); + InputImage = RuntimeDyldMachO::createObjectImage(std::move(InputBuffer)); if (!Dyld) - Dyld = createRuntimeDyldMachO(MM, ProcessAllSections).release(); + Dyld = createRuntimeDyldMachO( + static_cast<Triple::ArchType>(InputImage->getArch()), MM, + ProcessAllSections, Checker); break; case sys::fs::file_magic::unknown: case sys::fs::file_magic::bitcode: @@ -764,20 +840,19 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) { report_fatal_error("Incompatible object format!"); } - if (!Dyld->isCompatibleFormat(InputBuffer)) + if (!Dyld->isCompatibleFormat(InputBufferPtr)) report_fatal_error("Incompatible object format!"); - Dyld->loadObject(InputImage.get()); - return InputImage.release(); + return Dyld->loadObject(std::move(InputImage)); } -void *RuntimeDyld::getSymbolAddress(StringRef Name) { +void *RuntimeDyld::getSymbolAddress(StringRef Name) const { if (!Dyld) return nullptr; return Dyld->getSymbolAddress(Name); } -uint64_t RuntimeDyld::getSymbolLoadAddress(StringRef Name) { +uint64_t RuntimeDyld::getSymbolLoadAddress(StringRef Name) const { if (!Dyld) return 0; return Dyld->getSymbolLoadAddress(Name); diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp index 190bbbf..8818349 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -7,11 +7,13 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/STLExtras.h" #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 "llvm/Support/Path.h" +#include "RuntimeDyldCheckerImpl.h" #include "RuntimeDyldImpl.h" #include <cctype> #include <memory> @@ -22,579 +24,696 @@ 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; +// Helper class that implements the language evaluated by RuntimeDyldChecker. +class RuntimeDyldCheckerExprEval { +public: + RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker, + raw_ostream &ErrStream) + : Checker(Checker) {} + + bool evaluate(StringRef Expr) const { + // Expect equality expression of the form 'LHS = RHS'. + Expr = Expr.trim(); + size_t EQIdx = Expr.find('='); + + ParseContext OutsideLoad(false); + + // Evaluate LHS. + StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim(); + StringRef RemainingExpr; + EvalResult LHSResult; + std::tie(LHSResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad); + 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, OutsideLoad), OutsideLoad); + if (RHSResult.hasError()) + return handleError(Expr, RHSResult); + if (RemainingExpr != "") + return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, "")); + + if (LHSResult.getValue() != RHSResult.getValue()) { + Checker.ErrStream << "Expression '" << Expr << "' is false: " + << format("0x%" PRIx64, LHSResult.getValue()) + << " != " << format("0x%" PRIx64, RHSResult.getValue()) + << "\n"; + return false; } + return true; + } + +private: + // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In + // particular, it needs to know whether a symbol is being evaluated in the + // context of a load, in which case we want the linker's local address for + // the symbol, or outside of a load, in which case we want the symbol's + // address in the remote target. + + struct ParseContext { + bool IsInsideLoad; + ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {} + }; + + const RuntimeDyldCheckerImpl &Checker; + + 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: - 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; - } + uint64_t Value; + std::string ErrorMsg; + }; - 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)); + 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; + } - 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; + 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)); + } - 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; - } + bool handleError(StringRef Expr, const EvalResult &R) const { + assert(R.hasError() && "Not an error result."); + Checker.ErrStream << "Error evaluating expression '" << Expr + << "': " << R.getErrorMsg() << "\n"; + return false; + } - return std::make_pair(Op, Expr.substr(1).ltrim()); + 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; } - 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()); - } - } + return std::make_pair(Op, Expr.substr(1).ltrim()); + } - // 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()); + 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()); } + } - // 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.checkSymbolIsValidForLoad(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."; - return std::make_pair(EvalResult(ErrMsgStream.str()), ""); - } + // 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()); + } - 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()), ""); - } + // 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()), + ""); - return std::make_pair(EvalResult(Op.getImm()), RemainingExpr); - } + if (!RemainingExpr.startswith(",")) + return std::make_pair( + unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); - // 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.checkSymbolIsValidForLoad(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); - } + EvalResult OpIdxExpr; + std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + if (OpIdxExpr.hasError()) + return std::make_pair(OpIdxExpr, ""); - // 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); - - // Looks like a plain symbol reference. - return std::make_pair(EvalResult(Checker.getSymbolAddress(Symbol)), - RemainingExpr); - } + if (!RemainingExpr.startswith(")")) + return std::make_pair( + unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); - // 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)); + 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()), ""); } - // 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); + 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()), ""); } - // 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); - } + return std::make_pair(EvalResult(Op.getImm()), 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(); - } + // 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 of the + // expression remaining to be evaluated. + std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr, + ParseContext PCtx) 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 InstSize; + if (!decodeInst(Symbol, Inst, InstSize)) + return std::make_pair( + EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), + ""); + + uint64_t SymbolAddr = PCtx.IsInsideLoad + ? Checker.getSymbolLinkerAddr(Symbol) + : Checker.getSymbolRemoteAddr(Symbol); + uint64_t NextPC = SymbolAddr + InstSize; - // Read symbol. - StringRef Symbol; - std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); + return std::make_pair(EvalResult(NextPC), RemainingExpr); + } - if (!Checker.checkSymbolIsValidForLoad(Symbol)) - return std::make_pair(EvalResult(("Cannot dereference unknown symbol '" - + Symbol + "'").str()), - ""); + // Evaluate a call to stub_addr. + // Look up and return the address of the stub for the given + // (<file name>, <section name>, <symbol name>) tuple. + // On success, returns a pair containing the stub address, plus the expression + // remaining to be evaluated. + std::pair<EvalResult, StringRef> evalStubAddr(StringRef Expr, + ParseContext PCtx) const { + if (!Expr.startswith("(")) + return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + + // Handle file-name specially, as it may contain characters that aren't + // legal for symbols. + StringRef FileName; + size_t ComaIdx = RemainingExpr.find(','); + FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); + RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); + + if (!RemainingExpr.startswith(",")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); - // Set up defaut offset. - int64_t Offset = 0; + StringRef SectionName; + std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); - // 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(); + if (!RemainingExpr.startswith(",")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); - EvalResult OffsetExpr; - std::tie(OffsetExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + StringRef Symbol; + std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); - Offset = (OpChar == '+') ? - OffsetExpr.getValue() : -1 * OffsetExpr.getValue(); + if (!RemainingExpr.startswith(")")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); - if (!RemainingExpr.startswith(")")) - return std::make_pair(EvalResult("Missing ')' in load address."), - ""); + uint64_t StubAddr; + std::string ErrorMsg = ""; + std::tie(StubAddr, ErrorMsg) = Checker.getStubAddrFor( + FileName, SectionName, Symbol, PCtx.IsInsideLoad); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - } + if (ErrorMsg != "") + return std::make_pair(EvalResult(ErrorMsg), ""); + return std::make_pair(EvalResult(StubAddr), RemainingExpr); + } + + std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr, + ParseContext PCtx) const { + if (!Expr.startswith("(")) + return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + + // Handle file-name specially, as it may contain characters that aren't + // legal for symbols. + StringRef FileName; + size_t ComaIdx = RemainingExpr.find(','); + FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); + RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); + + if (!RemainingExpr.startswith(",")) return std::make_pair( - EvalResult(Checker.readMemoryAtSymbol(Symbol, Offset, ReadSize)), - RemainingExpr); + unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + StringRef SectionName; + std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); + + if (!RemainingExpr.startswith(")")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + uint64_t StubAddr; + std::string ErrorMsg = ""; + std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr( + FileName, SectionName, PCtx.IsInsideLoad); + + if (ErrorMsg != "") + return std::make_pair(EvalResult(ErrorMsg), ""); + + return std::make_pair(EvalResult(StubAddr), 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, + ParseContext PCtx) 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, PCtx); + else if (Symbol == "stub_addr") + return evalStubAddr(RemainingExpr, PCtx); + else if (Symbol == "section_addr") + return evalSectionAddr(RemainingExpr, PCtx); + + 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), ""); } - // 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)); + // The value for the symbol depends on the context we're evaluating in: + // Inside a load this is the address in the linker's memory, outside a + // load it's the address in the target processes memory. + uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLinkerAddr(Symbol) + : Checker.getSymbolRemoteAddr(Symbol); - return std::make_pair(SubExprResult, RemainingExpr); + // Looks like a plain symbol reference. + return std::make_pair(EvalResult(Value), 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, + ParseContext PCtx) const { + assert(Expr.startswith("(") && "Not a parenthesized expression"); + EvalResult SubExprResult; + StringRef RemainingExpr; + std::tie(SubExprResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx); + 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 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 + // Evaluate an expression in one of the following forms: + // *{<number>}<expr> + // 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(); + + // Evaluate the expression representing the load address. + ParseContext LoadCtx(true); + EvalResult LoadAddrExprResult; + std::tie(LoadAddrExprResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx); + + if (LoadAddrExprResult.hasError()) + return std::make_pair(LoadAddrExprResult, ""); + + uint64_t LoadAddr = LoadAddrExprResult.getValue(); + + return std::make_pair( + EvalResult(Checker.readMemoryAtAddr(LoadAddr, 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, + ParseContext PCtx) 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, PCtx); + else if (Expr[0] == '*') + std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr); + else if (isalpha(Expr[0]) || Expr[0] == '_') + std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx); + else if (isdigit(Expr[0])) + std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr); + else + return std::make_pair( + unexpectedToken(Expr, Expr, + "expected '(', '*', identifier, or number"), ""); + + 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> LHSAndRemaining, + ParseContext PCtx) const { + EvalResult LHSResult; + StringRef RemainingExpr; + std::tie(LHSResult, RemainingExpr) = LHSAndRemaining; + + // If there was an error, or there's nothing left to evaluate, return 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); - } + if (LHSResult.hasError() || RemainingExpr == "") + return std::make_pair(LHSResult, 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)); - } + // Otherwise check if this is a binary expressioan. + BinOpToken BinOp; + std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr); - bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { - MCDisassembler *Dis = Checker.Disassembler; - StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol); - StringRefMemoryObject SectionBytes(SectionMem, 0); + // If this isn't a recognized expression just return. + if (BinOp == BinOpToken::Invalid) + return std::make_pair(LHSResult, RemainingExpr); - MCDisassembler::DecodeStatus S = - Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls()); + // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop. + EvalResult RHSResult; + std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx); - return (S == MCDisassembler::Success); - } + // 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), PCtx); + } + bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { + MCDisassembler *Dis = Checker.Disassembler; + StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol); + ArrayRef<uint8_t> SectionBytes( + reinterpret_cast<const uint8_t *>(SectionMem.data()), + SectionMem.size()); + + MCDisassembler::DecodeStatus S = + Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls()); + + return (S == MCDisassembler::Success); + } +}; } -bool RuntimeDyldChecker::check(StringRef CheckExpr) const { +RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, + MCDisassembler *Disassembler, + MCInstPrinter *InstPrinter, + raw_ostream &ErrStream) + : RTDyld(RTDyld), Disassembler(Disassembler), InstPrinter(InstPrinter), + ErrStream(ErrStream) { + RTDyld.Checker = this; +} + +bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const { CheckExpr = CheckExpr.trim(); - DEBUG(llvm::dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr - << "'...\n"); + DEBUG(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"); + DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' " + << (Result ? "passed" : "FAILED") << ".\n"); return Result; } -bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix, - MemoryBuffer* MemBuf) const { +bool RuntimeDyldCheckerImpl::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)) + 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') + while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' && + *LineEnd != '\n') ++LineEnd; StringRef Line(LineStart, LineEnd - LineStart); @@ -605,37 +724,210 @@ bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix, // Eat whitespace. LineStart = LineEnd; - while (LineStart != MemBuf->getBufferEnd() && - std::isspace(*LineStart)) + while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart)) ++LineStart; } return DidAllTestsPass && (NumRules != 0); } -bool RuntimeDyldChecker::checkSymbolIsValidForLoad(StringRef Symbol) const { - return RTDyld.getSymbolAddress(Symbol) != nullptr; +bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const { + return getRTDyld().getSymbolAddress(Symbol) != nullptr; } -uint64_t RuntimeDyldChecker::getSymbolAddress(StringRef Symbol) const { - return RTDyld.getAnySymbolRemoteAddress(Symbol); +uint64_t RuntimeDyldCheckerImpl::getSymbolLinkerAddr(StringRef Symbol) const { + return static_cast<uint64_t>( + reinterpret_cast<uintptr_t>(getRTDyld().getSymbolAddress(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; +uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { + return getRTDyld().getAnySymbolRemoteAddress(Symbol); +} + +uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, + unsigned Size) const { + uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr); + assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range."); + uint8_t *Src = reinterpret_cast<uint8_t*>(PtrSizedAddr); + return getRTDyld().readBytesUnaligned(Src, Size); } -StringRef RuntimeDyldChecker::getSubsectionStartingAt(StringRef Name) const { + +std::pair<const RuntimeDyldCheckerImpl::SectionAddressInfo*, std::string> +RuntimeDyldCheckerImpl::findSectionAddrInfo(StringRef FileName, + StringRef SectionName) const { + + auto SectionMapItr = Stubs.find(FileName); + if (SectionMapItr == Stubs.end()) { + std::string ErrorMsg = "File '"; + ErrorMsg += FileName; + ErrorMsg += "' not found. "; + if (Stubs.empty()) + ErrorMsg += "No stubs registered."; + else { + ErrorMsg += "Available files are:"; + for (const auto& StubEntry : Stubs) { + ErrorMsg += " '"; + ErrorMsg += StubEntry.first; + ErrorMsg += "'"; + } + } + ErrorMsg += "\n"; + return std::make_pair(nullptr, ErrorMsg); + } + + auto SectionInfoItr = SectionMapItr->second.find(SectionName); + if (SectionInfoItr == SectionMapItr->second.end()) + return std::make_pair(nullptr, + ("Section '" + SectionName + "' not found in file '" + + FileName + "'\n").str()); + + return std::make_pair(&SectionInfoItr->second, std::string("")); +} + +std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr( + StringRef FileName, StringRef SectionName, bool IsInsideLoad) const { + + const SectionAddressInfo *SectionInfo = nullptr; + { + std::string ErrorMsg; + std::tie(SectionInfo, ErrorMsg) = + findSectionAddrInfo(FileName, SectionName); + if (ErrorMsg != "") + return std::make_pair(0, ErrorMsg); + } + + unsigned SectionID = SectionInfo->SectionID; + uint64_t Addr; + if (IsInsideLoad) + Addr = + static_cast<uint64_t>( + reinterpret_cast<uintptr_t>(getRTDyld().Sections[SectionID].Address)); + else + Addr = getRTDyld().Sections[SectionID].LoadAddress; + + return std::make_pair(Addr, std::string("")); +} + +std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubAddrFor( + StringRef FileName, StringRef SectionName, StringRef SymbolName, + bool IsInsideLoad) const { + + const SectionAddressInfo *SectionInfo = nullptr; + { + std::string ErrorMsg; + std::tie(SectionInfo, ErrorMsg) = + findSectionAddrInfo(FileName, SectionName); + if (ErrorMsg != "") + return std::make_pair(0, ErrorMsg); + } + + unsigned SectionID = SectionInfo->SectionID; + const StubOffsetsMap &SymbolStubs = SectionInfo->StubOffsets; + auto StubOffsetItr = SymbolStubs.find(SymbolName); + if (StubOffsetItr == SymbolStubs.end()) + return std::make_pair(0, + ("Stub for symbol '" + SymbolName + "' not found. " + "If '" + SymbolName + "' is an internal symbol this " + "may indicate that the stub target offset is being " + "computed incorrectly.\n").str()); + + uint64_t StubOffset = StubOffsetItr->second; + + uint64_t Addr; + if (IsInsideLoad) { + uintptr_t SectionBase = + reinterpret_cast<uintptr_t>(getRTDyld().Sections[SectionID].Address); + Addr = static_cast<uint64_t>(SectionBase) + StubOffset; + } else { + uint64_t SectionBase = getRTDyld().Sections[SectionID].LoadAddress; + Addr = SectionBase + StubOffset; + } + + return std::make_pair(Addr, std::string("")); +} + +StringRef +RuntimeDyldCheckerImpl::getSubsectionStartingAt(StringRef Name) const { RuntimeDyldImpl::SymbolTableMap::const_iterator pos = - RTDyld.GlobalSymbolTable.find(Name); - if (pos == RTDyld.GlobalSymbolTable.end()) + getRTDyld().GlobalSymbolTable.find(Name); + if (pos == getRTDyld().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); + uint8_t *SectionAddr = getRTDyld().getSectionAddress(Loc.first); + return StringRef(reinterpret_cast<const char *>(SectionAddr) + Loc.second, + getRTDyld().Sections[Loc.first].Size - Loc.second); +} + +void RuntimeDyldCheckerImpl::registerSection( + StringRef FilePath, unsigned SectionID) { + StringRef FileName = sys::path::filename(FilePath); + const SectionEntry &Section = getRTDyld().Sections[SectionID]; + StringRef SectionName = Section.Name; + + Stubs[FileName][SectionName].SectionID = SectionID; +} + +void RuntimeDyldCheckerImpl::registerStubMap( + StringRef FilePath, unsigned SectionID, + const RuntimeDyldImpl::StubMap &RTDyldStubs) { + StringRef FileName = sys::path::filename(FilePath); + const SectionEntry &Section = getRTDyld().Sections[SectionID]; + StringRef SectionName = Section.Name; + + Stubs[FileName][SectionName].SectionID = SectionID; + + for (auto &StubMapEntry : RTDyldStubs) { + std::string SymbolName = ""; + + if (StubMapEntry.first.SymbolName) + SymbolName = StubMapEntry.first.SymbolName; + else { + // If this is a (Section, Offset) pair, do a reverse lookup in the + // global symbol table to find the name. + for (auto &GSTEntry : getRTDyld().GlobalSymbolTable) { + if (GSTEntry.second.first == StubMapEntry.first.SectionID && + GSTEntry.second.second == + static_cast<uint64_t>(StubMapEntry.first.Offset)) { + SymbolName = GSTEntry.first(); + break; + } + } + } + + if (SymbolName != "") + Stubs[FileName][SectionName].StubOffsets[SymbolName] = + StubMapEntry.second; + } +} + +RuntimeDyldChecker::RuntimeDyldChecker(RuntimeDyld &RTDyld, + MCDisassembler *Disassembler, + MCInstPrinter *InstPrinter, + raw_ostream &ErrStream) + : Impl(make_unique<RuntimeDyldCheckerImpl>(RTDyld, Disassembler, + InstPrinter, ErrStream)) {} + +RuntimeDyldChecker::~RuntimeDyldChecker() {} + +RuntimeDyld& RuntimeDyldChecker::getRTDyld() { + return Impl->RTDyld; +} + +const RuntimeDyld& RuntimeDyldChecker::getRTDyld() const { + return Impl->RTDyld; +} + +bool RuntimeDyldChecker::check(StringRef CheckExpr) const { + return Impl->check(CheckExpr); +} + +bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix, + MemoryBuffer *MemBuf) const { + return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf); +} + +std::pair<uint64_t, std::string> +RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName, + bool LinkerAddress) { + return Impl->getSectionAddr(FileName, SectionName, LinkerAddress); } diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h new file mode 100644 index 0000000..de20c1e --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h @@ -0,0 +1,76 @@ +//===-- RuntimeDyldCheckerImpl.h -- RuntimeDyld test framework --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDCHECKERIMPL_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDCHECKERIMPL_H + +#include "RuntimeDyldImpl.h" +#include <set> + +namespace llvm { + +class RuntimeDyldCheckerImpl { + friend class RuntimeDyldChecker; + friend class RuntimeDyldImpl; + friend class RuntimeDyldCheckerExprEval; + +public: + RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, MCDisassembler *Disassembler, + MCInstPrinter *InstPrinter, + llvm::raw_ostream &ErrStream); + + bool check(StringRef CheckExpr) const; + bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const; + +private: + + // StubMap typedefs. + typedef std::map<std::string, uint64_t> StubOffsetsMap; + struct SectionAddressInfo { + uint64_t SectionID; + StubOffsetsMap StubOffsets; + }; + typedef std::map<std::string, SectionAddressInfo> SectionMap; + typedef std::map<std::string, SectionMap> StubMap; + + RuntimeDyldImpl &getRTDyld() const { return *RTDyld.Dyld; } + + bool isSymbolValid(StringRef Symbol) const; + uint64_t getSymbolLinkerAddr(StringRef Symbol) const; + uint64_t getSymbolRemoteAddr(StringRef Symbol) const; + uint64_t readMemoryAtAddr(uint64_t Addr, unsigned Size) const; + + std::pair<const SectionAddressInfo*, std::string> findSectionAddrInfo( + StringRef FileName, + StringRef SectionName) const; + + std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName, + StringRef SectionName, + bool IsInsideLoad) const; + + std::pair<uint64_t, std::string> getStubAddrFor(StringRef FileName, + StringRef SectionName, + StringRef Symbol, + bool IsInsideLoad) const; + StringRef getSubsectionStartingAt(StringRef Name) const; + + void registerSection(StringRef FilePath, unsigned SectionID); + void registerStubMap(StringRef FilePath, unsigned SectionID, + const RuntimeDyldImpl::StubMap &RTDyldStubs); + + RuntimeDyld &RTDyld; + MCDisassembler *Disassembler; + MCInstPrinter *InstPrinter; + llvm::raw_ostream &ErrStream; + + StubMap Stubs; +}; +} + +#endif diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 80e489c..d95cffe 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -23,6 +23,7 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ELF.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" using namespace llvm; @@ -55,9 +56,9 @@ template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { public: DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, - std::unique_ptr<MemoryBuffer> Wrapper, std::error_code &ec); + MemoryBufferRef Wrapper, std::error_code &ec); - DyldELFObject(std::unique_ptr<MemoryBuffer> Wrapper, std::error_code &ec); + DyldELFObject(MemoryBufferRef Wrapper, std::error_code &ec); void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr); @@ -76,8 +77,10 @@ template <class ELFT> class ELFObjectImage : public ObjectImageCommon { bool Registered; public: - ELFObjectImage(ObjectBuffer *Input, std::unique_ptr<DyldELFObject<ELFT>> Obj) - : ObjectImageCommon(Input, std::move(Obj)), Registered(false) {} + ELFObjectImage(std::unique_ptr<ObjectBuffer> Input, + std::unique_ptr<DyldELFObject<ELFT>> Obj) + : ObjectImageCommon(std::move(Input), std::move(Obj)), Registered(false) { + } virtual ~ELFObjectImage() { if (Registered) @@ -109,17 +112,15 @@ public: // 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(std::unique_ptr<MemoryBuffer> Wrapper, - std::error_code &EC) - : ELFObjectFile<ELFT>(std::move(Wrapper), EC) { +DyldELFObject<ELFT>::DyldELFObject(MemoryBufferRef Wrapper, std::error_code &EC) + : ELFObjectFile<ELFT>(Wrapper, EC) { this->isDyldELFObject = true; } 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), + MemoryBufferRef Wrapper, std::error_code &EC) + : ELFObjectFile<ELFT>(Wrapper, EC), UnderlyingFile(std::move(UnderlyingFile)) { this->isDyldELFObject = true; } @@ -185,36 +186,36 @@ RuntimeDyldELF::createObjectImageFromFile(std::unique_ptr<object::ObjectFile> Ob return nullptr; std::error_code ec; - std::unique_ptr<MemoryBuffer> Buffer( - MemoryBuffer::getMemBuffer(ObjFile->getData(), "", false)); + MemoryBufferRef Buffer = ObjFile->getMemoryBufferRef(); if (ObjFile->getBytesInAddress() == 4 && ObjFile->isLittleEndian()) { auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::little, 2, false>>>( - std::move(ObjFile), std::move(Buffer), ec); + std::move(ObjFile), 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); + std::move(ObjFile), 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); + std::move(ObjFile), 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); + std::move(ObjFile), 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) { +std::unique_ptr<ObjectImage> +RuntimeDyldELF::createObjectImage(std::unique_ptr<ObjectBuffer> Buffer) { if (Buffer->getBufferSize() < ELF::EI_NIDENT) llvm_unreachable("Unexpected ELF object size"); std::pair<unsigned char, unsigned char> Ident = @@ -222,34 +223,36 @@ ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) { (uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]); std::error_code ec; - std::unique_ptr<MemoryBuffer> Buf(Buffer->getMemBuffer()); + MemoryBufferRef Buf = Buffer->getMemBuffer(); if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { 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) { + Buf, ec); + return llvm::make_unique< + ELFObjectImage<ELFType<support::little, 4, false>>>(std::move(Buffer), + std::move(Obj)); + } + 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) { + llvm::make_unique<DyldELFObject<ELFType<support::big, 4, false>>>(Buf, + ec); + return llvm::make_unique<ELFObjectImage<ELFType<support::big, 4, false>>>( + std::move(Buffer), std::move(Obj)); + } + 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"); + Buf, ec); + return llvm::make_unique<ELFObjectImage<ELFType<support::big, 8, true>>>( + std::move(Buffer), std::move(Obj)); + } + assert(Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB && + "Unexpected ELF format"); + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 8, true>>>(Buf, + ec); + return llvm::make_unique<ELFObjectImage<ELFType<support::little, 8, true>>>( + std::move(Buffer), std::move(Obj)); } RuntimeDyldELF::~RuntimeDyldELF() {} @@ -263,10 +266,9 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, llvm_unreachable("Relocation type not implemented yet!"); break; case ELF::R_X86_64_64: { - uint64_t *Target = reinterpret_cast<uint64_t *>(Section.Address + Offset); - *Target = Value + Addend; + support::ulittle64_t::ref(Section.Address + Offset) = Value + Addend; DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " - << format("%p\n", Target)); + << format("%p\n", Section.Address + Offset)); break; } case ELF::R_X86_64_32: @@ -276,17 +278,15 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, (Type == ELF::R_X86_64_32S && ((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); - *Target = TruncatedAddr; + support::ulittle32_t::ref(Section.Address + Offset) = TruncatedAddr; DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at " - << format("%p\n", Target)); + << format("%p\n", Section.Address + Offset)); 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; // 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 @@ -294,30 +294,29 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress; assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); - *Target = TruncOffset; + support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset; break; } 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); + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint64_t FinalAddress = Section.LoadAddress + Offset; - int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress; + int64_t RealOffset = Placeholder + Value + Addend - FinalAddress; assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); - *Target = TruncOffset; + support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset; break; } 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); + support::ulittle64_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint64_t FinalAddress = Section.LoadAddress + Offset; - *Target = *Placeholder + Value + Addend - FinalAddress; + support::ulittle64_t::ref(Section.Address + Offset) = + Placeholder + Value + Addend - FinalAddress; break; } } @@ -330,21 +329,20 @@ void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, 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); - *Target = *Placeholder + Value + Addend; + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); + support::ulittle32_t::ref(Section.Address + Offset) = + 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); + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); - uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; - *Target = RealOffset; + uint32_t RealOffset = Placeholder + Value + Addend - FinalAddress; + support::ulittle32_t::ref(Section.Address + Offset) = RealOffset; break; } default: @@ -704,8 +702,7 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, section_iterator tsi(Obj.end_sections()); check(TargetSymbol->getSection(tsi)); - bool IsCode = false; - tsi->isText(IsCode); + bool IsCode = tsi->isText(); Rel.SectionID = findOrEmitSection(Obj, (*tsi), IsCode, LocalSections); Rel.Addend = (intptr_t)Addend; return; @@ -911,8 +908,6 @@ 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. @@ -987,9 +982,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( 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); + bool isCode = si->isText(); Value.SectionID = findOrEmitSection(Obj, (*si), isCode, ObjSectionToID); Value.Addend = Addend; break; @@ -1018,8 +1011,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset << "\n"); - if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be || - Arch == Triple::arm64 || Arch == Triple::arm64_be) && + if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_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."); @@ -1141,6 +1133,10 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( } } 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. @@ -1148,10 +1144,18 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( 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 @@ -1179,7 +1183,8 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; uint8_t *StubTargetAddr = - createStubFunction(Section.Address + Section.StubOffset); + createStubFunction(Section.Address + Section.StubOffset, + AbiVariant); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, ELF::R_PPC64_ADDR64, Value.Addend); @@ -1217,9 +1222,13 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( RelType, 0); Section.StubOffset += getMaxStubSize(); } - if (SymType == SymbolRef::ST_Unknown) + if (SymType == SymbolRef::ST_Unknown) { // Restore the TOC for external calls - writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1) + 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 || @@ -1306,7 +1315,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( Stubs[Value] = StubOffset; createStubFunction((uint8_t *)StubAddress); RelocationEntry RE(SectionID, StubOffset + 8, ELF::R_390_64, - Value.Addend - Addend); + Value.Offset); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else @@ -1414,8 +1423,6 @@ size_t RuntimeDyldELF::getGOTEntrySize() { 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: diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index 59fdfbe..4aeab81 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_RUNTIME_DYLD_ELF_H -#define LLVM_RUNTIME_DYLD_ELF_H +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H #include "RuntimeDyldImpl.h" #include "llvm/ADT/DenseMap.h" @@ -58,8 +58,7 @@ class RuntimeDyldELF : public RuntimeDyldImpl { uint64_t Value, uint32_t Type, int64_t Addend); unsigned getMaxStubSize() override { - if (Arch == Triple::aarch64 || Arch == Triple::arm64 || - Arch == Triple::aarch64_be || Arch == Triple::arm64_be) + if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) return 20; // movz; movk; movk; movk; br if (Arch == Triple::arm || Arch == Triple::thumb) return 8; // 32-bit instruction and 32-bit address @@ -120,7 +119,8 @@ public: ObjSectionToIDMap &SectionMap) override; virtual ~RuntimeDyldELF(); - static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); + static std::unique_ptr<ObjectImage> + createObjectImage(std::unique_ptr<ObjectBuffer> InputBuffer); static ObjectImage *createObjectImageFromFile(std::unique_ptr<object::ObjectFile> Obj); }; diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index 0336cba..69ea3b4 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_RUNTIME_DYLD_IMPL_H -#define LLVM_RUNTIME_DYLD_IMPL_H +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -70,7 +70,7 @@ 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), + LoadAddress(reinterpret_cast<uintptr_t>(address)), StubOffset(size), ObjAddress(objAddress) {} }; @@ -159,7 +159,7 @@ public: }; class RuntimeDyldImpl { - friend class RuntimeDyldChecker; + friend class RuntimeDyldCheckerImpl; private: uint64_t getAnySymbolRemoteAddress(StringRef Symbol) { @@ -172,6 +172,9 @@ protected: // The MemoryManager to load objects into. RTDyldMemoryManager *MemMgr; + // Attached RuntimeDyldChecker instance. Null if no instance attached. + RuntimeDyldCheckerImpl *Checker; + // A list of all sections emitted by the dynamic linker. These sections are // referenced in the code by means of their index in this list - SectionID. typedef SmallVector<SectionEntry, 64> SectionList; @@ -211,6 +214,7 @@ protected: // modules. This map is indexed by symbol name. StringMap<RelocationList> ExternalSymbolRelocations; + typedef std::map<RelocationValueRef, uintptr_t> StubMap; Triple::ArchType Arch; @@ -245,11 +249,11 @@ protected: return true; } - uint64_t getSectionLoadAddress(unsigned SectionID) { + uint64_t getSectionLoadAddress(unsigned SectionID) const { return Sections[SectionID].LoadAddress; } - uint8_t *getSectionAddress(unsigned SectionID) { + uint8_t *getSectionAddress(unsigned SectionID) const { return (uint8_t *)Sections[SectionID].Address; } @@ -282,6 +286,13 @@ protected: *(Addr + 7) = Value & 0xFF; } + /// Endian-aware read Read the least significant Size bytes from Src. + uint64_t readBytesUnaligned(uint8_t *Src, unsigned Size) const; + + /// Endian-aware write. Write the least significant Size bytes from Value to + /// Dst. + void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const; + /// \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. @@ -312,7 +323,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); @@ -349,7 +360,7 @@ protected: public: RuntimeDyldImpl(RTDyldMemoryManager *mm) - : MemMgr(mm), ProcessAllSections(false), HasError(false) { + : MemMgr(mm), Checker(nullptr), ProcessAllSections(false), HasError(false) { } virtual ~RuntimeDyldImpl(); @@ -358,9 +369,14 @@ public: this->ProcessAllSections = ProcessAllSections; } - ObjectImage *loadObject(ObjectImage *InputObject); + void setRuntimeDyldChecker(RuntimeDyldCheckerImpl *Checker) { + this->Checker = Checker; + } + + std::unique_ptr<ObjectImage> + loadObject(std::unique_ptr<ObjectImage> InputObject); - uint8_t* getSymbolAddress(StringRef Name) { + uint8_t* getSymbolAddress(StringRef Name) const { // FIXME: Just look up as a function for now. Overly simple of course. // Work in progress. SymbolTableMap::const_iterator pos = GlobalSymbolTable.find(Name); @@ -370,7 +386,7 @@ public: return getSectionAddress(Loc.first) + Loc.second; } - uint64_t getSymbolLoadAddress(StringRef Name) { + uint64_t getSymbolLoadAddress(StringRef Name) const { // FIXME: Just look up as a function for now. Overly simple of course. // Work in progress. SymbolTableMap::const_iterator pos = GlobalSymbolTable.find(Name); diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index 4eb516c..d3d6f5d 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -14,8 +14,12 @@ #include "RuntimeDyldMachO.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" -#include "ObjectImageCommon.h" -#include "JITRegistrar.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; @@ -23,164 +27,231 @@ using namespace llvm::object; namespace llvm { -class MachOObjectImage : public ObjectImageCommon { -private: - typedef SmallVector<uint64_t, 1> SectionAddrList; - SectionAddrList OldSectionAddrList; - -protected: - bool is64; - bool Registered; - -private: - void initOldAddress() { - MachOObjectFile *objf = static_cast<MachOObjectFile *>(ObjFile.get()); - // Unfortunately we need to do this, since there's information encoded - // in the original addr of the section that we could not otherwise - // recover. The reason for this is that symbols do not actually store - // their file offset, but only their vmaddr. This means that in order - // to locate the symbol correctly in the object file, we need to know - // where the original start of the section was (including any padding, - // etc). - for (section_iterator i = objf->section_begin(), e = objf->section_end(); - i != e; ++i) { - uint64_t Addr; - i->getAddress(Addr); - OldSectionAddrList[i->getRawDataRefImpl().d.a] = Addr; +int64_t RuntimeDyldMachO::memcpyAddend(const RelocationEntry &RE) const { + unsigned NumBytes = 1 << RE.Size; + uint8_t *Src = Sections[RE.SectionID].Address + RE.Offset; + + return static_cast<int64_t>(readBytesUnaligned(Src, NumBytes)); +} + +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.Offset = SI->second.second + RE.Addend; + } else { + SI = GlobalSymbolTable.find(TargetName.data()); + if (SI != GlobalSymbolTable.end()) { + Value.SectionID = SI->second.first; + Value.Offset = SI->second.second + RE.Addend; + } else { + Value.SymbolName = TargetName.data(); + Value.Offset = RE.Addend; + } } + } else { + SectionRef Sec = Obj.getRelocationSection(RelInfo); + bool IsCode = Sec.isText(); + Value.SectionID = findOrEmitSection(ObjImg, Sec, IsCode, ObjSectionToID); + uint64_t Addr = Sec.getAddress(); + Value.Offset = RE.Addend - Addr; } -public: - MachOObjectImage(ObjectBuffer *Input, bool is64) - : ObjectImageCommon(Input), - OldSectionAddrList(ObjFile->section_end()->getRawDataRefImpl().d.a, 0), - is64(is64), Registered(false) { - initOldAddress(); - } + return Value; +} - MachOObjectImage(std::unique_ptr<object::ObjectFile> Input, bool is64) - : ObjectImageCommon(std::move(Input)), - OldSectionAddrList(ObjFile->section_end()->getRawDataRefImpl().d.a, 0), - is64(is64), Registered(false) { - initOldAddress(); +void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef &Value, + ObjectImage &ObjImg, + const relocation_iterator &RI, + unsigned OffsetToNextPC) { + 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); + Value.Offset += RelocAddr + OffsetToNextPC; } +} + +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("0x%016" PRIx64, FinalAddress) + << " Value: " << format("0x%016" PRIx64, Value) << " Addend: " << RE.Addend + << " isPCRel: " << RE.IsPCRel << " MachoType: " << RE.RelType + << " Size: " << (1 << RE.Size) << "\n"; +} - virtual ~MachOObjectImage() { - if (Registered) - deregisterWithDebugger(); +section_iterator +RuntimeDyldMachO::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 = SI->getAddress(); + uint64_t SSize = SI->getSize(); + if ((Addr >= SAddr) && (Addr < SAddr + SSize)) + return SI; } - // 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) { - MachOObjectFile *objf = static_cast<MachOObjectFile *>(ObjFile.get()); - char *data = - const_cast<char *>(objf->getSectionPointer(Sec.getRawDataRefImpl())); + return SE; +} - uint64_t oldAddr = OldSectionAddrList[Sec.getRawDataRefImpl().d.a]; - if (is64) { - ((MachO::section_64 *)data)->addr = Addr; - } else { - ((MachO::section *)data)->addr = Addr; - } +// Populate __pointers section. +void RuntimeDyldMachO::populateIndirectSymbolPointersSection( + MachOObjectFile &Obj, + const SectionRef &PTSection, + unsigned PTSectionID) { + assert(!Obj.is64Bit() && + "Pointer table section not supported in 64-bit MachO."); - for (symbol_iterator i = objf->symbol_begin(), e = objf->symbol_end(); - i != e; ++i) { - section_iterator symSec(objf->section_end()); - (*i).getSection(symSec); - if (*symSec == Sec) { - uint64_t symAddr; - (*i).getAddress(symAddr); - updateSymbolAddress(*i, symAddr + Addr - oldAddr); - } - } - } + 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; - uint64_t getOldSectionAddr(const SectionRef &Sec) const { - return OldSectionAddrList[Sec.getRawDataRefImpl().d.a]; - } + assert((PTSectionSize % PTEntrySize) == 0 && + "Pointers section does not contain a whole number of stubs?"); - virtual void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) { - char *data = const_cast<char *>( - reinterpret_cast<const char *>(Sym.getRawDataRefImpl().p)); - if (is64) - ((MachO::nlist_64 *)data)->n_value = Addr; - else - ((MachO::nlist *)data)->n_value = Addr; - } + DEBUG(dbgs() << "Populating pointer table section " + << Sections[PTSectionID].Name + << ", Section ID " << PTSectionID << ", " + << NumPTEntries << " entries, " << PTEntrySize + << " bytes each:\n"); - virtual void registerWithDebugger() { - JITRegistrar::getGDBRegistrar().registerObject(*Buffer); - Registered = true; + 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; } +} - virtual void deregisterWithDebugger() { - JITRegistrar::getGDBRegistrar().deregisterObject(*Buffer); - } -}; - -ObjectImage *RuntimeDyldMachO::createObjectImage(ObjectBuffer *Buffer) { - uint32_t magic = *((const uint32_t *)Buffer->getBufferStart()); - bool is64 = (magic == MachO::MH_MAGIC_64); - assert((magic == MachO::MH_MAGIC_64 || magic == MachO::MH_MAGIC) && - "Unrecognized Macho Magic"); - return new MachOObjectImage(Buffer, is64); +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; } -ObjectImage *RuntimeDyldMachO::createObjectImageFromFile( - std::unique_ptr<object::ObjectFile> ObjFile) { - if (!ObjFile) - return nullptr; +bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const { + return Obj->isMachO(); +} - MemoryBuffer *Buffer = - MemoryBuffer::getMemBuffer(ObjFile->getData(), "", false); +template <typename Impl> +void RuntimeDyldMachOCRTPBase<Impl>::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; - uint32_t magic = *((const uint32_t *)Buffer->getBufferStart()); - bool is64 = (magic == MachO::MH_MAGIC_64); - assert((magic == MachO::MH_MAGIC_64 || magic == MachO::MH_MAGIC) && - "Unrecognized Macho Magic"); - return new MachOObjectImage(std::move(ObjFile), is64); + 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)); } -static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, - intptr_t DeltaForEH) { +template <typename Impl> +unsigned char *RuntimeDyldMachOCRTPBase<Impl>::processFDE(unsigned char *P, + int64_t DeltaForText, + int64_t DeltaForEH) { + typedef typename Impl::TargetPtrT TargetPtrT; + DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText << ", Delta for EH: " << DeltaForEH << "\n"); - uint32_t Length = *((uint32_t *)P); + uint32_t Length = readBytesUnaligned(P, 4); P += 4; unsigned char *Ret = P + Length; - uint32_t Offset = *((uint32_t *)P); + uint32_t Offset = readBytesUnaligned(P, 4); if (Offset == 0) // is a CIE return Ret; P += 4; - intptr_t FDELocation = *((intptr_t *)P); - intptr_t NewLocation = FDELocation - DeltaForText; - *((intptr_t *)P) = NewLocation; - P += sizeof(intptr_t); + TargetPtrT FDELocation = readBytesUnaligned(P, sizeof(TargetPtrT)); + TargetPtrT NewLocation = FDELocation - DeltaForText; + writeBytesUnaligned(NewLocation, P, sizeof(TargetPtrT)); + + P += sizeof(TargetPtrT); // Skip the FDE address range - P += sizeof(intptr_t); + P += sizeof(TargetPtrT); uint8_t Augmentationsize = *P; P += 1; if (Augmentationsize != 0) { - intptr_t LSDA = *((intptr_t *)P); - intptr_t NewLSDA = LSDA - DeltaForEH; - *((intptr_t *)P) = NewLSDA; + TargetPtrT LSDA = readBytesUnaligned(P, sizeof(TargetPtrT)); + TargetPtrT NewLSDA = LSDA - DeltaForEH; + writeBytesUnaligned(NewLSDA, P, sizeof(TargetPtrT)); } return Ret; } -static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) { - intptr_t ObjDistance = A->ObjAddress - B->ObjAddress; - intptr_t MemDistance = A->LoadAddress - B->LoadAddress; +static int64_t computeDelta(SectionEntry *A, SectionEntry *B) { + int64_t ObjDistance = A->ObjAddress - B->ObjAddress; + int64_t MemDistance = A->LoadAddress - B->LoadAddress; return ObjDistance - MemDistance; } -void RuntimeDyldMachO::registerEHFrames() { +template <typename Impl> +void RuntimeDyldMachOCRTPBase<Impl>::registerEHFrames() { if (!MemMgr) return; @@ -195,8 +266,8 @@ void RuntimeDyldMachO::registerEHFrames() { if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID) ExceptTab = &Sections[SectionInfo.ExceptTabSID]; - intptr_t DeltaForText = computeDelta(Text, EHFrame); - intptr_t DeltaForEH = 0; + int64_t DeltaForText = computeDelta(Text, EHFrame); + int64_t DeltaForEH = 0; if (ExceptTab) DeltaForEH = computeDelta(ExceptTab, EHFrame); @@ -212,615 +283,17 @@ void RuntimeDyldMachO::registerEHFrames() { UnregisteredEHFrameSections.clear(); } -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; - 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 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)); -} - -// 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) { - 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. +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(RE, Value); - break; - case Triple::x86: - resolveI386Relocation(RE, Value); - break; - case Triple::arm: // Fall through. - case Triple::thumb: - resolveARMRelocation(RE, Value); - break; - case Triple::aarch64: - case Triple::arm64: - resolveAArch64Relocation(RE, Value); - break; - } -} - -bool RuntimeDyldMachO::resolveI386Relocation(const RelocationEntry &RE, - uint64_t 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: - 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(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 (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; // see MachOX86_64::resolveRelocation. - } - - 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: - 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: - case MachO::X86_64_RELOC_TLV: - return Error("Relocation type not implemented yet!"); - } -} - -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 (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: - 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. - 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) - 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) | FinalValue; + llvm_unreachable("Unsupported target for RuntimeDyldMachO."); break; + case Triple::arm: return make_unique<RuntimeDyldMachOARM>(MM); + case Triple::aarch64: 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_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; -} - -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 (RE.IsPCRel) { - uint64_t FinalAddress = Section.LoadAddress + RE.Offset; - Value -= FinalAddress; - } - - switch (RE.RelType) { - default: - llvm_unreachable("Invalid relocation type!"); - 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. - uint32_t *p = (uint32_t *)LocalAddress; - // The low two bits of the value are not encoded. - Value >>= 2; - // Mask the value to 26 bits. - 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) | FinalValue; - break; - } - case MachO::ARM64_RELOC_SUBTRACTOR: - case MachO::ARM64_RELOC_PAGE21: - case MachO::ARM64_RELOC_PAGEOFF12: - case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: - case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: - case MachO::ARM64_RELOC_POINTER_TO_GOT: - case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: - case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: - case MachO::ARM64_RELOC_ADDEND: - return Error("Relocation type not implemented yet!"); - } - 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, - StubMap &Stubs) { - const ObjectFile *OF = Obj.getObjectFile(); - const MachOObjectImage &MachOObj = *static_cast<MachOObjectImage *>(&Obj); - 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. - // 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 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; - } - } - - // 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; - Sec.isText(IsCode); - Value.SectionID = findOrEmitSection(Obj, Sec, IsCode, ObjSectionToID); - uint64_t Addr = MachOObj.getOldSectionAddr(Sec); - DEBUG(dbgs() << "\nAddr: " << Addr << "\nAddend: " << Addend); - Value.Addend = Addend - Addr; - if (IsPCRel) - Value.Addend += Offset + NumBytes; - } - - if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT || - 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()) { - Addr = Section.Address + i->second; - } else { - Stubs[Value] = Section.StubOffset; - uint8_t *GOTEntry = Section.Address + Section.StubOffset; - RelocationEntry GOTRE(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(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); - 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(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, Offset, RelType, 0, IsPCRel, - Size); - resolveRelocation(TargetRE, (uint64_t)Addr); - } else { - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, IsPCRel, Size); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } - return ++RelI; -} - -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(); } } // end namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index 35f0720..7583474 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -11,74 +11,33 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_RUNTIME_DYLD_MACHO_H -#define LLVM_RUNTIME_DYLD_MACHO_H +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDMACHO_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDMACHO_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 { -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) - return 8; // 32-bit instruction and 32-bit address - else if (Arch == Triple::x86_64) - return 8; // GOT entry - else - return 0; - } - - 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); +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) {} SID EHFrameSID; @@ -91,25 +50,116 @@ private: // EH frame sections with the memory manager. SmallVector<EHFrameRelatedSections, 2> UnregisteredEHFrameSections; -public: RuntimeDyldMachO(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} - 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; + /// This convenience method uses memcpy to extract a contiguous addend (the + /// addend size and offset are taken from the corresponding fields of the RE). + int64_t memcpyAddend(const RelocationEntry &RE) const; + + /// Given a relocation_iterator for a non-scattered relocation, construct a + /// RelocationEntry and fill in the common fields. The 'Addend' field is *not* + /// filled in, since immediate encodings are highly target/opcode specific. + /// For targets/opcodes with simple, contiguous immediates (e.g. X86) the + /// memcpyAddend method can be used to read the immediate. + RelocationEntry getRelocationEntry(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()); + + bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo); + unsigned Size = Obj.getAnyRelocationLength(RelInfo); + uint64_t Offset; + RI->getOffset(Offset); + MachO::RelocationInfoType RelType = + static_cast<MachO::RelocationInfoType>(Obj.getAnyRelocationType(RelInfo)); + + return RelocationEntry(SectionID, Offset, RelType, 0, IsPCRel, Size); + } + + /// 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, + unsigned OffsetToNextPC); + + /// Dump information about the relocation entry (RE) and resolved value. + void dumpRelocationToResolve(const RelocationEntry &RE, uint64_t Value) const; + + // Return a section iterator for the section containing the given address. + static section_iterator getSectionByAddress(const MachOObjectFile &Obj, + uint64_t Addr); + + + // Populate __pointers section. + void populateIndirectSymbolPointersSection(MachOObjectFile &Obj, + const SectionRef &PTSection, + unsigned PTSectionID); + +public: + /// Create an ObjectImage from the given ObjectBuffer. + static std::unique_ptr<ObjectImage> + createObjectImage(std::unique_ptr<ObjectBuffer> InputBuffer) { + return llvm::make_unique<ObjectImageCommon>(std::move(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); + + 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); } + + unsigned char *processFDE(unsigned char *P, int64_t DeltaForText, + int64_t DeltaForEH); + +public: + RuntimeDyldMachOCRTPBase(RTDyldMemoryManager *mm) : RuntimeDyldMachO(mm) {} + void finalizeLoad(ObjectImage &ObjImg, ObjSectionToIDMap &SectionMap) override; - - static ObjectImage *createObjectImage(ObjectBuffer *Buffer); - static ObjectImage * - createObjectImageFromFile(std::unique_ptr<object::ObjectFile> InputObject); + void registerEHFrames() override; }; } // 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 0000000..f5cf9ac --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h @@ -0,0 +1,405 @@ +//===-- 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_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H + +#include "../RuntimeDyldMachO.h" +#include "llvm/Support/Endian.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOAArch64 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> { +public: + + typedef uint64_t TargetPtrT; + + RuntimeDyldMachOAArch64(RTDyldMemoryManager *MM) + : RuntimeDyldMachOCRTPBase(MM) {} + + unsigned getMaxStubSize() override { return 8; } + + unsigned getStubAlignment() override { return 8; } + + /// Extract the addend encoded in the instruction / memory location. + int64_t decodeAddend(const RelocationEntry &RE) const { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.Address + RE.Offset; + unsigned NumBytes = 1 << RE.Size; + int64_t Addend = 0; + // Verify that the relocation has the correct size and alignment. + switch (RE.RelType) { + default: + llvm_unreachable("Unsupported relocation type!"); + case MachO::ARM64_RELOC_UNSIGNED: + assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size."); + break; + case MachO::ARM64_RELOC_BRANCH26: + case MachO::ARM64_RELOC_PAGE21: + case MachO::ARM64_RELOC_PAGEOFF12: + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: + assert(NumBytes == 4 && "Invalid relocation size."); + assert((((uintptr_t)LocalAddress & 0x3) == 0) && + "Instruction address is not aligned to 4 bytes."); + break; + } + + switch (RE.RelType) { + default: + llvm_unreachable("Unsupported relocation type!"); + case MachO::ARM64_RELOC_UNSIGNED: + // This could be an unaligned memory location. + if (NumBytes == 4) + Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress); + else + Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress); + break; + case MachO::ARM64_RELOC_BRANCH26: { + // Verify that the relocation points to the expected branch instruction. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((*p & 0xFC000000) == 0x14000000 && "Expected branch instruction."); + + // Get the 26 bit addend encoded in the branch instruction and sign-extend + // to 64 bit. The lower 2 bits are always zeros and are therefore implicit + // (<< 2). + Addend = (*p & 0x03FFFFFF) << 2; + Addend = SignExtend64(Addend, 28); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_PAGE21: { + // Verify that the relocation points to the expected adrp instruction. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction."); + + // Get the 21 bit addend encoded in the adrp instruction and sign-extend + // to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are + // therefore implicit (<< 12). + Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12; + Addend = SignExtend64(Addend, 33); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: { + // Verify that the relocation points to one of the expected load / store + // instructions. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + (void)p; + assert((*p & 0x3B000000) == 0x39000000 && + "Only expected load / store instructions."); + } // fall-through + case MachO::ARM64_RELOC_PAGEOFF12: { + // Verify that the relocation points to one of the expected load / store + // or add / sub instructions. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((((*p & 0x3B000000) == 0x39000000) || + ((*p & 0x11C00000) == 0x11000000) ) && + "Expected load / store or add/sub instruction."); + + // Get the 12 bit addend encoded in the instruction. + Addend = (*p & 0x003FFC00) >> 10; + + // Check which instruction we are decoding to obtain the implicit shift + // factor of the instruction. + int ImplicitShift = 0; + if ((*p & 0x3B000000) == 0x39000000) { // << load / store + // For load / store instructions the size is encoded in bits 31:30. + ImplicitShift = ((*p >> 30) & 0x3); + if (ImplicitShift == 0) { + // Check if this a vector op to get the correct shift value. + if ((*p & 0x04800000) == 0x04800000) + ImplicitShift = 4; + } + } + // Compensate for implicit shift. + Addend <<= ImplicitShift; + break; + } + } + return Addend; + } + + /// Extract the addend encoded in the instruction. + void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes, + MachO::RelocationInfoType RelType, int64_t Addend) const { + // Verify that the relocation has the correct alignment. + switch (RelType) { + default: + llvm_unreachable("Unsupported relocation type!"); + case MachO::ARM64_RELOC_UNSIGNED: + assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size."); + break; + case MachO::ARM64_RELOC_BRANCH26: + case MachO::ARM64_RELOC_PAGE21: + case MachO::ARM64_RELOC_PAGEOFF12: + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: + assert(NumBytes == 4 && "Invalid relocation size."); + assert((((uintptr_t)LocalAddress & 0x3) == 0) && + "Instruction address is not aligned to 4 bytes."); + break; + } + + switch (RelType) { + default: + llvm_unreachable("Unsupported relocation type!"); + case MachO::ARM64_RELOC_UNSIGNED: + // This could be an unaligned memory location. + if (NumBytes == 4) + *reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend; + else + *reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend; + break; + case MachO::ARM64_RELOC_BRANCH26: { + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + // Verify that the relocation points to the expected branch instruction. + assert((*p & 0xFC000000) == 0x14000000 && "Expected branch instruction."); + + // Verify addend value. + assert((Addend & 0x3) == 0 && "Branch target is not aligned"); + assert(isInt<28>(Addend) && "Branch target is out of range."); + + // Encode the addend as 26 bit immediate in the branch instruction. + *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_PAGE21: { + // Verify that the relocation points to the expected adrp instruction. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction."); + + // Check that the addend fits into 21 bits (+ 12 lower bits). + assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned."); + assert(isInt<33>(Addend) && "Invalid page reloc value."); + + // Encode the addend into the instruction. + uint32_t ImmLoValue = (uint32_t)(Addend << 17) & 0x60000000; + uint32_t ImmHiValue = (uint32_t)(Addend >> 9) & 0x00FFFFE0; + *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue; + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: { + // Verify that the relocation points to one of the expected load / store + // instructions. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((*p & 0x3B000000) == 0x39000000 && + "Only expected load / store instructions."); + (void)p; + } // fall-through + case MachO::ARM64_RELOC_PAGEOFF12: { + // Verify that the relocation points to one of the expected load / store + // or add / sub instructions. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((((*p & 0x3B000000) == 0x39000000) || + ((*p & 0x11C00000) == 0x11000000) ) && + "Expected load / store or add/sub instruction."); + + // Check which instruction we are decoding to obtain the implicit shift + // factor of the instruction and verify alignment. + int ImplicitShift = 0; + if ((*p & 0x3B000000) == 0x39000000) { // << load / store + // For load / store instructions the size is encoded in bits 31:30. + ImplicitShift = ((*p >> 30) & 0x3); + switch (ImplicitShift) { + case 0: + // Check if this a vector op to get the correct shift value. + if ((*p & 0x04800000) == 0x04800000) { + ImplicitShift = 4; + assert(((Addend & 0xF) == 0) && + "128-bit LDR/STR not 16-byte aligned."); + } + break; + case 1: + assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned."); + break; + case 2: + assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned."); + break; + case 3: + assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned."); + break; + } + } + // Compensate for implicit shift. + Addend >>= ImplicitShift; + assert(isUInt<12>(Addend) && "Addend cannot be encoded."); + + // Encode the addend into the instruction. + *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00); + break; + } + } + } + + 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. + 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); + int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo); + // Sign-extend the 24-bit to 64-bit. + ExplicitAddend = SignExtend64(RawAddend, 24); + ++RelI; + RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl()); + } + + RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI)); + RE.Addend = decodeAddend(RE); + RelocationValueRef Value( + getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols)); + + assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\ + "ARM64_RELOC_ADDEND and embedded addend in the instruction."); + if (ExplicitAddend) { + RE.Addend = ExplicitAddend; + Value.Offset = ExplicitAddend; + } + + bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + if (!IsExtern && RE.IsPCRel) + makeValueAddendPCRel(Value, ObjImg, RelI, 1 << RE.Size); + + RE.Addend = Value.Offset; + + 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) override { + DEBUG(dumpRelocationToResolve(RE, Value)); + + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.Address + RE.Offset; + MachO::RelocationInfoType RelType = + static_cast<MachO::RelocationInfoType>(RE.RelType); + + switch (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"); + + encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend); + break; + } + case MachO::ARM64_RELOC_BRANCH26: { + assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported"); + // Check if branch is in range. + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + int64_t PCRelVal = Value - FinalAddress + RE.Addend; + encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_PAGE21: { + assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported"); + // Adjust for PC-relative relocation and offset. + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + int64_t PCRelVal = + ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096)); + encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: + case MachO::ARM64_RELOC_PAGEOFF12: { + assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported"); + // Add the offset from the symbol. + Value += RE.Addend; + // Mask out the page address and only use the lower 12 bits. + Value &= 0xFFF; + encodeAddend(LocalAddress, /*Size=*/4, RelType, Value); + 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 yet implemented!"); + 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); + int64_t Offset; + if (i != Stubs.end()) + Offset = static_cast<int64_t>(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.Offset, + /*IsPCRel=*/false, /*Size=*/3); + if (Value.SymbolName) + addRelocationForSymbol(GOTRE, Value.SymbolName); + else + addRelocationForSection(GOTRE, Value.SectionID); + Section.StubOffset = StubOffset + getMaxStubSize(); + Offset = static_cast<int64_t>(StubOffset); + } + RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset, + RE.IsPCRel, RE.Size); + addRelocationForSection(TargetRE, RE.SectionID); + } +}; +} + +#undef DEBUG_TYPE + +#endif diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h new file mode 100644 index 0000000..9766751 --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h @@ -0,0 +1,277 @@ +//===----- 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_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H + +#include "../RuntimeDyldMachO.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOARM + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> { +private: + typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT; + +public: + + typedef uint32_t TargetPtrT; + + RuntimeDyldMachOARM(RTDyldMemoryManager *MM) : RuntimeDyldMachOCRTPBase(MM) {} + + unsigned getMaxStubSize() override { return 8; } + + unsigned getStubAlignment() override { return 4; } + + int64_t decodeAddend(const RelocationEntry &RE) const { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.Address + RE.Offset; + + switch (RE.RelType) { + default: + return memcpyAddend(RE); + case MachO::ARM_RELOC_BR24: { + uint32_t Temp = readBytesUnaligned(LocalAddress, 4); + Temp &= 0x00ffffff; // Mask out the opcode. + // Now we've got the shifted immediate, shift by 2, sign extend and ret. + return SignExtend32<26>(Temp << 2); + } + } + } + + 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::ARM_RELOC_HALF_SECTDIFF) + return processHALFSECTDIFFRelocation(SectionID, RelI, ObjImg, + ObjSectionToID); + else + return ++++RelI; + } + + RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI)); + RE.Addend = decodeAddend(RE); + RelocationValueRef Value( + getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols)); + + if (RE.IsPCRel) + makeValueAddendPCRel(Value, ObjImg, RelI, 8); + + if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24) + processBranchRelocation(RE, Value, Stubs); + else { + RE.Addend = Value.Offset; + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + 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(Value + RE.Addend, LocalAddress, 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. + Value += RE.Addend; + // The low two bits of the value are not encoded. + Value >>= 2; + // Mask the value to 24 bits. + uint64_t FinalValue = 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. + uint32_t Temp = readBytesUnaligned(LocalAddress, 4); + writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4); + + break; + } + case MachO::ARM_RELOC_HALF_SECTDIFF: { + uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress; + uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress; + assert((Value == SectionABase || Value == SectionBBase) && + "Unexpected HALFSECTDIFF relocation value."); + Value = SectionABase - SectionBBase + RE.Addend; + if (RE.Size & 0x1) // :upper16: + Value = (Value >> 16); + Value &= 0xffff; + + uint32_t Insn = readBytesUnaligned(LocalAddress, 4); + Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff); + writeBytesUnaligned(Insn, LocalAddress, 4); + break; + } + + case MachO::ARM_THUMB_RELOC_BR22: + case MachO::ARM_THUMB_32BIT_BRANCH: + case MachO::ARM_RELOC_HALF: + 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) { + StringRef Name; + Section.getName(Name); + + if (Name == "__nl_symbol_ptr") + populateIndirectSymbolPointersSection( + cast<MachOObjectFile>(*ObjImg.getObjectFile()), + Section, SectionID); + } + +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.Offset, false, + 2); + if (Value.SymbolName) + addRelocationForSymbol(StubRE, Value.SymbolName); + else + addRelocationForSection(StubRE, Value.SectionID); + Addr = Section.Address + Section.StubOffset; + Section.StubOffset += getMaxStubSize(); + } + RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0, + RE.IsPCRel, RE.Size); + resolveRelocation(TargetRE, (uint64_t)Addr); + } + + relocation_iterator + processHALFSECTDIFFRelocation(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()); + + + // For a half-diff relocation the length bits actually record whether this + // is a movw/movt, and whether this is arm or thumb. + // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1). + // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1). + unsigned HalfDiffKindBits = MachO->getAnyRelocationLength(RE); + if (HalfDiffKindBits & 0x2) + llvm_unreachable("Thumb not yet supported."); + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = MachO->getAnyRelocationType(RE); + bool IsPCRel = MachO->getAnyRelocationPCRel(RE); + uint64_t Offset; + RelI->getOffset(Offset); + uint8_t *LocalAddress = Section.Address + Offset; + int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out. + Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff); + + ++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(); + uint64_t SectionAOffset = AddrA - SectionABase; + SectionRef SectionA = *SAI; + bool IsCode = SectionA.isText(); + 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(); + uint64_t SectionBOffset = AddrB - SectionBBase; + SectionRef SectionB = *SBI; + uint32_t SectionBID = + findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID); + + uint32_t OtherHalf = MachO->getAnyRelocationAddress(RE2) & 0xffff; + unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0; + uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift)); + int64_t Addend = FullImmVal - (AddrA - AddrB); + + // addend = Encoded - Expected + // = Encoded - (AddrA - AddrB) + + 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, Addend, SectionAID, + SectionAOffset, SectionBID, SectionBOffset, IsPCRel, + HalfDiffKindBits); + + addRelocationForSection(R, SectionAID); + addRelocationForSection(R, SectionBID); + + return ++RelI; + } + +}; +} + +#undef DEBUG_TYPE + +#endif diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h new file mode 100644 index 0000000..258b847 --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h @@ -0,0 +1,261 @@ +//===---- 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_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H + +#include "../RuntimeDyldMachO.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOI386 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> { +public: + + typedef uint32_t TargetPtrT; + + 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 (RelType == MachO::GENERIC_RELOC_VANILLA) + return processI386ScatteredVANILLA(SectionID, RelI, ObjImg, + ObjSectionToID); + llvm_unreachable("Unhandled scattered relocation."); + } + + RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI)); + RE.Addend = memcpyAddend(RE); + 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, 1 << RE.Size); + + RE.Addend = Value.Offset; + + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + 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(Value + RE.Addend, LocalAddress, 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(Value, LocalAddress, 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") + populateIndirectSymbolPointersSection( + 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; + uint64_t Addend = readBytesUnaligned(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(); + uint64_t SectionAOffset = AddrA - SectionABase; + SectionRef SectionA = *SAI; + bool IsCode = SectionA.isText(); + 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(); + 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 = readBytesUnaligned(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(); + SectionRef TargetSection = *TargetSI; + bool IsCode = TargetSection.isText(); + 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; + } + } + +}; +} + +#undef DEBUG_TYPE + +#endif diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h new file mode 100644 index 0000000..84d9e80 --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h @@ -0,0 +1,136 @@ +//===-- 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_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H + +#include "../RuntimeDyldMachO.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOX86_64 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOX86_64> { +public: + + typedef uint64_t TargetPtrT; + + 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(getRelocationEntry(SectionID, ObjImg, RelI)); + RE.Addend = memcpyAddend(RE); + RelocationValueRef Value( + getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols)); + + bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + if (!IsExtern && RE.IsPCRel) + makeValueAddendPCRel(Value, ObjImg, RelI, 1 << RE.Size); + + if (RE.RelType == MachO::X86_64_RELOC_GOT || + RE.RelType == MachO::X86_64_RELOC_GOT_LOAD) + processGOTRelocation(RE, Value, Stubs); + else { + RE.Addend = Value.Offset; + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + 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(Value + RE.Addend, LocalAddress, 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.Offset -= 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.Offset, 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 |