diff options
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp')
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 175 |
1 files changed, 91 insertions, 84 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 80e489c..d95cffe 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -23,6 +23,7 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ELF.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" using namespace llvm; @@ -55,9 +56,9 @@ template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { public: DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, - std::unique_ptr<MemoryBuffer> Wrapper, std::error_code &ec); + MemoryBufferRef Wrapper, std::error_code &ec); - DyldELFObject(std::unique_ptr<MemoryBuffer> Wrapper, std::error_code &ec); + DyldELFObject(MemoryBufferRef Wrapper, std::error_code &ec); void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr); @@ -76,8 +77,10 @@ template <class ELFT> class ELFObjectImage : public ObjectImageCommon { bool Registered; public: - ELFObjectImage(ObjectBuffer *Input, std::unique_ptr<DyldELFObject<ELFT>> Obj) - : ObjectImageCommon(Input, std::move(Obj)), Registered(false) {} + ELFObjectImage(std::unique_ptr<ObjectBuffer> Input, + std::unique_ptr<DyldELFObject<ELFT>> Obj) + : ObjectImageCommon(std::move(Input), std::move(Obj)), Registered(false) { + } virtual ~ELFObjectImage() { if (Registered) @@ -109,17 +112,15 @@ public: // actual memory. Ultimately, the Binary parent class will take ownership of // this MemoryBuffer object but not the underlying memory. template <class ELFT> -DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<MemoryBuffer> Wrapper, - std::error_code &EC) - : ELFObjectFile<ELFT>(std::move(Wrapper), EC) { +DyldELFObject<ELFT>::DyldELFObject(MemoryBufferRef Wrapper, std::error_code &EC) + : ELFObjectFile<ELFT>(Wrapper, EC) { this->isDyldELFObject = true; } template <class ELFT> DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, - std::unique_ptr<MemoryBuffer> Wrapper, - std::error_code &EC) - : ELFObjectFile<ELFT>(std::move(Wrapper), EC), + MemoryBufferRef Wrapper, std::error_code &EC) + : ELFObjectFile<ELFT>(Wrapper, EC), UnderlyingFile(std::move(UnderlyingFile)) { this->isDyldELFObject = true; } @@ -185,36 +186,36 @@ RuntimeDyldELF::createObjectImageFromFile(std::unique_ptr<object::ObjectFile> Ob return nullptr; std::error_code ec; - std::unique_ptr<MemoryBuffer> Buffer( - MemoryBuffer::getMemBuffer(ObjFile->getData(), "", false)); + MemoryBufferRef Buffer = ObjFile->getMemoryBufferRef(); if (ObjFile->getBytesInAddress() == 4 && ObjFile->isLittleEndian()) { auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::little, 2, false>>>( - std::move(ObjFile), std::move(Buffer), ec); + std::move(ObjFile), Buffer, ec); return new ELFObjectImage<ELFType<support::little, 2, false>>( nullptr, std::move(Obj)); } else if (ObjFile->getBytesInAddress() == 4 && !ObjFile->isLittleEndian()) { auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 2, false>>>( - std::move(ObjFile), std::move(Buffer), ec); + std::move(ObjFile), Buffer, ec); return new ELFObjectImage<ELFType<support::big, 2, false>>(nullptr, std::move(Obj)); } else if (ObjFile->getBytesInAddress() == 8 && !ObjFile->isLittleEndian()) { auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 2, true>>>( - std::move(ObjFile), std::move(Buffer), ec); + std::move(ObjFile), Buffer, ec); return new ELFObjectImage<ELFType<support::big, 2, true>>(nullptr, std::move(Obj)); } else if (ObjFile->getBytesInAddress() == 8 && ObjFile->isLittleEndian()) { auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::little, 2, true>>>( - std::move(ObjFile), std::move(Buffer), ec); + std::move(ObjFile), Buffer, ec); return new ELFObjectImage<ELFType<support::little, 2, true>>( nullptr, std::move(Obj)); } else llvm_unreachable("Unexpected ELF format"); } -ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) { +std::unique_ptr<ObjectImage> +RuntimeDyldELF::createObjectImage(std::unique_ptr<ObjectBuffer> Buffer) { if (Buffer->getBufferSize() < ELF::EI_NIDENT) llvm_unreachable("Unexpected ELF object size"); std::pair<unsigned char, unsigned char> Ident = @@ -222,34 +223,36 @@ ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) { (uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]); std::error_code ec; - std::unique_ptr<MemoryBuffer> Buf(Buffer->getMemBuffer()); + MemoryBufferRef Buf = Buffer->getMemBuffer(); if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::little, 4, false>>>( - std::move(Buf), ec); - return new ELFObjectImage<ELFType<support::little, 4, false>>( - Buffer, std::move(Obj)); - } else if (Ident.first == ELF::ELFCLASS32 && - Ident.second == ELF::ELFDATA2MSB) { + Buf, ec); + return llvm::make_unique< + ELFObjectImage<ELFType<support::little, 4, false>>>(std::move(Buffer), + std::move(Obj)); + } + if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) { auto Obj = - llvm::make_unique<DyldELFObject<ELFType<support::big, 4, false>>>( - std::move(Buf), ec); - return new ELFObjectImage<ELFType<support::big, 4, false>>(Buffer, - std::move(Obj)); - } else if (Ident.first == ELF::ELFCLASS64 && - Ident.second == ELF::ELFDATA2MSB) { + llvm::make_unique<DyldELFObject<ELFType<support::big, 4, false>>>(Buf, + ec); + return llvm::make_unique<ELFObjectImage<ELFType<support::big, 4, false>>>( + std::move(Buffer), std::move(Obj)); + } + if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) { auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 8, true>>>( - std::move(Buf), ec); - return new ELFObjectImage<ELFType<support::big, 8, true>>(Buffer, std::move(Obj)); - } else if (Ident.first == ELF::ELFCLASS64 && - Ident.second == ELF::ELFDATA2LSB) { - auto Obj = - llvm::make_unique<DyldELFObject<ELFType<support::little, 8, true>>>( - std::move(Buf), ec); - return new ELFObjectImage<ELFType<support::little, 8, true>>(Buffer, std::move(Obj)); - } else - llvm_unreachable("Unexpected ELF format"); + Buf, ec); + return llvm::make_unique<ELFObjectImage<ELFType<support::big, 8, true>>>( + std::move(Buffer), std::move(Obj)); + } + assert(Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB && + "Unexpected ELF format"); + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 8, true>>>(Buf, + ec); + return llvm::make_unique<ELFObjectImage<ELFType<support::little, 8, true>>>( + std::move(Buffer), std::move(Obj)); } RuntimeDyldELF::~RuntimeDyldELF() {} @@ -263,10 +266,9 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, llvm_unreachable("Relocation type not implemented yet!"); break; case ELF::R_X86_64_64: { - uint64_t *Target = reinterpret_cast<uint64_t *>(Section.Address + Offset); - *Target = Value + Addend; + support::ulittle64_t::ref(Section.Address + Offset) = Value + Addend; DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " - << format("%p\n", Target)); + << format("%p\n", Section.Address + Offset)); break; } case ELF::R_X86_64_32: @@ -276,17 +278,15 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, (Type == ELF::R_X86_64_32S && ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); - uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); - *Target = TruncatedAddr; + support::ulittle32_t::ref(Section.Address + Offset) = TruncatedAddr; DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at " - << format("%p\n", Target)); + << format("%p\n", Section.Address + Offset)); break; } case ELF::R_X86_64_GOTPCREL: { // findGOTEntry returns the 'G + GOT' part of the relocation calculation // based on the load/target address of the GOT (not the current/local addr). uint64_t GOTAddr = findGOTEntry(Value, SymOffset); - uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); uint64_t FinalAddress = Section.LoadAddress + Offset; // The processRelocationRef method combines the symbol offset and the addend // and in most cases that's what we want. For this relocation type, we need @@ -294,30 +294,29 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress; assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); - *Target = TruncOffset; + support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset; break; } case ELF::R_X86_64_PC32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = - reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); - uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint64_t FinalAddress = Section.LoadAddress + Offset; - int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress; + int64_t RealOffset = Placeholder + Value + Addend - FinalAddress; assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); - *Target = TruncOffset; + support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset; break; } case ELF::R_X86_64_PC64: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint64_t *Placeholder = - reinterpret_cast<uint64_t *>(Section.ObjAddress + Offset); - uint64_t *Target = reinterpret_cast<uint64_t *>(Section.Address + Offset); + support::ulittle64_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint64_t FinalAddress = Section.LoadAddress + Offset; - *Target = *Placeholder + Value + Addend - FinalAddress; + support::ulittle64_t::ref(Section.Address + Offset) = + Placeholder + Value + Addend - FinalAddress; break; } } @@ -330,21 +329,20 @@ void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, case ELF::R_386_32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = - reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); - uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); - *Target = *Placeholder + Value + Addend; + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); + support::ulittle32_t::ref(Section.Address + Offset) = + Placeholder + Value + Addend; break; } case ELF::R_386_PC32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = - reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); - uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset); + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); - uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; - *Target = RealOffset; + uint32_t RealOffset = Placeholder + Value + Addend - FinalAddress; + support::ulittle32_t::ref(Section.Address + Offset) = RealOffset; break; } default: @@ -704,8 +702,7 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, section_iterator tsi(Obj.end_sections()); check(TargetSymbol->getSection(tsi)); - bool IsCode = false; - tsi->isText(IsCode); + bool IsCode = tsi->isText(); Rel.SectionID = findOrEmitSection(Obj, (*tsi), IsCode, LocalSections); Rel.Addend = (intptr_t)Addend; return; @@ -911,8 +908,6 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, break; case Triple::aarch64: case Triple::aarch64_be: - case Triple::arm64: - case Triple::arm64_be: resolveAArch64Relocation(Section, Offset, Value, Type, Addend); break; case Triple::arm: // Fall through. @@ -987,9 +982,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( if (si == Obj.end_sections()) llvm_unreachable("Symbol section not found, bad object file format!"); DEBUG(dbgs() << "\t\tThis is section symbol\n"); - // Default to 'true' in case isText fails (though it never does). - bool isCode = true; - si->isText(isCode); + bool isCode = si->isText(); Value.SectionID = findOrEmitSection(Obj, (*si), isCode, ObjSectionToID); Value.Addend = Addend; break; @@ -1018,8 +1011,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset << "\n"); - if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be || - Arch == Triple::arm64 || Arch == Triple::arm64_be) && + if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be) && (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26)) { // This is an AArch64 branch relocation, need to use a stub function. DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation."); @@ -1141,6 +1133,10 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( } } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { if (RelType == ELF::R_PPC64_REL24) { + // Determine ABI variant in use for this object. + unsigned AbiVariant; + Obj.getObjectFile()->getPlatformFlags(AbiVariant); + AbiVariant &= ELF::EF_PPC64_ABI; // A PPC branch relocation will need a stub function if the target is // an external symbol (Symbol::ST_Unknown) or if the target address // is not within the signed 24-bits branch address. @@ -1148,10 +1144,18 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( uint8_t *Target = Section.Address + Offset; bool RangeOverflow = false; if (SymType != SymbolRef::ST_Unknown) { - // A function call may points to the .opd entry, so the final symbol - // value - // in calculated based in the relocation values in .opd section. - findOPDEntrySection(Obj, ObjSectionToID, Value); + if (AbiVariant != 2) { + // In the ELFv1 ABI, a function call may point to the .opd entry, + // so the final symbol value is calculated based on the relocation + // values in the .opd section. + findOPDEntrySection(Obj, ObjSectionToID, Value); + } else { + // In the ELFv2 ABI, a function symbol may provide a local entry + // point, which must be used for direct calls. + uint8_t SymOther; + Symbol->getOther(SymOther); + Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther); + } uint8_t *RelocTarget = Sections[Value.SectionID].Address + Value.Addend; int32_t delta = static_cast<int32_t>(Target - RelocTarget); // If it is within 24-bits branch range, just set the branch target @@ -1179,7 +1183,8 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.StubOffset; uint8_t *StubTargetAddr = - createStubFunction(Section.Address + Section.StubOffset); + createStubFunction(Section.Address + Section.StubOffset, + AbiVariant); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, ELF::R_PPC64_ADDR64, Value.Addend); @@ -1217,9 +1222,13 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( RelType, 0); Section.StubOffset += getMaxStubSize(); } - if (SymType == SymbolRef::ST_Unknown) + if (SymType == SymbolRef::ST_Unknown) { // Restore the TOC for external calls - writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1) + if (AbiVariant == 2) + writeInt32BE(Target + 4, 0xE8410018); // ld r2,28(r1) + else + writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1) + } } } else if (RelType == ELF::R_PPC64_TOC16 || RelType == ELF::R_PPC64_TOC16_DS || @@ -1306,7 +1315,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( Stubs[Value] = StubOffset; createStubFunction((uint8_t *)StubAddress); RelocationEntry RE(SectionID, StubOffset + 8, ELF::R_390_64, - Value.Addend - Addend); + Value.Offset); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else @@ -1414,8 +1423,6 @@ size_t RuntimeDyldELF::getGOTEntrySize() { case Triple::x86_64: case Triple::aarch64: case Triple::aarch64_be: - case Triple::arm64: - case Triple::arm64_be: case Triple::ppc64: case Triple::ppc64le: case Triple::systemz: |