From c22eb2bea61c3099eab67d2f32771fc7112992cd Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 21 Jul 2015 20:50:53 +0000 Subject: [PATCH 1/1] Don't iterate over the program headers in the constructor of ELFFile. Not every program needs this information. In particular, it is necessary and sufficient for a static linker to scan the section table. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242833 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/ELF.h | 170 ++------------------------- tools/llvm-readobj/ELFDumper.cpp | 190 ++++++++++++++++++++++++++----- 2 files changed, 172 insertions(+), 188 deletions(-) diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 4f7adbfa83e..775403c23df 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -157,23 +157,22 @@ public: typedef iterator_range Elf_Sym_Range; + const uint8_t *base() const { + return reinterpret_cast(Buf.data()); + } + private: typedef SmallVector Sections_t; typedef DenseMap IndexMap_t; StringRef Buf; - const uint8_t *base() const { - return reinterpret_cast(Buf.data()); - } - const Elf_Ehdr *Header; const Elf_Shdr *SectionHeaderTable = nullptr; StringRef DotShstrtab; // Section header string table. StringRef DotStrtab; // Symbol header string table. const Elf_Shdr *dot_symtab_sec = nullptr; // Symbol table section. const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. - const Elf_Hash *HashTable = nullptr; const Elf_Shdr *SymbolTableSectionHeaderIndex = nullptr; DenseMap ExtendedSymbolTable; @@ -182,24 +181,6 @@ private: const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d - /// \brief Represents a region described by entries in the .dynamic table. - struct DynRegionInfo { - DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} - /// \brief Address in current address space. - const void *Addr; - /// \brief Size in bytes of the region. - uintX_t Size; - /// \brief Size of each entity in the region. - uintX_t EntSize; - }; - - DynRegionInfo DynamicRegion; - DynRegionInfo DynStrRegion; - DynRegionInfo DynRelaRegion; - - // SONAME entry in dynamic string table - StringRef DTSoname; - // Records for each version index the corresponding Verdef or Vernaux entry. // This is filled the first time LoadVersionMap() is called. class VersionMapEntry : public PointerIntPair { @@ -226,8 +207,6 @@ private: void LoadVersionNeeds(const Elf_Shdr *ec) const; void LoadVersionMap() const; - void scanDynamicTable(); - public: template const T *getEntry(uint32_t Section, uint32_t Entry) const; @@ -236,16 +215,11 @@ public: const Elf_Shdr *getDotSymtabSec() const { return dot_symtab_sec; } const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } - const Elf_Hash *getHashTable() const { return HashTable; } - StringRef getDynamicStringTable() const { - return StringRef((const char *)DynStrRegion.Addr, DynStrRegion.Size); - } ErrorOr getStringTable(const Elf_Shdr *Section) const; ErrorOr getStringTableForSymtab(const Elf_Shdr &Section) const; - const char *getDynamicString(uintX_t Offset) const; - ErrorOr getSymbolVersion(const Elf_Sym *Symb, + ErrorOr getSymbolVersion(StringRef StrTab, const Elf_Sym *Symb, bool &IsDefault) const; void VerifyStrTab(const Elf_Shdr *sh) const; @@ -283,12 +257,6 @@ public: return make_range(symbol_begin(), symbol_end()); } - const Elf_Dyn *dynamic_table_begin() const; - const Elf_Dyn *dynamic_table_end() const; - Elf_Dyn_Range dynamic_table() const { - return make_range(dynamic_table_begin(), dynamic_table_end()); - } - const Elf_Sym *dynamic_symbol_begin() const { if (!DotDynSymSec) return nullptr; @@ -308,25 +276,8 @@ public: return make_range(dynamic_symbol_begin(), dynamic_symbol_end()); } - const Elf_Rela *dyn_rela_begin() const { - if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela)) - report_fatal_error("Invalid relocation entry size"); - return reinterpret_cast(DynRelaRegion.Addr); - } - - const Elf_Rela *dyn_rela_end() const { - uint64_t Size = DynRelaRegion.Size; - if (Size % sizeof(Elf_Rela)) - report_fatal_error("Invalid relocation table size"); - return dyn_rela_begin() + Size / sizeof(Elf_Rela); - } - typedef iterator_range Elf_Rela_Range; - Elf_Rela_Range dyn_relas() const { - return make_range(dyn_rela_begin(), dyn_rela_end()); - } - const Elf_Rela *rela_begin(const Elf_Shdr *sec) const { if (sec->sh_entsize != sizeof(Elf_Rela)) report_fatal_error("Invalid relocation entry size"); @@ -389,7 +340,6 @@ public: ErrorOr getSectionName(const Elf_Shdr *Section) const; ErrorOr > getSectionContents(const Elf_Shdr *Sec) const; - StringRef getLoadName() const; }; typedef ELFFile> ELF32LEFile; @@ -596,10 +546,8 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) Header = reinterpret_cast(base()); - if (Header->e_shoff == 0) { - scanDynamicTable(); + if (Header->e_shoff == 0) return; - } const uint64_t SectionTableOffset = Header->e_shoff; @@ -624,13 +572,6 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) for (const Elf_Shdr &Sec : sections()) { switch (Sec.sh_type) { - case ELF::SHT_HASH: - if (HashTable) { - EC = object_error::parse_failed; - return; - } - HashTable = reinterpret_cast(base() + Sec.sh_offset); - break; case ELF::SHT_SYMTAB_SHNDX: if (SymbolTableSectionHeaderIndex) { // More than one .symtab_shndx! @@ -708,8 +649,6 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) } } - scanDynamicTable(); - EC = std::error_code(); } @@ -718,68 +657,6 @@ static bool compareAddr(uint64_t VAddr, const Elf_Phdr_Impl *Phdr) { return VAddr < Phdr->p_vaddr; } -template void ELFFile::scanDynamicTable() { - SmallVector LoadSegments; - for (const Elf_Phdr &Phdr : program_headers()) { - if (Phdr.p_type == ELF::PT_DYNAMIC) { - DynamicRegion.Addr = base() + Phdr.p_offset; - DynamicRegion.Size = Phdr.p_filesz; - continue; - } - if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) - continue; - LoadSegments.push_back(&Phdr); - } - - auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { - const Elf_Phdr **I = std::upper_bound( - LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr); - if (I == LoadSegments.begin()) - report_fatal_error("Virtual address is not in any segment"); - --I; - const Elf_Phdr &Phdr = **I; - uint64_t Delta = VAddr - Phdr.p_vaddr; - if (Delta >= Phdr.p_filesz) - report_fatal_error("Virtual address is not in any segment"); - return this->base() + Phdr.p_offset + Delta; - }; - - uint64_t SONameOffset = 0; - for (const Elf_Dyn &Dyn : dynamic_table()) { - switch (Dyn.d_tag) { - case ELF::DT_HASH: - if (HashTable) - continue; - HashTable = - reinterpret_cast(toMappedAddr(Dyn.getPtr())); - break; - case ELF::DT_STRTAB: - if (!DynStrRegion.Addr) - DynStrRegion.Addr = toMappedAddr(Dyn.getPtr()); - break; - case ELF::DT_STRSZ: - if (!DynStrRegion.Size) - DynStrRegion.Size = Dyn.getVal(); - break; - case ELF::DT_RELA: - if (!DynRelaRegion.Addr) - DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); - break; - case ELF::DT_RELASZ: - DynRelaRegion.Size = Dyn.getVal(); - break; - case ELF::DT_RELAENT: - DynRelaRegion.EntSize = Dyn.getVal(); - break; - case ELF::DT_SONAME: - SONameOffset = Dyn.getVal(); - break; - } - } - if (SONameOffset) - DTSoname = getDynamicString(SONameOffset); -} - template const typename ELFFile::Elf_Shdr *ELFFile::section_begin() const { if (Header->e_shentsize != sizeof(Elf_Shdr)) @@ -810,27 +687,6 @@ const typename ELFFile::Elf_Sym *ELFFile::symbol_end() const { dot_symtab_sec->sh_size); } -template -const typename ELFFile::Elf_Dyn * -ELFFile::dynamic_table_begin() const { - return reinterpret_cast(DynamicRegion.Addr); -} - -template -const typename ELFFile::Elf_Dyn * -ELFFile::dynamic_table_end() const { - uint64_t Size = DynamicRegion.Size; - if (Size % sizeof(Elf_Dyn)) - report_fatal_error("Invalid dynamic table size"); - - return dynamic_table_begin() + Size / sizeof(Elf_Dyn); -} - -template -StringRef ELFFile::getLoadName() const { - return DTSoname; -} - template template const T *ELFFile::getEntry(uint32_t Section, uint32_t Entry) const { @@ -886,13 +742,6 @@ ELFFile::getStringTableForSymtab(const Elf_Shdr &Sec) const { return getStringTable(*SectionOrErr); } -template -const char *ELFFile::getDynamicString(uintX_t Offset) const { - if (Offset >= DynStrRegion.Size) - return nullptr; - return (const char *)DynStrRegion.Addr + Offset; -} - template ErrorOr ELFFile::getSectionName(const Elf_Shdr *Section) const { @@ -903,7 +752,8 @@ ELFFile::getSectionName(const Elf_Shdr *Section) const { } template -ErrorOr ELFFile::getSymbolVersion(const Elf_Sym *symb, +ErrorOr ELFFile::getSymbolVersion(StringRef StrTab, + const Elf_Sym *symb, bool &IsDefault) const { // This is a dynamic symbol. Look in the GNU symbol version table. if (!dot_gnu_version_sec) { @@ -951,9 +801,9 @@ ErrorOr ELFFile::getSymbolVersion(const Elf_Sym *symb, IsDefault = false; } - if (name_offset >= DynStrRegion.Size) + if (name_offset >= StrTab.size()) return object_error::parse_failed; - return StringRef(getDynamicString(name_offset)); + return StringRef(StrTab.data() + name_offset); } /// This function returns the hash value for a symbol in the .dynsym section diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 787b485972a..8074a35ed46 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -42,8 +42,7 @@ namespace { template class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFFile *Obj, StreamWriter &Writer) - : ObjDumper(Writer), Obj(Obj) {} + ELFDumper(const ELFFile *Obj, StreamWriter &Writer); void printFileHeaders() override; void printSections() override; @@ -70,6 +69,24 @@ private: typedef ELFFile ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; + typedef typename ELFO::Elf_Dyn Elf_Dyn; + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; + typedef typename ELFO::Elf_Rela Elf_Rela; + typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range; + typedef typename ELFO::Elf_Phdr Elf_Phdr; + typedef typename ELFO::Elf_Hash Elf_Hash; + typedef typename ELFO::uintX_t uintX_t; + + /// \brief Represents a region described by entries in the .dynamic table. + struct DynRegionInfo { + DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} + /// \brief Address in current address space. + const void *Addr; + /// \brief Size in bytes of the region. + uintX_t Size; + /// \brief Size of each entity in the region. + uintX_t EntSize; + }; void printSymbol(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic); @@ -77,7 +94,22 @@ private: void printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel); void printValue(uint64_t Type, uint64_t Value); + const Elf_Rela *dyn_rela_begin() const; + const Elf_Rela *dyn_rela_end() const; + Elf_Rela_Range dyn_relas() const; + StringRef getDynamicString(uint64_t Offset) const; + const Elf_Dyn *dynamic_table_begin() const; + const Elf_Dyn *dynamic_table_end() const; + Elf_Dyn_Range dynamic_table() const { + return make_range(dynamic_table_begin(), dynamic_table_end()); + } + const ELFO *Obj; + DynRegionInfo DynRelaRegion; + DynRegionInfo DynamicRegion; + StringRef DynamicStringTable; + StringRef SOName; + const Elf_Hash *HashTable = nullptr; }; template T errorOrDefault(ErrorOr Val, T Default = T()) { @@ -135,7 +167,8 @@ static std::string getFullSymbolName(const ELFO &Obj, std::string FullSymbolName(SymbolName); bool IsDefault; - ErrorOr Version = Obj.getSymbolVersion(&*Symbol, IsDefault); + ErrorOr Version = + Obj.getSymbolVersion(StrTable, &*Symbol, IsDefault); if (Version) { FullSymbolName += (IsDefault ? "@@" : "@"); FullSymbolName += *Version; @@ -566,6 +599,108 @@ static const EnumEntry ElfHeaderMipsFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6) }; +template +ELFDumper::ELFDumper(const ELFFile *Obj, StreamWriter &Writer) + : ObjDumper(Writer), Obj(Obj) { + + SmallVector LoadSegments; + for (const Elf_Phdr &Phdr : Obj->program_headers()) { + if (Phdr.p_type == ELF::PT_DYNAMIC) { + DynamicRegion.Addr = Obj->base() + Phdr.p_offset; + uint64_t Size = Phdr.p_filesz; + if (Size % sizeof(Elf_Dyn)) + report_fatal_error("Invalid dynamic table size"); + DynamicRegion.Size = Phdr.p_filesz; + continue; + } + if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) + continue; + LoadSegments.push_back(&Phdr); + } + + auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { + const Elf_Phdr **I = std::upper_bound( + LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr); + if (I == LoadSegments.begin()) + report_fatal_error("Virtual address is not in any segment"); + --I; + const Elf_Phdr &Phdr = **I; + uint64_t Delta = VAddr - Phdr.p_vaddr; + if (Delta >= Phdr.p_filesz) + report_fatal_error("Virtual address is not in any segment"); + return Obj->base() + Phdr.p_offset + Delta; + }; + + uint64_t SONameOffset = 0; + const char *StringTableBegin = nullptr; + uint64_t StringTableSize = 0; + for (const Elf_Dyn &Dyn : dynamic_table()) { + switch (Dyn.d_tag) { + case ELF::DT_HASH: + HashTable = + reinterpret_cast(toMappedAddr(Dyn.getPtr())); + break; + case ELF::DT_RELA: + DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_RELASZ: + DynRelaRegion.Size = Dyn.getVal(); + break; + case ELF::DT_RELAENT: + DynRelaRegion.EntSize = Dyn.getVal(); + break; + case ELF::DT_SONAME: + SONameOffset = Dyn.getVal(); + break; + case ELF::DT_STRTAB: + StringTableBegin = (const char *)toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_STRSZ: + StringTableSize = Dyn.getVal(); + break; + } + } + if (StringTableBegin) + DynamicStringTable = StringRef(StringTableBegin, StringTableSize); + if (SONameOffset) + SOName = getDynamicString(SONameOffset); +} + +template +const typename ELFDumper::Elf_Rela * +ELFDumper::dyn_rela_begin() const { + if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast(DynRelaRegion.Addr); +} + +template +const typename ELFDumper::Elf_Rela * +ELFDumper::dyn_rela_end() const { + uint64_t Size = DynRelaRegion.Size; + if (Size % sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation table size"); + return dyn_rela_begin() + Size / sizeof(Elf_Rela); +} + +template +typename ELFDumper::Elf_Rela_Range ELFDumper::dyn_relas() const { + return make_range(dyn_rela_begin(), dyn_rela_end()); +} + +template +const typename ELFDumper::Elf_Dyn * +ELFDumper::dynamic_table_begin() const { + return reinterpret_cast(DynamicRegion.Addr); +} + +template +const typename ELFDumper::Elf_Dyn * +ELFDumper::dynamic_table_end() const { + uint64_t Size = DynamicRegion.Size; + return dynamic_table_begin() + Size / sizeof(Elf_Dyn); +} + template void ELFDumper::printFileHeaders() { const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); @@ -695,14 +830,13 @@ template void ELFDumper::printDynamicRelocations() { W.startLine() << "Dynamic Relocations {\n"; W.indent(); - StringRef StringTable = Obj->getDynamicStringTable(); - for (const typename ELFO::Elf_Rela &Rel : Obj->dyn_relas()) { + for (const typename ELFO::Elf_Rela &Rel : dyn_relas()) { SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef SymbolName; uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); const typename ELFO::Elf_Sym *Sym = Obj->dynamic_symbol_begin() + SymIndex; - SymbolName = errorOrDefault(Sym->getName(StringTable)); + SymbolName = errorOrDefault(Sym->getName(DynamicStringTable)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); W.printHex("Offset", Rel.r_offset); @@ -960,11 +1094,10 @@ void printFlags(T Value, ArrayRef> Flags, raw_ostream &OS) { } template -static const char *getDynamicString(const ELFFile &O, uint64_t Value) { - const char *Ret = O.getDynamicString(Value); - if (!Ret) +StringRef ELFDumper::getDynamicString(uint64_t Value) const { + if (Value >= DynamicStringTable.size()) reportError("Invalid dynamic string table reference"); - return Ret; + return StringRef(DynamicStringTable.data() + Value); } template @@ -1025,14 +1158,14 @@ void ELFDumper::printValue(uint64_t Type, uint64_t Value) { OS << Value << " (bytes)"; break; case DT_NEEDED: - OS << "SharedLibrary (" << getDynamicString(*Obj, Value) << ")"; + OS << "SharedLibrary (" << getDynamicString(Value) << ")"; break; case DT_SONAME: - OS << "LibrarySoname (" << getDynamicString(*Obj, Value) << ")"; + OS << "LibrarySoname (" << getDynamicString(Value) << ")"; break; case DT_RPATH: case DT_RUNPATH: - OS << getDynamicString(*Obj, Value); + OS << getDynamicString(Value); break; case DT_MIPS_FLAGS: printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); @@ -1067,8 +1200,8 @@ template <> void ELFDumper>::printUnwindInfo() { template void ELFDumper::printDynamicTable() { - auto I = Obj->dynamic_table_begin(); - auto E = Obj->dynamic_table_end(); + auto I = dynamic_table_begin(); + auto E = dynamic_table_end(); if (I == E) return; @@ -1113,9 +1246,9 @@ void ELFDumper::printNeededLibraries() { typedef std::vector LibsTy; LibsTy Libs; - for (const auto &Entry : Obj->dynamic_table()) + for (const auto &Entry : dynamic_table()) if (Entry.d_tag == ELF::DT_NEEDED) - Libs.push_back(getDynamicString(*Obj, Entry.d_un.d_val)); + Libs.push_back(getDynamicString(Entry.d_un.d_val)); std::stable_sort(Libs.begin(), Libs.end()); @@ -1146,17 +1279,16 @@ void ELFDumper::printProgramHeaders() { template void ELFDumper::printHashTable() { DictScope D(W, "HashTable"); - auto HT = Obj->getHashTable(); - if (!HT) + if (!HashTable) return; - W.printNumber("Num Buckets", HT->nbucket); - W.printNumber("Num Chains", HT->nchain); - W.printList("Buckets", HT->buckets()); - W.printList("Chains", HT->chains()); + W.printNumber("Num Buckets", HashTable->nbucket); + W.printNumber("Num Chains", HashTable->nchain); + W.printList("Buckets", HashTable->buckets()); + W.printList("Chains", HashTable->chains()); } template void ELFDumper::printLoadName() { - outs() << "LoadName: " << Obj->getLoadName() << '\n'; + outs() << "LoadName: " << SOName << '\n'; } template @@ -1201,8 +1333,9 @@ public: typedef object::ELFFile ObjectFile; typedef typename ObjectFile::Elf_Shdr Elf_Shdr; typedef typename ObjectFile::Elf_Sym Elf_Sym; + typedef typename ObjectFile::Elf_Dyn_Range Elf_Dyn_Range; - MipsGOTParser(const ObjectFile *Obj, StreamWriter &W); + MipsGOTParser(const ObjectFile *Obj, Elf_Dyn_Range DynTable, StreamWriter &W); void parseGOT(); void parsePLT(); @@ -1235,9 +1368,10 @@ private: } template -MipsGOTParser::MipsGOTParser(const ObjectFile *Obj, StreamWriter &W) +MipsGOTParser::MipsGOTParser(const ObjectFile *Obj, + Elf_Dyn_Range DynTable, StreamWriter &W) : Obj(Obj), W(W) { - for (const auto &Entry : Obj->dynamic_table()) { + for (const auto &Entry : DynTable) { switch (Entry.getTag()) { case ELF::DT_PLTGOT: DtPltGot = Entry.getVal(); @@ -1503,7 +1637,7 @@ template void ELFDumper::printMipsPLTGOT() { return; } - MipsGOTParser GOTParser(Obj, W); + MipsGOTParser GOTParser(Obj, dynamic_table(), W); GOTParser.parseGOT(); GOTParser.parsePLT(); } -- 2.34.1