Index: llvm/include/llvm/Object/ELF.h =================================================================== --- llvm/include/llvm/Object/ELF.h +++ llvm/include/llvm/Object/ELF.h @@ -128,6 +128,8 @@ Expected> getSHNDXTable(const Elf_Shdr &Section, Elf_Shdr_Range Sections) const; + Expected getDynSymtabSize() const; + StringRef getRelocationTypeName(uint32_t Type) const; void getRelocationTypeName(uint32_t Type, SmallVectorImpl &Result) const; @@ -519,6 +521,93 @@ return getStringTable(Sections[Index], WarnHandler); } +/// This function finds the number of dynamic symbols using a GNU hash table. +/// +/// @param Table The GNU hash table for .dynsym. +template +static uint64_t +getDynSymtabSizeFromGnuHash(const typename ELFT::GnuHash &Table) { + using Elf_Word = typename ELFT::Word; + if (Table.nbuckets == 0) + return Table.symndx + 1; + uint64_t LastSymIdx = 0; + // Find the index of the first symbol in the last chain. + for (Elf_Word Val : Table.buckets()) + LastSymIdx = std::max(LastSymIdx, (uint64_t)Val); + const Elf_Word *It = + reinterpret_cast(Table.values(LastSymIdx).end()); + // Locate the end of the chain to find the last symbol index. + // TODO: Might cause infinite loop Fix it. + while ((*It & 1) == 0) { + LastSymIdx++; + It++; + } + return LastSymIdx + 1; +} + +/// This function determines the number of dynamic symbols. It reads section +/// headers first. If section headers are not available, the number of +/// symbols will be inferred by parsing dynamic hash tables. +template +Expected ELFFile::getDynSymtabSize() const { + // Read .dynsym section header first if available. + Expected SectionsOrError = sections(); + if (!SectionsOrError) + return SectionsOrError.takeError(); + for (const Elf_Shdr &Sec : *SectionsOrError) { + if (Sec.sh_type == ELF::SHT_DYNSYM) { + if (Sec.sh_size % Sec.sh_entsize != 0) { + return createStringError( + object_error::parse_failed, + "malformed ELF, sh_size % sh_entsize is not 0"); + } + return Sec.sh_size / Sec.sh_entsize; + } + } + + if (!SectionsOrError->empty()) { + // Section headers are available but .dynsym header is not found. + // Return 0 as .dynsym does not exist. + return 0; + } + + // Section headers do not exist. Falling back to infer + // upper bound of .dynsym from .gnu.hash and .hash. + Expected DynTable = dynamicEntries(); + if (!DynTable) + return DynTable.takeError(); + llvm::Optional ElfHash; + llvm::Optional ElfGnuHash; + for (const Elf_Dyn &Entry : *DynTable) { + switch (Entry.d_tag) { + case ELF::DT_HASH: + ElfHash = Entry.d_un.d_ptr; + break; + case ELF::DT_GNU_HASH: + ElfGnuHash = Entry.d_un.d_ptr; + break; + } + } + if (ElfGnuHash) { + Expected TablePtr = toMappedAddr(*ElfGnuHash); + if (!TablePtr) + return TablePtr.takeError(); + const Elf_GnuHash *Table = + reinterpret_cast(TablePtr.get()); + return getDynSymtabSizeFromGnuHash(*Table); + } + + // Search SYSV hash table to try to find the upper bound of dynsym. + if (ElfHash) { + Expected TablePtr = toMappedAddr(*ElfHash); + if (!TablePtr) + return TablePtr.takeError(); + const Elf_Hash *Table = reinterpret_cast(TablePtr.get()); + return Table->nchain; + } + return 0; +} + template ELFFile::ELFFile(StringRef Object) : Buf(Object) {} template Index: llvm/lib/InterfaceStub/ELFObjHandler.cpp =================================================================== --- llvm/lib/InterfaceStub/ELFObjHandler.cpp +++ llvm/lib/InterfaceStub/ELFObjHandler.cpp @@ -440,62 +440,6 @@ return Error::success(); } -/// This function finds the number of dynamic symbols using a GNU hash table. -/// -/// @param Table The GNU hash table for .dynsym. -template -static uint64_t getDynSymtabSize(const typename ELFT::GnuHash &Table) { - using Elf_Word = typename ELFT::Word; - if (Table.nbuckets == 0) - return Table.symndx + 1; - uint64_t LastSymIdx = 0; - uint64_t BucketVal = 0; - // Find the index of the first symbol in the last chain. - for (Elf_Word Val : Table.buckets()) { - BucketVal = std::max(BucketVal, (uint64_t)Val); - } - LastSymIdx += BucketVal; - const Elf_Word *It = - reinterpret_cast(Table.values(BucketVal).end()); - // Locate the end of the chain to find the last symbol index. - while ((*It & 1) == 0) { - LastSymIdx++; - It++; - } - return LastSymIdx + 1; -} - -/// This function determines the number of dynamic symbols. -/// Without access to section headers, the number of symbols must be determined -/// by parsing dynamic hash tables. -/// -/// @param Dyn Entries with the locations of hash tables. -/// @param ElfFile The ElfFile that the section contents reside in. -template -static Expected getNumSyms(DynamicEntries &Dyn, - const ELFFile &ElfFile) { - using Elf_Hash = typename ELFT::Hash; - using Elf_GnuHash = typename ELFT::GnuHash; - // Search GNU hash table to try to find the upper bound of dynsym. - if (Dyn.GnuHash.hasValue()) { - Expected TablePtr = ElfFile.toMappedAddr(*Dyn.GnuHash); - if (!TablePtr) - return TablePtr.takeError(); - const Elf_GnuHash *Table = - reinterpret_cast(TablePtr.get()); - return getDynSymtabSize(*Table); - } - // Search SYSV hash table to try to find the upper bound of dynsym. - if (Dyn.ElfHash.hasValue()) { - Expected TablePtr = ElfFile.toMappedAddr(*Dyn.ElfHash); - if (!TablePtr) - return TablePtr.takeError(); - const Elf_Hash *Table = reinterpret_cast(TablePtr.get()); - return Table->nchain; - } - return 0; -} - /// This function extracts symbol type from a symbol's st_info member and /// maps it to an ELFSymbolType enum. /// Currently, STT_NOTYPE, STT_OBJECT, STT_FUNC, and STT_TLS are supported. @@ -637,7 +581,7 @@ } // Populate Symbols from .dynsym table and dynamic string table. - Expected SymCount = getNumSyms(DynEnt, ElfFile); + Expected SymCount = ElfFile.getDynSymtabSize(); if (!SymCount) return SymCount.takeError(); if (*SymCount > 0) {