Index: llvm/trunk/include/llvm/Object/ELF.h =================================================================== --- llvm/trunk/include/llvm/Object/ELF.h +++ llvm/trunk/include/llvm/Object/ELF.h @@ -53,6 +53,7 @@ typedef Elf_Vernaux_Impl Elf_Vernaux; typedef Elf_Versym_Impl Elf_Versym; typedef Elf_Hash_Impl Elf_Hash; + typedef Elf_GnuHash_Impl Elf_GnuHash; typedef iterator_range Elf_Dyn_Range; typedef iterator_range Elf_Shdr_Range; typedef iterator_range Elf_Sym_Range; Index: llvm/trunk/include/llvm/Object/ELFTypes.h =================================================================== --- llvm/trunk/include/llvm/Object/ELFTypes.h +++ llvm/trunk/include/llvm/Object/ELFTypes.h @@ -484,6 +484,30 @@ } }; +// .gnu.hash section +template +struct Elf_GnuHash_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word nbuckets; + Elf_Word symndx; + Elf_Word maskwords; + Elf_Word shift2; + + ArrayRef filter() const { + return ArrayRef(reinterpret_cast(&shift2 + 1), + maskwords); + } + + ArrayRef buckets() const { + return ArrayRef( + reinterpret_cast(filter().end()), nbuckets); + } + + ArrayRef values(unsigned DynamicSymCount) const { + return ArrayRef(buckets().end(), DynamicSymCount - symndx); + } +}; + // MIPS .reginfo section template struct Elf_Mips_RegInfo; Index: llvm/trunk/test/tools/llvm-readobj/elf-gnuhash.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/elf-gnuhash.test +++ llvm/trunk/test/tools/llvm-readobj/elf-gnuhash.test @@ -0,0 +1,63 @@ +// Check dumping of the GNU Hash section +// The input was generated using the following: +// $ llvm-mc -filetype=obj -triple=i386-pc-linux -o example-i386.o example.s +// $ llvm-mc -filetype=obj -triple=x86_64-pc-linux -o example-x86_64.o example.s +// $ llvm-mc -filetype=obj -triple=powerpc-pc-linux -o example-ppc.o example.s +// $ llvm-mc -filetype=obj -triple=powerpc64-pc-linux -o example-ppc64.o example.s +// $ ld -shared -m elf_i386 -hash-style=gnu -o gnuhash.so.elf-i386 example-i386.o +// $ ld -shared -m elf_x86_64 -hash-style=gnu -o gnuhash.so.elf-x86_64 example-x86_64.o +// $ ld -shared -m elf32ppc -hash-style=gnu -o gnuhash.so.elf-ppc example-ppc.o +// $ ld -shared -m elf64ppc -hash-style=gnu -o gnuhash.so.elf-ppc64 example-ppc64.o +// $ cat example.s +// .globl foo +// foo: + +RUN: llvm-readobj -gnu-hash-table %p/Inputs/gnuhash.so.elf-i386 | FileCheck %s -check-prefix I386 +RUN: llvm-readobj -gnu-hash-table %p/Inputs/gnuhash.so.elf-x86_64 | FileCheck %s -check-prefix X86_64 +RUN: llvm-readobj -gnu-hash-table %p/Inputs/gnuhash.so.elf-ppc | FileCheck %s -check-prefix PPC +RUN: llvm-readobj -gnu-hash-table %p/Inputs/gnuhash.so.elf-ppc64 | FileCheck %s -check-prefix PPC64 + +I386: Arch: i386 +I386: GnuHashTable { +I386-NEXT: Num Buckets: 3 +I386-NEXT: First Hashed Symbol Index: 1 +I386-NEXT: Num Mask Words: 1 +I386-NEXT: Shift Count: 5 +I386-NEXT: Bloom Filter: [0x39004608] +I386-NEXT: Buckets: [1, 4, 0] +I386-NEXT: Values: [0xB887388, 0xECD54542, 0x7C92E3BB, 0x1C5871D9] +I386-NEXT: } + +X86_64: Arch: x86_64 +X86_64: GnuHashTable { +X86_64-NEXT: Num Buckets: 3 +X86_64-NEXT: First Hashed Symbol Index: 1 +X86_64-NEXT: Num Mask Words: 1 +X86_64-NEXT: Shift Count: 6 +X86_64-NEXT: Bloom Filter: [0x800000001204288] +X86_64-NEXT: Buckets: [1, 4, 0] +X86_64-NEXT: Values: [0xB887388, 0xECD54542, 0x7C92E3BB, 0x1C5871D9] +X86_64-NEXT: } + +PPC: Arch: powerpc +PPC: GnuHashTable { +PPC-NEXT: Num Buckets: 3 +PPC-NEXT: First Hashed Symbol Index: 1 +PPC-NEXT: Num Mask Words: 1 +PPC-NEXT: Shift Count: 5 +PPC-NEXT: Bloom Filter: [0x3D00460A] +PPC-NEXT: Buckets: [1, 5, 0] +PPC-NEXT: Values: [0xEEBEC3A, 0xB887388, 0xECD54542, 0x7C92E3BB, 0x1C5871D9] +PPC-NEXT: } + +PPC64: Arch: powerpc64 +PPC64: GnuHashTable { +PPC64-NEXT: Num Buckets: 3 +PPC64-NEXT: First Hashed Symbol Index: 1 +PPC64-NEXT: Num Mask Words: 1 +PPC64-NEXT: Shift Count: 6 +PPC64-NEXT: Bloom Filter: [0x800000001204288] +PPC64-NEXT: Buckets: [1, 4, 0] +PPC64-NEXT: Values: [0xB887388, 0xECD54542, 0x7C92E3BB, 0x1C5871D9] +PPC64-NEXT: } + Index: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp +++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp @@ -56,6 +56,7 @@ void printNeededLibraries() override; void printProgramHeaders() override; void printHashTable() override; + void printGnuHashTable() override; void printLoadName() override; void printAttributes() override; @@ -76,6 +77,7 @@ 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::Elf_GnuHash Elf_GnuHash; typedef typename ELFO::Elf_Ehdr Elf_Ehdr; typedef typename ELFO::Elf_Word Elf_Word; typedef typename ELFO::uintX_t uintX_t; @@ -136,6 +138,7 @@ const Elf_Sym *DynSymStart = nullptr; StringRef SOName; const Elf_Hash *HashTable = nullptr; + const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotDynSymSec = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; ArrayRef ShndxTable; @@ -850,6 +853,10 @@ HashTable = reinterpret_cast(toMappedAddr(Dyn.getPtr())); break; + case ELF::DT_GNU_HASH: + GnuHashTable = + reinterpret_cast(toMappedAddr(Dyn.getPtr())); + break; case ELF::DT_RELA: DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); break; @@ -1533,6 +1540,23 @@ W.printList("Chains", HashTable->chains()); } +template +void ELFDumper::printGnuHashTable() { + DictScope D(W, "GnuHashTable"); + if (!GnuHashTable) + return; + W.printNumber("Num Buckets", GnuHashTable->nbuckets); + W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx); + W.printNumber("Num Mask Words", GnuHashTable->maskwords); + W.printNumber("Shift Count", GnuHashTable->shift2); + W.printHexList("Bloom Filter", GnuHashTable->filter()); + W.printList("Buckets", GnuHashTable->buckets()); + if (!DotDynSymSec) + reportError("No dynamic symbol section"); + W.printHexList("Values", + GnuHashTable->values(DotDynSymSec->getEntityCount())); +} + template void ELFDumper::printLoadName() { outs() << "LoadName: " << SOName << '\n'; } Index: llvm/trunk/tools/llvm-readobj/ObjDumper.h =================================================================== --- llvm/trunk/tools/llvm-readobj/ObjDumper.h +++ llvm/trunk/tools/llvm-readobj/ObjDumper.h @@ -39,6 +39,7 @@ virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } virtual void printHashTable() { } + virtual void printGnuHashTable() { } virtual void printLoadName() {} // Only implemented for ARM ELF at this time. Index: llvm/trunk/tools/llvm-readobj/StreamWriter.h =================================================================== --- llvm/trunk/tools/llvm-readobj/StreamWriter.h +++ llvm/trunk/tools/llvm-readobj/StreamWriter.h @@ -194,6 +194,19 @@ OS << "]\n"; } + template + void printHexList(StringRef Label, const T &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + OS << hex(Item); + Comma = true; + } + OS << "]\n"; + } + template void printHex(StringRef Label, T Value) { startLine() << Label << ": " << hex(Value) << "\n"; Index: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp +++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp @@ -132,6 +132,10 @@ cl::opt HashTable("hash-table", cl::desc("Display ELF hash table")); + // -gnu-hash-table + cl::opt GnuHashTable("gnu-hash-table", + cl::desc("Display ELF .gnu.hash section")); + // -expand-relocs cl::opt ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); @@ -322,6 +326,8 @@ Dumper->printProgramHeaders(); if (opts::HashTable) Dumper->printHashTable(); + if (opts::GnuHashTable) + Dumper->printGnuHashTable(); if (Obj->getArch() == llvm::Triple::arm && Obj->isELF()) if (opts::ARMAttributes) Dumper->printAttributes();