[llvm] 5c1639f - [yaml2obj][obj2yaml] Support custom ELF section header string table name

James Henderson via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 16 02:02:47 PDT 2021


Author: James Henderson
Date: 2021-06-16T10:02:23+01:00
New Revision: 5c1639fe064b548adff67d45e1f8cedae395ed6f

URL: https://github.com/llvm/llvm-project/commit/5c1639fe064b548adff67d45e1f8cedae395ed6f
DIFF: https://github.com/llvm/llvm-project/commit/5c1639fe064b548adff67d45e1f8cedae395ed6f.diff

LOG: [yaml2obj][obj2yaml] Support custom ELF section header string table name

This patch adds support for a new field in the FileHeader, which states
the name to use for the section header string table. This also allows
combining the string table with another string table in the object, e.g.
the symbol name string table. The field is optional. By default,
.shstrtab will continue to be used.

This partially fixes https://bugs.llvm.org/show_bug.cgi?id=50506.

Reviewed by: Higuoxing

Differential Revision: https://reviews.llvm.org/D104035

Added: 
    llvm/test/tools/obj2yaml/ELF/shstrtab.yaml
    llvm/test/tools/yaml2obj/ELF/shstrtab.yaml

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml
    llvm/tools/obj2yaml/elf2yaml.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 874aa32acdc0c..521bdee8b49c8 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -118,6 +118,7 @@ struct FileHeader {
   Optional<ELF_EM> Machine;
   ELF_EF Flags;
   llvm::yaml::Hex64 Entry;
+  Optional<StringRef> SectionHeaderStringTable;
 
   Optional<llvm::yaml::Hex64> EPhOff;
   Optional<llvm::yaml::Hex16> EPhEntSize;

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index a4e0fe004988a..aa273a1c165e4 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -177,15 +177,24 @@ template <class ELFT> class ELFState {
 
   enum class SymtabType { Static, Dynamic };
 
-  /// The future ".strtab" section.
+  /// The future symbol table string section.
   StringTableBuilder DotStrtab{StringTableBuilder::ELF};
 
-  /// The future ".shstrtab" section.
+  /// The future section header string table section, if a unique string table
+  /// is needed. Don't reference this variable direectly: use the
+  /// ShStrtabStrings member instead.
   StringTableBuilder DotShStrtab{StringTableBuilder::ELF};
 
-  /// The future ".dynstr" section.
+  /// The future dynamic symbol string section.
   StringTableBuilder DotDynstr{StringTableBuilder::ELF};
 
+  /// The name of the section header string table section. If it is .strtab or
+  /// .dynstr, the section header strings will be written to the same string
+  /// table as the static/dynamic symbols respectively. Otherwise a dedicated
+  /// section will be created with that name.
+  StringRef SectionHeaderStringTableName = ".shstrtab";
+  StringTableBuilder *ShStrtabStrings = &DotShStrtab;
+
   NameToIdxMap SN2I;
   NameToIdxMap SymN2I;
   NameToIdxMap DynSymN2I;
@@ -327,6 +336,18 @@ template <class T> static void zero(T &Obj) { memset(&Obj, 0, sizeof(Obj)); }
 template <class ELFT>
 ELFState<ELFT>::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH)
     : Doc(D), ErrHandler(EH) {
+  // The input may explicitly request to store the section header table strings
+  // in the same string table as dynamic or static symbol names. Set the
+  // ShStrtabStrings member accordingly.
+  if (Doc.Header.SectionHeaderStringTable) {
+    SectionHeaderStringTableName = *Doc.Header.SectionHeaderStringTable;
+    if (*Doc.Header.SectionHeaderStringTable == ".strtab")
+      ShStrtabStrings = &DotStrtab;
+    else if (*Doc.Header.SectionHeaderStringTable == ".dynstr")
+      ShStrtabStrings = &DotDynstr;
+    // Otherwise, the unique table will be used.
+  }
+
   std::vector<ELFYAML::Section *> Sections = Doc.getSections();
   // Insert SHT_NULL section implicitly when it is not defined in YAML.
   if (Sections.empty() || Sections.front()->Type != ELF::SHT_NULL)
@@ -363,19 +384,35 @@ ELFState<ELFT>::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH)
                   "' at YAML section/fill number " + Twine(I));
   }
 
-  std::vector<StringRef> ImplicitSections;
-  if (Doc.DynamicSymbols)
-    ImplicitSections.insert(ImplicitSections.end(), {".dynsym", ".dynstr"});
-  if (Doc.Symbols)
-    ImplicitSections.push_back(".symtab");
+  SmallSetVector<StringRef, 8> ImplicitSections;
+  if (Doc.DynamicSymbols) {
+    if (SectionHeaderStringTableName == ".dynsym")
+      reportError("cannot use '.dynsym' as the section header name table when "
+                  "there are dynamic symbols");
+    ImplicitSections.insert(".dynsym");
+    ImplicitSections.insert(".dynstr");
+  }
+  if (Doc.Symbols) {
+    if (SectionHeaderStringTableName == ".symtab")
+      reportError("cannot use '.symtab' as the section header name table when "
+                  "there are symbols");
+    ImplicitSections.insert(".symtab");
+  }
   if (Doc.DWARF)
     for (StringRef DebugSecName : Doc.DWARF->getNonEmptySectionNames()) {
       std::string SecName = ("." + DebugSecName).str();
-      ImplicitSections.push_back(StringRef(SecName).copy(StringAlloc));
+      // TODO: For .debug_str it should be possible to share the string table,
+      // in the same manner as the symbol string tables.
+      if (SectionHeaderStringTableName == SecName)
+        reportError("cannot use '" + SecName +
+                    "' as the section header name table when it is needed for "
+                    "DWARF output");
+      ImplicitSections.insert(StringRef(SecName).copy(StringAlloc));
     }
-  ImplicitSections.insert(ImplicitSections.end(), {".strtab"});
+  // TODO: Only create the .strtab here if any symbols have been requested.
+  ImplicitSections.insert(".strtab");
   if (!SecHdrTable || !SecHdrTable->NoHeaders.getValueOr(false))
-    ImplicitSections.insert(ImplicitSections.end(), {".shstrtab"});
+    ImplicitSections.insert(SectionHeaderStringTableName);
 
   // Insert placeholders for implicit sections that are not
   // defined explicitly in YAML.
@@ -387,7 +424,9 @@ ELFState<ELFT>::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH)
         ELFYAML::Chunk::ChunkKind::RawContent, true /*IsImplicit*/);
     Sec->Name = SecName;
 
-    if (SecName == ".dynsym")
+    if (SecName == SectionHeaderStringTableName)
+      Sec->Type = ELF::SHT_STRTAB;
+    else if (SecName == ".dynsym")
       Sec->Type = ELF::SHT_DYNSYM;
     else if (SecName == ".symtab")
       Sec->Type = ELF::SHT_SYMTAB;
@@ -480,8 +519,9 @@ void ELFState<ELFT>::writeELFHeader(raw_ostream &OS) {
 
   if (Doc.Header.EShStrNdx)
     Header.e_shstrndx = *Doc.Header.EShStrNdx;
-  else if (SectionHeaders.Offset && !ExcludedSectionHeaders.count(".shstrtab"))
-    Header.e_shstrndx = SN2I.get(".shstrtab");
+  else if (SectionHeaders.Offset &&
+           !ExcludedSectionHeaders.count(SectionHeaderStringTableName))
+    Header.e_shstrndx = SN2I.get(SectionHeaderStringTableName);
   else
     Header.e_shstrndx = 0;
 
@@ -615,16 +655,16 @@ bool ELFState<ELFT>::initImplicitHeader(ContiguousBlobAccumulator &CBA,
   if (Header.sh_offset)
     return false;
 
-  if (SecName == ".symtab")
-    initSymtabSectionHeader(Header, SymtabType::Static, CBA, YAMLSec);
-  else if (SecName == ".strtab")
+  if (SecName == ".strtab")
     initStrtabSectionHeader(Header, SecName, DotStrtab, CBA, YAMLSec);
-  else if (SecName == ".shstrtab")
-    initStrtabSectionHeader(Header, SecName, DotShStrtab, CBA, YAMLSec);
-  else if (SecName == ".dynsym")
-    initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec);
   else if (SecName == ".dynstr")
     initStrtabSectionHeader(Header, SecName, DotDynstr, CBA, YAMLSec);
+  else if (SecName == SectionHeaderStringTableName)
+    initStrtabSectionHeader(Header, SecName, *ShStrtabStrings, CBA, YAMLSec);
+  else if (SecName == ".symtab")
+    initSymtabSectionHeader(Header, SymtabType::Static, CBA, YAMLSec);
+  else if (SecName == ".dynsym")
+    initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec);
   else if (SecName.startswith(".debug_")) {
     // If a ".debug_*" section's type is a preserved one, e.g., SHT_DYNAMIC, we
     // will not treat it as a debug section.
@@ -671,7 +711,7 @@ uint64_t ELFState<ELFT>::getSectionNameOffset(StringRef Name) {
   // the string table.
   if (ExcludedSectionHeaders.count(Name))
     return 0;
-  return DotShStrtab.getOffset(Name);
+  return ShStrtabStrings->getOffset(Name);
 }
 
 static uint64_t writeContent(ContiguousBlobAccumulator &CBA,
@@ -995,7 +1035,7 @@ void ELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name,
                                              StringTableBuilder &STB,
                                              ContiguousBlobAccumulator &CBA,
                                              ELFYAML::Section *YAMLSec) {
-  SHeader.sh_name = getSectionNameOffset(Name);
+  SHeader.sh_name = getSectionNameOffset(ELFYAML::dropUniqueSuffix(Name));
   SHeader.sh_type = YAMLSec ? YAMLSec->Type : ELF::SHT_STRTAB;
   SHeader.sh_addralign = YAMLSec ? (uint64_t)YAMLSec->AddressAlign : 1;
 
@@ -1817,10 +1857,8 @@ template <class ELFT> void ELFState<ELFT>::buildSectionIndex() {
       llvm_unreachable("buildSectionIndex() failed");
 
     if (!ExcludedSectionHeaders.count(S->Name))
-      DotShStrtab.add(ELFYAML::dropUniqueSuffix(S->Name));
+      ShStrtabStrings->add(ELFYAML::dropUniqueSuffix(S->Name));
   }
-
-  DotShStrtab.finalize();
 }
 
 template <class ELFT> void ELFState<ELFT>::buildSymbolIndexes() {
@@ -1870,6 +1908,11 @@ template <class ELFT> void ELFState<ELFT>::finalizeStrings() {
   }
 
   DotDynstr.finalize();
+
+  // Don't finalize the section header string table a second time if it has
+  // already been finalized due to being one of the symbol string tables.
+  if (ShStrtabStrings != &DotStrtab && ShStrtabStrings != &DotDynstr)
+    ShStrtabStrings->finalize();
 }
 
 template <class ELFT>
@@ -1879,14 +1922,16 @@ bool ELFState<ELFT>::writeELF(raw_ostream &OS, ELFYAML::Object &Doc,
   if (State.HasError)
     return false;
 
-  // Finalize .strtab and .dynstr sections. We do that early because want to
-  // finalize the string table builders before writing the content of the
-  // sections that might want to use them.
-  State.finalizeStrings();
-
+  // Build the section index, which adds sections to the section header string
+  // table first, so that we can finalise the section header string table.
   State.buildSectionIndex();
   State.buildSymbolIndexes();
 
+  // Finalize section header string table and the .strtab and .dynstr sections.
+  // We do this early because we want to finalize the string table builders
+  // before writing the content of the sections that might want to use them.
+  State.finalizeStrings();
+
   if (State.HasError)
     return false;
 

diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 96c5b5c100242..31bae6bf1f333 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1007,6 +1007,7 @@ void MappingTraits<ELFYAML::FileHeader>::mapping(IO &IO,
   IO.mapOptional("Machine", FileHdr.Machine);
   IO.mapOptional("Flags", FileHdr.Flags, ELFYAML::ELF_EF(0));
   IO.mapOptional("Entry", FileHdr.Entry, Hex64(0));
+  IO.mapOptional("SectionHeaderStringTable", FileHdr.SectionHeaderStringTable);
 
   // obj2yaml does not dump these fields.
   assert(!IO.outputting() ||

diff  --git a/llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml b/llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml
index 40667b57a9749..ffb039fd6d069 100644
--- a/llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml
@@ -11,6 +11,7 @@
 # CHECK-NEXT:   Class: ELFCLASS64
 # CHECK-NEXT:   Data:  ELFDATA2LSB
 # CHECK-NEXT:   Type:  ET_REL
+# CHECK-NEXT:   SectionHeaderStringTable: {{.*}}
 # CHECK-NEXT: Sections:
 # CHECK-NEXT:   - Name: "{{.*}}"
 # CHECK-NEXT:     Type: SHT_PROGBITS

diff  --git a/llvm/test/tools/obj2yaml/ELF/shstrtab.yaml b/llvm/test/tools/obj2yaml/ELF/shstrtab.yaml
new file mode 100644
index 0000000000000..c4c1874221785
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/ELF/shstrtab.yaml
@@ -0,0 +1,447 @@
+## Show that the SectionHeaderStringTable field in the document header is set,
+## iff the section name is not ".shstrtab".
+## Also show that no section appears in the Sections table for this section,
+## unless some property is 
diff erent to the default.
+
+## Show the case when the name is a custom string (the key should be set).
+# RUN: yaml2obj --docnum=1 %s -o %t1.o
+# RUN: obj2yaml %t1.o > %t1.yaml
+# RUN: FileCheck %s --input-file=%t1.yaml --check-prefix=CUSTOM
+
+# CUSTOM:      --- !ELF
+# CUSTOM-NEXT: FileHeader:
+# CUSTOM-NEXT:   Class:           ELFCLASS64
+# CUSTOM-NEXT:   Data:            ELFDATA2LSB
+# CUSTOM-NEXT:   Type:            ET_EXEC
+# CUSTOM-NEXT:   SectionHeaderStringTable: .foo
+# CUSTOM-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .foo
+
+## Show the case when the e_shstrndx value is 0 and the name is not ".shstrtab"
+## (the key should be set).
+# RUN: yaml2obj --docnum=2 %s -o %t2.o
+# RUN: obj2yaml %t2.o > %t2.yaml
+# RUN: FileCheck %s --input-file=%t2.yaml --check-prefix=XINDEX
+
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_EXEC
+  EShStrNdx: 0xffff
+  SectionHeaderStringTable: .foo
+Sections:
+  - Type: SHT_NULL
+    Link: .foo
+
+# XINDEX:      --- !ELF
+# XINDEX-NEXT: FileHeader:
+# XINDEX-NEXT:   Class:           ELFCLASS64
+# XINDEX-NEXT:   Data:            ELFDATA2LSB
+# XINDEX-NEXT:   Type:            ET_EXEC
+# XINDEX-NEXT:   SectionHeaderStringTable: .foo
+# XINDEX-NEXT: Sections:
+# XINDEX-NEXT:   - Type:            SHT_NULL
+# XINDEX-NEXT:     Link:            .foo
+# XINDEX-NEXT:     Size:            0x0
+# XINDEX-NEXT: ...
+
+## Show the case when the string table section is also the symbol table's string
+## table (the key should be set).
+# RUN: yaml2obj --docnum=3 %s -o %t3.o
+# RUN: obj2yaml %t3.o > %t3.yaml
+# RUN: FileCheck %s --input-file=%t3.yaml --check-prefix=STRTAB
+
+# STRTAB:      --- !ELF
+# STRTAB-NEXT: FileHeader:
+# STRTAB-NEXT:   Class:           ELFCLASS64
+# STRTAB-NEXT:   Data:            ELFDATA2LSB
+# STRTAB-NEXT:   Type:            ET_EXEC
+# STRTAB-NEXT:   SectionHeaderStringTable: .strtab
+# STRTAB-NEXT: Symbols:
+# STRTAB-NEXT:   - Name:            boz
+# STRTAB-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: ".strtab"
+Symbols:
+  - Name: boz
+
+## Document the case when the string table section is also the symbol table's
+## dynamic string table (the key should be set).
+## FIXME: Regardless of whether it is shared with the section header string
+##        table or not, the dynstr (and also the dynsym) should be omitted if
+##        they match the default behaviour.
+# RUN: yaml2obj --docnum=4 %s -o %t4.o
+# RUN: obj2yaml %t4.o > %t4.yaml
+# RUN: FileCheck %s --input-file=%t4.yaml --check-prefix=DYNSTR
+
+# DYNSTR:      --- !ELF
+# DYNSTR-NEXT: FileHeader:
+# DYNSTR-NEXT:   Class:           ELFCLASS64
+# DYNSTR-NEXT:   Data:            ELFDATA2LSB
+# DYNSTR-NEXT:   Type:            ET_EXEC
+# DYNSTR-NEXT:   SectionHeaderStringTable: .dynstr
+# DYNSTR-NEXT: Sections:
+# DYNSTR-NEXT:   - Name:            .dynsym
+# DYNSTR-NEXT:     Type:            SHT_DYNSYM
+# DYNSTR-NEXT:     Flags:           [ SHF_ALLOC ]
+# DYNSTR-NEXT:     Link:            .dynstr
+# DYNSTR-NEXT:     AddressAlign:    0x8
+# DYNSTR-NEXT:   - Name:            .dynstr
+# DYNSTR-NEXT:     Type:            SHT_STRTAB
+# DYNSTR-NEXT:     Flags:           [ SHF_ALLOC ]
+# DYNSTR-NEXT:     Address:         0x30
+# DYNSTR-NEXT:     AddressAlign:    0x1
+# DYNSTR-NEXT: DynamicSymbols:
+# DYNSTR-NEXT:   - Name:            boz
+# DYNSTR-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: ".dynstr"
+DynamicSymbols:
+  - Name: boz
+
+## Show the case when the name is the default ".shstrtab" (the key should not be
+## set).
+# RUN: yaml2obj --docnum=5 %s -o %t5.o
+# RUN: obj2yaml %t5.o > %t5.yaml
+# RUN: FileCheck %s --input-file=%t5.yaml --check-prefix=DEFAULT
+
+# DEFAULT:      --- !ELF
+# DEFAULT-NEXT: FileHeader:
+# DEFAULT-NEXT:   Class:           ELFCLASS64
+# DEFAULT-NEXT:   Data:            ELFDATA2LSB
+# DEFAULT-NEXT:   Type:            ET_EXEC
+# DEFAULT-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+
+## Show the case when the e_shstrndx value is 0 and the name is ".shstrtab" (the
+## key should not be set).
+# RUN: yaml2obj --docnum=6 %s -o %t6.o
+# RUN: obj2yaml %t6.o > %t6.yaml
+# RUN: FileCheck %s --input-file=%t6.yaml --check-prefix=DEFXINDEX
+
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_EXEC
+  EShStrNdx: 0xffff
+Sections:
+  - Type: SHT_NULL
+    Link: .shstrtab
+
+# DEFXINDEX:      --- !ELF
+# DEFXINDEX-NEXT: FileHeader:
+# DEFXINDEX-NEXT:   Class:           ELFCLASS64
+# DEFXINDEX-NEXT:   Data:            ELFDATA2LSB
+# DEFXINDEX-NEXT:   Type:            ET_EXEC
+# DEFXINDEX-NEXT: Sections:
+# DEFXINDEX-NEXT:   - Type:            SHT_NULL
+# DEFXINDEX-NEXT:     Link:            .shstrtab
+# DEFXINDEX-NEXT:     Size:            0x0
+# DEFXINDEX-NEXT: ...
+
+## Show that if there are no section headers, the key is not set.
+# RUN: yaml2obj --docnum=7 %s -o %t7.o
+# RUN: obj2yaml %t7.o > %t7.yaml
+# RUN: FileCheck %s --input-file=%t7.yaml --check-prefix=NOHDRS
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+Sections:
+  - Type: SectionHeaderTable
+    NoHeaders: true
+
+# NOHDRS:      --- !ELF
+# NOHDRS-NEXT: FileHeader:
+# NOHDRS-NEXT:   Class:  ELFCLASS64
+# NOHDRS-NEXT:   Data:   ELFDATA2LSB
+# NOHDRS-NEXT:   Type:   ET_EXEC
+## FIXME: There should be a SectionHeaderTable key as per the input.
+# NOHDRS-NEXT: ...
+
+## Show that a custom-named section header string table can be in a reordered
+## section header table.
+# RUN: yaml2obj --docnum=8 %s -o %t8.o
+# RUN: obj2yaml %t8.o > %t8.yaml
+# RUN: FileCheck %s --input-file=%t8.yaml --check-prefix=REORDER
+
+# REORDER:      --- !ELF
+# REORDER-NEXT: FileHeader:
+# REORDER-NEXT:   Class:           ELFCLASS64
+# REORDER-NEXT:   Data:            ELFDATA2LSB
+# REORDER-NEXT:   Type:            ET_EXEC
+# REORDER-NEXT:   SectionHeaderStringTable: .foo
+# REORDER-NEXT: Sections:
+# REORDER-NEXT:   - Name:            .baz
+# REORDER-NEXT:     Type:            SHT_PROGBITS
+# REORDER-NEXT:     Offset:          0x180
+# REORDER-NEXT:   - Name:            .bar
+# REORDER-NEXT:     Type:            SHT_PROGBITS
+## FIXME: This should be at the start of the sections list.
+# REORDER-NEXT:   - Type:            SectionHeaderTable
+# REORDER-NEXT:     Sections:
+# REORDER-NEXT:       - Name:            .baz
+# REORDER-NEXT:       - Name:            .foo
+# REORDER-NEXT:       - Name:            .bar
+# REORDER-NEXT:       - Name:            .strtab
+# REORDER-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .foo
+Sections:
+  - Type: SectionHeaderTable
+    Sections:
+      - Name: .baz
+      - Name: .foo
+      - Name: .bar
+      ## FIXME: we shouldn't need a .strtab section if there are no symbols.
+      - Name: .strtab
+  - Name: .baz
+    Type: SHT_PROGBITS
+  - Name: .bar
+    Type: SHT_PROGBITS
+
+## Document what happens when a custom-named section header string table is
+## placed in between other sections.
+## FIXME: obj2yaml should preserve the ordering in the Sections list, but it
+##        doesn't for custom or default named tables.
+# RUN: yaml2obj --docnum=9 %s -o %t9.o
+# RUN: obj2yaml %t9.o > %t9.yaml
+# RUN: FileCheck %s --input-file=%t9.yaml --check-prefix=PLACED
+
+# PLACED:      --- !ELF
+# PLACED-NEXT: FileHeader:
+# PLACED-NEXT:   Class:           ELFCLASS64
+# PLACED-NEXT:   Data:            ELFDATA2LSB
+# PLACED-NEXT:   Type:            ET_EXEC
+# PLACED-NEXT:   SectionHeaderStringTable: .foo
+# PLACED-NEXT: Sections:
+# PLACED-NEXT:   - Name:            .baz
+# PLACED-NEXT:     Type:            SHT_PROGBITS
+# PLACED-NEXT:   - Name:            .bar
+# PLACED-NEXT:     Type:            SHT_PROGBITS
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .foo
+Sections:
+  - Name: .baz
+    Type: SHT_PROGBITS
+  - Name: .foo
+    Type: SHT_STRTAB
+  - Name: .bar
+    Type: SHT_PROGBITS
+
+## Show that a custom-named section header string table can be given 
diff erent
+## properties.
+# RUN: yaml2obj --docnum=10 %s -o %t10.o
+# RUN: obj2yaml %t10.o > %t10.yaml
+# RUN: FileCheck %s --input-file=%t10.yaml --check-prefix=PROPS
+
+# PROPS:      --- !ELF
+# PROPS-NEXT: FileHeader:
+# PROPS-NEXT:   Class: ELFCLASS64
+# PROPS-NEXT:   Data:  ELFDATA2LSB
+# PROPS-NEXT:   Type:  ET_EXEC
+# PROPS-NEXT:   SectionHeaderStringTable: .foo
+# PROPS-NEXT: Sections:
+# PROPS-NEXT:   - Name:  .foo
+# PROPS-NEXT:     Type:  SHT_STRTAB
+# PROPS-NEXT:     Flags: [ SHF_ALLOC ]
+# PROPS-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .foo
+Sections:
+  - Name:  .foo
+    Type:  SHT_STRTAB
+    Flags: [ SHF_ALLOC ]
+
+## Show that an error is reported if the section header string table name cannot
+## be read.
+# RUN: yaml2obj --docnum=11 %s -o %t11.o
+# RUNasda: not obj2yaml %t11.o 2>&1 | FileCheck %s --check-prefix=ERR -DFILE=%t11.o
+
+# ERR: Error reading file: [[FILE]]: unable to read section header string table name: a section [index 1] has an invalid sh_name (0x10000) offset which goes past the end of the section name string table
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+Sections:
+  - Name:  .shstrtab
+    Type:  SHT_STRTAB
+    ShName: 0x10000
+
+## Show that the name is uniquified if necessary.
+
+## Case 1: generic name.
+# RUN: yaml2obj --docnum=12 %s -o %t12.o
+# RUN: obj2yaml %t12.o > %t12.yaml
+# RUN: FileCheck %s --input-file=%t12.yaml --check-prefix=UNIQUIFY1
+
+# UNIQUIFY1:      --- !ELF
+# UNIQUIFY1-NEXT: FileHeader:
+# UNIQUIFY1-NEXT:   Class: ELFCLASS64
+# UNIQUIFY1-NEXT:   Data:  ELFDATA2LSB
+# UNIQUIFY1-NEXT:   Type:  ET_EXEC
+# UNIQUIFY1-NEXT:   SectionHeaderStringTable: '.strings (1)'
+# UNIQUIFY1-NEXT: Sections:
+# UNIQUIFY1-NEXT:   - Name:  .strings
+# UNIQUIFY1-NEXT:     Type:  SHT_PROGBITS
+# UNIQUIFY1-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: '.strings (1)'
+Sections:
+  - Name: '.strings (2)'
+    Type: SHT_PROGBITS
+
+## Case 2: '.strtab' when symbols are present.
+# RUN: yaml2obj --docnum=13 %s -o %t13.o '-DNAME=".strtab (1)"'
+# RUN: obj2yaml %t13.o > %t13.yaml
+# RUN: FileCheck %s --input-file=%t13.yaml --check-prefix=UNIQUIFY2 \
+# RUN:   -DNAME=.strtab
+
+# UNIQUIFY2:      --- !ELF
+# UNIQUIFY2-NEXT: FileHeader:
+# UNIQUIFY2-NEXT:   Class: ELFCLASS64
+# UNIQUIFY2-NEXT:   Data:  ELFDATA2LSB
+# UNIQUIFY2-NEXT:   Type:  ET_EXEC
+# UNIQUIFY2-NEXT:   SectionHeaderStringTable: '[[NAME]] (1)'
+# UNIQUIFY2-NEXT: Symbols:
+# UNIQUIFY2-NEXT:   - Name:  foo
+# UNIQUIFY2-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: [[NAME]]
+Symbols:
+  - Name: foo
+
+## Case 3: '.symtab' when symbols are present.
+# RUN: yaml2obj --docnum=13 %s -o %t14.o '-DNAME=".symtab (1)"'
+# RUN: obj2yaml %t14.o > %t14.yaml
+# RUN: FileCheck %s --input-file=%t14.yaml --check-prefix=UNIQUIFY2 \
+# RUN:   -DNAME=.symtab
+
+## Case 4: '.dynstr' when dynamic symbols are present.
+# RUN: yaml2obj --docnum=14 %s -o %t15.o '-DNAME=".dynstr (1)"'
+# RUN: obj2yaml %t15.o > %t15.yaml
+# RUN: FileCheck %s --input-file=%t15.yaml --check-prefix=UNIQUIFY3 \
+# RUN:   -DNAME=.dynstr
+
+# UNIQUIFY3:      --- !ELF
+# UNIQUIFY3-NEXT: FileHeader:
+# UNIQUIFY3-NEXT:   Class: ELFCLASS64
+# UNIQUIFY3-NEXT:   Data:  ELFDATA2LSB
+# UNIQUIFY3-NEXT:   Type:  ET_EXEC
+# UNIQUIFY3-NEXT:   SectionHeaderStringTable: '[[NAME]] (1)'
+## FIXME: The .dynsym and .dynstr sections shouldn't need to be emitted, since
+##        their values are the default produced by yaml2obj.
+# UNIQUIFY3-NEXT: Sections:
+# UNIQUIFY3-NEXT:   - Name:            .dynsym
+# UNIQUIFY3-NEXT:     Type:            SHT_DYNSYM
+# UNIQUIFY3-NEXT:     Flags:           [ SHF_ALLOC ]
+# UNIQUIFY3-NEXT:     Link:            .dynstr
+# UNIQUIFY3-NEXT:     AddressAlign:    0x8
+# UNIQUIFY3-NEXT:   - Name:            .dynstr
+# UNIQUIFY3-NEXT:     Type:            SHT_STRTAB
+# UNIQUIFY3-NEXT:     Flags:           [ SHF_ALLOC ]
+# UNIQUIFY3-NEXT:     Address:         0x30
+# UNIQUIFY3-NEXT:     AddressAlign:    0x1
+# UNIQUIFY3-NEXT: DynamicSymbols:
+# UNIQUIFY3-NEXT:   - Name:  foo
+# UNIQUIFY3-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: [[NAME]]
+DynamicSymbols:
+  - Name: foo
+
+## Case 5: '.dynsym' when dynamic symbols are present.
+# RUN: yaml2obj --docnum=14 %s -o %t16.o '-DNAME=".dynsym (1)"'
+# RUN: obj2yaml %t16.o > %t16.yaml
+# RUN: FileCheck %s --input-file=%t16.yaml --check-prefix=UNIQUIFY3 \
+# RUN:   -DNAME=.dynsym
+
+## Case 6: Document what happens for '.debug_str' when DWARF debug strings are
+##         requested. The dwarf2yaml code uses the last .debug_* named section
+##         to populate the corresponding DWARF block. As a result, the original
+##         .debug_str content is lost.
+## TODO: We should prevent the dwarf2yaml code from using the section header
+##       string table to populate the DWARF block.
+# RUN: yaml2obj --docnum=15 %s -o %t17.o
+# RUN: obj2yaml %t17.o > %t17.yaml
+# RUN: FileCheck %s --input-file=%t17.yaml --check-prefix=UNIQUIFY6
+
+# UNIQUIFY6:      --- !ELF
+# UNIQUIFY6-NEXT: FileHeader:
+# UNIQUIFY6-NEXT:   Class:           ELFCLASS64
+# UNIQUIFY6-NEXT:   Data:            ELFDATA2LSB
+# UNIQUIFY6-NEXT:   Type:            ET_EXEC
+# UNIQUIFY6-NEXT:   SectionHeaderStringTable: '.debug_str (1)'
+# UNIQUIFY6-NEXT: DWARF:
+# UNIQUIFY6-NEXT:   debug_str:
+# UNIQUIFY6-NEXT:     - ''
+# UNIQUIFY6-NEXT:     - .debug_str
+# UNIQUIFY6-NEXT:     - .strtab
+# UNIQUIFY6-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: '.debug_str (1)'
+DWARF:
+  debug_str:
+    - string

diff  --git a/llvm/test/tools/yaml2obj/ELF/shstrtab.yaml b/llvm/test/tools/yaml2obj/ELF/shstrtab.yaml
new file mode 100644
index 0000000000000..e16d20d019b2c
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/ELF/shstrtab.yaml
@@ -0,0 +1,545 @@
+## A user should be able to specify any arbitrary string table as the section
+## header string table, including the symbol string table. This test covers
+## various cases to do with this.
+
+## Case 1: custom name specified for string table.
+# RUN: yaml2obj --docnum=1 %s -o %t1 -DSHSTRTAB=.strings
+# RUN: llvm-readelf -S -p=.strings %t1 | FileCheck %s --check-prefix=CASE1
+
+# CASE1:      There are 5 section headers
+# CASE1-EMPTY:
+# CASE1-NEXT: Section Headers:
+# CASE1-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg  Lk Inf Al
+# CASE1-NEXT:   [ 0]              NULL
+# CASE1-NEXT:   [ 1] .foo{{ }}
+# CASE1-NEXT:   [ 2] .bar{{ }}
+# CASE1-NEXT:   [ 3] .strtab{{ }}
+# CASE1-NEXT:   [ 4] .strings     STRTAB 0000000000000000 [[#%x,]] 00001c 00       0   0  1
+
+# CASE1:      String dump of section '.strings':
+# CASE1-NEXT: [     1] .strings{{$}}
+# CASE1-NEXT: [     a] .bar{{$}}
+# CASE1-NEXT: [     f] .foo{{$}}
+# CASE1-NEXT: [    14] .strtab{{$}}
+# CASE1-EMPTY:
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: [[SHSTRTAB=<none>]]
+Sections:
+  - Name: .foo
+    Type: SHT_PROGBITS
+  - Name: [[OTHER=.bar]]
+    Type: SHT_PROGBITS
+
+## Case 2: reuse symbol string table.
+# RUN: yaml2obj --docnum=2 %s -o %t2 -DSHSTRTAB=.strtab
+# RUN: llvm-readelf -S -s -p=.strtab %t2 | FileCheck %s --check-prefix=CASE2
+
+# CASE2: There are 5 section headers
+# CASE2-EMPTY:
+# CASE2-NEXT: Section Headers:
+# CASE2-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg Lk Inf Al
+# CASE2-NEXT:   [ 0]              NULL
+# CASE2-NEXT:   [ 1] .foo{{ }}
+# CASE2-NEXT:   [ 2] .bar{{ }}
+# CASE2-NEXT:   [ 3] .symtab{{ }}
+# CASE2-NEXT:   [ 4] .strtab      STRTAB 0000000000000000 [[#%x,]] 000023 00      0   0  1
+
+# CASE2:      Symbol table '.symtab' contains 3 entries:
+# CASE2-NEXT:    Num: {{.*}} Ndx Name
+# CASE2-NEXT:      0: {{.*}} UND {{$}}
+# CASE2-NEXT:      1: {{.*}}     baz{{$}}
+# CASE2-NEXT:      2: {{.*}}     bob{{$}}
+
+# CASE2:      String dump of section '.strtab':
+# CASE2-NEXT: [     1] baz{{$}}
+# CASE2-NEXT: [     5] .bar{{$}}
+# CASE2-NEXT: [     a] .foo{{$}}
+# CASE2-NEXT: [     f] bob{{$}}
+# CASE2-NEXT: [    13] .strtab{{$}}
+# CASE2-NEXT: [    1b] .symtab{{$}}
+# CASE2-EMPTY:
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: [[SHSTRTAB]]
+Sections:
+  - Name: .foo
+    Type: SHT_PROGBITS
+  - Name: .bar
+    Type: SHT_PROGBITS
+Symbols:
+  - Name: baz
+  - Name: bob
+
+## Case 3: reuse dynamic string table.
+# RUN: yaml2obj --docnum=3 %s -o %t3 -DSHSTRTAB=.dynstr
+# RUN: llvm-readelf -S --dyn-syms -p=.dynstr %t3 | FileCheck %s --check-prefix=CASE3
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: [[SHSTRTAB]]
+Sections:
+  - Name: .foo
+    Type: SHT_PROGBITS
+  - Name: .bar
+    Type: SHT_PROGBITS
+DynamicSymbols:
+  - Name: baz
+  - Name: bob
+
+# CASE3:      There are 6 section headers
+# CASE3-EMPTY:
+# CASE3-NEXT: Section Headers:
+# CASE3-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg Lk Inf Al
+# CASE3-NEXT:   [ 0]              NULL
+# CASE3-NEXT:   [ 1] .foo{{ }}
+# CASE3-NEXT:   [ 2] .bar{{ }}
+# CASE3-NEXT:   [ 3] .dynsym{{ }}
+# CASE3-NEXT:   [ 4] .dynstr      STRTAB 0000000000000048 [[#%x,]] 00002b 00   A  0   0  1
+# CASE3-NEXT:   [ 5] .strtab{{ }}
+
+# CASE3:      Symbol table '.dynsym' contains 3 entries:
+# CASE3-NEXT:    Num: {{.*}} Ndx Name
+# CASE3-NEXT:      0: {{.*}} UND {{$}}
+# CASE3-NEXT:      1: {{.*}}     baz{{$}}
+# CASE3-NEXT:      2: {{.*}}     bob{{$}}
+
+# CASE3:      String dump of section '.dynstr':
+# CASE3-NEXT: [     1] baz{{$}}
+# CASE3-NEXT: [     5] .dynstr{{$}}
+# CASE3-NEXT: [     d] .bar{{$}}
+# CASE3-NEXT: [    12] .foo{{$}}
+# CASE3-NEXT: [    17] .dynsym{{$}}
+# CASE3-NEXT: [    1f] bob{{$}}
+# CASE3-NEXT: [    23] .strtab{{$}}
+# CASE3-EMPTY:
+
+## Case 4: shstrtab specified to be otherwise ungenerated non-strtab implicit
+##         section.
+# RUN: yaml2obj --docnum=1 %s -o %t4 -DSHSTRTAB=.symtab
+# RUN: llvm-readelf -S -p=.symtab %t4 | FileCheck %s --check-prefix=CASE4
+
+# CASE4:      There are 5 section headers
+# CASE4-EMPTY:
+# CASE4-NEXT: Section Headers:
+# CASE4-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg Lk Inf Al
+# CASE4-NEXT:   [ 0]              NULL
+# CASE4-NEXT:   [ 1] .foo{{ }}
+# CASE4-NEXT:   [ 2] .bar{{ }}
+# CASE4-NEXT:   [ 3] .strtab{{ }}
+# CASE4-NEXT:   [ 4] .symtab      STRTAB 0000000000000000 [[#%x,]] 00001b 00      0   0  1
+
+# CASE4:      String dump of section '.symtab':
+# CASE4-NEXT: [     1] .bar{{$}}
+# CASE4-NEXT: [     6] .foo{{$}}
+# CASE4-NEXT: [     b] .strtab{{$}}
+# CASE4-NEXT: [    13] .symtab{{$}}
+
+## Case 5: shstrtab specified to be otherwise ungenerated .dynstr section. In
+##         this case, the SHF_ALLOC flag will be set.
+# RUN: yaml2obj --docnum=1 %s -o %t5 -DSHSTRTAB=.dynstr
+# RUN: llvm-readelf -S -p=.dynstr %t5 | FileCheck %s --check-prefix=CASE5
+
+# CASE5:      There are 5 section headers
+# CASE5-EMPTY:
+# CASE5-NEXT: Section Headers:
+# CASE5-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg Lk Inf Al
+# CASE5-NEXT:   [ 0]              NULL
+# CASE5-NEXT:   [ 1] .foo{{ }}
+# CASE5-NEXT:   [ 2] .bar{{ }}
+# CASE5-NEXT:   [ 3] .strtab{{ }}
+# CASE5-NEXT:   [ 4] .dynstr      STRTAB 0000000000000001 [[#%x,]] 00001b 00   A  0   0  1
+
+# CASE5:      String dump of section '.dynstr':
+# CASE5-NEXT: [     1] .dynstr{{$}}
+# CASE5-NEXT: [     9] .bar{{$}}
+# CASE5-NEXT: [     e] .foo{{$}}
+# CASE5-NEXT: [    13] .strtab{{$}}
+
+## Case 6: shstrtab specified to be otherwise ungenerated .debug_str section. In
+##         this case, the sh_entsize will be set to 1.
+# RUN: yaml2obj --docnum=1 %s -o %t6 -DSHSTRTAB=.debug_str
+# RUN: llvm-readelf -S -p=.debug_str %t6 | FileCheck %s --check-prefix=CASE6
+
+# CASE6:      There are 5 section headers
+# CASE6-EMPTY:
+# CASE6-NEXT: Section Headers:
+# CASE6-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg Lk Inf Al
+# CASE6-NEXT:   [ 0]              NULL
+# CASE6-NEXT:   [ 1] .foo{{ }}
+# CASE6-NEXT:   [ 2] .bar{{ }}
+# CASE6-NEXT:   [ 3] .strtab{{ }}
+# CASE6-NEXT:   [ 4] .debug_str   STRTAB 0000000000000000 [[#%x,]] 00001e 01      0   0  1
+
+# CASE6:      String dump of section '.debug_str':
+# CASE6-NEXT: [     1] .debug_str{{$}}
+# CASE6-NEXT: [     c] .bar{{$}}
+# CASE6-NEXT: [    11] .foo{{$}}
+# CASE6-NEXT: [    16] .strtab{{$}}
+
+## Case 7: shstrtab specified to be the .symtab section, when there are symbols.
+## This triggers an error (since the symbols cannot be represented in the
+## section as section names).
+# RUN: not yaml2obj --docnum=2 %s -o %t7 -DSHSTRTAB=.symtab 2>&1 | FileCheck %s --check-prefix=ERR1
+
+# ERR1: error: cannot use '.symtab' as the section header name table when there are symbols
+
+## Case 8: shstrtab specified to be the .dynsym section, when there are dynamic
+## symbols. This triggers an error (since the symbols cannot be represented in
+## the section as section names).
+# RUN: not yaml2obj --docnum=3 %s -o %t8 -DSHSTRTAB=.dynsym 2>&1 | FileCheck %s --check-prefix=ERR2
+
+# ERR2: error: cannot use '.dynsym' as the section header name table when there are dynamic symbols
+
+## Case 9: shstrtab specified to be the .debug_str section, when there are DWARF
+## debug strings. This triggers an error.
+# RUN: not yaml2obj --docnum=4 %s -o %t9 2>&1 | FileCheck %s --check-prefix=ERR3
+
+# ERR3: error: cannot use '.debug_str' as the section header name table when it is needed for DWARF output
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .debug_str
+DWARF:
+  debug_str:
+    - a
+
+## Case 10: can explicitly specifiy ".shstrtab" as shstrtab. Output will be the
+##         same as if it wasn't sepcified at all.
+# RUN: yaml2obj --docnum=1 %s -o %t10 -DSHSTRTAB=.shstrtab
+# RUN: llvm-readelf -S -p=.shstrtab %t10 | FileCheck %s --check-prefix=CASE10
+# RUN: yaml2obj --docnum=1 %s -o %t10.default
+# RUN: cmp %t10 %t10.default
+
+# CASE10:      There are 5 section headers
+# CASE10-EMPTY:
+# CASE10-NEXT: Section Headers:
+# CASE10-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg  Lk Inf Al
+# CASE10-NEXT:   [ 0]              NULL
+# CASE10-NEXT:   [ 1] .foo{{ }}
+# CASE10-NEXT:   [ 2] .bar{{ }}
+# CASE10-NEXT:   [ 3] .strtab{{ }}
+# CASE10-NEXT:   [ 4] .shstrtab    STRTAB 0000000000000000 [[#%x,]] 00001d 00       0   0  1
+
+# CASE10:      String dump of section '.shstrtab':
+# CASE10-NEXT: [     1] .bar{{$}}
+# CASE10-NEXT: [     6] .foo{{$}}
+# CASE10-NEXT: [     b] .shstrtab{{$}}
+# CASE10-NEXT: [    15] .strtab{{$}}
+# CASE10-EMPTY:
+
+## Case 11: can specify custom shstrtab properties.
+## FIXME: when the section is listed explicitly, the sh_addralign value is 0 if
+##        not overwritten, which is inconsistent with when the section is not
+##        specified at all.
+# RUN: yaml2obj --docnum=5 %s -o %t11 -DENTSIZE=2
+# RUN: llvm-readelf -S -p=.strings %t11 | FileCheck %s --check-prefix=CASE11
+
+# CASE11:      There are 5 section headers
+# CASE11-EMPTY:
+# CASE11-NEXT: Section Headers:
+# CASE11-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg  Lk Inf Al
+# CASE11-NEXT:   [ 0]              NULL
+# CASE11-NEXT:   [ 1] .foo{{ }}
+# CASE11-NEXT:   [ 2] .strings     STRTAB 0000000000000000 [[#%x,]] 00001c 02       0   0  0
+# CASE11-NEXT:   [ 3] .bar{{ }}
+# CASE11-NEXT:   [ 4] .strtab{{ }}
+
+# CASE11:      String dump of section '.strings':
+# CASE11-NEXT: [     1] .strings{{$}}
+# CASE11-NEXT: [     a] .bar{{$}}
+# CASE11-NEXT: [     f] .foo{{$}}
+# CASE11-NEXT: [    14] .strtab{{$}}
+# CASE11-EMPTY:
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .strings
+Sections:
+  - Name:         .foo
+    Type:         SHT_PROGBITS
+  - Name:         .strings
+    Type:         [[TYPE=SHT_STRTAB]]
+    EntSize:      [[ENTSIZE=<none>]]
+    Size:         [[SIZE=<none>]]
+    Content:      [[CONTENT=<none>]]
+  - Name:         .bar
+    Type:         SHT_PROGBITS
+
+## Case 12: shstrtab does not have SHT_STRTAB type. Default properties will be
+##          derived from the specified section type.
+# RUN: yaml2obj --docnum=5 %s -o %t12 -DTYPE=SHT_RELA
+# RUN: llvm-readelf -S %t12 | FileCheck %s --check-prefix=CASE12
+
+# CASE12:      There are 5 section headers
+# CASE12-EMPTY:
+# CASE12-NEXT: Section Headers:
+# CASE12-NEXT:   [Nr] Name         Type Address          Off      Size   ES Flg  Lk Inf Al
+# CASE12-NEXT:   [ 0]              NULL
+# CASE12-NEXT:   [ 1] .foo{{ }}
+# CASE12-NEXT:   [ 2] .strings     RELA 0000000000000000 [[#%x,]] 00001c 18       0   0  0
+# CASE12-NEXT:   [ 3] .bar{{ }}
+# CASE12-NEXT:   [ 4] .strtab{{ }}
+
+## Case 13: shstrtab has specified Content. The specified content overrides the
+##          implicitly generated content.
+# RUN: yaml2obj --docnum=5 %s -o %t13 -DCONTENT="00616263646566676800696a6b6c006d6e6f70007172737475767700787a7b7c00"
+# RUN: llvm-readelf -S %t13 | FileCheck %s --check-prefix=CASE13
+
+# CASE13:      There are 5 section headers
+# CASE13-EMPTY:
+# CASE13-NEXT: Section Headers:
+# CASE13-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg  Lk Inf Al
+# CASE13-NEXT:   [ 0]              NULL
+# CASE13-NEXT:   [ 1] mnop{{ }}
+# CASE13-NEXT:   [ 2] abcdefgh     STRTAB 0000000000000000 [[#%x,]] 000021 00       0   0  0
+# CASE13-NEXT:   [ 3] ijkl{{ }}
+# CASE13-NEXT:   [ 4] qrstuvw{{ }}
+
+## Case 14: shstrtab has specified Size. The section will be filled with zeros
+##          to the requested size.
+# RUN: yaml2obj --docnum=5 %s -o %t14 -DSIZE=32
+# RUN: llvm-readelf -S -p=2 %t14 | FileCheck %s --check-prefix=CASE14
+
+# CASE14:      There are 5 section headers
+# CASE14-EMPTY:
+# CASE14-NEXT: Section Headers:
+# CASE14-NEXT:   [Nr] Name Type     Address          Off      Size   ES Flg  Lk Inf Al
+# CASE14-NEXT:   [ 0]      NULL
+# CASE14-NEXT:   [ 1]      PROGBITS
+# CASE14-NEXT:   [ 2]      STRTAB   0000000000000000 [[#%x,]] 000020 00       0   0  0
+# CASE14-NEXT:   [ 3]      PROGBITS
+# CASE14-NEXT:   [ 4]      STRTAB
+
+# CASE14:      String dump of section '':
+# CASE14-EMPTY:
+
+## Case 15: custom shstrtab and no section header table. The section header
+##          names shouldn't appear anywhere in the output file.
+# RUN: yaml2obj --docnum=6 %s -o %t15
+# RUN: FileCheck %s --input-file=%t15 \
+# RUN:   --implicit-check-not=.strings --implicit-check-not=.foo \
+# RUN:   --implicit-check-not=.bar
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .strings
+Sections:
+  - Name:      .foo
+    Type:      SHT_PROGBITS
+  - Name:      .bar
+    Type:      SHT_PROGBITS
+  - Type:      SectionHeaderTable
+    NoHeaders: true
+
+## Case 16: custom shstrtab can be reordered in the section header table.
+# RUN: yaml2obj --docnum=7 %s -o %t16
+# RUN: llvm-readelf -S %t16 | FileCheck %s --check-prefix=CASE16
+
+# CASE16:      There are 5 section headers
+# CASE16-EMPTY:
+# CASE16-NEXT: Section Headers:
+# CASE16-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg  Lk Inf Al
+# CASE16-NEXT:   [ 0]              NULL
+# CASE16-NEXT:   [ 1] .foo{{ }}
+# CASE16-NEXT:   [ 2] .strings     STRTAB 0000000000000000 [[#%x,]] 00001c 00       0   0  1
+# CASE16-NEXT:   [ 3] .bar{{ }}
+# CASE16-NEXT:   [ 4] .strtab{{ }}
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .strings
+Sections:
+  - Name:      .foo
+    Type:      SHT_PROGBITS
+  - Name:      .bar
+    Type:      SHT_PROGBITS
+  - Type:      SectionHeaderTable
+    Sections:
+      - Name: .foo
+      - Name: .strings
+      - Name: .bar
+      - Name: .strtab
+
+## Case 17: custom shstrtab section header can be excluded.
+# RUN: yaml2obj --docnum=8 %s -o %t17
+# RUN: llvm-readelf -h -S %t17 | FileCheck %s --check-prefix=CASE17
+
+# CASE17:      Section header string table index: 0
+# CASE17:      There are 4 section headers
+# CASE17-EMPTY:
+# CASE17-NEXT: Section Headers:
+# CASE17-NEXT:   [Nr] Name         Type
+# CASE17-NEXT:   [ 0] <no-strings> NULL
+# CASE17-NEXT:   [ 1] <no-strings> PROGBITS
+# CASE17-NEXT:   [ 2] <no-strings> PROGBITS
+# CASE17-NEXT:   [ 3] <no-strings> STRTAB
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .strings
+Sections:
+  - Name:      .foo
+    Type:      SHT_PROGBITS
+  - Name:      .bar
+    Type:      SHT_PROGBITS
+  - Type:      SectionHeaderTable
+    Sections:
+      - Name: .foo
+      - Name: .bar
+      - Name: .strtab
+    Excluded:
+      - Name: .strings
+
+## Case 18: section name for excluded section does not appear in custom
+##          shstrtab.
+# RUN: yaml2obj --docnum=9 %s -o %t18
+# RUN: llvm-readelf -S -p=.strings %t18 | FileCheck %s --check-prefix=CASE18
+
+# CASE18:      There are 4 section headers
+# CASE18-EMPTY:
+# CASE18-NEXT: Section Headers:
+# CASE18-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg  Lk Inf Al
+# CASE18-NEXT:   [ 0]              NULL
+# CASE18-NEXT:   [ 1] .foo{{ }}
+# CASE18-NEXT:   [ 2] .strings     STRTAB 0000000000000000 [[#%x,]] 000017 00       0   0  1
+# CASE18-NEXT:   [ 3] .strtab{{ }}
+
+# CASE18:      String dump of section '.strings':
+# CASE18-NEXT: [     1] .strings
+# CASE18-NEXT: [     a] .foo
+# CASE18-NEXT: [     f] .strtab
+# CASE18-EMPTY:
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+  SectionHeaderStringTable: .strings
+Sections:
+  - Name:      .foo
+    Type:      SHT_PROGBITS
+  - Name:      .bar
+    Type:      SHT_PROGBITS
+  - Type:      SectionHeaderTable
+    Sections:
+      - Name: .foo
+      - Name: .strings
+      - Name: .strtab
+    Excluded:
+      - Name: .bar
+
+## Case 19: custom shstrtab can have a uniqued name.
+# RUN: yaml2obj --docnum=1 %s -o %t19 '-DSHSTRTAB=.strings (1)' '-DOTHER=.strings (0)'
+# RUN: llvm-readelf -S -p=4 %t19 | FileCheck %s --check-prefix=CASE19
+
+# CASE19:      There are 5 section headers
+# CASE19-EMPTY:
+# CASE19-NEXT: Section Headers:
+# CASE19-NEXT:   [Nr] Name         Type     Address          Off      Size   ES Flg  Lk Inf Al
+# CASE19-NEXT:   [ 0]              NULL
+# CASE19-NEXT:   [ 1] .foo{{ }}
+# CASE19-NEXT:   [ 2] .strings     PROGBITS
+# CASE19-NEXT:   [ 3] .strtab{{ }}
+# CASE19-NEXT:   [ 4] .strings     STRTAB   0000000000000000 [[#%x,]] 000017 00       0   0  1
+
+# CASE19:      String dump of section '.strings':
+# CASE19-NEXT: [     1] .strings{{$}}
+# CASE19-NEXT: [     a] .foo{{$}}
+# CASE19-NEXT: [     f] .strtab{{$}}
+# CASE19-EMPTY:
+
+## Case 20: custom shstrtab named ".strtab" with uniquifying ID.
+# RUN: yaml2obj --docnum=2 %s -o %t20 '-DSHSTRTAB=.strtab (1)'
+# RUN: llvm-readelf -S -s -p=4 -p=5 %t20 | FileCheck %s --check-prefix=CASE20
+
+# CASE20: There are 6 section headers
+# CASE20-EMPTY:
+# CASE20-NEXT: Section Headers:
+# CASE20-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg Lk Inf Al
+# CASE20-NEXT:   [ 0]              NULL
+# CASE20-NEXT:   [ 1] .foo{{ }}
+# CASE20-NEXT:   [ 2] .bar{{ }}
+# CASE20-NEXT:   [ 3] .symtab{{ }}
+# CASE20-NEXT:   [ 4] .strtab      STRTAB [[#%x,]]         [[#%x,]] 000009 00      0   0  1
+# CASE20-NEXT:   [ 5] .strtab      STRTAB 0000000000000000 [[#%x,]] 00001b 00      0   0  1
+
+# CASE20:      Symbol table '.symtab' contains 3 entries:
+# CASE20-NEXT:    Num: {{.*}} Ndx Name
+# CASE20-NEXT:      0: {{.*}} UND {{$}}
+# CASE20-NEXT:      1: {{.*}}     baz{{$}}
+# CASE20-NEXT:      2: {{.*}}     bob{{$}}
+
+# CASE20:      String dump of section '.strtab':
+# CASE20-NEXT: [     1] baz
+# CASE20-NEXT: [     5] bob
+# CASE20-EMPTY:
+
+# CASE20:      String dump of section '.strtab':
+# CASE20-NEXT: [     1] .bar{{$}}
+# CASE20-NEXT: [     6] .foo{{$}}
+# CASE20-NEXT: [     b] .strtab{{$}}
+# CASE20-NEXT: [    13] .symtab{{$}}
+# CASE20-EMPTY:
+
+## Case 21: custom shstrtab named ".dynstr" with uniquifying ID.
+# RUN: yaml2obj --docnum=3 %s -o %t21 '-DSHSTRTAB=.dynstr (1)'
+# RUN: llvm-readelf -S --dyn-syms -p=4 -p=6 %t21 | FileCheck %s --check-prefix=CASE21
+
+# CASE21: There are 7 section headers
+# CASE21-EMPTY:
+# CASE21-NEXT: Section Headers:
+# CASE21-NEXT:   [Nr] Name         Type   Address          Off      Size   ES Flg Lk Inf Al
+# CASE21-NEXT:   [ 0]              NULL
+# CASE21-NEXT:   [ 1] .foo{{ }}
+# CASE21-NEXT:   [ 2] .bar{{ }}
+# CASE21-NEXT:   [ 3] .dynsym{{ }}
+# CASE21-NEXT:   [ 4] .dynstr      STRTAB [[#%x,]]         [[#%x,]] 000009 00   A  0   0  1
+# CASE21-NEXT:   [ 5] .strtab{{ }}
+# CASE21-NEXT:   [ 6] .dynstr      STRTAB 0000000000000000 [[#%x,]] 000023 00      0   0  1
+
+# CASE21:      Symbol table '.dynsym' contains 3 entries:
+# CASE21-NEXT:    Num: {{.*}} Ndx Name
+# CASE21-NEXT:      0: {{.*}} UND {{$}}
+# CASE21-NEXT:      1: {{.*}}     baz{{$}}
+# CASE21-NEXT:      2: {{.*}}     bob{{$}}
+
+# CASE21:      String dump of section '.dynstr':
+# CASE21-NEXT: [     1] baz
+# CASE21-NEXT: [     5] bob
+# CASE21-EMPTY:
+
+# CASE21:      String dump of section '.dynstr':
+# CASE21-NEXT: [     1] .dynstr{{$}}
+# CASE21-NEXT: [     9] .bar{{$}}
+# CASE21-NEXT: [     e] .foo{{$}}
+# CASE21-NEXT: [    13] .dynsym{{$}}
+# CASE21-NEXT: [    1b] .strtab{{$}}
+# CASE21-EMPTY:

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index bbe5d7283bc56..97cb1f2508463 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -31,6 +31,7 @@ class ELFDumper {
 
   DenseMap<StringRef, uint32_t> UsedSectionNames;
   std::vector<std::string> SectionNames;
+  Optional<uint32_t> ShStrTabIndex;
 
   DenseMap<StringRef, uint32_t> UsedSymbolNames;
   std::vector<std::string> SymbolNames;
@@ -289,6 +290,13 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
   Sections = *SectionsOrErr;
   SectionNames.resize(Sections.size());
 
+  if (Sections.size() > 0) {
+    ShStrTabIndex = Obj.getHeader().e_shstrndx;
+    if (*ShStrTabIndex == ELF::SHN_XINDEX)
+      ShStrTabIndex = Sections[0].sh_link;
+    // TODO: Set EShStrndx if the value doesn't represent a real section.
+  }
+
   // Normally an object that does not have sections has e_shnum == 0.
   // Also, e_shnum might be 0, when the the number of entries in the section
   // header table is larger than or equal to SHN_LORESERVE (0xff00). In this
@@ -398,6 +406,29 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
     return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF);
   });
 
+  // The section header string table by default is assumed to be called
+  // ".shstrtab" and be in its own unique section. However, it's possible for it
+  // to be called something else and shared with another section. If the name
+  // isn't the default, provide this in the YAML.
+  if (ShStrTabIndex && *ShStrTabIndex != ELF::SHN_UNDEF &&
+      *ShStrTabIndex < Sections.size()) {
+    StringRef ShStrtabName;
+    if (SymTab && SymTab->sh_link == *ShStrTabIndex) {
+      // Section header string table is shared with the symbol table. Use that
+      // section's name (usually .strtab).
+      ShStrtabName = cantFail(Obj.getSectionName(Sections[SymTab->sh_link]));
+    } else if (DynSymTab && DynSymTab->sh_link == *ShStrTabIndex) {
+      // Section header string table is shared with the dynamic symbol table.
+      // Use that section's name (usually .dynstr).
+      ShStrtabName = cantFail(Obj.getSectionName(Sections[DynSymTab->sh_link]));
+    } else {
+      // Otherwise, the section name potentially needs uniquifying.
+      ShStrtabName = cantFail(getUniquedSectionName(Sections[*ShStrTabIndex]));
+    }
+    if (ShStrtabName != ".shstrtab")
+      Y->Header.SectionHeaderStringTable = ShStrtabName;
+  }
+
   Y->Chunks = std::move(Chunks);
   return Y.release();
 }
@@ -486,6 +517,12 @@ Optional<DWARFYAML::Data> ELFDumper<ELFT>::dumpDWARFSections(
 
     if (ELFYAML::RawContentSection *RawSec =
             dyn_cast<ELFYAML::RawContentSection>(C.get())) {
+      // FIXME: The debugDebug* functions should take the content as stored in
+      // RawSec. Currently, they just use the last section with the matching
+      // name, which defeats this attempt to skip reading a section header
+      // string table with the same name as a DWARF section.
+      if (ShStrTabIndex && RawSec->OriginalSecNdx == *ShStrTabIndex)
+        continue;
       Error Err = Error::success();
       cantFail(std::move(Err));
 


        


More information about the llvm-commits mailing list