diff options
Diffstat (limited to 'llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp')
-rw-r--r-- | llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 260 |
1 files changed, 151 insertions, 109 deletions
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index d213cc93793..d95cffef03f 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -12,23 +12,27 @@ //===----------------------------------------------------------------------===// #include "RuntimeDyldELF.h" +#include "JITRegistrar.h" +#include "ObjectImageCommon.h" #include "llvm/ADT/IntervalMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" -#include "llvm/MC/MCStreamer.h" +#include "llvm/ExecutionEngine/ObjectBuffer.h" +#include "llvm/ExecutionEngine/ObjectImage.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; #define DEBUG_TYPE "dyld" +namespace { + static inline std::error_code check(std::error_code Err) { if (Err) { report_fatal_error(Err.message()); @@ -36,8 +40,6 @@ static inline std::error_code check(std::error_code Err) { return Err; } -namespace { - template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) @@ -50,12 +52,16 @@ template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { typedef typename ELFDataTypeTypedefHelper<ELFT>::value_type addr_type; + std::unique_ptr<ObjectFile> UnderlyingFile; + public: + DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, + MemoryBufferRef Wrapper, std::error_code &ec); + DyldELFObject(MemoryBufferRef Wrapper, std::error_code &ec); void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); - - void updateSymbolAddress(const SymbolRef &SymRef, uint64_t Addr); + void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr); // Methods for type inquiry through isa, cast and dyn_cast static inline bool classof(const Binary *v) { @@ -65,10 +71,42 @@ public: static inline bool classof(const ELFObjectFile<ELFT> *v) { return v->isDyldType(); } - }; +template <class ELFT> class ELFObjectImage : public ObjectImageCommon { + bool Registered; + +public: + 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) + deregisterWithDebugger(); + } + + // Subclasses can override these methods to update the image with loaded + // addresses for sections and common symbols + void updateSectionAddress(const SectionRef &Sec, uint64_t Addr) override { + static_cast<DyldELFObject<ELFT>*>(getObjectFile()) + ->updateSectionAddress(Sec, Addr); + } + + void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) override { + static_cast<DyldELFObject<ELFT>*>(getObjectFile()) + ->updateSymbolAddress(Sym, Addr); + } + void registerWithDebugger() override { + JITRegistrar::getGDBRegistrar().registerObject(*Buffer); + Registered = true; + } + void deregisterWithDebugger() override { + 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 @@ -80,6 +118,14 @@ DyldELFObject<ELFT>::DyldELFObject(MemoryBufferRef Wrapper, std::error_code &EC) } template <class ELFT> +DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, + MemoryBufferRef Wrapper, std::error_code &EC) + : ELFObjectFile<ELFT>(Wrapper, EC), + UnderlyingFile(std::move(UnderlyingFile)) { + this->isDyldELFObject = true; +} + +template <class ELFT> void DyldELFObject<ELFT>::updateSectionAddress(const SectionRef &Sec, uint64_t Addr) { DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); @@ -103,89 +149,10 @@ void DyldELFObject<ELFT>::updateSymbolAddress(const SymbolRef &SymRef, sym->st_value = static_cast<addr_type>(Addr); } -class LoadedELFObjectInfo : public RuntimeDyld::LoadedObjectInfo { -public: - LoadedELFObjectInfo(RuntimeDyldImpl &RTDyld, unsigned BeginIdx, - unsigned EndIdx) - : RuntimeDyld::LoadedObjectInfo(RTDyld, BeginIdx, EndIdx) {} - - OwningBinary<ObjectFile> - getObjectForDebug(const ObjectFile &Obj) const override; -}; - -template <typename ELFT> -std::unique_ptr<DyldELFObject<ELFT>> -createRTDyldELFObject(MemoryBufferRef Buffer, - const LoadedELFObjectInfo &L, - std::error_code &ec) { - typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename ELFDataTypeTypedefHelper<ELFT>::value_type addr_type; - - std::unique_ptr<DyldELFObject<ELFT>> Obj = - llvm::make_unique<DyldELFObject<ELFT>>(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<Elf_Shdr *>( - reinterpret_cast<const Elf_Shdr *>(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<addr_type>(SecLoadAddr); - } - } - } - - return Obj; -} - -OwningBinary<ObjectFile> createELFDebugObject(const ObjectFile &Obj, - const LoadedELFObjectInfo &L) { - assert(Obj.isELF() && "Not an ELF object file."); - - std::unique_ptr<MemoryBuffer> Buffer = - MemoryBuffer::getMemBufferCopy(Obj.getData(), Obj.getFileName()); - - std::error_code ec; - - std::unique_ptr<ObjectFile> DebugObj; - if (Obj.getBytesInAddress() == 4 && Obj.isLittleEndian()) { - typedef ELFType<support::little, 2, false> ELF32LE; - DebugObj = createRTDyldELFObject<ELF32LE>(Buffer->getMemBufferRef(), L, ec); - } else if (Obj.getBytesInAddress() == 4 && !Obj.isLittleEndian()) { - typedef ELFType<support::big, 2, false> ELF32BE; - DebugObj = createRTDyldELFObject<ELF32BE>(Buffer->getMemBufferRef(), L, ec); - } else if (Obj.getBytesInAddress() == 8 && !Obj.isLittleEndian()) { - typedef ELFType<support::big, 2, true> ELF64BE; - DebugObj = createRTDyldELFObject<ELF64BE>(Buffer->getMemBufferRef(), L, ec); - } else if (Obj.getBytesInAddress() == 8 && Obj.isLittleEndian()) { - typedef ELFType<support::little, 2, true> ELF64LE; - DebugObj = createRTDyldELFObject<ELF64LE>(Buffer->getMemBufferRef(), L, ec); - } else - llvm_unreachable("Unexpected ELF format"); - - assert(!ec && "Could not construct copy ELF object file"); - - return OwningBinary<ObjectFile>(std::move(DebugObj), std::move(Buffer)); -} - -OwningBinary<ObjectFile> -LoadedELFObjectInfo::getObjectForDebug(const ObjectFile &Obj) const { - return createELFDebugObject(Obj, *this); -} - } // namespace namespace llvm { -RuntimeDyldELF::RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} -RuntimeDyldELF::~RuntimeDyldELF() {} - void RuntimeDyldELF::registerEHFrames() { if (!MemMgr) return; @@ -213,14 +180,83 @@ void RuntimeDyldELF::deregisterEHFrames() { RegisteredEHFrameSections.clear(); } -std::unique_ptr<RuntimeDyld::LoadedObjectInfo> -RuntimeDyldELF::loadObject(const object::ObjectFile &O) { - unsigned SectionStartIdx, SectionEndIdx; - std::tie(SectionStartIdx, SectionEndIdx) = loadObjectImpl(O); - return llvm::make_unique<LoadedELFObjectInfo>(*this, SectionStartIdx, - SectionEndIdx); +ObjectImage * +RuntimeDyldELF::createObjectImageFromFile(std::unique_ptr<object::ObjectFile> ObjFile) { + if (!ObjFile) + return nullptr; + + std::error_code ec; + MemoryBufferRef Buffer = ObjFile->getMemoryBufferRef(); + + if (ObjFile->getBytesInAddress() == 4 && ObjFile->isLittleEndian()) { + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 2, false>>>( + 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), 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), 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), Buffer, ec); + return new ELFObjectImage<ELFType<support::little, 2, true>>( + nullptr, std::move(Obj)); + } else + llvm_unreachable("Unexpected ELF format"); } +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 = + std::make_pair((uint8_t)Buffer->getBufferStart()[ELF::EI_CLASS], + (uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]); + std::error_code ec; + + MemoryBufferRef Buf = Buffer->getMemBuffer(); + + if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { + auto Obj = + llvm::make_unique<DyldELFObject<ELFType<support::little, 4, false>>>( + 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>>>(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>>>( + 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() {} + void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend, @@ -579,7 +615,7 @@ void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, } // Return the .TOC. section and offset. -void RuntimeDyldELF::findPPC64TOCSection(const ObjectFile &Obj, +void RuntimeDyldELF::findPPC64TOCSection(ObjectImage &Obj, ObjSectionToIDMap &LocalSections, RelocationValueRef &Rel) { // Set a default SectionID in case we do not find a TOC section below. @@ -592,7 +628,7 @@ void RuntimeDyldELF::findPPC64TOCSection(const ObjectFile &Obj, // The TOC consists of sections .got, .toc, .tocbss, .plt in that // order. The TOC starts where the first of these sections starts. - for (section_iterator si = Obj.section_begin(), se = Obj.section_end(); + for (section_iterator si = Obj.begin_sections(), se = Obj.end_sections(); si != se; ++si) { StringRef SectionName; @@ -614,15 +650,15 @@ void RuntimeDyldELF::findPPC64TOCSection(const ObjectFile &Obj, // Returns the sections and offset associated with the ODP entry referenced // by Symbol. -void RuntimeDyldELF::findOPDEntrySection(const ObjectFile &Obj, +void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, ObjSectionToIDMap &LocalSections, RelocationValueRef &Rel) { // Get the ELF symbol value (st_value) to compare with Relocation offset in // .opd entries - for (section_iterator si = Obj.section_begin(), se = Obj.section_end(); + for (section_iterator si = Obj.begin_sections(), se = Obj.end_sections(); si != se; ++si) { section_iterator RelSecI = si->getRelocatedSection(); - if (RelSecI == Obj.section_end()) + if (RelSecI == Obj.end_sections()) continue; StringRef RelSectionName; @@ -664,7 +700,7 @@ void RuntimeDyldELF::findOPDEntrySection(const ObjectFile &Obj, if (Rel.Addend != (int64_t)TargetSymbolOffset) continue; - section_iterator tsi(Obj.section_end()); + section_iterator tsi(Obj.end_sections()); check(TargetSymbol->getSection(tsi)); bool IsCode = tsi->isText(); Rel.SectionID = findOrEmitSection(Obj, (*tsi), IsCode, LocalSections); @@ -899,8 +935,7 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, } relocation_iterator RuntimeDyldELF::processRelocationRef( - unsigned SectionID, relocation_iterator RelI, - const ObjectFile &Obj, + unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj, ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols, StubMap &Stubs) { uint64_t RelType; @@ -911,7 +946,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( // Obtain the symbol name which is referenced in the relocation StringRef TargetName; - if (Symbol != Obj.symbol_end()) + if (Symbol != Obj.end_symbols()) Symbol->getName(TargetName); DEBUG(dbgs() << "\t\tRelType: " << RelType << " Addend: " << Addend << " TargetName: " << TargetName << "\n"); @@ -919,7 +954,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( // 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.symbol_end()) { + if (Symbol != Obj.end_symbols()) { lsi = Symbols.find(TargetName.data()); Symbol->getType(SymType); } @@ -930,7 +965,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( } else { // Search for the symbol in the global symbol table SymbolTableMap::const_iterator gsi = GlobalSymbolTable.end(); - if (Symbol != Obj.symbol_end()) + if (Symbol != Obj.end_symbols()) gsi = GlobalSymbolTable.find(TargetName.data()); if (gsi != GlobalSymbolTable.end()) { Value.SectionID = gsi->second.first; @@ -942,9 +977,9 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( // 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()); + section_iterator si(Obj.end_sections()); Symbol->getSection(si); - if (si == Obj.section_end()) + if (si == Obj.end_sections()) llvm_unreachable("Symbol section not found, bad object file format!"); DEBUG(dbgs() << "\t\tThis is section symbol\n"); bool isCode = si->isText(); @@ -1100,7 +1135,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef( if (RelType == ELF::R_PPC64_REL24) { // Determine ABI variant in use for this object. unsigned AbiVariant; - Obj.getPlatformFlags(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 @@ -1460,7 +1495,7 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, uint64_t Offset) { return 0; } -void RuntimeDyldELF::finalizeLoad(const ObjectFile &Obj, +void RuntimeDyldELF::finalizeLoad(ObjectImage &ObjImg, ObjSectionToIDMap &SectionMap) { // If necessary, allocate the global offset table if (MemMgr) { @@ -1498,8 +1533,15 @@ void RuntimeDyldELF::finalizeLoad(const ObjectFile &Obj, } } -bool RuntimeDyldELF::isCompatibleFile(const object::ObjectFile &Obj) const { - return Obj.isELF(); +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 |