X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FExecutionEngine%2FRuntimeDyld%2FRuntimeDyldELF.cpp;h=0f3ca0f2f3921551bbe4a019c313e4623cafca36;hp=a438dcd87991159f11341374cd2adf833b273521;hb=61bd005d1bad6dcea556e541fdbd31e7451b33aa;hpb=9cffedbbfd009131699c4fcbcb2f820555762812 diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index a438dcd8799..0f3ca0f2f39 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -11,208 +11,228 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "dyld" #include "RuntimeDyldELF.h" -#include "JITRegistrar.h" -#include "ObjectImageCommon.h" #include "llvm/ADT/IntervalMap.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" -#include "llvm/ExecutionEngine/ObjectBuffer.h" -#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/MC/MCStreamer.h" #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" +#include "llvm/Support/TargetRegistry.h" + using namespace llvm; using namespace llvm::object; -namespace { +#define DEBUG_TYPE "dyld" -static inline -error_code check(error_code Err) { +static inline std::error_code check(std::error_code Err) { if (Err) { report_fatal_error(Err.message()); } return Err; } -template -class DyldELFObject - : public ELFObjectFile { +namespace { + +template class DyldELFObject : public ELFObjectFile { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) typedef Elf_Shdr_Impl Elf_Shdr; typedef Elf_Sym_Impl Elf_Sym; - typedef - Elf_Rel_Impl Elf_Rel; - typedef - Elf_Rel_Impl Elf_Rela; + typedef Elf_Rel_Impl Elf_Rel; + typedef Elf_Rel_Impl Elf_Rela; typedef Elf_Ehdr_Impl Elf_Ehdr; - typedef typename ELFDataTypeTypedefHelper< - ELFT>::value_type addr_type; + typedef typename ELFDataTypeTypedefHelper::value_type addr_type; public: - DyldELFObject(MemoryBuffer *Wrapper, 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); + + void updateSymbolAddress(const SymbolRef &SymRef, uint64_t Addr); // Methods for type inquiry through isa, cast and dyn_cast static inline bool classof(const Binary *v) { - return (isa >(v) - && classof(cast >(v))); + return (isa>(v) && + classof(cast>(v))); } - static inline bool classof( - const ELFObjectFile *v) { + static inline bool classof(const ELFObjectFile *v) { return v->isDyldType(); } -}; - -template -class ELFObjectImage : public ObjectImageCommon { - protected: - DyldELFObject *DyldObj; - bool Registered; - - public: - ELFObjectImage(ObjectBuffer *Input, - DyldELFObject *Obj) - : ObjectImageCommon(Input, Obj), - DyldObj(Obj), - Registered(false) {} - - virtual ~ELFObjectImage() { - if (Registered) - deregisterWithDebugger(); - } - // 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) - { - DyldObj->updateSectionAddress(Sec, Addr); - } +}; - virtual void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) - { - DyldObj->updateSymbolAddress(Sym, Addr); - } - virtual void registerWithDebugger() - { - JITRegistrar::getGDBRegistrar().registerObject(*Buffer); - Registered = true; - } - virtual void deregisterWithDebugger() - { - JITRegistrar::getGDBRegistrar().deregisterObject(*Buffer); - } -}; // The MemoryBuffer passed into this constructor is just a wrapper around the // actual memory. Ultimately, the Binary parent class will take ownership of // this MemoryBuffer object but not the underlying memory. -template -DyldELFObject::DyldELFObject(MemoryBuffer *Wrapper, error_code &ec) - : ELFObjectFile(Wrapper, ec) { +template +DyldELFObject::DyldELFObject(MemoryBufferRef Wrapper, std::error_code &EC) + : ELFObjectFile(Wrapper, EC) { this->isDyldELFObject = true; } -template +template void DyldELFObject::updateSectionAddress(const SectionRef &Sec, uint64_t Addr) { DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); - Elf_Shdr *shdr = const_cast( - reinterpret_cast(ShdrRef.p)); + Elf_Shdr *shdr = + const_cast(reinterpret_cast(ShdrRef.p)); // This assumes the address passed in matches the target address bitness // The template-based type cast handles everything else. shdr->sh_addr = static_cast(Addr); } -template +template void DyldELFObject::updateSymbolAddress(const SymbolRef &SymRef, uint64_t Addr) { - Elf_Sym *sym = const_cast( - ELFObjectFile::getSymbol(SymRef.getRawDataRefImpl())); + Elf_Sym *sym = const_cast( + ELFObjectFile::getSymbol(SymRef.getRawDataRefImpl())); // This assumes the address passed in matches the target address bitness // The template-based type cast handles everything else. sym->st_value = static_cast(Addr); } +class LoadedELFObjectInfo : public RuntimeDyld::LoadedObjectInfo { +public: + LoadedELFObjectInfo(RuntimeDyldImpl &RTDyld, unsigned BeginIdx, + unsigned EndIdx) + : RuntimeDyld::LoadedObjectInfo(RTDyld, BeginIdx, EndIdx) {} + + OwningBinary + getObjectForDebug(const ObjectFile &Obj) const override; +}; + +template +std::unique_ptr> +createRTDyldELFObject(MemoryBufferRef Buffer, + const LoadedELFObjectInfo &L, + std::error_code &ec) { + typedef typename ELFFile::Elf_Shdr Elf_Shdr; + typedef typename ELFDataTypeTypedefHelper::value_type addr_type; + + std::unique_ptr> Obj = + llvm::make_unique>(Buffer, ec); + + // Iterate over all sections in the object. + for (const auto &Sec : Obj->sections()) { + StringRef SectionName; + Sec.getName(SectionName); + if (SectionName != "") { + DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); + Elf_Shdr *shdr = const_cast( + reinterpret_cast(ShdrRef.p)); + + if (uint64_t SecLoadAddr = L.getSectionLoadAddress(SectionName)) { + // This assumes that the address passed in matches the target address + // bitness. The template-based type cast handles everything else. + shdr->sh_addr = static_cast(SecLoadAddr); + } + } + } + + return Obj; +} + +OwningBinary createELFDebugObject(const ObjectFile &Obj, + const LoadedELFObjectInfo &L) { + assert(Obj.isELF() && "Not an ELF object file."); + + std::unique_ptr Buffer = + MemoryBuffer::getMemBufferCopy(Obj.getData(), Obj.getFileName()); + + std::error_code ec; + + std::unique_ptr DebugObj; + if (Obj.getBytesInAddress() == 4 && Obj.isLittleEndian()) { + typedef ELFType ELF32LE; + DebugObj = createRTDyldELFObject(Buffer->getMemBufferRef(), L, ec); + } else if (Obj.getBytesInAddress() == 4 && !Obj.isLittleEndian()) { + typedef ELFType ELF32BE; + DebugObj = createRTDyldELFObject(Buffer->getMemBufferRef(), L, ec); + } else if (Obj.getBytesInAddress() == 8 && !Obj.isLittleEndian()) { + typedef ELFType ELF64BE; + DebugObj = createRTDyldELFObject(Buffer->getMemBufferRef(), L, ec); + } else if (Obj.getBytesInAddress() == 8 && Obj.isLittleEndian()) { + typedef ELFType ELF64LE; + DebugObj = createRTDyldELFObject(Buffer->getMemBufferRef(), L, ec); + } else + llvm_unreachable("Unexpected ELF format"); + + assert(!ec && "Could not construct copy ELF object file"); + + return OwningBinary(std::move(DebugObj), std::move(Buffer)); +} + +OwningBinary +LoadedELFObjectInfo::getObjectForDebug(const ObjectFile &Obj) const { + return createELFDebugObject(Obj, *this); +} + } // namespace namespace llvm { -StringRef RuntimeDyldELF::getEHFrameSection() { - for (int i = 0, e = Sections.size(); i != e; ++i) { - if (Sections[i].Name == ".eh_frame") - return StringRef((const char*)Sections[i].Address, Sections[i].Size); +RuntimeDyldELF::RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} +RuntimeDyldELF::~RuntimeDyldELF() {} + +void RuntimeDyldELF::registerEHFrames() { + if (!MemMgr) + return; + for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { + SID EHFrameSID = UnregisteredEHFrameSections[i]; + uint8_t *EHFrameAddr = Sections[EHFrameSID].Address; + uint64_t EHFrameLoadAddr = Sections[EHFrameSID].LoadAddress; + size_t EHFrameSize = Sections[EHFrameSID].Size; + MemMgr->registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); + RegisteredEHFrameSections.push_back(EHFrameSID); } - return StringRef(); + UnregisteredEHFrameSections.clear(); } -ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) { - if (Buffer->getBufferSize() < ELF::EI_NIDENT) - llvm_unreachable("Unexpected ELF object size"); - std::pair Ident = std::make_pair( - (uint8_t)Buffer->getBufferStart()[ELF::EI_CLASS], - (uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]); - error_code ec; - - if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { - DyldELFObject > *Obj = - new DyldELFObject >( - Buffer->getMemBuffer(), ec); - return new ELFObjectImage >(Buffer, Obj); - } - else if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) { - DyldELFObject > *Obj = - new DyldELFObject >( - Buffer->getMemBuffer(), ec); - return new ELFObjectImage >(Buffer, Obj); +void RuntimeDyldELF::deregisterEHFrames() { + if (!MemMgr) + return; + for (int i = 0, e = RegisteredEHFrameSections.size(); i != e; ++i) { + SID EHFrameSID = RegisteredEHFrameSections[i]; + uint8_t *EHFrameAddr = Sections[EHFrameSID].Address; + uint64_t EHFrameLoadAddr = Sections[EHFrameSID].LoadAddress; + size_t EHFrameSize = Sections[EHFrameSID].Size; + MemMgr->deregisterEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); } - else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) { - DyldELFObject > *Obj = - new DyldELFObject >( - Buffer->getMemBuffer(), ec); - return new ELFObjectImage >(Buffer, Obj); - } - else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB) { - DyldELFObject > *Obj = - new DyldELFObject >( - Buffer->getMemBuffer(), ec); - return new ELFObjectImage >(Buffer, Obj); - } - else - llvm_unreachable("Unexpected ELF format"); + RegisteredEHFrameSections.clear(); } -RuntimeDyldELF::~RuntimeDyldELF() { +std::unique_ptr +RuntimeDyldELF::loadObject(const object::ObjectFile &O) { + unsigned SectionStartIdx, SectionEndIdx; + std::tie(SectionStartIdx, SectionEndIdx) = loadObjectImpl(O); + return llvm::make_unique(*this, SectionStartIdx, + SectionEndIdx); } void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, uint64_t SymOffset) { switch (Type) { default: llvm_unreachable("Relocation type not implemented yet!"); - break; + break; case ELF::R_X86_64_64: { - uint64_t *Target = reinterpret_cast(Section.Address + Offset); - *Target = Value + Addend; - DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) - << " at " << format("%p\n",Target)); + support::ulittle64_t::ref(Section.Address + Offset) = Value + Addend; + DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " + << format("%p\n", Section.Address + Offset)); break; } case ELF::R_X86_64_32: @@ -220,103 +240,94 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, Value += Addend; assert((Type == ELF::R_X86_64_32 && (Value <= UINT32_MAX)) || (Type == ELF::R_X86_64_32S && - ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); + ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); - uint32_t *Target = reinterpret_cast(Section.Address + Offset); - *Target = TruncatedAddr; - DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) - << " at " << format("%p\n",Target)); + support::ulittle32_t::ref(Section.Address + Offset) = TruncatedAddr; + DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at " + << 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(Section.Address + Offset); - uint64_t FinalAddress = Section.LoadAddress + 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 // the raw addend, so we subtract the symbol offset to get it. 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(Section.ObjAddress - + Offset); - uint32_t *Target = reinterpret_cast(Section.Address + Offset); - uint64_t FinalAddress = Section.LoadAddress + Offset; - int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress; + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); + uint64_t FinalAddress = Section.LoadAddress + Offset; + 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(Section.ObjAddress - + Offset); - uint64_t *Target = reinterpret_cast(Section.Address + Offset); - uint64_t FinalAddress = Section.LoadAddress + Offset; - *Target = *Placeholder + Value + Addend - FinalAddress; + support::ulittle64_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); + uint64_t FinalAddress = Section.LoadAddress + Offset; + support::ulittle64_t::ref(Section.Address + Offset) = + Placeholder + Value + Addend - FinalAddress; break; } } } void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend) { + uint64_t Offset, uint32_t Value, + uint32_t Type, int32_t Addend) { switch (Type) { 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(Section.ObjAddress - + Offset); - uint32_t *Target = reinterpret_cast(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(Section.ObjAddress - + Offset); - uint32_t *Target = reinterpret_cast(Section.Address + Offset); - uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); - uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; - *Target = RealOffset; + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); + uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); + uint32_t RealOffset = Placeholder + Value + Addend - FinalAddress; + support::ulittle32_t::ref(Section.Address + Offset) = RealOffset; + break; + } + default: + // There are other relocation types, but it appears these are the + // only ones currently used by the LLVM ELF object writer + llvm_unreachable("Relocation type not implemented yet!"); break; - } - default: - // There are other relocation types, but it appears these are the - // only ones currently used by the LLVM ELF object writer - llvm_unreachable("Relocation type not implemented yet!"); - break; } } void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend) { - uint32_t *TargetPtr = reinterpret_cast(Section.Address + Offset); + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + Offset); uint64_t FinalAddress = Section.LoadAddress + Offset; DEBUG(dbgs() << "resolveAArch64Relocation, LocalAddress: 0x" << format("%llx", Section.Address + Offset) - << " FinalAddress: 0x" << format("%llx",FinalAddress) - << " Value: 0x" << format("%llx",Value) - << " Type: 0x" << format("%x",Type) - << " Addend: 0x" << format("%llx",Addend) + << " FinalAddress: 0x" << format("%llx", FinalAddress) + << " Value: 0x" << format("%llx", Value) << " Type: 0x" + << format("%x", Type) << " Addend: 0x" << format("%llx", Addend) << "\n"); switch (Type) { @@ -324,7 +335,8 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, llvm_unreachable("Relocation type not implemented yet!"); break; case ELF::R_AARCH64_ABS64: { - uint64_t *TargetPtr = reinterpret_cast(Section.Address + Offset); + uint64_t *TargetPtr = + reinterpret_cast(Section.Address + Offset); *TargetPtr = Value + Addend; break; } @@ -400,35 +412,77 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, assert((*TargetPtr >> 21 & 0x3) == 0 && "invalid shift for relocation"); break; } + case ELF::R_AARCH64_ADR_PREL_PG_HI21: { + // Operation: Page(S+A) - Page(P) + uint64_t Result = + ((Value + Addend) & ~0xfffULL) - (FinalAddress & ~0xfffULL); + + // Check that -2^32 <= X < 2^32 + assert(static_cast(Result) >= (-1LL << 32) && + static_cast(Result) < (1LL << 32) && + "overflow check failed for relocation"); + + // AArch64 code is emitted with .rela relocations. The data already in any + // bits affected by the relocation on entry is garbage. + *TargetPtr &= 0x9f00001fU; + // Immediate goes in bits 30:29 + 5:23 of ADRP instruction, taken + // from bits 32:12 of X. + *TargetPtr |= ((Result & 0x3000U) << (29 - 12)); + *TargetPtr |= ((Result & 0x1ffffc000ULL) >> (14 - 5)); + break; + } + case ELF::R_AARCH64_LDST32_ABS_LO12_NC: { + // Operation: S + A + uint64_t Result = Value + Addend; + + // AArch64 code is emitted with .rela relocations. The data already in any + // bits affected by the relocation on entry is garbage. + *TargetPtr &= 0xffc003ffU; + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:2 of X + *TargetPtr |= ((Result & 0xffc) << (10 - 2)); + break; + } + case ELF::R_AARCH64_LDST64_ABS_LO12_NC: { + // Operation: S + A + uint64_t Result = Value + Addend; + + // AArch64 code is emitted with .rela relocations. The data already in any + // bits affected by the relocation on entry is garbage. + *TargetPtr &= 0xffc003ffU; + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:3 of X + *TargetPtr |= ((Result & 0xff8) << (10 - 3)); + break; + } } } void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend) { + uint64_t Offset, uint32_t Value, + uint32_t Type, int32_t Addend) { // TODO: Add Thumb relocations. - uint32_t *Placeholder = reinterpret_cast(Section.ObjAddress + - Offset); - uint32_t* TargetPtr = (uint32_t*)(Section.Address + Offset); + uint32_t *Placeholder = + reinterpret_cast(Section.ObjAddress + Offset); + uint32_t *TargetPtr = (uint32_t *)(Section.Address + Offset); uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); Value += Addend; DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " << Section.Address + Offset - << " FinalAddress: " << format("%p",FinalAddress) - << " Value: " << format("%x",Value) - << " Type: " << format("%x",Type) - << " Addend: " << format("%x",Addend) - << "\n"); + << " FinalAddress: " << format("%p", FinalAddress) << " Value: " + << format("%x", Value) << " Type: " << format("%x", Type) + << " Addend: " << format("%x", Addend) << "\n"); - switch(Type) { + switch (Type) { default: llvm_unreachable("Not implemented relocation type!"); + case ELF::R_ARM_NONE: + break; // Write a 32bit value to relocation address, taking into account the // implicit addend encoded in the target. + case ELF::R_ARM_PREL31: case ELF::R_ARM_TARGET1: case ELF::R_ARM_ABS32: *TargetPtr = *Placeholder + Value; @@ -456,8 +510,8 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, *TargetPtr |= ((Value >> 12) & 0xF) << 16; break; // Write 24 bit relative value to the branch instruction. - case ELF::R_ARM_PC24 : // Fall through. - case ELF::R_ARM_CALL : // Fall through. + case ELF::R_ARM_PC24: // Fall through. + case ELF::R_ARM_CALL: // Fall through. case ELF::R_ARM_JUMP24: { int32_t RelValue = static_cast(Value - FinalAddress - 8); RelValue = (RelValue & 0x03FFFFFC) >> 2; @@ -477,25 +531,20 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, } void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, - uint32_t Type, - int32_t Addend) { - uint32_t *Placeholder = reinterpret_cast(Section.ObjAddress + - Offset); - uint32_t* TargetPtr = (uint32_t*)(Section.Address + Offset); + uint64_t Offset, uint32_t Value, + uint32_t Type, int32_t Addend) { + uint32_t *Placeholder = + reinterpret_cast(Section.ObjAddress + Offset); + uint32_t *TargetPtr = (uint32_t *)(Section.Address + Offset); Value += Addend; DEBUG(dbgs() << "resolveMipselocation, LocalAddress: " - << Section.Address + Offset - << " FinalAddress: " - << format("%p",Section.LoadAddress + Offset) - << " Value: " << format("%x",Value) - << " Type: " << format("%x",Type) - << " Addend: " << format("%x",Addend) - << "\n"); + << Section.Address + Offset << " FinalAddress: " + << format("%p", Section.LoadAddress + Offset) << " Value: " + << format("%x", Value) << " Type: " << format("%x", Type) + << " Addend: " << format("%x", Addend) << "\n"); - switch(Type) { + switch (Type) { default: llvm_unreachable("Not implemented relocation type!"); break; @@ -503,13 +552,13 @@ void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, *TargetPtr = Value + (*Placeholder); break; case ELF::R_MIPS_26: - *TargetPtr = ((*Placeholder) & 0xfc000000) | (( Value & 0x0fffffff) >> 2); + *TargetPtr = ((*Placeholder) & 0xfc000000) | ((Value & 0x0fffffff) >> 2); break; case ELF::R_MIPS_HI16: // Get the higher 16-bits. Also add 1 if bit 15 is 1. Value += ((*Placeholder) & 0x0000ffff) << 16; - *TargetPtr = ((*Placeholder) & 0xffff0000) | - (((Value + 0x8000) >> 16) & 0xffff); + *TargetPtr = + ((*Placeholder) & 0xffff0000) | (((Value + 0x8000) >> 16) & 0xffff); break; case ELF::R_MIPS_LO16: Value += ((*Placeholder) & 0x0000ffff); @@ -520,56 +569,60 @@ void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, // are used for internal JIT purpose. These relocations are similar to // R_MIPS_HI16 and R_MIPS_LO16, but they do not take any addend into // account. - *TargetPtr = ((*TargetPtr) & 0xffff0000) | - (((Value + 0x8000) >> 16) & 0xffff); + *TargetPtr = + ((*TargetPtr) & 0xffff0000) | (((Value + 0x8000) >> 16) & 0xffff); break; case ELF::R_MIPS_UNUSED2: *TargetPtr = ((*TargetPtr) & 0xffff0000) | (Value & 0xffff); break; - } + } } -// Return the .TOC. section address to R_PPC64_TOC relocations. -uint64_t RuntimeDyldELF::findPPC64TOC() const { +// Return the .TOC. section and offset. +void RuntimeDyldELF::findPPC64TOCSection(const ObjectFile &Obj, + ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel) { + // Set a default SectionID in case we do not find a TOC section below. + // This may happen for references to TOC base base (sym@toc, .odp + // relocation) without a .toc directive. In this case just use the + // first section (which is usually the .odp) since the code won't + // reference the .toc base directly. + Rel.SymbolName = NULL; + Rel.SectionID = 0; + // The TOC consists of sections .got, .toc, .tocbss, .plt in that // order. The TOC starts where the first of these sections starts. - SectionList::const_iterator it = Sections.begin(); - SectionList::const_iterator ite = Sections.end(); - for (; it != ite; ++it) { - if (it->Name == ".got" || - it->Name == ".toc" || - it->Name == ".tocbss" || - it->Name == ".plt") + for (section_iterator si = Obj.section_begin(), se = Obj.section_end(); + si != se; ++si) { + + StringRef SectionName; + check(si->getName(SectionName)); + + if (SectionName == ".got" + || SectionName == ".toc" + || SectionName == ".tocbss" + || SectionName == ".plt") { + Rel.SectionID = findOrEmitSection(Obj, *si, false, LocalSections); break; + } } - if (it == ite) { - // This may happen for - // * references to TOC base base (sym@toc, .odp relocation) without - // a .toc directive. - // In this case just use the first section (which is usually - // the .odp) since the code won't reference the .toc base - // directly. - it = Sections.begin(); - } - assert (it != ite); + // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. - return it->LoadAddress + 0x8000; + Rel.Addend = 0x8000; } // Returns the sections and offset associated with the ODP entry referenced // by Symbol. -void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, +void RuntimeDyldELF::findOPDEntrySection(const ObjectFile &Obj, ObjSectionToIDMap &LocalSections, RelocationValueRef &Rel) { // Get the ELF symbol value (st_value) to compare with Relocation offset in // .opd entries - - error_code err; - for (section_iterator si = Obj.begin_sections(), - se = Obj.end_sections(); si != se; si.increment(err)) { + for (section_iterator si = Obj.section_begin(), se = Obj.section_end(); + si != se; ++si) { section_iterator RelSecI = si->getRelocatedSection(); - if (RelSecI == Obj.end_sections()) + if (RelSecI == Obj.section_end()) continue; StringRef RelSectionName; @@ -577,16 +630,15 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, if (RelSectionName != ".opd") continue; - for (relocation_iterator i = si->begin_relocations(), - e = si->end_relocations(); i != e;) { - check(err); - + for (relocation_iterator i = si->relocation_begin(), + e = si->relocation_end(); + i != e;) { // The R_PPC64_ADDR64 relocation indicates the first field // of a .opd entry uint64_t TypeFunc; check(i->getType(TypeFunc)); if (TypeFunc != ELF::R_PPC64_ADDR64) { - i.increment(err); + ++i; continue; } @@ -596,10 +648,9 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, int64_t Addend; check(getELFRelocationAddend(*i, Addend)); - i = i.increment(err); + ++i; if (i == e) break; - check(err); // Just check if following relocation is a R_PPC64_TOC uint64_t TypeTOC; @@ -613,9 +664,10 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, if (Rel.Addend != (int64_t)TargetSymbolOffset) continue; - section_iterator tsi(Obj.end_sections()); + section_iterator tsi(Obj.section_end()); check(TargetSymbol->getSection(tsi)); - Rel.SectionID = findOrEmitSection(Obj, (*tsi), true, LocalSections); + bool IsCode = tsi->isText(); + Rel.SectionID = findOrEmitSection(Obj, (*tsi), IsCode, LocalSections); Rel.Addend = (intptr_t)Addend; return; } @@ -623,69 +675,103 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, llvm_unreachable("Attempting to get address of ODP entry!"); } -// Relocation masks following the #lo(value), #hi(value), #higher(value), -// and #highest(value) macros defined in section 4.5.1. Relocation Types -// in PPC-elf64abi document. -// -static inline -uint16_t applyPPClo (uint64_t value) -{ - return value & 0xffff; -} +// Relocation masks following the #lo(value), #hi(value), #ha(value), +// #higher(value), #highera(value), #highest(value), and #highesta(value) +// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi +// document. + +static inline uint16_t applyPPClo(uint64_t value) { return value & 0xffff; } -static inline -uint16_t applyPPChi (uint64_t value) -{ +static inline uint16_t applyPPChi(uint64_t value) { return (value >> 16) & 0xffff; } -static inline -uint16_t applyPPChigher (uint64_t value) -{ +static inline uint16_t applyPPCha (uint64_t value) { + return ((value + 0x8000) >> 16) & 0xffff; +} + +static inline uint16_t applyPPChigher(uint64_t value) { return (value >> 32) & 0xffff; } -static inline -uint16_t applyPPChighest (uint64_t value) -{ +static inline uint16_t applyPPChighera (uint64_t value) { + return ((value + 0x8000) >> 32) & 0xffff; +} + +static inline uint16_t applyPPChighest(uint64_t value) { return (value >> 48) & 0xffff; } +static inline uint16_t applyPPChighesta (uint64_t value) { + return ((value + 0x8000) >> 48) & 0xffff; +} + void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend) { - uint8_t* LocalAddress = Section.Address + Offset; + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + uint8_t *LocalAddress = Section.Address + Offset; switch (Type) { default: llvm_unreachable("Relocation type not implemented yet!"); - break; - case ELF::R_PPC64_ADDR16_LO : - writeInt16BE(LocalAddress, applyPPClo (Value + Addend)); break; - case ELF::R_PPC64_ADDR16_HI : - writeInt16BE(LocalAddress, applyPPChi (Value + Addend)); + case ELF::R_PPC64_ADDR16: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_DS: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); + break; + case ELF::R_PPC64_ADDR16_LO: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_LO_DS: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); + break; + case ELF::R_PPC64_ADDR16_HI: + writeInt16BE(LocalAddress, applyPPChi(Value + Addend)); break; - case ELF::R_PPC64_ADDR16_HIGHER : - writeInt16BE(LocalAddress, applyPPChigher (Value + Addend)); + case ELF::R_PPC64_ADDR16_HA: + writeInt16BE(LocalAddress, applyPPCha(Value + Addend)); break; - case ELF::R_PPC64_ADDR16_HIGHEST : - writeInt16BE(LocalAddress, applyPPChighest (Value + Addend)); + case ELF::R_PPC64_ADDR16_HIGHER: + writeInt16BE(LocalAddress, applyPPChigher(Value + Addend)); break; - case ELF::R_PPC64_ADDR14 : { + case ELF::R_PPC64_ADDR16_HIGHERA: + writeInt16BE(LocalAddress, applyPPChighera(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHEST: + writeInt16BE(LocalAddress, applyPPChighest(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHESTA: + writeInt16BE(LocalAddress, applyPPChighesta(Value + Addend)); + break; + case ELF::R_PPC64_ADDR14: { assert(((Value + Addend) & 3) == 0); // Preserve the AA/LK bits in the branch instruction - uint8_t aalk = *(LocalAddress+3); + uint8_t aalk = *(LocalAddress + 3); writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc)); } break; - case ELF::R_PPC64_ADDR32 : { + case ELF::R_PPC64_REL16_LO: { + uint64_t FinalAddress = (Section.LoadAddress + Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPClo(Delta)); + } break; + case ELF::R_PPC64_REL16_HI: { + uint64_t FinalAddress = (Section.LoadAddress + Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPChi(Delta)); + } break; + case ELF::R_PPC64_REL16_HA: { + uint64_t FinalAddress = (Section.LoadAddress + Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPCha(Delta)); + } break; + case ELF::R_PPC64_ADDR32: { int32_t Result = static_cast(Value + Addend); if (SignExtend32<32>(Result) != Result) llvm_unreachable("Relocation R_PPC64_ADDR32 overflow"); writeInt32BE(LocalAddress, Result); } break; - case ELF::R_PPC64_REL24 : { + case ELF::R_PPC64_REL24: { uint64_t FinalAddress = (Section.LoadAddress + Offset); int32_t delta = static_cast(Value - FinalAddress + Addend); if (SignExtend32<24>(delta) != delta) @@ -693,7 +779,7 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, // Generates a 'bl
' instruction writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC)); } break; - case ELF::R_PPC64_REL32 : { + case ELF::R_PPC64_REL32: { uint64_t FinalAddress = (Section.LoadAddress + Offset); int32_t delta = static_cast(Value - FinalAddress + Addend); if (SignExtend32<32>(delta) != delta) @@ -705,30 +791,15 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, uint64_t Delta = Value - FinalAddress + Addend; writeInt64BE(LocalAddress, Delta); } break; - case ELF::R_PPC64_ADDR64 : + case ELF::R_PPC64_ADDR64: writeInt64BE(LocalAddress, Value + Addend); break; - case ELF::R_PPC64_TOC : - writeInt64BE(LocalAddress, findPPC64TOC()); - break; - case ELF::R_PPC64_TOC16 : { - uint64_t TOCStart = findPPC64TOC(); - Value = applyPPClo((Value + Addend) - TOCStart); - writeInt16BE(LocalAddress, applyPPClo(Value)); - } break; - case ELF::R_PPC64_TOC16_DS : { - uint64_t TOCStart = findPPC64TOC(); - Value = ((Value + Addend) - TOCStart); - writeInt16BE(LocalAddress, applyPPClo(Value)); - } break; } } void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend) { + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { uint8_t *LocalAddress = Section.Address + Offset; switch (Type) { default: @@ -788,136 +859,119 @@ void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, } void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, - uint64_t Offset, - uint64_t Value, - uint32_t Type, - int64_t Addend, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, uint64_t SymOffset) { switch (Arch) { case Triple::x86_64: resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset); break; case Triple::x86: - resolveX86Relocation(Section, Offset, - (uint32_t)(Value & 0xffffffffL), Type, + resolveX86Relocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; case Triple::aarch64: + case Triple::aarch64_be: resolveAArch64Relocation(Section, Offset, Value, Type, Addend); break; - case Triple::arm: // Fall through. + case Triple::arm: // Fall through. + case Triple::armeb: case Triple::thumb: - resolveARMRelocation(Section, Offset, - (uint32_t)(Value & 0xffffffffL), Type, + case Triple::thumbeb: + resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; - case Triple::mips: // Fall through. + case Triple::mips: // Fall through. case Triple::mipsel: - resolveMIPSRelocation(Section, Offset, - (uint32_t)(Value & 0xffffffffL), Type, - (uint32_t)(Addend & 0xffffffffL)); + resolveMIPSRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), + Type, (uint32_t)(Addend & 0xffffffffL)); break; - case Triple::ppc64: // Fall through. + case Triple::ppc64: // Fall through. case Triple::ppc64le: resolvePPC64Relocation(Section, Offset, Value, Type, Addend); break; case Triple::systemz: resolveSystemZRelocation(Section, Offset, Value, Type, Addend); break; - default: llvm_unreachable("Unsupported CPU type!"); + default: + llvm_unreachable("Unsupported CPU type!"); } } -void RuntimeDyldELF::processRelocationRef(unsigned SectionID, - RelocationRef RelI, - ObjectImage &Obj, - ObjSectionToIDMap &ObjSectionToID, - const SymbolTableMap &Symbols, - StubMap &Stubs) { +relocation_iterator RuntimeDyldELF::processRelocationRef( + unsigned SectionID, relocation_iterator RelI, + const ObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) { uint64_t RelType; - Check(RelI.getType(RelType)); + Check(RelI->getType(RelType)); int64_t Addend; - Check(getELFRelocationAddend(RelI, Addend)); - symbol_iterator Symbol = RelI.getSymbol(); + Check(getELFRelocationAddend(*RelI, Addend)); + symbol_iterator Symbol = RelI->getSymbol(); // Obtain the symbol name which is referenced in the relocation StringRef TargetName; - if (Symbol != Obj.end_symbols()) + if (Symbol != Obj.symbol_end()) Symbol->getName(TargetName); - DEBUG(dbgs() << "\t\tRelType: " << RelType - << " Addend: " << Addend - << " TargetName: " << TargetName - << "\n"); + DEBUG(dbgs() << "\t\tRelType: " << RelType << " Addend: " << Addend + << " TargetName: " << TargetName << "\n"); RelocationValueRef Value; // First search for the symbol in the local symbol table - SymbolTableMap::const_iterator lsi = Symbols.end(); SymbolRef::Type SymType = SymbolRef::ST_Unknown; - if (Symbol != Obj.end_symbols()) { - lsi = Symbols.find(TargetName.data()); + + // Search for the symbol in the global symbol table + RTDyldSymbolTable::const_iterator gsi = GlobalSymbolTable.end(); + if (Symbol != Obj.symbol_end()) { + gsi = GlobalSymbolTable.find(TargetName.data()); Symbol->getType(SymType); } - if (lsi != Symbols.end()) { - Value.SectionID = lsi->second.first; - Value.Offset = lsi->second.second; - Value.Addend = lsi->second.second + Addend; + if (gsi != GlobalSymbolTable.end()) { + const auto &SymInfo = gsi->second; + Value.SectionID = SymInfo.getSectionID(); + Value.Offset = SymInfo.getOffset(); + Value.Addend = SymInfo.getOffset() + Addend; } else { - // Search for the symbol in the global symbol table - SymbolTableMap::const_iterator gsi = GlobalSymbolTable.end(); - if (Symbol != Obj.end_symbols()) - gsi = GlobalSymbolTable.find(TargetName.data()); - if (gsi != GlobalSymbolTable.end()) { - Value.SectionID = gsi->second.first; - Value.Offset = gsi->second.second; - Value.Addend = gsi->second.second + Addend; - } else { - switch (SymType) { - case SymbolRef::ST_Debug: { - // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously - // and can be changed by another developers. Maybe best way is add - // a new symbol type ST_Section to SymbolRef and use it. - section_iterator si(Obj.end_sections()); - Symbol->getSection(si); - 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); - Value.SectionID = findOrEmitSection(Obj, - (*si), - isCode, - ObjSectionToID); - Value.Addend = Addend; - break; - } - case SymbolRef::ST_Data: - case SymbolRef::ST_Unknown: { - Value.SymbolName = TargetName.data(); - Value.Addend = Addend; - - // Absolute relocations will have a zero symbol ID (STN_UNDEF), which - // will manifest here as a NULL symbol name. - // We can set this as a valid (but empty) symbol name, and rely - // on addRelocationForSymbol to handle this. - if (!Value.SymbolName) - Value.SymbolName = ""; - break; - } - default: - llvm_unreachable("Unresolved symbol type!"); - break; - } + switch (SymType) { + case SymbolRef::ST_Debug: { + // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously + // and can be changed by another developers. Maybe best way is add + // a new symbol type ST_Section to SymbolRef and use it. + section_iterator si(Obj.section_end()); + Symbol->getSection(si); + if (si == Obj.section_end()) + llvm_unreachable("Symbol section not found, bad object file format!"); + DEBUG(dbgs() << "\t\tThis is section symbol\n"); + bool isCode = si->isText(); + Value.SectionID = findOrEmitSection(Obj, (*si), isCode, ObjSectionToID); + Value.Addend = Addend; + break; + } + case SymbolRef::ST_Data: + case SymbolRef::ST_Unknown: { + Value.SymbolName = TargetName.data(); + Value.Addend = Addend; + + // Absolute relocations will have a zero symbol ID (STN_UNDEF), which + // will manifest here as a NULL symbol name. + // We can set this as a valid (but empty) symbol name, and rely + // on addRelocationForSymbol to handle this. + if (!Value.SymbolName) + Value.SymbolName = ""; + break; + } + default: + llvm_unreachable("Unresolved symbol type!"); + break; } } + uint64_t Offset; - Check(RelI.getOffset(Offset)); + Check(RelI->getOffset(Offset)); - DEBUG(dbgs() << "\t\tSectionID: " << SectionID - << " Offset: " << Offset + DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset << "\n"); - if (Arch == Triple::aarch64 && - (RelType == ELF::R_AARCH64_CALL26 || - RelType == ELF::R_AARCH64_JUMP26)) { + 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."); SectionEntry &Section = Sections[SectionID]; @@ -925,24 +979,21 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // Look for an existing stub. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) { - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + i->second, RelType, 0); + resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, + RelType, 0); DEBUG(dbgs() << " Stub function found\n"); } else { // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset); - RelocationEntry REmovz_g3(SectionID, - StubTargetAddr - Section.Address, + RelocationEntry REmovz_g3(SectionID, StubTargetAddr - Section.Address, ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend); - RelocationEntry REmovk_g2(SectionID, - StubTargetAddr - Section.Address + 4, + RelocationEntry REmovk_g2(SectionID, StubTargetAddr - Section.Address + 4, ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend); - RelocationEntry REmovk_g1(SectionID, - StubTargetAddr - Section.Address + 8, + RelocationEntry REmovk_g1(SectionID, StubTargetAddr - Section.Address + 8, ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend); RelocationEntry REmovk_g0(SectionID, StubTargetAddr - Section.Address + 12, @@ -960,14 +1011,13 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, addRelocationForSection(REmovk_g0, Value.SectionID); } resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, - RelType, 0); + (uint64_t)Section.Address + Section.StubOffset, RelType, + 0); Section.StubOffset += getMaxStubSize(); } } else if (Arch == Triple::arm && - (RelType == ELF::R_ARM_PC24 || - RelType == ELF::R_ARM_CALL || - RelType == ELF::R_ARM_JUMP24)) { + (RelType == ELF::R_ARM_PC24 || RelType == ELF::R_ARM_CALL || + RelType == ELF::R_ARM_JUMP24)) { // This is an ARM branch relocation, need to use a stub function. DEBUG(dbgs() << "\t\tThis is an ARM branch relocation."); SectionEntry &Section = Sections[SectionID]; @@ -975,15 +1025,15 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // Look for an existing stub. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) { - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + i->second, RelType, 0); + resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, + RelType, 0); DEBUG(dbgs() << " Stub function found\n"); } else { // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, ELF::R_ARM_PRIVATE_0, Value.Addend); if (Value.SymbolName) @@ -992,8 +1042,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, addRelocationForSection(RE, Value.SectionID); resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, - RelType, 0); + (uint64_t)Section.Address + Section.StubOffset, RelType, + 0); Section.StubOffset += getMaxStubSize(); } } else if ((Arch == Triple::mipsel || Arch == Triple::mips) && @@ -1012,22 +1062,20 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // 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); + RelocationEntry RE(SectionID, Offset, RelType, i->second); + addRelocationForSection(RE, SectionID); DEBUG(dbgs() << " Stub function found\n"); } else { // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset); // Creating Hi and Lo relocations for the filled stub instructions. - RelocationEntry REHi(SectionID, - StubTargetAddr - Section.Address, + RelocationEntry REHi(SectionID, StubTargetAddr - Section.Address, ELF::R_MIPS_UNUSED1, Value.Addend); - RelocationEntry RELo(SectionID, - StubTargetAddr - Section.Address + 4, + RelocationEntry RELo(SectionID, StubTargetAddr - Section.Address + 4, ELF::R_MIPS_UNUSED2, Value.Addend); if (Value.SymbolName) { @@ -1038,13 +1086,16 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, addRelocationForSection(RELo, Value.SectionID); } - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, - RelType, 0); + RelocationEntry RE(SectionID, Offset, RelType, Section.StubOffset); + addRelocationForSection(RE, SectionID); Section.StubOffset += getMaxStubSize(); } } 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.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. @@ -1052,9 +1103,18 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, 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(Target - RelocTarget); // If it is within 24-bits branch range, just set the branch target @@ -1081,53 +1141,100 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; - uint8_t *StubTargetAddr = createStubFunction(Section.Address + - Section.StubOffset); + uint8_t *StubTargetAddr = + createStubFunction(Section.Address + Section.StubOffset, + AbiVariant); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, ELF::R_PPC64_ADDR64, Value.Addend); // Generates the 64-bits address loads as exemplified in section - // 4.5.1 in PPC64 ELF ABI. - RelocationEntry REhst(SectionID, - StubTargetAddr - Section.Address + 2, + // 4.5.1 in PPC64 ELF ABI. Note that the relocations need to + // apply to the low part of the instructions, so we have to update + // the offset according to the target endianness. + uint64_t StubRelocOffset = StubTargetAddr - Section.Address; + if (!IsTargetLittleEndian) + StubRelocOffset += 2; + + RelocationEntry REhst(SectionID, StubRelocOffset + 0, ELF::R_PPC64_ADDR16_HIGHEST, Value.Addend); - RelocationEntry REhr(SectionID, - StubTargetAddr - Section.Address + 6, + RelocationEntry REhr(SectionID, StubRelocOffset + 4, ELF::R_PPC64_ADDR16_HIGHER, Value.Addend); - RelocationEntry REh(SectionID, - StubTargetAddr - Section.Address + 14, + RelocationEntry REh(SectionID, StubRelocOffset + 12, ELF::R_PPC64_ADDR16_HI, Value.Addend); - RelocationEntry REl(SectionID, - StubTargetAddr - Section.Address + 18, + RelocationEntry REl(SectionID, StubRelocOffset + 16, ELF::R_PPC64_ADDR16_LO, Value.Addend); if (Value.SymbolName) { addRelocationForSymbol(REhst, Value.SymbolName); - addRelocationForSymbol(REhr, Value.SymbolName); - addRelocationForSymbol(REh, Value.SymbolName); - addRelocationForSymbol(REl, Value.SymbolName); + addRelocationForSymbol(REhr, Value.SymbolName); + addRelocationForSymbol(REh, Value.SymbolName); + addRelocationForSymbol(REl, Value.SymbolName); } else { addRelocationForSection(REhst, Value.SectionID); - addRelocationForSection(REhr, Value.SectionID); - addRelocationForSection(REh, Value.SectionID); - addRelocationForSection(REl, Value.SectionID); + addRelocationForSection(REhr, Value.SectionID); + addRelocationForSection(REh, Value.SectionID); + addRelocationForSection(REl, Value.SectionID); } resolveRelocation(Section, Offset, (uint64_t)Section.Address + Section.StubOffset, RelType, 0); - if (SymType == SymbolRef::ST_Unknown) - // Restore the TOC for external calls - writeInt32BE(Target+4, 0xE8410028); // ld r2,40(r1) Section.StubOffset += getMaxStubSize(); } + if (SymType == SymbolRef::ST_Unknown) { + // Restore the TOC for external calls + 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 || + RelType == ELF::R_PPC64_TOC16_LO || + RelType == ELF::R_PPC64_TOC16_LO_DS || + RelType == ELF::R_PPC64_TOC16_HI || + RelType == ELF::R_PPC64_TOC16_HA) { + // These relocations are supposed to subtract the TOC address from + // the final value. This does not fit cleanly into the RuntimeDyld + // scheme, since there may be *two* sections involved in determining + // the relocation value (the section of the symbol refered to by the + // relocation, and the TOC section associated with the current module). + // + // Fortunately, these relocations are currently only ever generated + // refering to symbols that themselves reside in the TOC, which means + // that the two sections are actually the same. Thus they cancel out + // and we can immediately resolve the relocation right now. + switch (RelType) { + case ELF::R_PPC64_TOC16: RelType = ELF::R_PPC64_ADDR16; break; + case ELF::R_PPC64_TOC16_DS: RelType = ELF::R_PPC64_ADDR16_DS; break; + case ELF::R_PPC64_TOC16_LO: RelType = ELF::R_PPC64_ADDR16_LO; break; + case ELF::R_PPC64_TOC16_LO_DS: RelType = ELF::R_PPC64_ADDR16_LO_DS; break; + case ELF::R_PPC64_TOC16_HI: RelType = ELF::R_PPC64_ADDR16_HI; break; + case ELF::R_PPC64_TOC16_HA: RelType = ELF::R_PPC64_ADDR16_HA; break; + default: llvm_unreachable("Wrong relocation type."); + } + + RelocationValueRef TOCValue; + findPPC64TOCSection(Obj, ObjSectionToID, TOCValue); + if (Value.SymbolName || Value.SectionID != TOCValue.SectionID) + llvm_unreachable("Unsupported TOC relocation."); + Value.Addend -= TOCValue.Addend; + resolveRelocation(Sections[SectionID], Offset, Value.Addend, RelType, 0); } else { + // There are two ways to refer to the TOC address directly: either + // via a ELF::R_PPC64_TOC relocation (where both symbol and addend are + // ignored), or via any relocation that refers to the magic ".TOC." + // symbols (in which case the addend is respected). + if (RelType == ELF::R_PPC64_TOC) { + RelType = ELF::R_PPC64_ADDR64; + findPPC64TOCSection(Obj, ObjSectionToID, Value); + } else if (TargetName == ".TOC.") { + findPPC64TOCSection(Obj, ObjSectionToID, Value); + Value.Addend += Addend; + } + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); - // Extra check to avoid relocation againt empty symbols (usually - // the R_PPC64_TOC). - if (SymType != SymbolRef::ST_Unknown && TargetName.empty()) - Value.SymbolName = NULL; if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); @@ -1135,8 +1242,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, addRelocationForSection(RE, Value.SectionID); } } else if (Arch == Triple::systemz && - (RelType == ELF::R_390_PLT32DBL || - RelType == ELF::R_390_GOTENT)) { + (RelType == ELF::R_390_PLT32DBL || RelType == ELF::R_390_GOTENT)) { // Create function stubs for both PLT and GOT references, regardless of // whether the GOT reference is to data or code. The stub contains the // full address of the symbol, as needed by GOT references, and the @@ -1161,14 +1267,14 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, uintptr_t BaseAddress = uintptr_t(Section.Address); uintptr_t StubAlignment = getStubAlignment(); - StubAddress = (BaseAddress + Section.StubOffset + - StubAlignment - 1) & -StubAlignment; + StubAddress = (BaseAddress + Section.StubOffset + StubAlignment - 1) & + -StubAlignment; unsigned StubOffset = StubAddress - BaseAddress; Stubs[Value] = StubOffset; createStubFunction((uint8_t *)StubAddress); - RelocationEntry RE(SectionID, StubOffset + 8, - ELF::R_390_64, Value.Addend - Addend); + RelocationEntry RE(SectionID, StubOffset + 8, ELF::R_390_64, + Value.Offset); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else @@ -1177,15 +1283,17 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, } if (RelType == ELF::R_390_GOTENT) - resolveRelocation(Section, Offset, StubAddress + 8, - ELF::R_390_PC32DBL, Addend); + resolveRelocation(Section, Offset, StubAddress + 8, ELF::R_390_PC32DBL, + Addend); else resolveRelocation(Section, Offset, StubAddress, RelType, Addend); } else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) { - // The way the PLT relocations normally work is that the linker allocates the + // The way the PLT relocations normally work is that the linker allocates + // the // PLT and this relocation makes a PC-relative call into the PLT. The PLT - // entry will then jump to an address provided by the GOT. On first call, the - // GOT address will point back into PLT code that resolves the symbol. After + // entry will then jump to an address provided by the GOT. On first call, + // the + // GOT address will point back into PLT code that resolves the symbol. After // the first call, the GOT entry points to the actual function. // // For local functions we're ignoring all of that here and just replacing @@ -1211,8 +1319,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, uintptr_t BaseAddress = uintptr_t(Section.Address); uintptr_t StubAlignment = getStubAlignment(); - StubAddress = (BaseAddress + Section.StubOffset + - StubAlignment - 1) & -StubAlignment; + StubAddress = (BaseAddress + Section.StubOffset + StubAlignment - 1) & + -StubAlignment; unsigned StubOffset = StubAddress - BaseAddress; Stubs[Value] = StubOffset; createStubFunction((uint8_t *)StubAddress); @@ -1221,8 +1329,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, GOTEntries.push_back(Value); // Make our stub function a relative call to the GOT entry. - RelocationEntry RE(SectionID, StubOffset + 2, - ELF::R_X86_64_GOTPCREL, -4); + RelocationEntry RE(SectionID, StubOffset + 2, ELF::R_X86_64_GOTPCREL, + -4); addRelocationForSymbol(RE, Value.SymbolName); // Bump our stub offset counter @@ -1230,8 +1338,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, } // Make the target call a call into the stub table. - resolveRelocation(Section, Offset, StubAddress, - ELF::R_X86_64_PC32, Addend); + resolveRelocation(Section, Offset, StubAddress, ELF::R_X86_64_PC32, + Addend); } else { RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend, Value.Offset); @@ -1247,17 +1355,19 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, else addRelocationForSection(RE, Value.SectionID); } + return ++RelI; } void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) { - SmallVectorImpl >::iterator it; - SmallVectorImpl >::iterator end = GOTs.end(); + SmallVectorImpl>::iterator it; + SmallVectorImpl>::iterator end = GOTs.end(); for (it = GOTs.begin(); it != end; ++it) { GOTRelocations &GOTEntries = it->second; for (int i = 0, e = GOTEntries.size(); i != e; ++i) { - if (GOTEntries[i].SymbolName != 0 && GOTEntries[i].SymbolName == Name) { + if (GOTEntries[i].SymbolName != nullptr && + GOTEntries[i].SymbolName == Name) { GOTEntries[i].Offset = Addr; } } @@ -1271,6 +1381,7 @@ size_t RuntimeDyldELF::getGOTEntrySize() { switch (Arch) { case Triple::x86_64: case Triple::aarch64: + case Triple::aarch64_be: case Triple::ppc64: case Triple::ppc64le: case Triple::systemz: @@ -1283,18 +1394,19 @@ size_t RuntimeDyldELF::getGOTEntrySize() { case Triple::mipsel: Result = sizeof(uint32_t); break; - default: llvm_unreachable("Unsupported CPU type!"); + default: + llvm_unreachable("Unsupported CPU type!"); } return Result; } -uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, - uint64_t Offset) { +uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, uint64_t Offset) { const size_t GOTEntrySize = getGOTEntrySize(); - SmallVectorImpl >::const_iterator it; - SmallVectorImpl >::const_iterator end = GOTs.end(); + SmallVectorImpl>::const_iterator it; + SmallVectorImpl>::const_iterator end = + GOTs.end(); int GOTIndex = -1; for (it = GOTs.begin(); it != end; ++it) { @@ -1304,7 +1416,7 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, // Find the matching entry in our vector. uint64_t SymbolOffset = 0; for (int i = 0, e = GOTEntries.size(); i != e; ++i) { - if (GOTEntries[i].SymbolName == 0) { + if (!GOTEntries[i].SymbolName) { if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress && GOTEntries[i].Offset == Offset) { GOTIndex = i; @@ -1324,11 +1436,11 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, if (GOTIndex != -1) { if (GOTEntrySize == sizeof(uint64_t)) { - uint64_t *LocalGOTAddr = (uint64_t*)getSectionAddress(GOTSectionID); + uint64_t *LocalGOTAddr = (uint64_t *)getSectionAddress(GOTSectionID); // Fill in this entry with the address of the symbol being referenced. LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset; } else { - uint32_t *LocalGOTAddr = (uint32_t*)getSectionAddress(GOTSectionID); + uint32_t *LocalGOTAddr = (uint32_t *)getSectionAddress(GOTSectionID); // Fill in this entry with the address of the symbol being referenced. LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset); } @@ -1342,7 +1454,9 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, return 0; } -void RuntimeDyldELF::finalizeLoad() { +void RuntimeDyldELF::finalizeLoad(const ObjectFile &Obj, + ObjSectionToIDMap &SectionMap) { + // If necessary, allocate the global offset table if (MemMgr) { // Allocate the GOT if necessary size_t numGOTEntries = GOTEntries.size(); @@ -1361,15 +1475,25 @@ void RuntimeDyldELF::finalizeLoad() { // needed when GOT-based relocations are applied. memset(Addr, 0, TotalSize); } - } - else { + } else { report_fatal_error("Unable to allocate memory for GOT!"); } + + // Look for and record the EH frame section. + 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") { + UnregisteredEHFrameSections.push_back(i->second); + break; + } + } } -bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const { - if (Buffer->getBufferSize() < strlen(ELF::ElfMagic)) - return false; - return (memcmp(Buffer->getBufferStart(), ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0; +bool RuntimeDyldELF::isCompatibleFile(const object::ObjectFile &Obj) const { + return Obj.isELF(); } + } // namespace llvm