diff options
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp')
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp | 919 |
1 files changed, 196 insertions, 723 deletions
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 |