diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -71,6 +71,21 @@ uint32_t getELFRelativeRelocationType(uint32_t Machine); StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type); +/// This function returns the hash value for a symbol in the .dynsym section +/// Name of the API remains consistent as specified in the libelf +/// REF : http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash +inline unsigned hashSysV(StringRef SymbolName) { + unsigned h = 0, g; + for (char C : SymbolName) { + h = (h << 4) + C; + g = h & 0xf0000000L; + if (g != 0) + h ^= g >> 24; + h &= ~g; + } + return h; +} + // Subclasses of ELFFile may need this for template instantiation inline std::pair getElfArchType(StringRef Object) { @@ -380,6 +395,9 @@ Expected getSymbol(const Elf_Shdr *Sec, uint32_t Index) const; + Expected getSymbolFromHashTable(const Elf_Shdr &Sec, + StringRef Name) const; + Expected getSectionName(const Elf_Shdr &Section, WarningHandler WarnHandler = &defaultWarningHandler) const; @@ -480,6 +498,42 @@ return &Symbols[Index]; } +template +Expected +ELFFile::getSymbolFromHashTable(const Elf_Shdr &Sec, StringRef Name) const { + if (Sec.sh_type != ELF::SHT_HASH) + return createError("invalid sh_type for hash table, expected SHT_HASH"); + Expected SectionsOrError = sections(); + if (!SectionsOrError) + return SectionsOrError.takeError(); + + auto SymTabOrErr = + object::getSection(*SectionsOrError, Sec.sh_link); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + auto StrTabOrErr = getStringTableForSymtab(**SymTabOrErr, *SectionsOrError); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + + const uint32_t *HashTab = + reinterpret_cast(base() + Sec.sh_offset); + const Elf_Sym *SymTab = + reinterpret_cast(base() + (*SymTabOrErr)->sh_offset); + StringRef StrTab = *StrTabOrErr; + + const uint32_t Hash = hashSysV(Name); + const uint32_t NumBuckets = HashTab[0]; + const uint32_t *Bucket = &HashTab[2]; + const uint32_t *Chain = &HashTab[NumBuckets + 2]; + + for (uint32_t I = Bucket[Hash % NumBuckets]; I != 0; I = Chain[I]) { + if (StrTab.drop_front(SymTab[I].st_name).data() == Name) + return &SymTab[I]; + } + + return nullptr; +} + template template Expected> @@ -1208,21 +1262,6 @@ return StringRef(DotShstrtab.data() + Offset); } -/// This function returns the hash value for a symbol in the .dynsym section -/// Name of the API remains consistent as specified in the libelf -/// REF : http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash -inline unsigned hashSysV(StringRef SymbolName) { - unsigned h = 0, g; - for (char C : SymbolName) { - h = (h << 4) + C; - g = h & 0xf0000000L; - if (g != 0) - h ^= g >> 24; - h &= ~g; - } - return h; -} - } // end namespace object } // end namespace llvm diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp --- a/llvm/unittests/Object/ELFObjectFileTest.cpp +++ b/llvm/unittests/Object/ELFObjectFileTest.cpp @@ -806,3 +806,75 @@ RelocatableFileYamlString += ContentsString; DoCheck(RelocatableFileYamlString); } + +// Test for getSymbolFromHashTable: check that it returns the expected symbol +// using its associated name. +TEST(ELFObjectFileTest, SymbolFromHashTableTest) { + SmallString<0> Storage; + Expected> ElfOrErr = toBinary(Storage, R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN +Sections: + - Name: .hash + Type: SHT_HASH + Flags: [ SHF_ALLOC ] + Address: 0x100 + Link: .dynsym + AddressAlign: 0x8 + Bucket: [ 1 ] + Chain: [ 0, 2, 0 ] + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Address: 0x200 + Link: .dynstr + AddressAlign: 0x8 + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Address: 0x300 + AddressAlign: 0x1 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x2000 + AddressAlign: 0x4 + Content: DEADBEEFDEADBEEF +DynamicSymbols: + - Name: y + Type: STT_OBJECT + Section: .data + Binding: STB_GLOBAL + Value: 0x2004 + Size: 0x4 + - Name: x + Type: STT_OBJECT + Section: .data + Binding: STB_GLOBAL + Value: 0x2000 + Size: 0x4 +)"); + + ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded()); + const ELFFile &Elf = ElfOrErr->getELFFile(); + + auto HashOrErr = Elf.getSection(/* SHT_HASH */ 1); + ASSERT_THAT_EXPECTED(HashOrErr, Succeeded()); + + auto StrTabOrErr = Elf.getSection(/* SHT_STRTAB */ 3); + ASSERT_THAT_EXPECTED(StrTabOrErr, Succeeded()); + auto ContentsOrErr = Elf.getSectionContentsAsArray(**StrTabOrErr); + ASSERT_THAT_EXPECTED(ContentsOrErr, Succeeded()); + auto StrTab = StringRef(ContentsOrErr->begin(), ContentsOrErr->size()); + + for (StringRef SymbolName : {"x", "y"}) { + auto SymOrErr = Elf.getSymbolFromHashTable(**HashOrErr, SymbolName); + ASSERT_THAT_EXPECTED(SymOrErr, Succeeded()); + auto FoundSymNameOrErr = (*SymOrErr)->getName(StrTab); + ASSERT_THAT_EXPECTED(FoundSymNameOrErr, Succeeded()); + ASSERT_TRUE(*FoundSymNameOrErr == SymbolName); + } +}