[llvm] ea8c8a5 - [obj2yaml] - Teach tool to emit the "SectionHeaderTable" key and sort sections by file offset.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 1 02:07:03 PST 2020


Author: Georgii Rymar
Date: 2020-12-01T12:59:15+03:00
New Revision: ea8c8a50976fd5b9ca9799414bd3c412fce37f03

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

LOG: [obj2yaml] - Teach tool to emit the "SectionHeaderTable" key and sort sections by file offset.

Currently when we dump sections, we dump them in the order,
which is specified in the sections header table.

With that the order in the output might not match the order in the file.
This patch starts sorting them by by file offsets when dumping.

When the order in the section header table doesn't match the order
in the file, we should emit the "SectionHeaderTable" key. This patch does it.

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

Added: 
    

Modified: 
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/test/Object/X86/obj2yaml-dup-section-name.s
    llvm/test/Object/obj2yaml.test
    llvm/test/tools/obj2yaml/ELF/offset.yaml
    llvm/tools/obj2yaml/elf2yaml.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 5c60705e291e..92b9c284e064 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1648,12 +1648,12 @@ 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);
   IO.mapOptional("DynamicSymbols", Object.DynamicSymbols);
   IO.mapOptional("DWARF", Object.DWARF);
+  IO.mapOptional("SectionHeaderTable", Object.SectionHeaders);
   if (Object.DWARF) {
     Object.DWARF->IsLittleEndian =
         Object.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB);

diff  --git a/llvm/test/Object/X86/obj2yaml-dup-section-name.s b/llvm/test/Object/X86/obj2yaml-dup-section-name.s
index 17fc7a4d9003..9c0a2bef6ac6 100644
--- a/llvm/test/Object/X86/obj2yaml-dup-section-name.s
+++ b/llvm/test/Object/X86/obj2yaml-dup-section-name.s
@@ -2,18 +2,18 @@
 # RUN: obj2yaml %t.o | FileCheck %s
 
 # CHECK: Sections:
+# CHECK: - Name:            .text.foo{{$}}
+# CHECK: - Name:            '.text.foo (1)'
 # CHECK: - Name:            .group{{$}}
 # CHECK:   Members:
 # CHECK:     - SectionOrType:   .text.foo{{$}}
 # CHECK:     - SectionOrType:   .rela.text.foo{{$}}
-# CHECK: - Name:            .text.foo{{$}}
-# CHECK: - Name:            .rela.text.foo{{$}}
-# CHECK:   Info:            .text.foo{{$}}
 # CHECK: - Name:            '.group (1)'
 # CHECK:   Members:
 # CHECK:     - SectionOrType:   '.text.foo (1)'
 # CHECK:     - SectionOrType:   '.rela.text.foo (1)'
-# CHECK: - Name:            '.text.foo (1)'
+# CHECK: - Name:            .rela.text.foo{{$}}
+# CHECK:   Info:            .text.foo{{$}}
 # CHECK: - Name:            '.rela.text.foo (1)'
 # CHECK:   Info:            '.text.foo (1)'
 # CHECK: Symbols:

diff  --git a/llvm/test/Object/obj2yaml.test b/llvm/test/Object/obj2yaml.test
index 840440406456..ea538a16782c 100644
--- a/llvm/test/Object/obj2yaml.test
+++ b/llvm/test/Object/obj2yaml.test
@@ -358,35 +358,10 @@
 # ELF-MIPSEL-NEXT:     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
 # ELF-MIPSEL-NEXT:     AddressAlign:    0x4
 # ELF-MIPSEL-NEXT:     Content:         0000023C00004224E8FFBD271400BFAF1000B0AF218059000000018E000024240000198E09F8200321E000020000198E09F8200321E00002000002241000B08F1400BF8F0800E0031800BD27
-# ELF-MIPSEL-NEXT:   - Name:            .rel.text
-# ELF-MIPSEL-NEXT:     Type:            SHT_REL
-# ELF-MIPSEL-NEXT:     Link:            .symtab
-# ELF-MIPSEL-NEXT:     AddressAlign:    0x4
-# ELF-MIPSEL-NEXT:     Offset:          0x434
-# ELF-MIPSEL-NEXT:     Info:            .text
-# ELF-MIPSEL-NEXT:     Relocations:
-# ELF-MIPSEL-NEXT:       - Symbol:          _gp_disp
-# ELF-MIPSEL-NEXT:         Type:            R_MIPS_HI16
-# ELF-MIPSEL-NEXT:       - Offset:          0x4
-# ELF-MIPSEL-NEXT:         Symbol:          _gp_disp
-# ELF-MIPSEL-NEXT:         Type:            R_MIPS_LO16
-# ELF-MIPSEL-NEXT:       - Offset:          0x18
-# ELF-MIPSEL-NEXT:         Symbol:          '$.str'
-# ELF-MIPSEL-NEXT:         Type:            R_MIPS_GOT16
-# ELF-MIPSEL-NEXT:       - Offset:          0x1C
-# ELF-MIPSEL-NEXT:         Symbol:          '$.str'
-# ELF-MIPSEL-NEXT:         Type:            R_MIPS_LO16
-# ELF-MIPSEL-NEXT:       - Offset:          0x20
-# ELF-MIPSEL-NEXT:         Symbol:          puts
-# ELF-MIPSEL-NEXT:         Type:            R_MIPS_CALL16
-# ELF-MIPSEL-NEXT:       - Offset:          0x2C
-# ELF-MIPSEL-NEXT:         Symbol:          SomeOtherFunction
-# ELF-MIPSEL-NEXT:         Type:            R_MIPS_CALL16
 # ELF-MIPSEL-NEXT:   - Name:            .data
 # ELF-MIPSEL-NEXT:     Type:            SHT_PROGBITS
 # ELF-MIPSEL-NEXT:     Flags:           [ SHF_WRITE, SHF_ALLOC ]
 # ELF-MIPSEL-NEXT:     AddressAlign:    0x4
-# ELF-MIPSEL-NEXT:     Offset:          0x80
 # ELF-MIPSEL-NEXT:   - Name:            .bss
 # ELF-MIPSEL-NEXT:     Type:            SHT_NOBITS
 # ELF-MIPSEL-NEXT:     Flags:           [ SHF_WRITE, SHF_ALLOC ]
@@ -416,6 +391,29 @@
 # ELF-MIPSEL-NEXT:     GPRSize:         REG_32
 # ELF-MIPSEL-NEXT:     CPR1Size:        REG_32
 # ELF-MIPSEL-NEXT:     Flags1:          [ ODDSPREG ]
+# ELF-MIPSEL-NEXT:   - Name:            .rel.text
+# ELF-MIPSEL-NEXT:     Type:            SHT_REL
+# ELF-MIPSEL-NEXT:     Link:            .symtab
+# ELF-MIPSEL-NEXT:     AddressAlign:    0x4
+# ELF-MIPSEL-NEXT:     Info:            .text
+# ELF-MIPSEL-NEXT:     Relocations:
+# ELF-MIPSEL-NEXT:       - Symbol:          _gp_disp
+# ELF-MIPSEL-NEXT:         Type:            R_MIPS_HI16
+# ELF-MIPSEL-NEXT:       - Offset:          0x4
+# ELF-MIPSEL-NEXT:         Symbol:          _gp_disp
+# ELF-MIPSEL-NEXT:         Type:            R_MIPS_LO16
+# ELF-MIPSEL-NEXT:       - Offset:          0x18
+# ELF-MIPSEL-NEXT:         Symbol:          '$.str'
+# ELF-MIPSEL-NEXT:         Type:            R_MIPS_GOT16
+# ELF-MIPSEL-NEXT:       - Offset:          0x1C
+# ELF-MIPSEL-NEXT:         Symbol:          '$.str'
+# ELF-MIPSEL-NEXT:         Type:            R_MIPS_LO16
+# ELF-MIPSEL-NEXT:       - Offset:          0x20
+# ELF-MIPSEL-NEXT:         Symbol:          puts
+# ELF-MIPSEL-NEXT:         Type:            R_MIPS_CALL16
+# ELF-MIPSEL-NEXT:       - Offset:          0x2C
+# ELF-MIPSEL-NEXT:         Symbol:          SomeOtherFunction
+# ELF-MIPSEL-NEXT:         Type:            R_MIPS_CALL16
 # ELF-MIPSEL-NEXT: Symbols:
 # ELF-MIPSEL-NEXT:     - Name:            trivial.ll
 # ELF-MIPSEL-NEXT:       Type:            STT_FILE
@@ -461,6 +459,20 @@
 # ELF-MIPSEL-NEXT:       Binding:         STB_GLOBAL
 # ELF-MIPSEL-NEXT:     - Name:            puts
 # ELF-MIPSEL-NEXT:       Binding:         STB_GLOBAL
+# ELF-MIPSEL-NEXT: SectionHeaderTable:
+# ELF-MIPSEL-NEXT:   Sections:
+# ELF-MIPSEL-NEXT:     - Name: .text
+# ELF-MIPSEL-NEXT:     - Name: .rel.text
+# ELF-MIPSEL-NEXT:     - Name: .data
+# ELF-MIPSEL-NEXT:     - Name: .bss
+# ELF-MIPSEL-NEXT:     - Name: .mdebug.abi32
+# ELF-MIPSEL-NEXT:     - Name: .rodata.str1.1
+# ELF-MIPSEL-NEXT:     - Name: .reginfo
+# ELF-MIPSEL-NEXT:     - Name: .MIPS.abiflags
+# ELF-MIPSEL-NEXT:     - Name: .shstrtab
+# ELF-MIPSEL-NEXT:     - Name: .symtab
+# ELF-MIPSEL-NEXT:     - Name: .strtab
+# ELF-MIPSEL-NEXT: ...
 
 # RUN: obj2yaml %p/Inputs/trivial-object-test.elf-mips64el | FileCheck %s --check-prefix ELF-MIPS64EL
 
@@ -480,20 +492,10 @@
 # ELF-MIPS64EL-NEXT:     Flags:           [ SHF_WRITE, SHF_ALLOC ]
 # ELF-MIPS64EL-NEXT:     AddressAlign:    0x10
 # ELF-MIPS64EL-NEXT:     Content:         '00000000000000000000000000000000'
-# ELF-MIPS64EL-NEXT:   - Name:            .rela.data
-# ELF-MIPS64EL-NEXT:     Type:            SHT_RELA
-# ELF-MIPS64EL-NEXT:     Link:            .symtab
-# ELF-MIPS64EL-NEXT:     AddressAlign:    0x8
-# ELF-MIPS64EL-NEXT:     Offset:          0x410
-# ELF-MIPS64EL-NEXT:     Info:            .data
-# ELF-MIPS64EL-NEXT:     Relocations:
-# ELF-MIPS64EL-NEXT:       - Symbol:          zed
-# ELF-MIPS64EL-NEXT:         Type:            R_MIPS_64
 # ELF-MIPS64EL-NEXT:   - Name:            .bss
 # ELF-MIPS64EL-NEXT:     Type:            SHT_NOBITS
 # ELF-MIPS64EL-NEXT:     Flags:           [ SHF_WRITE, SHF_ALLOC ]
 # ELF-MIPS64EL-NEXT:     AddressAlign:    0x10
-# ELF-MIPS64EL-NEXT:     Offset:          0x50
 # ELF-MIPS64EL-NEXT:   - Name:            .MIPS.options
 # ELF-MIPS64EL-NEXT:     Type:            SHT_MIPS_OPTIONS
 # ELF-MIPS64EL-NEXT:     Flags:           [ SHF_ALLOC, SHF_MIPS_NOSTRIP ]
@@ -503,6 +505,14 @@
 # ELF-MIPS64EL-NEXT:   - Name:            .pdr
 # ELF-MIPS64EL-NEXT:     Type:            SHT_PROGBITS
 # ELF-MIPS64EL-NEXT:     AddressAlign:    0x4
+# ELF-MIPS64EL-NEXT:   - Name:            .rela.data
+# ELF-MIPS64EL-NEXT:     Type:            SHT_RELA
+# ELF-MIPS64EL-NEXT:     Link:            .symtab
+# ELF-MIPS64EL-NEXT:     AddressAlign:    0x8
+# ELF-MIPS64EL-NEXT:     Info:            .data
+# ELF-MIPS64EL-NEXT:     Relocations:
+# ELF-MIPS64EL-NEXT:       - Symbol:          zed
+# ELF-MIPS64EL-NEXT:         Type:            R_MIPS_64
 # ELF-MIPS64EL-NEXT: Symbols:
 # ELF-MIPS64EL-NEXT:     - Name:            .text
 # ELF-MIPS64EL-NEXT:       Type:            STT_SECTION
@@ -523,6 +533,18 @@
 # ELF-MIPS64EL-NEXT:       Section:         .pdr
 # ELF-MIPS64EL-NEXT:     - Name:            zed
 # ELF-MIPS64EL-NEXT:       Binding:         STB_GLOBAL
+# ELF-MIPS64EL-NEXT: SectionHeaderTable:
+# ELF-MIPS64EL-NEXT:   Sections:
+# ELF-MIPS64EL-NEXT:     - Name: .text
+# ELF-MIPS64EL-NEXT:     - Name: .data
+# ELF-MIPS64EL-NEXT:     - Name: .rela.data
+# ELF-MIPS64EL-NEXT:     - Name: .bss
+# ELF-MIPS64EL-NEXT:     - Name: .MIPS.options
+# ELF-MIPS64EL-NEXT:     - Name: .pdr
+# ELF-MIPS64EL-NEXT:     - Name: .shstrtab
+# ELF-MIPS64EL-NEXT:     - Name: .symtab
+# ELF-MIPS64EL-NEXT:     - Name: .strtab
+# ELF-MIPS64EL-NEXT: ...
 
 # RUN: yaml2obj %s -o %t-x86-64
 # RUN: obj2yaml %t-x86-64 | FileCheck %s --check-prefix ELF-X86-64

diff  --git a/llvm/test/tools/obj2yaml/ELF/offset.yaml b/llvm/test/tools/obj2yaml/ELF/offset.yaml
index 2dc04b617417..1eb464c9839b 100644
--- a/llvm/test/tools/obj2yaml/ELF/offset.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/offset.yaml
@@ -5,37 +5,49 @@
 # RUN: yaml2obj %s -o %t1.o
 # RUN: obj2yaml %t1.o | FileCheck %s --check-prefix=BASIC
 
-# BASIC:      --- !ELF
-# BASIC-NEXT: FileHeader:
-# BASIC-NEXT:   Class: ELFCLASS64
-# BASIC-NEXT:   Data:  ELFDATA2LSB
-# BASIC-NEXT:   Type:  ET_REL
-# BASIC-NEXT: Sections:
-# BASIC-NEXT:   - Name:         .foo1
-# BASIC-NEXT:     Type:         SHT_PROGBITS
-# BASIC-NEXT:     Content:      '00'
-# BASIC-NEXT:   - Name:         .foo2
-# BASIC-NEXT:     Type:         SHT_PROGBITS
-# BASIC-NEXT:     Content:      '00'
-# BASIC-NEXT:   - Name:         .foo3
-# BASIC-NEXT:     Type:         SHT_PROGBITS
-# BASIC-NEXT:     Content:      '00'
-# BASIC-NEXT:   - Name:         .bar1
-# BASIC-NEXT:     Type:         SHT_PROGBITS
-# BASIC-NEXT:     Offset:       0x100
-# BASIC-NEXT:     Content:      '00'
-# BASIC-NEXT:   - Name:         .bar2
-# BASIC-NEXT:     Type:         SHT_PROGBITS
-# BASIC-NEXT:     AddressAlign: 0x10
-# BASIC-NEXT:     Content:      '00'
-# BASIC-NEXT:   - Name:         .bar3
-# BASIC-NEXT:     Type:         SHT_PROGBITS
-# BASIC-NEXT:     AddressAlign: 0x10
-# BASIC-NEXT:     Offset:       0x200
-# BASIC-NEXT:   - Name:         .bar4
-# BASIC-NEXT:     Type:         SHT_PROGBITS
-# BASIC-NEXT:     AddressAlign: 0x100000000
-# BASIC-NEXT:     Offset:       0x210
+#   BASIC:      --- !ELF
+#   BASIC-NEXT: FileHeader:
+#   BASIC-NEXT:   Class: ELFCLASS64
+#   BASIC-NEXT:   Data:  ELFDATA2LSB
+#   BASIC-NEXT:   Type:  ET_REL
+#   BASIC-NEXT: Sections:
+#   BASIC-NEXT:   - Name:         .foo1
+#   BASIC-NEXT:     Type:         SHT_PROGBITS
+#   BASIC-NEXT:     Content:      '00'
+#   BASIC-NEXT:   - Name:         .foo2
+#   BASIC-NEXT:     Type:         SHT_PROGBITS
+#   BASIC-NEXT:     Content:      '00'
+#   BASIC-NEXT:   - Name:         .foo3
+#   BASIC-NEXT:     Type:         SHT_PROGBITS
+#   BASIC-NEXT:     Content:      '00'
+#   BASIC-NEXT:   - Name:         .bar1
+#   BASIC-NEXT:     Type:         SHT_PROGBITS
+#   BASIC-NEXT:     Offset:       0x100
+#   BASIC-NEXT:     Content:      '00'
+#   BASIC-NEXT:   - Name:         .bar2
+#   BASIC-NEXT:     Type:         SHT_PROGBITS
+#   BASIC-NEXT:     AddressAlign: 0x10
+#   BASIC-NEXT:     Content:      '00'
+#   BASIC-NEXT:   - Name:         .bar3
+#   BASIC-NEXT:     Type:         SHT_PROGBITS
+#   BASIC-NEXT:     AddressAlign: 0x10
+#   BASIC-NEXT:     Offset:       0x200
+#   BASIC-NEXT:   - Name:         .bar4
+#   BASIC-NEXT:     Type:         SHT_PROGBITS
+#   BASIC-NEXT:     AddressAlign: 0x100000000
+#   BASIC-NEXT:     Offset:       0x210
+# HEADERS-NEXT: SectionHeaderTable:
+# HEADERS-NEXT:   Sections:
+# HEADERS-NEXT:     - Name:            .bar4
+# HEADERS-NEXT:     - Name:            .bar3
+# HEADERS-NEXT:     - Name:            .bar2
+# HEADERS-NEXT:     - Name:            .bar1
+# HEADERS-NEXT:     - Name:            .foo3
+# HEADERS-NEXT:     - Name:            .foo2
+# HEADERS-NEXT:     - Name:            .foo1
+# HEADERS-NEXT:     - Name:            .strtab
+# HEADERS-NEXT:     - Name:            .shstrtab
+# BASIC-NEXT: ...
 
 --- !ELF
 FileHeader:
@@ -91,6 +103,25 @@ Sections:
     Type:         SHT_PROGBITS
     AddressAlign: 0x100000000
     Offset:       0x210
+SectionHeaderTable:
+  Sections:
+## By default we have the same order of sections as defined by the "Sections" key.
+    - Name: [[SEC1=.foo1]]
+    - Name: [[SEC2=.foo2]]
+    - Name: [[SEC3=.foo3]]
+    - Name: [[SEC4=.bar1]]
+    - Name: [[SEC5=.bar2]]
+    - Name: [[SEC6=.bar3]]
+    - Name: [[SEC7=.bar4]]
+    - Name: .strtab
+    - Name: .shstrtab
+
+## In this case we change the order of sections in the section header table.
+## Check that we still dump offsets correctly.
+
+# RUN: yaml2obj %s -DSEC1=.bar4 -DSEC2=.bar3 -DSEC3=.bar2 \
+# RUN:   -DSEC4=.bar1 -DSEC5=.foo3 -DSEC6=.foo2 -DSEC7=.foo1 -o %t1-sechdr.o
+# RUN: obj2yaml %t1-sechdr.o | FileCheck --check-prefixes=BASIC,HEADERS %s
 
 ## Show we dump the "Offset" key for the first section when
 ## it has an unexpected file offset.

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index ea2f2911712b..0a85179a7b93 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -359,6 +359,20 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
     return ChunksOrErr.takeError();
   std::vector<std::unique_ptr<ELFYAML::Chunk>> Chunks = std::move(*ChunksOrErr);
 
+  std::vector<ELFYAML::Section *> OriginalOrder;
+  if (!Chunks.empty())
+    for (const std::unique_ptr<ELFYAML::Chunk> &C :
+         makeArrayRef(Chunks).drop_front())
+      OriginalOrder.push_back(cast<ELFYAML::Section>(C.get()));
+
+  // Sometimes the order of sections in the section header table does not match
+  // their actual order. Here we sort sections by the file offset.
+  llvm::stable_sort(Chunks, [&](const std::unique_ptr<ELFYAML::Chunk> &A,
+                                const std::unique_ptr<ELFYAML::Chunk> &B) {
+    return Sections[cast<ELFYAML::Section>(A.get())->OriginalSecNdx].sh_offset <
+           Sections[cast<ELFYAML::Section>(B.get())->OriginalSecNdx].sh_offset;
+  });
+
   // Dump program headers.
   Expected<std::vector<ELFYAML::ProgramHeader>> PhdrsOrErr =
       dumpProgramHeaders(Chunks);
@@ -372,6 +386,21 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
   // Dump DWARF sections.
   Y->DWARF = dumpDWARFSections(Chunks);
 
+  // We emit the "SectionHeaderTable" key when the order of sections in the
+  // sections header table doesn't match the file order.
+  const bool SectionsSorted =
+      llvm::is_sorted(Chunks, [&](const std::unique_ptr<ELFYAML::Chunk> &A,
+                                  const std::unique_ptr<ELFYAML::Chunk> &B) {
+        return cast<ELFYAML::Section>(A.get())->OriginalSecNdx <
+               cast<ELFYAML::Section>(B.get())->OriginalSecNdx;
+      });
+  if (!SectionsSorted) {
+    Y->SectionHeaders.emplace();
+    Y->SectionHeaders->Sections.emplace();
+    for (ELFYAML::Section *S : OriginalOrder)
+      Y->SectionHeaders->Sections->push_back({S->Name});
+  }
+
   llvm::erase_if(Chunks, [this, &Y](const std::unique_ptr<ELFYAML::Chunk> &C) {
     const ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
     return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF);


        


More information about the llvm-commits mailing list