X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FExecutionEngine%2FRuntimeDyld%2FRuntimeDyldMachO.cpp;h=9e4d3ac82afb3d21cd86cf60a244d572fc580b34;hb=34ea0a1de3dc93dd0e586c9d68db7ad400ce623e;hp=ddac59fd36482174034b4a13d09a82ab537474fb;hpb=ca0e73610056110e9a175c14dd82d6d616fd830f;p=oota-llvm.git diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index ddac59fd364..9e4d3ac82af 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -11,319 +11,235 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" #include "RuntimeDyldMachO.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" + +#include "Targets/RuntimeDyldMachOARM.h" +#include "Targets/RuntimeDyldMachOAArch64.h" +#include "Targets/RuntimeDyldMachOI386.h" +#include "Targets/RuntimeDyldMachOX86_64.h" + using namespace llvm; using namespace llvm::object; +#define DEBUG_TYPE "dyld" + namespace llvm { -void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE, - uint64_t Value) { +int64_t RuntimeDyldMachO::memcpyAddend(const RelocationEntry &RE) const { const SectionEntry &Section = Sections[RE.SectionID]; - return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, - RE.IsPCRel, RE.Size); -} - -void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, - bool isPCRel, - unsigned LogSize) { - uint8_t *LocalAddress = Section.Address + Offset; - uint64_t FinalAddress = Section.LoadAddress + Offset; - unsigned MachoType = Type; - unsigned Size = 1 << LogSize; - - DEBUG(dbgs() << "resolveRelocation LocalAddress: " - << format("%p", LocalAddress) - << " FinalAddress: " << format("%p", FinalAddress) - << " Value: " << format("%p", Value) - << " Addend: " << Addend - << " isPCRel: " << isPCRel - << " MachoType: " << MachoType - << " Size: " << Size - << "\n"); - - // This just dispatches to the proper target specific routine. - switch (Arch) { - default: llvm_unreachable("Unsupported CPU type!"); - case Triple::x86_64: - resolveX86_64Relocation(LocalAddress, - FinalAddress, - (uintptr_t)Value, - isPCRel, - MachoType, - Size, - Addend); - break; - case Triple::x86: - resolveI386Relocation(LocalAddress, - FinalAddress, - (uintptr_t)Value, - isPCRel, - MachoType, - Size, - Addend); - break; - case Triple::arm: // Fall through. - case Triple::thumb: - resolveARMRelocation(LocalAddress, - FinalAddress, - (uintptr_t)Value, - isPCRel, - MachoType, - Size, - Addend); - break; - } -} - -bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend) { - if (isPCRel) - Value -= FinalAddress + 4; // see resolveX86_64Relocation - - switch (Type) { - default: - llvm_unreachable("Invalid relocation type!"); - case macho::RIT_Vanilla: { - uint8_t *p = LocalAddress; - uint64_t ValueToWrite = Value + Addend; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)(ValueToWrite & 0xff); - ValueToWrite >>= 8; - } - return false; - } - case macho::RIT_Difference: - case macho::RIT_Generic_LocalDifference: - case macho::RIT_Generic_PreboundLazyPointer: - return Error("Relocation type not implemented yet!"); + unsigned NumBytes = 1 << RE.Size; + int64_t Addend = 0; + uint8_t *LocalAddress = Section.Address + RE.Offset; + uint8_t *Dst = reinterpret_cast(&Addend); + + if (IsTargetLittleEndian == sys::IsLittleEndianHost) { + if (!sys::IsLittleEndianHost) + Dst += sizeof(Addend) - NumBytes; + memcpy(Dst, LocalAddress, NumBytes); + } else { + Dst += NumBytes - 1; + for (unsigned i = 0; i < NumBytes; ++i) + *Dst-- = *LocalAddress++; } -} -bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend) { - // If the relocation is PC-relative, the value to be encoded is the - // pointer difference. - if (isPCRel) - // FIXME: It seems this value needs to be adjusted by 4 for an effective PC - // address. Is that expected? Only for branches, perhaps? - Value -= FinalAddress + 4; - - switch(Type) { - default: - llvm_unreachable("Invalid relocation type!"); - case macho::RIT_X86_64_Signed1: - case macho::RIT_X86_64_Signed2: - case macho::RIT_X86_64_Signed4: - case macho::RIT_X86_64_Signed: - case macho::RIT_X86_64_Unsigned: - case macho::RIT_X86_64_Branch: { - Value += Addend; - // Mask in the target value a byte at a time (we don't have an alignment - // guarantee for the target address, so this is safest). - uint8_t *p = (uint8_t*)LocalAddress; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)Value; - Value >>= 8; - } - return false; - } - case macho::RIT_X86_64_GOTLoad: - case macho::RIT_X86_64_GOT: - case macho::RIT_X86_64_Subtractor: - case macho::RIT_X86_64_TLV: - return Error("Relocation type not implemented yet!"); - } + return Addend; } -bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - bool isPCRel, - unsigned Type, - unsigned Size, - int64_t Addend) { - // If the relocation is PC-relative, the value to be encoded is the - // pointer difference. - if (isPCRel) { - Value -= FinalAddress; - // ARM PCRel relocations have an effective-PC offset of two instructions - // (four bytes in Thumb mode, 8 bytes in ARM mode). - // FIXME: For now, assume ARM mode. - Value -= 8; - } +RelocationValueRef RuntimeDyldMachO::getRelocationValueRef( + ObjectImage &ObjImg, const relocation_iterator &RI, + const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols) { - switch(Type) { - default: - llvm_unreachable("Invalid relocation type!"); - case macho::RIT_Vanilla: { - // Mask in the target value a byte at a time (we don't have an alignment - // guarantee for the target address, so this is safest). - uint8_t *p = (uint8_t*)LocalAddress; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)Value; - Value >>= 8; - } - break; - } - case macho::RIT_ARM_Branch24Bit: { - // Mask the value into the target address. We know instructions are - // 32-bit aligned, so we can do it all at once. - uint32_t *p = (uint32_t*)LocalAddress; - // The low two bits of the value are not encoded. - Value >>= 2; - // Mask the value to 24 bits. - Value &= 0xffffff; - // FIXME: If the destination is a Thumb function (and the instruction - // is a non-predicated BL instruction), we need to change it to a BLX - // instruction instead. - - // Insert the value into the instruction. - *p = (*p & ~0xffffff) | Value; - break; - } - case macho::RIT_ARM_ThumbBranch22Bit: - case macho::RIT_ARM_ThumbBranch32Bit: - case macho::RIT_ARM_Half: - case macho::RIT_ARM_HalfDifference: - case macho::RIT_Pair: - case macho::RIT_Difference: - case macho::RIT_ARM_LocalDifference: - case macho::RIT_ARM_PreboundLazyPointer: - return Error("Relocation type not implemented yet!"); - } - return false; -} - -void RuntimeDyldMachO::processRelocationRef(unsigned SectionID, - RelocationRef RelI, - ObjectImage &Obj, - ObjSectionToIDMap &ObjSectionToID, - const SymbolTableMap &Symbols, - StubMap &Stubs) { - const ObjectFile *OF = Obj.getObjectFile(); - const MachOObjectFile *MachO = static_cast(OF); - macho::RelocationEntry RE = MachO->getRelocation(RelI.getRawDataRefImpl()); - - uint32_t RelType = MachO->getAnyRelocationType(RE); + const MachOObjectFile &Obj = + static_cast(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RI->getRawDataRefImpl()); RelocationValueRef Value; - SectionEntry &Section = Sections[SectionID]; - - bool isExtern = MachO->getPlainRelocationExternal(RE); - bool IsPCRel = MachO->getAnyRelocationPCRel(RE); - unsigned Size = MachO->getAnyRelocationLength(RE); - if (isExtern) { - // Obtain the symbol name which is referenced in the relocation - SymbolRef Symbol; - RelI.getSymbol(Symbol); + + bool IsExternal = Obj.getPlainRelocationExternal(RelInfo); + if (IsExternal) { + symbol_iterator Symbol = RI->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; + Symbol->getName(TargetName); + SymbolTableMap::const_iterator SI = Symbols.find(TargetName.data()); + if (SI != Symbols.end()) { + Value.SectionID = SI->second.first; + Value.Addend = SI->second.second + RE.Addend; } else { - // 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; - } else + SI = GlobalSymbolTable.find(TargetName.data()); + if (SI != GlobalSymbolTable.end()) { + Value.SectionID = SI->second.first; + Value.Addend = SI->second.second + RE.Addend; + } else { Value.SymbolName = TargetName.data(); + Value.Addend = RE.Addend; + } } } else { - error_code err; - uint8_t sectionIndex = static_cast(RelType & 0xFF); - section_iterator si = Obj.begin_sections(), - se = Obj.end_sections(); - for (uint8_t i = 1; i < sectionIndex; i++) { - error_code err; - si.increment(err); - if (si == se) - break; - } - assert(si != se && "No section containing relocation!"); - Value.SectionID = findOrEmitSection(Obj, *si, true, ObjSectionToID); - Value.Addend = 0; - // FIXME: The size and type of the relocation determines if we can - // encode an Addend in the target location itself, and if so, how many - // bytes we should read in order to get it. We don't yet support doing - // that, and just assuming it's sizeof(intptr_t) is blatantly wrong. - //Value.Addend = *(const intptr_t *)Target; - if (Value.Addend) { - // The MachO addend is an offset from the current section. We need it - // to be an offset from the destination section - Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; - } + SectionRef Sec = Obj.getRelocationSection(RelInfo); + bool IsCode = false; + Sec.isText(IsCode); + Value.SectionID = findOrEmitSection(ObjImg, Sec, IsCode, ObjSectionToID); + uint64_t Addr; + Sec.getAddress(Addr); + Value.Addend = RE.Addend - Addr; } - uint64_t Offset; - RelI.getOffset(Offset); - if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { - // This is an ARM branch relocation, need to use a stub function. - - // Look up for existing stub. - StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + i->second, - RelType, 0, IsPCRel, Size); - else { - // Create a new stub function. - Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); - RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, - macho::RIT_Vanilla, Value.Addend); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, - RelType, 0, IsPCRel, Size); - Section.StubOffset += getMaxStubSize(); - } - } else { - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, - IsPCRel, Size); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); + return Value; +} + +void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef &Value, + ObjectImage &ObjImg, + const relocation_iterator &RI, + unsigned OffsetToNextPC) { + const MachOObjectFile &Obj = + static_cast(*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.Addend += 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%x", FinalAddress) + << " Value: " << format("0x%x", Value) << " Addend: " << RE.Addend + << " isPCRel: " << RE.IsPCRel << " MachoType: " << RE.RelType + << " Size: " << (1 << RE.Size) << "\n"; +} + +bool RuntimeDyldMachO::writeBytesUnaligned(uint8_t *Dst, uint64_t Value, + unsigned Size) { + + uint8_t *Src = reinterpret_cast(&Value); + // If host and target endianness match use memcpy, otherwise copy in reverse + // order. + if (IsTargetLittleEndian == sys::IsLittleEndianHost) { + if (!sys::IsLittleEndianHost) + Src += sizeof(Value) - Size; + memcpy(Dst, Src, Size); + } else { + Src += Size - 1; + for (unsigned i = 0; i < Size; ++i) + *Dst++ = *Src--; + } + + return false; +} -bool RuntimeDyldMachO::isCompatibleFormat( - const ObjectBuffer *InputBuffer) const { +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; + if (Magic == "\xFE\xED\xFA\xCE") + return true; + if (Magic == "\xCE\xFA\xED\xFE") + return true; + if (Magic == "\xFE\xED\xFA\xCF") + return true; + if (Magic == "\xCF\xFA\xED\xFE") + return true; return false; } +bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const { + return Obj->isMachO(); +} + +static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, + intptr_t DeltaForEH) { + DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText + << ", Delta for EH: " << DeltaForEH << "\n"); + uint32_t Length = *((uint32_t *)P); + P += 4; + unsigned char *Ret = P + Length; + uint32_t Offset = *((uint32_t *)P); + 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); + + // Skip the FDE address range + P += sizeof(intptr_t); + + uint8_t Augmentationsize = *P; + P += 1; + if (Augmentationsize != 0) { + intptr_t LSDA = *((intptr_t *)P); + intptr_t NewLSDA = LSDA - DeltaForEH; + *((intptr_t *)P) = NewLSDA; + } + + return Ret; +} + +static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) { + intptr_t ObjDistance = A->ObjAddress - B->ObjAddress; + intptr_t MemDistance = A->LoadAddress - B->LoadAddress; + return ObjDistance - MemDistance; +} + +void RuntimeDyldMachO::registerEHFrames() { + + if (!MemMgr) + return; + for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { + EHFrameRelatedSections &SectionInfo = UnregisteredEHFrameSections[i]; + if (SectionInfo.EHFrameSID == RTDYLD_INVALID_SECTION_ID || + SectionInfo.TextSID == RTDYLD_INVALID_SECTION_ID) + continue; + SectionEntry *Text = &Sections[SectionInfo.TextSID]; + SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID]; + SectionEntry *ExceptTab = nullptr; + if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID) + ExceptTab = &Sections[SectionInfo.ExceptTabSID]; + + intptr_t DeltaForText = computeDelta(Text, EHFrame); + intptr_t DeltaForEH = 0; + if (ExceptTab) + DeltaForEH = computeDelta(ExceptTab, EHFrame); + + unsigned char *P = EHFrame->Address; + unsigned char *End = P + EHFrame->Size; + do { + P = processFDE(P, DeltaForText, DeltaForEH); + } while (P != End); + + MemMgr->registerEHFrames(EHFrame->Address, EHFrame->LoadAddress, + EHFrame->Size); + } + UnregisteredEHFrameSections.clear(); +} + +std::unique_ptr +llvm::RuntimeDyldMachO::create(Triple::ArchType Arch, RTDyldMemoryManager *MM) { + switch (Arch) { + default: + llvm_unreachable("Unsupported target for RuntimeDyldMachO."); + break; + case Triple::arm: return make_unique(MM); + case Triple::aarch64: return make_unique(MM); + case Triple::x86: return make_unique(MM); + case Triple::x86_64: return make_unique(MM); + } +} + } // end namespace llvm