X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FExecutionEngine%2FRuntimeDyld%2FRuntimeDyldMachO.cpp;h=a22689a40d926adee25ed450bc15a09d913dda49;hb=41db8128a2d7d34dbca8cb1906135e0a34b2f31f;hp=b7f515d6ce658d6d01ae7184e7376b8b0c57093f;hpb=689ff9c00f4f3dcf3491778bcdbda79e19e2285d;p=oota-llvm.git diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index b7f515d6ce6..a22689a40d9 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -11,283 +11,235 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/STLExtras.h" #include "RuntimeDyldMachO.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(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, - uint32_t Type, - int64_t Addend) { - bool isPCRel = (Type >> 24) & 1; - unsigned MachoType = (Type >> 28) & 0xf; - unsigned Size = 1 << ((Type >> 25) & 3); - - 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, - Type, - Size, - Addend); - break; - case Triple::arm: // Fall through. - case Triple::thumb: - resolveARMRelocation(LocalAddress, - FinalAddress, - (uintptr_t)Value, - isPCRel, - MachoType, - Size, - Addend); - break; +int64_t RuntimeDyldMachO::memcpyAddend(const RelocationEntry &RE) const { + const SectionEntry &Section = Sections[RE.SectionID]; + 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++; } + + return Addend; } -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; +RelocationValueRef RuntimeDyldMachO::getRelocationValueRef( + ObjectImage &ObjImg, const relocation_iterator &RI, + const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID, + const SymbolTableMap &Symbols) { + + const MachOObjectFile &Obj = + static_cast(*ObjImg.getObjectFile()); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RI->getRawDataRefImpl()); + RelocationValueRef Value; + + bool IsExternal = Obj.getPlainRelocationExternal(RelInfo); + if (IsExternal) { + symbol_iterator Symbol = RI->getSymbol(); + StringRef TargetName; + Symbol->getName(TargetName); + SymbolTableMap::const_iterator SI = Symbols.find(TargetName.data()); + if (SI != Symbols.end()) { + Value.SectionID = SI->second.first; + Value.Addend = SI->second.second + RE.Addend; + } else { + SI = GlobalSymbolTable.find(TargetName.data()); + if (SI != GlobalSymbolTable.end()) { + Value.SectionID = SI->second.first; + Value.Addend = SI->second.second + RE.Addend; + } else { + Value.SymbolName = TargetName.data(); + Value.Addend = RE.Addend; + } } + } else { + SectionRef Sec = Obj.getRelocationSection(RelInfo); + bool IsCode = false; + Sec.isText(IsCode); + Value.SectionID = findOrEmitSection(ObjImg, Sec, IsCode, ObjSectionToID); + uint64_t Addr; + Sec.getAddress(Addr); + Value.Addend = RE.Addend - Addr; } - case macho::RIT_Difference: - case macho::RIT_Generic_LocalDifference: - case macho::RIT_Generic_PreboundLazyPointer: - return Error("Relocation type not implemented yet!"); - } + + return Value; } -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!"); +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; } } -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; - } +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"; +} - 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!"); +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; } -void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, - ObjectImage &Obj, - ObjSectionToIDMap &ObjSectionToID, - LocalSymbolMap &Symbols, - StubMap &Stubs) { +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; +} - uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL); - RelocationValueRef Value; - SectionEntry &Section = Sections[Rel.SectionID]; - uint8_t *Target = Section.Address + Rel.Offset; +bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const { + return Obj->isMachO(); +} - bool isExtern = (RelType >> 27) & 1; - if (isExtern) { - StringRef TargetName; - const SymbolRef &Symbol = Rel.Symbol; - Symbol.getName(TargetName); - // First look the symbol in object file symbols. - LocalSymbolMap::iterator lsi = Symbols.find(TargetName.data()); - if (lsi != Symbols.end()) { - Value.SectionID = lsi->second.first; - Value.Addend = lsi->second.second; - } else { - // Second look the symbol in global symbol table. - StringMap::iterator gsi = SymbolTable.find(TargetName.data()); - if (gsi != SymbolTable.end()) { - Value.SectionID = gsi->second.first; - Value.Addend = gsi->second.second; - } else - Value.SymbolName = TargetName.data(); - } - } 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 = *(const intptr_t *)Target; - if (Value.Addend) { - // The MachO addend is offset from the current section, we need set it - // as offset from destination section - Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; - } +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; } - if (Arch == Triple::arm && RelType == 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(Target, (uint64_t)Target, - (uint64_t)Section.Address + i->second, - RelType, 0); - else { - // Create a new stub function. - Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); - AddRelocation(Value, Rel.SectionID, StubTargetAddr - Section.Address, - macho::RIT_Vanilla); - resolveRelocation(Target, (uint64_t)Target, - (uint64_t)Section.Address + Section.StubOffset, - RelType, 0); - Section.StubOffset += getMaxStubSize(); - } - } else - AddRelocation(Value, Rel.SectionID, Rel.Offset, RelType); + 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; +} -bool RuntimeDyldMachO::isCompatibleFormat(const MemoryBuffer *InputBuffer) const { - StringRef Magic = InputBuffer->getBuffer().slice(0, 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; +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