[llvm-branch-commits] [llvm] 5edb90c - [obj2yaml] - Dump section offsets in some cases.

Georgii Rymar via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Nov 25 01:53:08 PST 2020


Author: Georgii Rymar
Date: 2020-11-25T12:41:01+03:00
New Revision: 5edb90c927131b9153da98634241ef74419a3b4d

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

LOG: [obj2yaml] - Dump section offsets in some cases.

Currently we never dump the `sh_offset` key.
Though it sometimes an important information.

To reduce the noise this patch implements the following logic:
1) The "Offset" key for the first section is always emitted.
2) If we can derive the offset for a next section naturally,
   then the "Offset" key is omitted.

By "naturally" I mean that section[X] offset is expected to be:
```
offsetOf(section[X]) == alignTo(section[X - 1].sh_offset + section[X - 1].sh_size, section[X].sh_addralign)
```

So, when it has the expected value, we omit it from the output.

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

Added: 
    llvm/test/tools/obj2yaml/ELF/offset.yaml

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/test/Object/obj2yaml.test
    llvm/tools/obj2yaml/elf2yaml.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 058d78d4f4fd..9015fb680b60 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -658,6 +658,9 @@ struct Object {
   unsigned getMachine() const;
 };
 
+bool shouldAllocateFileSpace(ArrayRef<ProgramHeader> Phdrs,
+                             const NoBitsSection &S);
+
 } // end namespace ELFYAML
 } // end namespace llvm
 

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index b31b7681adad..b8386bd46be2 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1135,8 +1135,8 @@ void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
   }
 }
 
-static bool shouldAllocateFileSpace(ArrayRef<ELFYAML::ProgramHeader> Phdrs,
-                                    const ELFYAML::NoBitsSection &S) {
+bool llvm::ELFYAML::shouldAllocateFileSpace(
+    ArrayRef<ELFYAML::ProgramHeader> Phdrs, const ELFYAML::NoBitsSection &S) {
   for (const ELFYAML::ProgramHeader &PH : Phdrs) {
     auto It = llvm::find_if(
         PH.Chunks, [&](ELFYAML::Chunk *C) { return C->Name == S.Name; });

diff  --git a/llvm/test/Object/obj2yaml.test b/llvm/test/Object/obj2yaml.test
index ea6194dee9a6..840440406456 100644
--- a/llvm/test/Object/obj2yaml.test
+++ b/llvm/test/Object/obj2yaml.test
@@ -362,6 +362,7 @@
 # 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
@@ -385,6 +386,7 @@
 # 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 ]
@@ -482,6 +484,7 @@
 # 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
@@ -490,6 +493,7 @@
 # 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 ]

diff  --git a/llvm/test/tools/obj2yaml/ELF/offset.yaml b/llvm/test/tools/obj2yaml/ELF/offset.yaml
new file mode 100644
index 000000000000..417c92aed1f8
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/ELF/offset.yaml
@@ -0,0 +1,260 @@
+## Check how the "Offset" field is dumped by obj2yaml.
+## For each section we calulate the expected offset.
+## When it does not match the actual offset, we emit the "Offset" key.
+
+# 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
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+Sections:
+## The offset of .foo1 by default is 0x40, because it is placed right
+## after the ELF header. In this case we don't dump the "Offset" key,
+## because the file offset is naturally expected.
+  - Name:         .foo1
+    Type:         SHT_PROGBITS
+    Size:         1
+    Offset:       [[FIRSTOFF=<none>]]
+    AddressAlign: [[FIRSTADDRALIGN=0]]
+## Offset of .foo2 == offset of .foo1 + size of .foo1.
+## We don't dump the "Offset" key in this case.
+## sh_offset of .foo2 is 0x41.
+  - Name: .foo2
+    Type: SHT_PROGBITS
+    Size: 1
+## Offset of .foo3 == offset of .foo2 + size of .foo2,
+## We don't dump the "Offset" key in this case.
+## sh_offset of .foo3 is 0x42.
+  - Name: .foo3
+    Type: SHT_PROGBITS
+    Size: 1
+## Offset of .bar1 != offset of .foo3 + size of .foo3.
+## We dump the "Offset" key in this case.
+## sh_offset of .bar1 is 0x100.
+  - Name:   .bar1
+    Type:   SHT_PROGBITS
+    Offset: 0x100
+    Size: 1
+## [Offset of .bar1 + size of .bar1] aligned by 0x10 is equal to the offset
+## of .bar2. We don't dump the "Offset" key in this case.
+## sh_offset of .bar2 is 0x110.
+  - Name:         .bar2
+    Type:         SHT_PROGBITS
+    AddressAlign: 0x10
+    Offset:       0x110
+    Size:         1
+## [Offset of .bar2 + size of .bar2] aligned by 0x10 is not equal to the offset
+## of .bar3. We dump the "Offset" key in this case.
+## sh_offset of .bar3 is 0x200.
+  - Name:         .bar3
+    Type:         SHT_PROGBITS
+    AddressAlign: 0x10
+    Offset:       0x200
+
+## Show we dump the "Offset" key for the first section when
+## it has an unexpected file offset.
+
+# RUN: yaml2obj %s -DFIRSTOFF=0x40 -o %t2a.o
+# RUN: obj2yaml %t2a.o | FileCheck %s --check-prefix=BASIC
+# RUN: yaml2obj %s -DFIRSTOFF=0x41 -o %t2b.o
+# RUN: obj2yaml %t2b.o | FileCheck %s --check-prefix=FIRSTSEC
+
+# FIRSTSEC:      Sections:
+# FIRSTSEC-NEXT:   - Name:    .foo1
+# FIRSTSEC-NEXT:     Type:    SHT_PROGBITS
+# FIRSTSEC-NEXT:     Offset:  0x41
+# FIRSTSEC-NEXT:     Content: '00'
+
+## Test that we take the alignment of the first section into account
+## when calculating the expected offset for it. In this case we don't
+## dump the "Offset", because it is expected.
+
+# RUN: yaml2obj %s -DFIRSTOFF=0x80 -DFIRSTADDRALIGN=0x80 -o %t3.o
+# RUN: obj2yaml %t3.o | FileCheck %s --check-prefix=FIRSTSECALIGN
+
+# FIRSTSECALIGN:      - Name:         .foo1
+# FIRSTSECALIGN-NEXT:   Type:         SHT_PROGBITS
+# FIRSTSECALIGN-NEXT:   AddressAlign: 0x80
+# FIRSTSECALIGN-NEXT:   Content:      '00'
+# FIRSTSECALIGN-NEXT: - Name:
+
+## Test that we take the program headers offset and size into account when calculating
+## the expected file offset of the first section.
+
+# RUN: yaml2obj %s --docnum=2 -o %t4a.o
+# RUN: obj2yaml %t4a.o | FileCheck %s --check-prefix=FIRSTSECPHDRS
+## The expected file offset of the first section is:
+## 0x40 (start of program headers) + 0x38 (size of program headers) * 2(number of program headers) = 0xB0
+# RUN: yaml2obj %s --docnum=2 -DFIRSTOFF=0xB0 -o %t4b.o
+# RUN: obj2yaml %t4b.o | FileCheck %s --check-prefix=FIRSTSECPHDRS
+# RUN: yaml2obj %s --docnum=2 -DFIRSTOFF=0xB1 -o %t4c.o
+# RUN: obj2yaml %t4c.o | FileCheck %s --check-prefixes=FIRSTSECPHDRS,FIRSTSECPHDRSOFFSET
+
+#       FIRSTSECPHDRS:      Sections:
+#       FIRSTSECPHDRS-NEXT:   - Name:   .foo
+#       FIRSTSECPHDRS-NEXT:     Type:   SHT_PROGBITS
+# FIRSTSECPHDRSOFFSET-NEXT:     Offset: 0xB1
+#       FIRSTSECPHDRS-NEXT:   ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+Sections:
+  - Name:   .foo
+    Type:   SHT_PROGBITS
+    Offset: [[FIRSTOFF=<none>]]
+ProgramHeaders:
+  - Type: PT_LOAD
+  - Type: PT_LOAD
+
+## Test that when there are no program headers in the file, we don't take SHT_NOBITS
+## section sizes into account, but respect their alignment when calculating the expected
+## section offsets.
+
+# RUN: yaml2obj %s --docnum=3 -o %t5.o
+# RUN: obj2yaml %t5.o | FileCheck %s --check-prefix=NOBITS
+
+# NOBITS:      Sections:
+# NOBITS-NEXT:   - Name:         .progbits1
+# NOBITS-NEXT:     Type:         SHT_PROGBITS
+# NOBITS-NEXT:     Content:      '00'
+# NOBITS-NEXT:   - Name:         .nobits1
+# NOBITS-NEXT:     Type:         SHT_NOBITS
+# NOBITS-NEXT:     Size:         0x10
+# NOBITS-NEXT:   - Name:         .progbits2
+# NOBITS-NEXT:     Type:         SHT_PROGBITS
+# NOBITS-NEXT:     Content:      '0000'
+# NOBITS-NEXT:   - Name:         .nobits2
+# NOBITS-NEXT:     Type:         SHT_NOBITS
+# NOBITS-NEXT:     AddressAlign: 0x100
+# NOBITS-NEXT:     Size:         0x100
+# NOBITS-NEXT:   - Name:         .progbits3
+# NOBITS-NEXT:     Type:         SHT_PROGBITS
+# NOBITS-NEXT:     Content:      '000000'
+# NOBITS-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+Sections:
+## sh_offset == 0x40.
+  - Name: .progbits1
+    Type: SHT_PROGBITS
+    Size: 0x1
+## sh_offset == 0x41.
+  - Name: .nobits1
+    Type: SHT_NOBITS
+    Size: 0x10
+## sh_offset == 0x41.
+  - Name: .progbits2
+    Type: SHT_PROGBITS
+    Size: 0x2
+## sh_offset == 0x100.
+  - Name:         .nobits2
+    Type:         SHT_NOBITS
+    Size:         0x100
+    AddressAlign: 0x100
+## sh_offset == 0x100.
+  - Name: .progbits3
+    Type: SHT_PROGBITS
+    Size: 0x3
+
+## Check that we might take sizes of SHT_NOBITS sections into account when calculating
+## the expected offsets when there are program headers in the file. The rule is the following:
+## we assume that the file space is allocated for the SHT_NOBITS section when there are
+## other non-nobits sections in the same segment that follows it.
+
+# RUN: yaml2obj %s --docnum=4 -o %t6.o
+# RUN: obj2yaml %t6.o | FileCheck %s --check-prefix=NOBITS-PHDRS
+
+# NOBITS-PHDRS:      Sections:
+# NOBITS-PHDRS-NEXT:   - Name:    .nobits1
+# NOBITS-PHDRS-NEXT:     Type:    SHT_NOBITS
+# NOBITS-PHDRS-NEXT:     Size:    0x1
+# NOBITS-PHDRS-NEXT:   - Name:    .progbits
+# NOBITS-PHDRS-NEXT:     Type:    SHT_PROGBITS
+# NOBITS-PHDRS-NEXT:     Content: '0000'
+# NOBITS-PHDRS-NEXT:   - Name:    .nobits3
+# NOBITS-PHDRS-NEXT:     Type:    SHT_NOBITS
+# NOBITS-PHDRS-NEXT:     Size:    0x100
+# NOBITS-PHDRS-NEXT:   - Name:    .nobits4
+# NOBITS-PHDRS-NEXT:     Type:    SHT_NOBITS
+# NOBITS-PHDRS-NEXT:     Size:    0x200
+# NOBITS-PHDRS-NEXT:   - Name:    .nobits5
+# NOBITS-PHDRS-NEXT:     Type:    SHT_NOBITS
+# NOBITS-PHDRS-NEXT:     Offset:  0x100
+# NOBITS-PHDRS-NEXT:     Size:    0x300
+# NOBITS-PHDRS-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+Sections:
+## sh_offset == 0xe8.
+  - Name: .nobits1
+    Type: SHT_NOBITS
+    Size: 0x1
+## sh_offset == 0xe9.
+  - Name: .progbits
+    Type: SHT_PROGBITS
+    Size: 0x2
+## sh_offset == 0xeb.
+  - Name: .nobits3
+    Type: SHT_NOBITS
+    Size: 0x100
+## sh_offset == 0xeb.
+  - Name: .nobits4
+    Type: SHT_NOBITS
+    Size: 0x200
+## sh_offset == 0x100.
+  - Name:   .nobits5
+    Type:   SHT_NOBITS
+    Size:   0x300
+    Offset: 0x100
+ProgramHeaders:
+  - Type:     PT_LOAD
+    FirstSec: .nobits1
+    LastSec:  .progbits
+  - Type:     PT_LOAD
+    FirstSec: .nobits3
+    LastSec:  .nobits4
+  - Type:     PT_LOAD
+    FirstSec: .nobits5
+    LastSec:  .nobits5

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 4f5ff19806ff..3aa74bab0c18 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -232,6 +232,40 @@ bool ELFDumper<ELFT>::shouldPrintSection(const ELFYAML::Section &S,
   return true;
 }
 
+template <class ELFT>
+static void dumpSectionOffsets(const typename ELFT::Ehdr &Header,
+                               ArrayRef<ELFYAML::ProgramHeader> Phdrs,
+                               std::vector<std::unique_ptr<ELFYAML::Chunk>> &V,
+                               ArrayRef<typename ELFT::Shdr> S) {
+  uint64_t ExpectedOffset;
+  if (Header.e_phoff > 0)
+    ExpectedOffset = Header.e_phoff + Header.e_phentsize * Header.e_phnum;
+  else
+    ExpectedOffset = sizeof(typename ELFT::Ehdr);
+
+  for (const std::unique_ptr<ELFYAML::Chunk> &C :
+       makeArrayRef(V).drop_front()) {
+    ELFYAML::Section &Sec = *cast<ELFYAML::Section>(C.get());
+    const typename ELFT::Shdr &SecHdr = S[Sec.OriginalSecNdx];
+
+    ExpectedOffset =
+        alignTo(ExpectedOffset, SecHdr.sh_addralign ? SecHdr.sh_addralign : 1);
+
+    // We only set the "Offset" field when it can't be naturally derived
+    // from the offset and size of the previous section. This reduces
+    // the noise in the YAML output.
+    if (SecHdr.sh_offset != ExpectedOffset)
+      Sec.Offset = (yaml::Hex64)SecHdr.sh_offset;
+
+    if (Sec.Type == ELF::SHT_NOBITS &&
+        !ELFYAML::shouldAllocateFileSpace(Phdrs,
+                                          *cast<ELFYAML::NoBitsSection>(&Sec)))
+      ExpectedOffset = SecHdr.sh_offset;
+    else
+      ExpectedOffset = SecHdr.sh_offset + SecHdr.sh_size;
+  }
+}
+
 template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
   auto Y = std::make_unique<ELFYAML::Object>();
 
@@ -321,6 +355,9 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
     return PhdrsOrErr.takeError();
   Y->ProgramHeaders = std::move(*PhdrsOrErr);
 
+  dumpSectionOffsets<ELFT>(Obj.getHeader(), Y->ProgramHeaders, Chunks,
+                           Sections);
+
   // Dump DWARF sections.
   Y->DWARF = dumpDWARFSections(Chunks);
 
@@ -397,6 +434,7 @@ ELFDumper<ELFT>::dumpProgramHeaders(
         if (!PH.FirstSec)
           PH.FirstSec = S.Name;
         PH.LastSec = S.Name;
+        PH.Chunks.push_back(C.get());
       }
     }
 


        


More information about the llvm-branch-commits mailing list