[llvm] ad07d5f - [yaml2obj] - Implement the "SectionHeaderTable" tag.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Thu May 28 03:43:02 PDT 2020


Author: Georgii Rymar
Date: 2020-05-28T13:42:43+03:00
New Revision: ad07d5f39425d4b7013346f4eb52a1e99e6c19a8

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

LOG: [yaml2obj] - Implement the "SectionHeaderTable" tag.

With the "SectionHeaderTable" it is now possible to reorder
entries in the section header table.

It also allows to stop emitting the table.

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

Added: 
    llvm/test/tools/yaml2obj/ELF/section-headers.yaml

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/lib/ObjectYAML/ELFYAML.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 22ed82289ca8..5d3384925631 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -86,6 +86,14 @@ struct FileHeader {
   Optional<llvm::yaml::Hex16> SHStrNdx;
 };
 
+struct SectionHeader {
+  StringRef Name;
+};
+
+struct SectionHeaderTable {
+  std::vector<SectionHeader> Sections;
+};
+
 struct SectionName {
   StringRef Section;
 };
@@ -508,6 +516,7 @@ struct ProgramHeader {
 
 struct Object {
   FileHeader Header;
+  Optional<SectionHeaderTable> SectionHeaders;
   std::vector<ProgramHeader> ProgramHeaders;
 
   // An object might contain output section descriptions as well as
@@ -539,6 +548,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::LinkerOption)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::CallGraphEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::NoteEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionHeader)
 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Chunk>)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerdefEntry)
@@ -670,6 +680,14 @@ struct MappingTraits<ELFYAML::FileHeader> {
   static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr);
 };
 
+template <> struct MappingTraits<ELFYAML::SectionHeaderTable> {
+  static void mapping(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable);
+};
+
+template <> struct MappingTraits<ELFYAML::SectionHeader> {
+  static void mapping(IO &IO, ELFYAML::SectionHeader &SHdr);
+};
+
 template <> struct MappingTraits<ELFYAML::ProgramHeader> {
   static void mapping(IO &IO, ELFYAML::ProgramHeader &FileHdr);
 };

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 78093491704b..2b7bad674fa4 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -218,6 +218,8 @@ template <class ELFT> class ELFState {
 
   void assignSectionAddress(Elf_Shdr &SHeader, ELFYAML::Section *YAMLSec);
 
+  DenseMap<StringRef, size_t> buildSectionHeaderReorderMap();
+
   BumpPtrAllocator StringAlloc;
   uint64_t alignToOffset(ContiguousBlobAccumulator &CBA, uint64_t Align,
                          llvm::Optional<llvm::yaml::Hex64> Offset);
@@ -318,12 +320,29 @@ void ELFState<ELFT>::writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream
   // other sections to the end of the file.
   uint64_t SHOff =
       alignToOffset(CBA, sizeof(typename ELFT::uint), /*Offset=*/None);
-  Header.e_shoff =
-      Doc.Header.SHOff ? typename ELFT::uint(*Doc.Header.SHOff) : SHOff;
-  Header.e_shnum =
-      Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : Doc.getSections().size();
-  Header.e_shstrndx = Doc.Header.SHStrNdx ? (uint16_t)*Doc.Header.SHStrNdx
-                                          : SN2I.get(".shstrtab");
+
+  if (Doc.Header.SHOff)
+    Header.e_shoff = *Doc.Header.SHOff;
+  else if (Doc.SectionHeaders && Doc.SectionHeaders->Sections.empty())
+    Header.e_shoff = 0;
+  else
+    Header.e_shoff = SHOff;
+
+  if (Doc.Header.SHNum)
+    Header.e_shnum = *Doc.Header.SHNum;
+  else if (!Doc.SectionHeaders)
+    Header.e_shnum = Doc.getSections().size();
+  else if (Doc.SectionHeaders->Sections.empty())
+    Header.e_shnum = 0;
+  else
+    Header.e_shnum = Doc.SectionHeaders->Sections.size() + /*Null section*/ 1;
+
+  if (Doc.Header.SHStrNdx)
+    Header.e_shstrndx = *Doc.Header.SHStrNdx;
+  else if (!Doc.SectionHeaders || !Doc.SectionHeaders->Sections.empty())
+    Header.e_shstrndx = SN2I.get(".shstrtab");
+  else
+    Header.e_shstrndx = 0;
 
   OS.write((const char *)&Header, sizeof(Header));
 }
@@ -1447,14 +1466,50 @@ void ELFState<ELFT>::writeFill(ELFYAML::Fill &Fill,
   Fill.Pattern->writeAsBinary(OS, Fill.Size - Written);
 }
 
+template <class ELFT>
+DenseMap<StringRef, size_t> ELFState<ELFT>::buildSectionHeaderReorderMap() {
+  if (!Doc.SectionHeaders || Doc.SectionHeaders->Sections.empty())
+    return DenseMap<StringRef, size_t>();
+
+  DenseMap<StringRef, size_t> Ret;
+  size_t SecNdx = 0;
+  StringSet<> Seen;
+  for (const ELFYAML::SectionHeader &Hdr : Doc.SectionHeaders->Sections) {
+    if (!Ret.try_emplace(Hdr.Name, ++SecNdx).second)
+      reportError("repeated section name: '" + Hdr.Name +
+                  "' in the section header description");
+    Seen.insert(Hdr.Name);
+  }
+
+  for (const ELFYAML::Section *S : Doc.getSections()) {
+    // Ignore special first SHT_NULL section.
+    if (S == Doc.getSections().front())
+      continue;
+    if (!Seen.count(S->Name))
+      reportError("section '" + S->Name +
+                  "' should be present in the 'Sections' list");
+    Seen.erase(S->Name);
+  }
+
+  for (const auto &It : Seen)
+    reportError("section header contains undefined section '" + It.getKey() +
+                "'");
+  return Ret;
+}
+
 template <class ELFT> void ELFState<ELFT>::buildSectionIndex() {
+  // A YAML description can have an explicit section header declaration that allows
+  // to change the order of section headers.
+  DenseMap<StringRef, size_t> ReorderMap = buildSectionHeaderReorderMap();
+
   size_t SecNdx = -1;
   for (const std::unique_ptr<ELFYAML::Chunk> &C : Doc.Chunks) {
     if (!isa<ELFYAML::Section>(C.get()))
       continue;
     ++SecNdx;
 
-    if (!SN2I.addName(C->Name, SecNdx))
+    size_t Index = ReorderMap.empty() ? SecNdx : ReorderMap.lookup(C->Name);
+    if (!SN2I.addName(C->Name, Index))
       llvm_unreachable("buildSectionIndex() failed");
     DotShStrtab.add(ELFYAML::dropUniqueSuffix(C->Name));
   }

diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 3a621d77a36b..d3e4d2ee3bd8 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -832,6 +832,16 @@ void ScalarBitSetTraits<ELFYAML::MIPS_AFL_FLAGS1>::bitset(
 #undef BCase
 }
 
+void MappingTraits<ELFYAML::SectionHeader>::mapping(
+    IO &IO, ELFYAML::SectionHeader &SHdr) {
+  IO.mapRequired("Name", SHdr.Name);
+}
+
+void MappingTraits<ELFYAML::SectionHeaderTable>::mapping(
+    IO &IO, ELFYAML::SectionHeaderTable &SectionHeader) {
+  IO.mapRequired("Sections", SectionHeader.Sections);
+}
+
 void MappingTraits<ELFYAML::FileHeader>::mapping(IO &IO,
                                                  ELFYAML::FileHeader &FileHdr) {
   IO.mapRequired("Class", FileHdr.Class);
@@ -1638,6 +1648,7 @@ void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
   IO.setContext(&Object);
   IO.mapTag("!ELF", true);
   IO.mapRequired("FileHeader", Object.Header);
+  IO.mapOptional("SectionHeaderTable", Object.SectionHeaders);
   IO.mapOptional("ProgramHeaders", Object.ProgramHeaders);
   IO.mapOptional("Sections", Object.Chunks);
   IO.mapOptional("Symbols", Object.Symbols);

diff  --git a/llvm/test/tools/yaml2obj/ELF/section-headers.yaml b/llvm/test/tools/yaml2obj/ELF/section-headers.yaml
new file mode 100644
index 000000000000..ee0049d4d31d
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/ELF/section-headers.yaml
@@ -0,0 +1,184 @@
+## Check we can use "SectionHeaderTable" tag to reorder section header entries.
+
+## This is a general test that has sections with unique prefixes, a fill and a
+## section without the unique prefix. The section header table describes sections
+## in the same order they are listed in the YAML.
+# RUN: yaml2obj %s --docnum=1 -o %t1 -DSEC1=".section (1)" -DSEC2=".section (2)" -DSEC3=".section.foo"
+# RUN: llvm-readelf --section-headers %t1 | FileCheck %s --check-prefix=NO-OP
+
+# NO-OP:      Section Headers:
+# NO-OP-NEXT:   [Nr] Name         Type     Address          Off    Size   ES Flg Lk Inf Al
+# NO-OP-NEXT:   [ 0]              NULL     0000000000000000 000000 000000 00      0   0  0
+# NO-OP-NEXT:   [ 1] .section     PROGBITS 0000000000000000 000040 000010 00      0   0  0
+# NO-OP-NEXT:   [ 2] .section     PROGBITS 0000000000000000 000050 000020 00      0   0  0
+# NO-OP-NEXT:   [ 3] .section.foo PROGBITS 0000000000000000 0000a0 000040 00      0   0  0
+# NO-OP-NEXT:   [ 4] .strtab      STRTAB   0000000000000000 0000e0 000001 00      0   0  1
+# NO-OP-NEXT:   [ 5] .shstrtab    STRTAB   0000000000000000 0000e1 000029 00      0   0  1
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Name: .section (1)
+    Type: SHT_PROGBITS
+    Size: 0x10
+  - Name: .section (2)
+    Type: SHT_PROGBITS
+    Size: 0x20
+  - Type:    Fill
+    Name:    .filler
+    Size:    0x30
+    Pattern: ""
+  - Name: .section.foo
+    Type: SHT_PROGBITS
+    Size: 0x40
+SectionHeaderTable:
+  Sections:
+    - Name: [[SEC1]]
+    - Name: [[SEC2]]
+    - Name: [[SEC3]]
+    - Name: .strtab
+    - Name: .shstrtab
+
+## Show we are able to reorder sections.
+# RUN: yaml2obj %s -o %t2 -DSEC3=".section (1)" -DSEC2=".section (2)" -DSEC1=".section.foo"
+# RUN: llvm-readelf --section-headers %t2 | FileCheck %s --check-prefix=REORDERED
+
+# REORDERED:      Section Headers:
+# REORDERED-NEXT:   [Nr] Name         Type     Address          Off    Size   ES Flg Lk Inf Al
+# REORDERED-NEXT:   [ 0]              NULL     0000000000000000 000000 000000 00      0   0  0
+# REORDERED-NEXT:   [ 1] .section.foo PROGBITS 0000000000000000 0000a0 000040 00      0   0  0
+# REORDERED-NEXT:   [ 2] .section     PROGBITS 0000000000000000 000050 000020 00      0   0  0
+# REORDERED-NEXT:   [ 3] .section     PROGBITS 0000000000000000 000040 000010 00      0   0  0
+# REORDERED-NEXT:   [ 4] .strtab      STRTAB   0000000000000000 0000e0 000001 00      0   0  1
+# REORDERED-NEXT:   [ 5] .shstrtab    STRTAB   0000000000000000 0000e1 000029 00      0   0  1
+
+## Show we report proper errors when the section header description:
+##  a) contains a repeated section name.
+##  b) omits any section that exists.
+##  c) contains a non-existent section.
+# RUN: not yaml2obj %s -o /dev/null -DSEC1=".section.foo" -DSEC2="unknown" -DSEC3=".section.foo" 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ERR1
+#   d) contains a repeated implicit section name.
+#   e) contains a fill name.
+# RUN: not yaml2obj %s -o /dev/null -DSEC1=".strtab" -DSEC2=".shstrtab" -DSEC3=".filler" 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ERR2
+
+# ERR1:      error: repeated section name: '.section.foo' in the section header description
+# ERR1-NEXT: error: section '.section (1)' should be present in the 'Sections' list
+# ERR1-NEXT: error: section '.section (2)' should be present in the 'Sections' list
+# ERR1-NEXT: error: section header contains undefined section 'unknown'
+
+# ERR2:      error: repeated section name: '.strtab' in the section header description
+# ERR2-NEXT: error: repeated section name: '.shstrtab' in the section header description
+# ERR2-NEXT: error: section '.section (1)' should be present in the 'Sections' list
+# ERR2-NEXT: error: section '.section (2)' should be present in the 'Sections' list
+# ERR2-NEXT: error: section '.section.foo' should be present in the 'Sections' list
+# ERR2-NEXT: error: section header contains undefined section '.filler'
+
+## Test that we are able to specify an empty sections list for
+## the "SectionHeaderTable" tag to produce no section header.
+# RUN: yaml2obj %s --docnum=2 -o %t3
+# RUN: llvm-readelf --file-headers %t3 | FileCheck %s --check-prefix=NO-HEADERS
+
+# NO-HEADERS: Start of section headers:          0  (bytes into file)
+# NO-HEADERS: Size of section headers:           64 (bytes)
+# NO-HEADERS: Number of section headers:         0
+# NO-HEADERS: Section header string table index: 0
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Name: .foo
+    Type: SHT_PROGBITS
+SectionHeaderTable:
+  Sections: []
+
+## Test that we are still able to override e_shoff, e_shnum and e_shstrndx
+## fields even when we do not produce section headers.
+# RUN: yaml2obj %s --docnum=3 -o %t4
+# RUN: llvm-readelf --file-headers %t4 | FileCheck %s --check-prefix=NO-HEADERS-OVERRIDE
+
+# NO-HEADERS-OVERRIDE: Start of section headers:          2 (bytes into file)
+# NO-HEADERS-OVERRIDE: Number of section headers:         3
+# NO-HEADERS-OVERRIDE: Section header string table index: 4
+
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_REL
+  Machine:   EM_X86_64
+  SHOff:     0x2
+  SHNum:     0x3
+  SHStrNdx:  0x4
+Sections:
+  - Name: .foo
+    Type: SHT_PROGBITS
+SectionHeaderTable:
+  Sections: []
+
+## Check that section indices are updated properly in other places when we
+## reorder sections in the section header table.
+# RUN: yaml2obj %s --docnum=4 -o %t5 -DSEC1=".foo" -DSEC2=".bar"
+# RUN: llvm-readelf --section-headers --symbols %t5 | FileCheck %s --check-prefix=INDICES-A
+# RUN: yaml2obj %s --docnum=4 -o %t6 -DSEC2=".foo" -DSEC1=".bar"
+# RUN: llvm-readelf --section-headers --symbols %t6 | FileCheck %s --check-prefix=INDICES-B
+
+# INDICES-A:      [Nr] Name       Type     Address          Off    Size   ES Flg Lk
+# INDICES-A:      [ 1] .foo       PROGBITS 0000000000000000 000040 000000 00      0
+# INDICES-A-NEXT: [ 2] .bar       PROGBITS 0000000000000000 000040 000000 00      0
+# INDICES-A-NEXT: [ 3] .another.1 PROGBITS 0000000000000000 000040 000000 00      1
+# INDICES-A-NEXT: [ 4] .another.2 PROGBITS 0000000000000000 000040 000000 00      2
+
+# INDICES-A:      Num:    Value          Size Type    Bind   Vis       Ndx Name
+# INDICES-A:        1: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT     1 foo
+# INDICES-A-NEXT:   2: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT     2 bar
+
+# INDICES-B:      [ 1] .bar       PROGBITS 0000000000000000 000040 000000 00      0
+# INDICES-B-NEXT: [ 2] .foo       PROGBITS 0000000000000000 000040 000000 00      0
+# INDICES-B-NEXT: [ 3] .another.1 PROGBITS 0000000000000000 000040 000000 00      2
+# INDICES-B-NEXT: [ 4] .another.2 PROGBITS 0000000000000000 000040 000000 00      1
+
+# INDICES-B:      Num: Value            Size Type   Bind  Vis     Ndx Name
+# INDICES-B:        1: 0000000000000000    0 NOTYPE LOCAL DEFAULT   2 foo
+# INDICES-B-NEXT:   2: 0000000000000000    0 NOTYPE LOCAL DEFAULT   1 bar
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Name: .foo
+    Type: SHT_PROGBITS
+  - Name: .bar
+    Type: SHT_PROGBITS
+  - Name: .another.1
+    Link: .foo
+    Type: SHT_PROGBITS
+  - Name: .another.2
+    Link: .bar
+    Type: SHT_PROGBITS
+SectionHeaderTable:
+  Sections:
+    - Name: [[SEC1]]
+    - Name: [[SEC2]]
+    - Name: .another.1
+    - Name: .another.2
+    - Name: .symtab
+    - Name: .strtab
+    - Name: .shstrtab
+Symbols:
+  - Name:    foo
+    Section: .foo
+  - Name:    bar
+    Section: .bar


        


More information about the llvm-commits mailing list