[llvm] r373315 - [yaml2obj/obj2yaml] - Add support for SHT_HASH sections.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 1 02:45:59 PDT 2019


Author: grimar
Date: Tue Oct  1 02:45:59 2019
New Revision: 373315

URL: http://llvm.org/viewvc/llvm-project?rev=373315&view=rev
Log:
[yaml2obj/obj2yaml] - Add support for SHT_HASH sections.

SHT_HASH specification is:
http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash

In short the format is the following: it has 2 uint32 fields
in its header: nbucket and nchain followed by (nbucket + nchain)
uint32 values.

This patch allows dumping and parsing such sections.

Differential revision: https://reviews.llvm.org/D68085

Added:
    llvm/trunk/test/tools/obj2yaml/elf-hash-section.yaml
    llvm/trunk/test/tools/yaml2obj/elf-hash-section.yaml
Modified:
    llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h
    llvm/trunk/lib/ObjectYAML/ELFEmitter.cpp
    llvm/trunk/lib/ObjectYAML/ELFYAML.cpp
    llvm/trunk/test/tools/llvm-readobj/elf-section-types.test
    llvm/trunk/test/tools/llvm-size/elf-sysv.test
    llvm/trunk/tools/obj2yaml/elf2yaml.cpp

Modified: llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h?rev=373315&r1=373314&r2=373315&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h (original)
+++ llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h Tue Oct  1 02:45:59 2019
@@ -131,6 +131,7 @@ struct Section {
     RawContent,
     Relocation,
     NoBits,
+    Hash,
     Verdef,
     Verneed,
     StackSizes,
@@ -220,6 +221,16 @@ struct NoBitsSection : Section {
   }
 };
 
+struct HashSection : Section {
+  Optional<yaml::BinaryRef> Content;
+  Optional<std::vector<uint32_t>> Bucket;
+  Optional<std::vector<uint32_t>> Chain;
+
+  HashSection() : Section(SectionKind::Hash) {}
+
+  static bool classof(const Section *S) { return S->Kind == SectionKind::Hash; }
+};
+
 struct VernauxEntry {
   uint32_t Hash;
   uint16_t Flags;

Modified: llvm/trunk/lib/ObjectYAML/ELFEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ObjectYAML/ELFEmitter.cpp?rev=373315&r1=373314&r2=373315&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/ELFEmitter.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/ELFEmitter.cpp Tue Oct  1 02:45:59 2019
@@ -171,6 +171,9 @@ template <class ELFT> class ELFState {
   void writeSectionContent(Elf_Shdr &SHeader,
                            const ELFYAML::StackSizesSection &Section,
                            ContiguousBlobAccumulator &CBA);
+  void writeSectionContent(Elf_Shdr &SHeader,
+                           const ELFYAML::HashSection &Section,
+                           ContiguousBlobAccumulator &CBA);
   ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH);
 
 public:
@@ -417,7 +420,9 @@ void ELFState<ELFT>::initSectionHeaders(
     } else if (auto S = dyn_cast<ELFYAML::VerdefSection>(Sec)) {
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::StackSizesSection>(Sec)) {
-      writeSectionContent(SHeader, *S, CBA);  
+      writeSectionContent(SHeader, *S, CBA);
+    } else if (auto S = dyn_cast<ELFYAML::HashSection>(Sec)) {
+      writeSectionContent(SHeader, *S, CBA);
     } else {
       llvm_unreachable("Unknown section type");
     }
@@ -809,6 +814,34 @@ void ELFState<ELFT>::writeSectionContent
 }
 
 template <class ELFT>
+void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
+                                         const ELFYAML::HashSection &Section,
+                                         ContiguousBlobAccumulator &CBA) {
+  raw_ostream &OS =
+      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
+
+  unsigned Link = 0;
+  if (SN2I.lookup(".dynsym", Link))
+    SHeader.sh_link = Link;
+
+  if (Section.Content) {
+    SHeader.sh_size = writeContent(OS, Section.Content, None);
+    return;
+  }
+
+  support::endian::write<uint32_t>(OS, Section.Bucket->size(),
+                                   ELFT::TargetEndianness);
+  support::endian::write<uint32_t>(OS, Section.Chain->size(),
+                                   ELFT::TargetEndianness);
+  for (uint32_t Val : *Section.Bucket)
+    support::endian::write<uint32_t>(OS, Val, ELFT::TargetEndianness);
+  for (uint32_t Val : *Section.Chain)
+    support::endian::write<uint32_t>(OS, Val, ELFT::TargetEndianness);
+
+  SHeader.sh_size = (2 + Section.Bucket->size() + Section.Chain->size()) * 4;
+}
+
+template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::VerdefSection &Section,
                                          ContiguousBlobAccumulator &CBA) {

Modified: llvm/trunk/lib/ObjectYAML/ELFYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ObjectYAML/ELFYAML.cpp?rev=373315&r1=373314&r2=373315&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/ELFYAML.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/ELFYAML.cpp Tue Oct  1 02:45:59 2019
@@ -1024,6 +1024,13 @@ static void sectionMapping(IO &IO, ELFYA
   IO.mapOptional("Entries", Section.Entries);
 }
 
+static void sectionMapping(IO &IO, ELFYAML::HashSection &Section) {
+  commonSectionMapping(IO, Section);
+  IO.mapOptional("Content", Section.Content);
+  IO.mapOptional("Bucket", Section.Bucket);
+  IO.mapOptional("Chain", Section.Chain);
+}
+
 static void sectionMapping(IO &IO, ELFYAML::NoBitsSection &Section) {
   commonSectionMapping(IO, Section);
   IO.mapOptional("Size", Section.Size, Hex64(0));
@@ -1123,6 +1130,11 @@ void MappingTraits<std::unique_ptr<ELFYA
       Section.reset(new ELFYAML::NoBitsSection());
     sectionMapping(IO, *cast<ELFYAML::NoBitsSection>(Section.get()));
     break;
+  case ELF::SHT_HASH:
+    if (!IO.outputting())
+      Section.reset(new ELFYAML::HashSection());
+    sectionMapping(IO, *cast<ELFYAML::HashSection>(Section.get()));
+    break;
   case ELF::SHT_MIPS_ABIFLAGS:
     if (!IO.outputting())
       Section.reset(new ELFYAML::MipsABIFlags());
@@ -1196,6 +1208,24 @@ StringRef MappingTraits<std::unique_ptr<
       return ".stack_sizes: Content and Entries cannot be used together";
     return {};
   }
+
+  if (const auto *HS = dyn_cast<ELFYAML::HashSection>(Section.get())) {
+    if (!HS->Content && !HS->Bucket && !HS->Chain)
+      return "one of \"Content\", \"Bucket\" or \"Chain\" must be specified";
+
+    if (HS->Content) {
+      if (HS->Bucket)
+        return "\"Content\" and \"Bucket\" cannot be used together";
+      if (HS->Chain)
+        return "\"Content\" and \"Chain\" cannot be used together";
+      return {};
+    }
+
+    if ((HS->Bucket && !HS->Chain) || (!HS->Bucket && HS->Chain))
+      return "\"Bucket\" and \"Chain\" must be used together";
+    return {};
+  }
+
   return {};
 }
 

Modified: llvm/trunk/test/tools/llvm-readobj/elf-section-types.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/elf-section-types.test?rev=373315&r1=373314&r2=373315&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/elf-section-types.test (original)
+++ llvm/trunk/test/tools/llvm-readobj/elf-section-types.test Tue Oct  1 02:45:59 2019
@@ -150,6 +150,7 @@ Sections:
     Info: progbits
   - Name: hash
     Type: SHT_HASH
+    Content: ''
   - Name: dynamic
     Type: SHT_DYNAMIC
   - Name: note

Modified: llvm/trunk/test/tools/llvm-size/elf-sysv.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-size/elf-sysv.test?rev=373315&r1=373314&r2=373315&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-size/elf-sysv.test (original)
+++ llvm/trunk/test/tools/llvm-size/elf-sysv.test Tue Oct  1 02:45:59 2019
@@ -63,6 +63,7 @@ Sections:
     Address: 0x20000
   - Name:    .hash
     Type:    SHT_HASH
+    Content: ''
     ShSize:  0x40
     Address: 0x10000
   - Name:    .dynamic

Added: llvm/trunk/test/tools/obj2yaml/elf-hash-section.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/obj2yaml/elf-hash-section.yaml?rev=373315&view=auto
==============================================================================
--- llvm/trunk/test/tools/obj2yaml/elf-hash-section.yaml (added)
+++ llvm/trunk/test/tools/obj2yaml/elf-hash-section.yaml Tue Oct  1 02:45:59 2019
@@ -0,0 +1,78 @@
+## Check how obj2yaml produces SHT_HASH section descriptions.
+
+## Check that obj2yaml uses "Bucket" and "Chain" tags to describe
+## a SHT_HASH section when it has content of a correct size.
+## I.e. data size == 4 * (2 + nbucket + nchain).
+
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: obj2yaml %t1 | FileCheck %s --check-prefix=CHAIN-BUCKET
+
+# CHAIN-BUCKET:      - Name:  .hash1
+# CHAIN-BUCKET-NEXT:  Type:   SHT_HASH
+# CHAIN-BUCKET-NEXT:  Bucket: [ 3 ]
+# CHAIN-BUCKET-NEXT:  Chain:  [ 4, 5 ]
+# CHAIN-BUCKET:      - Name:  .hash2
+# CHAIN-BUCKET-NEXT:  Type:   SHT_HASH
+# CHAIN-BUCKET-NEXT:  Bucket: [  ]
+# CHAIN-BUCKET-NEXT:  Chain:  [  ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+## Case 1: A non-empty hash table: nbucket == 1, nchain == 2. 
+  - Name:    .hash1
+    Type:    SHT_HASH
+    Content: '0100000002000000030000000400000005000000'
+## Case 2: An empty hash table: nbucket == 0, nchain == 0.
+  - Name:    .hash2
+    Type:    SHT_HASH
+    Content: '0000000000000000'
+
+## Check that obj2yaml falls back to using the "Content" tag when
+## hash sections are broken.
+
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=CONTENT
+
+# CONTENT:      - Name:    .empty_hash
+# CONTENT-NEXT:   Type:    SHT_HASH
+# CONTENT-NEXT:   Content: ''
+# CONTENT-NEXT: - Name:    .invalid_header
+# CONTENT-NEXT:   Type:    SHT_HASH
+# CONTENT-NEXT:   Content: '00'
+# CONTENT-NEXT: - Name:    .truncated
+# CONTENT-NEXT:   Type:    SHT_HASH
+# CONTENT-NEXT:   Content: '01000000020000000300000004000000'
+# CONTENT-NEXT: - Name:    .oversized
+# CONTENT-NEXT:   Type:    SHT_HASH
+# CONTENT-NEXT:   Content: '0100000002000000030000000400000000'
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+## Case 1: section has no data.
+  - Name:    .empty_hash
+    Type:    SHT_HASH
+    Content: ''
+## Case 2: section size is less than 2 * 4.
+  - Name:    .invalid_header
+    Type:    SHT_HASH
+    Content: '00'
+## Case 3: nbucket == 1, nchain == 2.
+##         Section size is less than (2 * nbucket + nchain) * 4.
+  - Name:    .truncated
+    Type:    SHT_HASH
+    Content: '01000000020000000300000004000000'
+## Case 4: nbucket == 1, nchain == 2.
+##         Section size is greater than (2 * nbucket + nchain) * 4.
+  - Name:    .oversized
+    Type:    SHT_HASH
+    Content: '0100000002000000030000000400000000'

Added: llvm/trunk/test/tools/yaml2obj/elf-hash-section.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/yaml2obj/elf-hash-section.yaml?rev=373315&view=auto
==============================================================================
--- llvm/trunk/test/tools/yaml2obj/elf-hash-section.yaml (added)
+++ llvm/trunk/test/tools/yaml2obj/elf-hash-section.yaml Tue Oct  1 02:45:59 2019
@@ -0,0 +1,147 @@
+## Check how yaml2obj produces SHT_HASH sections.
+
+## Check we can describe a SHT_HASH section using the "Content" tag.
+
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: llvm-readobj --sections --section-data %t1 | FileCheck %s --check-prefix=CONTENT
+
+# CONTENT:      Name: .hash
+# CONTENT-NEXT: Type: SHT_HASH
+# CONTENT-NEXT: Flags [
+# CONTENT-NEXT: ]
+# CONTENT-NEXT: Address: 0x0
+# CONTENT-NEXT: Offset: 0x44
+# CONTENT-NEXT: Size: 20
+# CONTENT-NEXT: Link: 1
+# CONTENT-NEXT: Info: 0
+# CONTENT-NEXT: AddressAlignment: 0
+# CONTENT-NEXT: EntrySize: 0
+# CONTENT-NEXT: SectionData (
+# CONTENT-NEXT:   0000: 01000000 02000000 03000000 04000000
+# CONTENT-NEXT:   0010: 05000000
+# CONTENT-NEXT: )
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+## SHT_HASH is linked to dynamic symbol table by default.
+  - Name: .dynsym
+    Type: SHT_DYNSYM
+  - Name:    .hash
+    Type:    SHT_HASH
+    Content: '0100000002000000030000000400000005000000'
+
+## Check we can describe a SHT_HASH section using "Bucket" and "Chain" tags.
+
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s --check-prefix=BUCKET-CHAIN
+
+# BUCKET-CHAIN:      Name: .hash
+# BUCKET-CHAIN:      Size:
+# BUCKET-CHAIN-SAME: 28
+# BUCKET-CHAIN:      Link:
+# BUCKET-CHAIN-SAME: 0
+# BUCKET-CHAIN:      SectionData (
+# BUCKET-CHAIN-NEXT:   0000: 02000000 03000000 01000000 02000000  |
+# BUCKET-CHAIN-NEXT:   0010: 03000000 04000000 05000000           |
+# BUCKET-CHAIN-NEXT: )
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+  - Name:   .hash
+    Type:   SHT_HASH
+    Bucket: [ 1, 2 ]
+    Chain:  [ 3, 4, 5 ]
+
+## Check we can't use "Content" and "Bucket" tags together.
+
+# RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=CONTENT-BUCKET
+
+# CONTENT-BUCKET: error: "Content" and "Bucket" cannot be used together
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+  - Name:   .hash
+    Type:   SHT_HASH
+    Bucket: [ 1 ]
+    Content: '00'
+
+## Check we can't use "Content" and "Chain" tags together.
+
+# RUN: not yaml2obj --docnum=4 %s 2>&1 | FileCheck %s --check-prefix=CONTENT-CHAIN
+
+# CONTENT-CHAIN: error: "Content" and "Chain" cannot be used together
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+  - Name:   .hash
+    Type:   SHT_HASH
+    Chain:  [ 1 ]
+    Content: '00'
+
+## Check we can't use "Bucket" without "Chain".
+
+# RUN: not yaml2obj --docnum=5 %s 2>&1 | FileCheck %s --check-prefix=NO-BUCKET-OR-CHAIN
+
+# NO-BUCKET-OR-CHAIN: error: "Bucket" and "Chain" must be used together
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+  - Name:   .hash
+    Type:   SHT_HASH
+    Bucket: [ 1 ]
+
+## Check we can't use "Chain" without "Bucket".
+
+# RUN: not yaml2obj --docnum=6 %s 2>&1 | FileCheck %s --check-prefix=NO-BUCKET-OR-CHAIN
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+  - Name:  .hash
+    Type:  SHT_HASH
+    Chain: [ 1 ]
+
+## Check we report an error if neither "Bucket", "Chain" nor "Content" were set.
+
+# RUN: not yaml2obj --docnum=7 %s 2>&1 | FileCheck %s --check-prefix=NO-TAGS
+
+# NO-TAGS: error: one of "Content", "Bucket" or "Chain" must be specified
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_386
+Sections:
+  - Name:  .hash
+    Type:  SHT_HASH

Modified: llvm/trunk/tools/obj2yaml/elf2yaml.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/obj2yaml/elf2yaml.cpp?rev=373315&r1=373314&r2=373315&view=diff
==============================================================================
--- llvm/trunk/tools/obj2yaml/elf2yaml.cpp (original)
+++ llvm/trunk/tools/obj2yaml/elf2yaml.cpp Tue Oct  1 02:45:59 2019
@@ -63,6 +63,7 @@ class ELFDumper {
   Expected<ELFYAML::SymtabShndxSection *>
   dumpSymtabShndxSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::NoBitsSection *> dumpNoBitsSection(const Elf_Shdr *Shdr);
+  Expected<ELFYAML::HashSection *> dumpHashSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::VerdefSection *> dumpVerdefSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::SymverSection *> dumpSymverSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::VerneedSection *> dumpVerneedSection(const Elf_Shdr *Shdr);
@@ -255,6 +256,13 @@ template <class ELFT> Expected<ELFYAML::
       Y->Sections.emplace_back(*SecOrErr);
       break;
     }
+    case ELF::SHT_HASH: {
+      Expected<ELFYAML::HashSection *> SecOrErr = dumpHashSection(&Sec);
+      if (!SecOrErr)
+        return SecOrErr.takeError();
+      Y->Sections.emplace_back(*SecOrErr);
+      break;
+    }
     case ELF::SHT_GNU_verdef: {
       Expected<ELFYAML::VerdefSection *> SecOrErr = dumpVerdefSection(&Sec);
       if (!SecOrErr)
@@ -616,6 +624,45 @@ ELFDumper<ELFT>::dumpNoBitsSection(const
   return S.release();
 }
 
+template <class ELFT>
+Expected<ELFYAML::HashSection *>
+ELFDumper<ELFT>::dumpHashSection(const Elf_Shdr *Shdr) {
+  auto S = std::make_unique<ELFYAML::HashSection>();
+  if (Error E = dumpCommonSection(Shdr, *S))
+    return std::move(E);
+
+  auto ContentOrErr = Obj.getSectionContents(Shdr);
+  if (!ContentOrErr)
+    return ContentOrErr.takeError();
+
+  ArrayRef<uint8_t> Content = *ContentOrErr;
+  if (Content.size() % 4 != 0 || Content.size() < 8) {
+    S->Content = yaml::BinaryRef(Content);
+    return S.release();
+  }
+
+  DataExtractor::Cursor Cur(0);
+  DataExtractor Data(Content, Obj.isLE(), /*AddressSize=*/0);
+  uint32_t NBucket = Data.getU32(Cur);
+  uint32_t NChain = Data.getU32(Cur);
+  if (Content.size() != (2 + NBucket + NChain) * 4) {
+    S->Content = yaml::BinaryRef(Content);
+    return S.release();
+  }
+
+  S->Bucket.emplace(NBucket);
+  for (uint32_t &V : *S->Bucket)
+    V = Data.getU32(Cur);
+
+  S->Chain.emplace(NChain);
+  for (uint32_t &V : *S->Chain)
+    V = Data.getU32(Cur);
+
+  if (!Cur)
+    llvm_unreachable("entries were not read correctly");
+  return S.release();
+}
+
 template <class ELFT>
 Expected<ELFYAML::VerdefSection *>
 ELFDumper<ELFT>::dumpVerdefSection(const Elf_Shdr *Shdr) {




More information about the llvm-commits mailing list