[llvm] a7a447b - [yaml2obj] - ProgramHeaders: introduce FirstSec/LastSec instead of Sections list.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 9 02:15:17 PST 2020


Author: Georgii Rymar
Date: 2020-11-09T13:00:50+03:00
New Revision: a7a447be0fa934505f0c423fb97b91a68c1cc715

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

LOG: [yaml2obj] - ProgramHeaders: introduce FirstSec/LastSec instead of Sections list.

Imagine we have a YAML declaration of few sections: `foo1`, `<unnamed 2>`, `foo3`, `foo4`.

To put them into segment we can do (1*):

```
Sections:
 - Section: foo1
 - Section: foo4
```

or we can use (2*):

```
Sections:
 - Section: foo1
 - Section: foo3
 - Section: foo4
```

or (3*) :

```
Sections:
 - Section: foo1
## "(index 2)" here is a name that we automatically created for a unnamed section.
 - Section: (index 2)
 - Section: foo3
 - Section: foo4
```

It looks really confusing that we don't have to list all of sections.

At first I've tried to make this rule stricter and report an error when there is a gap
(i.e. when a section is included into segment, but not listed explicitly).
This did not work perfect, because such approach conflicts with unnamed sections/fills (see (3*)).

This patch drops "Sections" key and introduces 2 keys instead: `FirstSec` and `LastSec`.
Both are optional.

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

Added: 
    

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/test/DebugInfo/symbolize-build-id-error.test
    llvm/test/DebugInfo/symbolize-build-id.test
    llvm/test/Object/invalid.test
    llvm/test/Object/obj2yaml.test
    llvm/test/tools/llvm-elfabi/binary-read-add-soname.test
    llvm/test/tools/llvm-elfabi/binary-read-arch.test
    llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test
    llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test
    llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test
    llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test
    llvm/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test
    llvm/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test
    llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test
    llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test
    llvm/test/tools/llvm-elfabi/binary-read-soname.test
    llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml
    llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml
    llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml
    llvm/test/tools/llvm-objcopy/ELF/add-symbol.test
    llvm/test/tools/llvm-objcopy/ELF/adjacent-segments.test
    llvm/test/tools/llvm-objcopy/ELF/bad-build-id.test
    llvm/test/tools/llvm-objcopy/ELF/basic-binary-copy.test
    llvm/test/tools/llvm-objcopy/ELF/binary-first-seg-offset-zero.test
    llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test
    llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test
    llvm/test/tools/llvm-objcopy/ELF/binary-remove-all-but-one.test
    llvm/test/tools/llvm-objcopy/ELF/binary-remove-end.test
    llvm/test/tools/llvm-objcopy/ELF/binary-remove-middle.test
    llvm/test/tools/llvm-objcopy/ELF/binary-segment-layout.test
    llvm/test/tools/llvm-objcopy/ELF/build-id-link-dir.test
    llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align-binary.test
    llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align.test
    llvm/test/tools/llvm-objcopy/ELF/copy-after-strip-sections.test
    llvm/test/tools/llvm-objcopy/ELF/dump-section.test
    llvm/test/tools/llvm-objcopy/ELF/empty-section.test
    llvm/test/tools/llvm-objcopy/ELF/identical-segments.test
    llvm/test/tools/llvm-objcopy/ELF/invalid-p_filesz-p_offset.test
    llvm/test/tools/llvm-objcopy/ELF/marker-segment.test
    llvm/test/tools/llvm-objcopy/ELF/no-build-id.test
    llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test
    llvm/test/tools/llvm-objcopy/ELF/overlap-chain.test
    llvm/test/tools/llvm-objcopy/ELF/parent-loop-check.test
    llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test
    llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test
    llvm/test/tools/llvm-objcopy/ELF/program-headers.test
    llvm/test/tools/llvm-objcopy/ELF/remove-section-in-segment.test
    llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test
    llvm/test/tools/llvm-objcopy/ELF/segment-shift.test
    llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test
    llvm/test/tools/llvm-objcopy/ELF/strip-all-gnu.test
    llvm/test/tools/llvm-objcopy/ELF/strip-all.test
    llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test
    llvm/test/tools/llvm-objcopy/ELF/strip-sections.test
    llvm/test/tools/llvm-objcopy/ELF/triple-overlap.test
    llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-end.test
    llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-first.test
    llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-third-sec.test
    llvm/test/tools/llvm-objdump/ELF/dynamic-section-machine-specific.test
    llvm/test/tools/llvm-objdump/ELF/dynamic-section.test
    llvm/test/tools/llvm-objdump/X86/elf-disassemble-dynamic-symbols.test
    llvm/test/tools/llvm-objdump/X86/elf-dynamic-relocs.test
    llvm/test/tools/llvm-objdump/X86/phdrs-lma.test
    llvm/test/tools/llvm-objdump/X86/phdrs-lma2.test
    llvm/test/tools/llvm-objdump/section-filter.test
    llvm/test/tools/llvm-objdump/warn-on-out-of-range-start-stop-address.test
    llvm/test/tools/llvm-readobj/ELF/all.test
    llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test
    llvm/test/tools/llvm-readobj/ELF/check-output-order.test
    llvm/test/tools/llvm-readobj/ELF/demangle.test
    llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test
    llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-empty.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-malformed.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-no-pt-dynamic.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-not-in-pt-dynamic.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-reloc-no-section-headers.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-table-dtnull.s
    llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
    llvm/test/tools/llvm-readobj/ELF/gnu-notes.test
    llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test
    llvm/test/tools/llvm-readobj/ELF/gnuhash.test
    llvm/test/tools/llvm-readobj/ELF/hash-histogram.test
    llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
    llvm/test/tools/llvm-readobj/ELF/hash-table.test
    llvm/test/tools/llvm-readobj/ELF/loadname.test
    llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test
    llvm/test/tools/llvm-readobj/ELF/needed-libs.test
    llvm/test/tools/llvm-readobj/ELF/non-dynamic-in-pt-dynamic.test
    llvm/test/tools/llvm-readobj/ELF/note-core-ntfile-bad.test
    llvm/test/tools/llvm-readobj/ELF/note-core-ntfile.test
    llvm/test/tools/llvm-readobj/ELF/note-core.test
    llvm/test/tools/llvm-readobj/ELF/program-headers.test
    llvm/test/tools/llvm-readobj/ELF/reloc-negative-addend-no-sym.test
    llvm/test/tools/llvm-readobj/ELF/reloc-zero-name-or-value.test
    llvm/test/tools/llvm-readobj/ELF/unwind.test
    llvm/test/tools/llvm-xray/ARM/extract-instrmap.test
    llvm/test/tools/obj2yaml/ELF/program-headers.yaml
    llvm/test/tools/yaml2obj/ELF/custom-fill.yaml
    llvm/test/tools/yaml2obj/ELF/dynamic-section-i386.yaml
    llvm/test/tools/yaml2obj/ELF/header-sh-fields.yaml
    llvm/test/tools/yaml2obj/ELF/program-header-address.yaml
    llvm/test/tools/yaml2obj/ELF/program-header-align.yaml
    llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
    llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml
    llvm/test/tools/yaml2obj/ELF/program-header.yaml
    llvm/tools/obj2yaml/elf2yaml.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 206d767de758..058d78d4f4fd 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -100,10 +100,6 @@ struct SectionHeaderTable {
   Optional<bool> NoHeaders;
 };
 
-struct SectionName {
-  StringRef Section;
-};
-
 struct Symbol {
   StringRef Name;
   ELF_STT Type;
@@ -627,9 +623,10 @@ struct ProgramHeader {
   Optional<llvm::yaml::Hex64> FileSize;
   Optional<llvm::yaml::Hex64> MemSize;
   Optional<llvm::yaml::Hex64> Offset;
+  Optional<StringRef> FirstSec;
+  Optional<StringRef> LastSec;
 
-  std::vector<SectionName> Sections;
-  // This vector is parallel to Sections and contains corresponding chunks.
+  // This vector contains all chunks from [FirstSec, LastSec].
   std::vector<Chunk *> Chunks;
 };
 
@@ -680,7 +677,6 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VernauxEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerneedEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionOrType)
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ARMIndexTableEntry)
 
 namespace llvm {
@@ -816,6 +812,7 @@ template <> struct MappingTraits<ELFYAML::SectionHeader> {
 
 template <> struct MappingTraits<ELFYAML::ProgramHeader> {
   static void mapping(IO &IO, ELFYAML::ProgramHeader &FileHdr);
+  static std::string validate(IO &IO, ELFYAML::ProgramHeader &FileHdr);
 };
 
 template <>
@@ -890,10 +887,6 @@ template <> struct MappingTraits<ELFYAML::SectionOrType> {
   static void mapping(IO &IO, ELFYAML::SectionOrType &sectionOrType);
 };
 
-template <> struct MappingTraits<ELFYAML::SectionName> {
-  static void mapping(IO &IO, ELFYAML::SectionName &sectionName);
-};
-
 } // end namespace yaml
 } // end namespace llvm
 

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index fbe31a3a12ee..b31b7681adad 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -467,12 +467,16 @@ void ELFState<ELFT>::writeELFHeader(raw_ostream &OS, Optional<uint64_t> SHOff) {
 template <class ELFT>
 void ELFState<ELFT>::initProgramHeaders(std::vector<Elf_Phdr> &PHeaders) {
   DenseMap<StringRef, ELFYAML::Fill *> NameToFill;
-  for (const std::unique_ptr<ELFYAML::Chunk> &D : Doc.Chunks)
-    if (auto S = dyn_cast<ELFYAML::Fill>(D.get()))
+  DenseMap<StringRef, size_t> NameToIndex;
+  for (size_t I = 0, E = Doc.Chunks.size(); I != E; ++I) {
+    if (auto S = dyn_cast<ELFYAML::Fill>(Doc.Chunks[I].get()))
       NameToFill[S->Name] = S;
+    NameToIndex[Doc.Chunks[I]->Name] = I + 1;
+  }
 
   std::vector<ELFYAML::Section *> Sections = Doc.getSections();
-  for (ELFYAML::ProgramHeader &YamlPhdr : Doc.ProgramHeaders) {
+  for (size_t I = 0, E = Doc.ProgramHeaders.size(); I != E; ++I) {
+    ELFYAML::ProgramHeader &YamlPhdr = Doc.ProgramHeaders[I];
     Elf_Phdr Phdr;
     zero(Phdr);
     Phdr.p_type = YamlPhdr.Type;
@@ -481,22 +485,30 @@ void ELFState<ELFT>::initProgramHeaders(std::vector<Elf_Phdr> &PHeaders) {
     Phdr.p_paddr = YamlPhdr.PAddr;
     PHeaders.push_back(Phdr);
 
-    // Map Sections list to corresponding chunks.
-    for (const ELFYAML::SectionName &SecName : YamlPhdr.Sections) {
-      if (ELFYAML::Fill *Fill = NameToFill.lookup(SecName.Section)) {
-        YamlPhdr.Chunks.push_back(Fill);
-        continue;
-      }
+    if (!YamlPhdr.FirstSec && !YamlPhdr.LastSec)
+      continue;
 
-      unsigned Index;
-      if (SN2I.lookup(SecName.Section, Index)) {
-        YamlPhdr.Chunks.push_back(Sections[Index]);
-        continue;
-      }
+    // Get the index of the section, or 0 in the case when the section doesn't exist.
+    size_t First = NameToIndex[*YamlPhdr.FirstSec];
+    if (!First)
+      reportError("unknown section or fill referenced: '" + *YamlPhdr.FirstSec +
+                  "' by the 'FirstSec' key of the program header with index " +
+                  Twine(I));
+    size_t Last = NameToIndex[*YamlPhdr.LastSec];
+    if (!Last)
+      reportError("unknown section or fill referenced: '" + *YamlPhdr.LastSec +
+                  "' by the 'LastSec' key of the program header with index " +
+                  Twine(I));
+    if (!First || !Last)
+      continue;
 
-      reportError("unknown section or fill referenced: '" + SecName.Section +
-                  "' by program header");
-    }
+    if (First > Last)
+      reportError("program header with index " + Twine(I) +
+                  ": the section index of " + *YamlPhdr.FirstSec +
+                  " is greater than the index of " + *YamlPhdr.LastSec);
+
+    for (size_t I = First; I <= Last; ++I)
+      YamlPhdr.Chunks.push_back(Doc.Chunks[I - 1].get());
   }
 }
 

diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index b2016dc9f13e..5c60705e291e 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -904,7 +904,8 @@ void MappingTraits<ELFYAML::ProgramHeader>::mapping(
     IO &IO, ELFYAML::ProgramHeader &Phdr) {
   IO.mapRequired("Type", Phdr.Type);
   IO.mapOptional("Flags", Phdr.Flags, ELFYAML::ELF_PF(0));
-  IO.mapOptional("Sections", Phdr.Sections);
+  IO.mapOptional("FirstSec", Phdr.FirstSec);
+  IO.mapOptional("LastSec", Phdr.LastSec);
   IO.mapOptional("VAddr", Phdr.VAddr, Hex64(0));
   IO.mapOptional("PAddr", Phdr.PAddr, Phdr.VAddr);
   IO.mapOptional("Align", Phdr.Align);
@@ -913,6 +914,15 @@ void MappingTraits<ELFYAML::ProgramHeader>::mapping(
   IO.mapOptional("Offset", Phdr.Offset);
 }
 
+std::string MappingTraits<ELFYAML::ProgramHeader>::validate(
+    IO &IO, ELFYAML::ProgramHeader &FileHdr) {
+  if (!FileHdr.FirstSec && FileHdr.LastSec)
+    return "the \"LastSec\" key can't be used without the \"FirstSec\" key";
+  if (FileHdr.FirstSec && !FileHdr.LastSec)
+    return "the \"FirstSec\" key can't be used without the \"LastSec\" key";
+  return "";
+}
+
 LLVM_YAML_STRONG_TYPEDEF(StringRef, StOtherPiece)
 
 template <> struct ScalarTraits<StOtherPiece> {
@@ -1260,11 +1270,6 @@ void MappingTraits<ELFYAML::SectionOrType>::mapping(
   IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
 }
 
-void MappingTraits<ELFYAML::SectionName>::mapping(
-    IO &IO, ELFYAML::SectionName &sectionName) {
-  IO.mapRequired("Section", sectionName.Section);
-}
-
 static void sectionMapping(IO &IO, ELFYAML::ARMIndexTableSection &Section) {
   commonSectionMapping(IO, Section);
   IO.mapOptional("Entries", Section.Entries);

diff  --git a/llvm/test/DebugInfo/symbolize-build-id-error.test b/llvm/test/DebugInfo/symbolize-build-id-error.test
index ef3972537c9f..8a517ee24e4d 100644
--- a/llvm/test/DebugInfo/symbolize-build-id-error.test
+++ b/llvm/test/DebugInfo/symbolize-build-id-error.test
@@ -17,7 +17,7 @@ Sections:
     Flags:   [ SHF_ALLOC ]
     Content: 0123456789
 ProgramHeaders:
-  - Type: PT_NOTE
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .note.invalid
+  - Type:     PT_NOTE
+    Flags:    [ PF_R ]
+    FirstSec: .note.invalid
+    LastSec:  .note.invalid

diff  --git a/llvm/test/DebugInfo/symbolize-build-id.test b/llvm/test/DebugInfo/symbolize-build-id.test
index 40221ae9e057..d63f43ff859e 100644
--- a/llvm/test/DebugInfo/symbolize-build-id.test
+++ b/llvm/test/DebugInfo/symbolize-build-id.test
@@ -22,7 +22,7 @@ Sections:
     Flags:   [ SHF_ALLOC ]
     Content: 040000000800000003000000474e5500abb50d82b6bdc861
 ProgramHeaders:
-  - Type: PT_NOTE
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .note.gnu.build-id
+  - Type:     PT_NOTE
+    Flags:    [ PF_R ]
+    FirstSec: .note.gnu.build-id
+    LastSec:  .note.gnu.build-id

diff  --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test
index 881145a8d8c7..e38c5e8b755b 100644
--- a/llvm/test/Object/invalid.test
+++ b/llvm/test/Object/invalid.test
@@ -454,10 +454,10 @@ Sections:
       - Tag:   DT_NULL
         Value: 0x0
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Check that llvm-readobj reports a warning when a dynamic relocation section
 ## has sh_entsize field with size != sizeof(Elf_Rela).
@@ -529,8 +529,8 @@ Sections:
 ProgramHeaders:
   - Type:     PT_DYNAMIC
     FileSize: 0xffff0000
-    Sections:
-      - Section: .dynamic
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # RUN: yaml2obj --docnum=24 %s -o %t24
 # RUN: not obj2yaml 2>&1 %t24 | FileCheck %s -DFILE=%t24 --check-prefix=INVALID-SHSTRNDX

diff  --git a/llvm/test/Object/obj2yaml.test b/llvm/test/Object/obj2yaml.test
index a1b0d1eff561..5def9631277d 100644
--- a/llvm/test/Object/obj2yaml.test
+++ b/llvm/test/Object/obj2yaml.test
@@ -660,17 +660,17 @@ Symbols:
 # ELF-AVR-NEXT:   Machine:         EM_AVR
 # ELF-AVR-NEXT:   Flags:           [ EF_AVR_ARCH_AVR2 ]
 # ELF-AVR-NEXT: ProgramHeaders:
-# ELF-AVR-NEXT:  - Type:  PT_LOAD
-# ELF-AVR-NEXT:    Flags: [ PF_X, PF_R ]
-# ELF-AVR-NEXT:    Sections:
-# ELF-AVR-NEXT:     - Section: .text
-# ELF-AVR-NEXT:    Align: 0x0000000000000002
-# ELF-AVR-NEXT:  - Type:  PT_LOAD
-# ELF-AVR-NEXT:    Flags: [ PF_W, PF_R ]
-# ELF-AVR-NEXT:    Sections:
-# ELF-AVR-NEXT:     - Section: .data
-# ELF-AVR-NEXT:    VAddr: 0x0000000000800060
-# ELF-AVR-NEXT:    PAddr: 0x0000000000000004
+# ELF-AVR-NEXT:  - Type:     PT_LOAD
+# ELF-AVR-NEXT:    Flags:    [ PF_X, PF_R ]
+# ELF-AVR-NEXT:    FirstSec: .text
+# ELF-AVR-NEXT:    LastSec:  .text
+# ELF-AVR-NEXT:    Align:    0x0000000000000002
+# ELF-AVR-NEXT:  - Type:     PT_LOAD
+# ELF-AVR-NEXT:    Flags:    [ PF_W, PF_R ]
+# ELF-AVR-NEXT:    FirstSec: .data
+# ELF-AVR-NEXT:    LastSec:  .data
+# ELF-AVR-NEXT:    VAddr:    0x0000000000800060
+# ELF-AVR-NEXT:    PAddr:    0x0000000000000004
 # ELF-AVR-NEXT: Sections:
 # ELF-AVR-NEXT:   - Name:            .text
 # ELF-AVR-NEXT:     Type:            SHT_PROGBITS

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-add-soname.test b/llvm/test/tools/llvm-elfabi/binary-read-add-soname.test
index 6539178f7651..0f75a4c3b341 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-add-soname.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-add-soname.test
@@ -30,18 +30,17 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x0000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x0000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
   - Type: PT_DYNAMIC
     Flags: [ PF_X, PF_R ]
     VAddr: 0x0008
-    Sections:
-      - Section: .dynamic
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # CHECK:      --- !tapi-tbe
 # CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}}

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-arch.test b/llvm/test/tools/llvm-elfabi/binary-read-arch.test
index 84c331bc2f30..e0e6ddd7f9cb 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-arch.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-arch.test
@@ -30,18 +30,17 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x0000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x0008
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x0000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x0008
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # CHECK:      --- !tapi-tbe
 # CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}}

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test b/llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test
index e555c6f38e92..032d3e1c82aa 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test
@@ -32,17 +32,16 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x0000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x0008
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x0000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x0008
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # CHECK: DT_SONAME string offset (0x000000000000000d) outside of dynamic string table

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test b/llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test
index fa713051166f..666a01acca62 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test
@@ -32,17 +32,16 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1008
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1008
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # CHECK: virtual address is not in any segment: 0x260 when locating .dynstr section contents

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test b/llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test
index 2acdf5b55ec8..3c2edcbb9eae 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test
@@ -36,16 +36,14 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:  PT_DYNAMIC
     Flags: [ PF_X, PF_R ]
     VAddr: 0x1024
-    Sections:
 
 # CHECK: DT_NEEDED string offset (0x000000000000ffff) outside of dynamic string table

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test b/llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test
index 8914cae85491..51adf60866c9 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test
@@ -35,17 +35,15 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
   - Type: PT_DYNAMIC
     Flags: [ PF_X, PF_R ]
     VAddr: 0x1024
-    Sections:
 
 # CHECK:      NeededLibs:
 # CHECK-NEXT:   - libfoo.so{{$}}

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test b/llvm/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test
index 643b814feda9..0a21fd84ead1 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test
@@ -27,17 +27,16 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x0000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x0008
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x0000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x0008
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # CHECK: Couldn't determine dynamic string table size (no DT_STRSZ entry)

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test b/llvm/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test
index 699c60c298eb..4d3c0c7601a3 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test
@@ -26,17 +26,16 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x0000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x0008
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x0000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x0008
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # CHECK: Couldn't locate dynamic string table (no DT_STRTAB entry)

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test b/llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test
index c8e592f9baaf..e58e8e9a7dcf 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test
@@ -34,18 +34,17 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1018
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1018
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # ORIGINAL: SoName: somelib.so{{$}}
 

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test b/llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test
index 8c499c942941..4ffa44ce98b3 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test
@@ -33,17 +33,16 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1018
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1018
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # CHECK: String overran bounds of string table (no null terminator) when reading DT_SONAME

diff  --git a/llvm/test/tools/llvm-elfabi/binary-read-soname.test b/llvm/test/tools/llvm-elfabi/binary-read-soname.test
index 5b67ada5848d..7436a3814704 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-soname.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-soname.test
@@ -33,18 +33,17 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Align: 8
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1018
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    Align:    8
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1018
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # CHECK:      --- !tapi-tbe
 # CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}}

diff  --git a/llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml b/llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml
index 38385717d92f..6fec33d84262 100644
--- a/llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml
+++ b/llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml
@@ -389,26 +389,8 @@ ProgramHeaders:
     Flags: [ PF_X, PF_R ]
     VAddr: 0x0000000000400000
     Align: 1024
-    Sections:
-      - Section: .interp
-      - Section: .interp
-      - Section: .note.ABI-tag
-      - Section: .note.gnu.build-id
-      - Section: .gnu.hash
-      - Section: .gnu.version
-      - Section: .gnu.version_r
-      - Section: .rela.dyn
-      - Section: .rela.plt
-      - Section: .init
-      - Section: .plt
-      - Section: .plt.got
-      - Section: .text
-      - Section: .fini
-      - Section: .rodata
-      - Section: .eh_frame_hdr
-      - Section: .eh_frame
-      - Section: .dynsym
-      - Section: .dynstr
+    FirstSec: .interp
+    LastSec:  .dynstr
 Symbols:
   - Name:            .interp
     Type:            STT_SECTION

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml b/llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml
index 3f142aeb2840..294647e60dc8 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml
+++ b/llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml
@@ -12,9 +12,9 @@ Sections:
     AddressAlign:    0x8
     Content:         "0001020304"
 ProgramHeaders:
-  - Type: PT_NULL
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0xF00000000
-    PAddr: 0x100000
-    Sections:
-      - Section: .text
+  - Type:     PT_NULL
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0xF00000000
+    PAddr:    0x100000
+    FirstSec: .text
+    LastSec:  .text

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml b/llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml
index c7d8a7affb82..ab678a607af1 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml
+++ b/llvm/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml
@@ -48,13 +48,9 @@ Sections:
     Size:            65536
     AddressAlign:    0x8
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0xF00000000
-    PAddr: 0x100000
-    Sections:
-      - Section: .text
-      - Section: .data1
-      - Section: .data2
-      - Section: .data3
-      - Section: .bss
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0xF00000000
+    PAddr:    0x100000
+    FirstSec: .text
+    LastSec:  .bss

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/add-symbol.test b/llvm/test/tools/llvm-objcopy/ELF/add-symbol.test
index 8950894d5078..c90c36b438ed 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/add-symbol.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/add-symbol.test
@@ -44,18 +44,18 @@ Sections:
     AddressAlign:    0x0000000000001000
     Size:            64
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1000
-    Align: 0x1000
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_R, PF_W ]
-    VAddr: 0x2000
-    Align: 0x1000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1000
+    Align:    0x1000
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W ]
+    VAddr:    0x2000
+    Align:    0x1000
+    FirstSec: .data
+    LastSec:  .data
 ## TODO (grimar): llvm-objcopy seems produce a broken output without
 ## the following line, i.e. when there is no symbol table in the input.
 Symbols: []

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/adjacent-segments.test b/llvm/test/tools/llvm-objcopy/ELF/adjacent-segments.test
index 45f4224f7e87..974c6319991a 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/adjacent-segments.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/adjacent-segments.test
@@ -23,14 +23,14 @@ Sections:
     AddressAlign:    0x10
     Size:            16
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text2
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text2
+    LastSec:  .text2
 
 #CHECK:     ProgramHeaders [
 #CHECK-NEXT:  ProgramHeader {

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/bad-build-id.test b/llvm/test/tools/llvm-objcopy/ELF/bad-build-id.test
index 7adbd2fbfa9c..0c97fc51d18e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/bad-build-id.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/bad-build-id.test
@@ -15,7 +15,7 @@ Sections:
     Flags:           [ SHF_ALLOC ]
     Content:         040000000100000003000000474E55004F000000
 ProgramHeaders:
-  - Type: PT_NOTE
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .note.gnu.build-id
+  - Type:     PT_NOTE
+    Flags:    [ PF_R ]
+    FirstSec: .note.gnu.build-id
+    LastSec:  .note.gnu.build-id

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/basic-binary-copy.test b/llvm/test/tools/llvm-objcopy/ELF/basic-binary-copy.test
index e49c82d85bde..a931aede6ccb 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/basic-binary-copy.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/basic-binary-copy.test
@@ -16,10 +16,10 @@ Sections:
     AddressAlign:    0x0000000000001000
     Content:         "c3c3c3c3"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text
 
 # CHECK: 0000000 c3c3 c3c3
 # SIZE:  4

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-first-seg-offset-zero.test b/llvm/test/tools/llvm-objcopy/ELF/binary-first-seg-offset-zero.test
index 9af417f245f0..0f15c040e4ba 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-first-seg-offset-zero.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-first-seg-offset-zero.test
@@ -23,11 +23,10 @@ Sections:
     Size:            4064
     Content:         "DEADBEEF"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .note
-      - Section: .rodata
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .note
+    LastSec:  .rodata
 
 # CHECK: 000000 de ad be ef

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test b/llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test
index 99cf19fad9c4..3914ff88e355 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test
@@ -32,18 +32,18 @@ Sections:
     AddressAlign:    0x0000000000000004
     Content:         "3232"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1000
-    PAddr: [[PADDR]]
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_R, PF_W ]
-    VAddr: 0x1004
-    PAddr: [[PADDR]]
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1000
+    PAddr:    [[PADDR]]
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W ]
+    VAddr:    0x1004
+    PAddr:    [[PADDR]]
+    FirstSec: .data
+    LastSec:  .data
 
 # CHECK: 0000000 3232 c3c3
 # SIZE:  4

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test b/llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test
index f7974a60ffd6..bee80b28b532 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test
@@ -35,11 +35,10 @@ Sections:
     AddressAlign:    0x1000
     Content:         "3232"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R, PF_W ]
-    Sections:
-      - Section: .text
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W ]
+    FirstSec: .text
+    LastSec:  .data
 
 ## The computed LMA of a section not in a PT_LOAD equals its sh_addr.
 
@@ -78,13 +77,13 @@ Sections:
     AddressAlign:    0x1000
     Content:         "3232"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R, PF_W ]
-    VAddr: 0x2000
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W ]
+    VAddr:    0x2000
     ## p_vaddr is increased from 0x2000 to 0x4000.
-    PAddr: 0x4000
-    Sections:
-      - Section: .data
+    PAddr:    0x4000
+    FirstSec: .data
+    LastSec:  .data
 
 ## Check that we use sh_offset instead of sh_addr to decide where to write section contents.
 
@@ -124,11 +123,11 @@ Sections:
     AddressAlign:    0x1000
     Content:         "3232"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R, PF_W ]
-    VAddr: 0x3000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W ]
+    VAddr:    0x3000
+    FirstSec: .data
+    LastSec:  .data
 
 ## The first section (.text) is empty. Test that we skip its LMA until the first
 ## non-empty section, otherwise we would leave a large number of leading zeroes.

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-remove-all-but-one.test b/llvm/test/tools/llvm-objcopy/ELF/binary-remove-all-but-one.test
index 1336b7d93951..6b6488d2d726 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-remove-all-but-one.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-remove-all-but-one.test
@@ -32,13 +32,11 @@ Sections:
     Content:         "32323232"
     Size:            0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .text2
-      - Section: .text3
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text3
 
 # CHECK: 000000 de ad be ef
 

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-remove-end.test b/llvm/test/tools/llvm-objcopy/ELF/binary-remove-end.test
index d9f27526dfb7..9714c95cffce 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-remove-end.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-remove-end.test
@@ -32,13 +32,11 @@ Sections:
     Content:         "32323232"
     Size:            0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .text2
-      - Section: .text3
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text3
 
 # CHECK: 000000 c3 c3 c3 c3
 # CHECK: 001000 de ad be ef

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-remove-middle.test b/llvm/test/tools/llvm-objcopy/ELF/binary-remove-middle.test
index 4ed3ca65934f..44d38e2ffd27 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-remove-middle.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-remove-middle.test
@@ -32,13 +32,11 @@ Sections:
     Content:         "32323232"
     Size:            0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .text2
-      - Section: .text3
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text3
 
 # CHECK: 000000 c3 c3 c3 c3
 # CHECK: 001000 00 00 00 00

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-segment-layout.test b/llvm/test/tools/llvm-objcopy/ELF/binary-segment-layout.test
index d3b24950c748..764af14437d2 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-segment-layout.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-segment-layout.test
@@ -23,16 +23,16 @@ Sections:
     Address:         0x08
     Content:         "3232"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x00
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x08
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x00
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x08
+    FirstSec: .data
+    LastSec:  .data
 
 # CHECK:       0000000 c3c3 c3c3 0000 0000 3232
 # SIZE:        10

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/build-id-link-dir.test b/llvm/test/tools/llvm-objcopy/ELF/build-id-link-dir.test
index c99d0efdf31b..a630bad79cc2 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/build-id-link-dir.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/build-id-link-dir.test
@@ -50,7 +50,7 @@ Sections:
     Flags:           [ SHF_ALLOC ]
     Content:         040000001000000003000000474E55004FCB712AA6387724A9F465A32CD8C14B
 ProgramHeaders:
-  - Type: PT_NOTE
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .note.gnu.build-id
+  - Type:     PT_NOTE
+    Flags:    [ PF_R ]
+    FirstSec: .note.gnu.build-id
+    LastSec:  .note.gnu.build-id

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align-binary.test b/llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align-binary.test
index c36f812bdb8b..f91d7afdddcd 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align-binary.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align-binary.test
@@ -22,17 +22,17 @@ Sections:
     AddressAlign:    0x0000000000000008
     Content:         "3232"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1000
-    Align: 0x1000
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_R, PF_W ]
-    VAddr: 0x1008
-    Align: 0x1000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1000
+    Align:    0x1000
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W ]
+    VAddr:    0x1008
+    Align:    0x1000
+    FirstSec: .data
+    LastSec:  .data
 
 # CHECK: 0000000 c3 c3 c3 c3 00 00 00 00 32 32

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align.test b/llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align.test
index 54c65ce4736d..54c1ab4ddc49 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/check-addr-offset-align.test
@@ -22,18 +22,18 @@ Sections:
     AddressAlign:    0x0000000000000008
     Content:         "3232"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1000
-    Align: 0x1000
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_R, PF_W ]
-    VAddr: 0x1008
-    Align: 0x1000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1000
+    Align:    0x1000
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W ]
+    VAddr:    0x1008
+    Align:    0x1000
+    FirstSec: .data
+    LastSec:  .data
 
 #CHECK:     ProgramHeaders [
 #CHECK-NEXT:   ProgramHeader {

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/copy-after-strip-sections.test b/llvm/test/tools/llvm-objcopy/ELF/copy-after-strip-sections.test
index 3b61649b2639..d55950d0a410 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/copy-after-strip-sections.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/copy-after-strip-sections.test
@@ -21,6 +21,6 @@ Sections:
     Type: SHT_PROGBITS
     Content: 'facefeed'
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .text
+  - Type:     PT_LOAD
+    FirstSec: .text
+    LastSec:  .text

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/dump-section.test b/llvm/test/tools/llvm-objcopy/ELF/dump-section.test
index fadd955a0f93..fe6f834b66ac 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/dump-section.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/dump-section.test
@@ -35,10 +35,10 @@ Sections:
     Type:            SHT_NOBITS
     Flags:           [ SHF_WRITE ]
 ProgramHeaders:
-- Type: PT_LOAD
-  Flags: [ PF_X, PF_R ]
-  Sections:
-    - Section: .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text
 
 # CHECK: 0000000 de ad be ef
 

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/empty-section.test b/llvm/test/tools/llvm-objcopy/ELF/empty-section.test
index 25c6c45d5528..1ccdf9f971a5 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/empty-section.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/empty-section.test
@@ -79,14 +79,13 @@ Sections:
     Address:      0x1000
     Size:         0x100
 ProgramHeaders:
-  - Type:  PT_LOAD
-    VAddr: 0
-    Align: 0x100
-    Sections:
-      - Section: .foo
-  - Type:  PT_LOAD
-    VAddr: 0x1000
-    Align: 0x1000
-    Sections:
-      - Section: .empty
-      - Section: .baz
+  - Type:     PT_LOAD
+    VAddr:    0
+    Align:    0x100
+    FirstSec: .foo
+    LastSec:  .foo
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    Align:    0x1000
+    FirstSec: .empty
+    LastSec:  .baz

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/identical-segments.test b/llvm/test/tools/llvm-objcopy/ELF/identical-segments.test
index 7273416da7ae..795118aa6063 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/identical-segments.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/identical-segments.test
@@ -24,20 +24,18 @@ Sections:
     AddressAlign:    0x1000
     Size:            4096
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text2
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text
-      - Section: .text2
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text
-      - Section: .text2
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text2
+    LastSec:  .text2
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text2
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text2
 
 #CHECK:     ProgramHeaders [
 #CHECK-NEXT:  ProgramHeader {

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/invalid-p_filesz-p_offset.test b/llvm/test/tools/llvm-objcopy/ELF/invalid-p_filesz-p_offset.test
index db6b59189fb0..c69ef804179d 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/invalid-p_filesz-p_offset.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/invalid-p_filesz-p_offset.test
@@ -16,10 +16,10 @@ Sections:
   - Name: .foo
     Type: SHT_PROGBITS
 ProgramHeaders:
-  - Type:        PT_LOAD
-    FileSize:    0x100000
-    Sections:    
-      - Section: .foo
+  - Type:     PT_LOAD
+    FileSize: 0x100000
+    FirstSec: .foo
+    LastSec:  .foo
 
 ## A similar case, but now the p_offset property of the program header is too large.
 

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/marker-segment.test b/llvm/test/tools/llvm-objcopy/ELF/marker-segment.test
index f52f9fbe7f98..9e58ed6cc0a9 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/marker-segment.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/marker-segment.test
@@ -29,28 +29,27 @@ Sections:
     Flags:           [ SHF_ALLOC ]
     Size:            64
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x1000
-    Align: 0x1000
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_R, PF_W ]
-    VAddr: 0x2000
-    Align: 0x1000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x1000
+    Align:    0x1000
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W ]
+    VAddr:    0x2000
+    Align:    0x1000
+    FirstSec: .data
+    LastSec:  .data
   - Type: PT_GNU_STACK
     Flags: [ PF_R, PF_W ]
     VAddr: 0x0000
     Align: 0x0000
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x2010
-    Sections:
-      - Section: .xdata
-      - Section: .after
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x2010
+    FirstSec: .xdata
+    LastSec:  .after
 
 #CHECK:     ProgramHeaders [
 #CHECK-NEXT:   ProgramHeader {

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/no-build-id.test b/llvm/test/tools/llvm-objcopy/ELF/no-build-id.test
index 93e4a82641ed..a75b343aa43d 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/no-build-id.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/no-build-id.test
@@ -15,7 +15,7 @@ Sections:
     Flags:           [ SHF_ALLOC ]
     Content:         000000000000000000000000
 ProgramHeaders:
-  - Type: PT_NOTE
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .note.foo
+  - Type:     PT_NOTE
+    Flags:    [ PF_R ]
+    FirstSec: .note.foo
+    LastSec:  .note.foo

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test b/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test
index 4d202ed56781..fe58792256f6 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test
@@ -97,28 +97,23 @@ ProgramHeaders:
     Flags:    [ PF_R, PF_X ]
     Offset:   0
     Align:    0x1000
-    Sections:
-      - Section: .note1
-      - Section: .note2
-      - Section: .text
+    FirstSec: .note1
+    LastSec:  .text
   - Type:     PT_LOAD
     Flags:    [ PF_R, PF_W ]
     VAddr:    0x1480    # Ensure Offset=VAddr (mod Align) if Offset changes
     Align:    0x1000
-    Sections:
-      - Section: .tdata
-      - Section: .bss
+    FirstSec: .tdata
+    LastSec:  .bss
   - Type:     PT_TLS
     Flags:    [ PF_R, PF_W ]
     VAddr:    0x1480    # Ensure Offset=VAddr (mod Align) if Offset changes
-    Sections:
-      - Section: .tdata
-      - Section: .tbss
+    FirstSec: .tdata
+    LastSec:  .tbss
   - Type:     PT_NOTE
     VAddr:    0x400
-    Sections:
-      - Section: .note1
-      - Section: .note2
+    FirstSec: .note1
+    LastSec:  .note2
 ...
 
 # RUN: yaml2obj --docnum=2 %s -o %t2
@@ -175,9 +170,8 @@ ProgramHeaders:
     Flags:    [ PF_R, PF_X ]
     Offset:   0
     Align:    4096
-    Sections:
-      - Section: .text
-      - Section: .note
+    FirstSec: .text
+    LastSec:  .note
   - Type:     PT_LOAD
     Flags:    [ PF_R, PF_W ]
     Offset:   0x202

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/overlap-chain.test b/llvm/test/tools/llvm-objcopy/ELF/overlap-chain.test
index 6b54e73b66a1..6d7893706459 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/overlap-chain.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/overlap-chain.test
@@ -40,26 +40,22 @@ Sections:
     AddressAlign:    0x1000
     Size:            4096
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text
-      - Section: .text2
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text4
-      - Section: .text5
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text3
-      - Section: .text4
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text2
-      - Section: .text3
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text2
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text4
+    LastSec:  .text5
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text3
+    LastSec:  .text4
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text2
+    LastSec:  .text3
 
 #CHECK:     ProgramHeaders [
 #CHECK-NEXT:  ProgramHeader {

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/parent-loop-check.test b/llvm/test/tools/llvm-objcopy/ELF/parent-loop-check.test
index bdd82af2058f..2fa126904727 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/parent-loop-check.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/parent-loop-check.test
@@ -33,16 +33,15 @@ Sections:
     Size:            4064
     Content:         "DEADBEEF"
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .note
-      - Section: .rodata
-  - Type: PT_NOTE
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .note
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .note
+    LastSec:  .rodata
+  - Type:     PT_NOTE
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .note
+    LastSec:  .note
 
 # CHECK: 000000 de ad be ef

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test b/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test
index c6824c4cb47f..4e7c35281a72 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test
@@ -37,6 +37,6 @@ ProgramHeaders:
     Offset:   0
     FileSize: 176 # sizeof(Elf64_Ehdr) + 2 * sizeof(Elf64_Phdr)
   - Type:     PT_LOAD
-    Sections:
-      - Section: .keep_me
+    FirstSec: .keep_me
+    LastSec:  .keep_me
 Symbols: []

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test b/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test
index ff575c8bc2d8..8ddef0a5a9f5 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test
@@ -311,188 +311,153 @@ Sections:
     Address: 0x5038
 ProgramHeaders:
   # First segment has unlabelled space at start and end.
-  - Type:  0x6ABCDEF0 # Non-specific segment type.
-    VAddr: 0x2000
-    Align: 0x2000
-    Sections:
-      - Section: blob1
-      - Section: section1
-      - Section: blob2
-      - Section: section2 # nobits
-      - Section: blob3
-      - Section: section3
-      - Section: blob4
+  - Type:     0x6ABCDEF0 # Non-specific segment type.
+    VAddr:    0x2000
+    Align:    0x2000
+    FirstSec: blob1
+    LastSec:  blob4
   # Second segment has sections at start and end.
-  - Type:  0x6ABCDEF0
-    VAddr: 0x2100
-    Align: 0x100
-    Sections:
-      - Section: section4
-      - Section: blob5
-      - Section: section5
+  - Type:     0x6ABCDEF0
+    VAddr:    0x2100
+    Align:    0x100
+    FirstSec: section4
+    LastSec:  section5
   # Third segment is all covered by a section.
-  - Type:  0x6ABCDEF0
-    VAddr: 0x2200
-    Align: 0x100
-    Sections:
-      - Section: section6
+  - Type:     0x6ABCDEF0
+    VAddr:    0x2200
+    Align:    0x100
+    FirstSec: section6
+    LastSec:  section6
   # Fourth segment has no sections (after removing blob headers).
-  - Type:  0x6ABCDEF0
-    VAddr: 0x2300
-    Align: 0x100
-    Sections:
-      - Section: blob6
+  - Type:     0x6ABCDEF0
+    VAddr:    0x2300
+    Align:    0x100
+    FirstSec: blob6
+    LastSec:  blob6
   # Fifth segment is empty.
   - Type:   0x6ABCDEF0
     VAddr:  0x2308
     Offset: 0x2308
-
   # The next few segments test behaviour of fully nested segments.
   # Sixth segment is the "parent" segment.
-  - Type:  0x6ABCDEF0
-    VAddr: 0x3000
-    Align: 0x1000
-    Sections:
-      - Section: sectionA
-      - Section: sectionB
-      - Section: blobA
-      - Section: sectionC
-      - Section: blobB
-      - Section: sectionD
-      - Section: blobC
-      - Section: sectionE
-      - Section: blobD
-      - Section: sectionF
-      - Section: blobE
-      - Section: blobF
-      - Section: sectionG
-      - Section: blobG
-      - Section: sectionH
-      - Section: blobH
-      - Section: sectionI
+  - Type:     0x6ABCDEF0
+    VAddr:    0x3000
+    Align:    0x1000
+    FirstSec: sectionA
+    LastSec:  sectionI
   # Seventh segment is empty and nested.
   - Type:   0x6ABCDEF0
     VAddr:  0x3002
     Offset: 0x3002
   # Eighth segment contains only a section and is nested.
-  - Type:  0x6ABCDEF0
-    VAddr: 0x3004
-    Sections:
-      - Section: sectionB
+  - Type:     0x6ABCDEF0
+    VAddr:    0x3004
+    FirstSec: sectionB
+    LastSec:  sectionB
   # Ninth segment contains only unlabelled space and is nested.
-  - Type:  0x6ABCDEF0
-    VAddr: 0x3008
-    Sections:
-      - Section: blobA
+  - Type:     0x6ABCDEF0
+    VAddr:    0x3008
+    FirstSec: blobA
+    LastSec:  blobA
   # Tenth segment contains two sections with space between and is nested.
-  - Type:  0x6ABCDEF0
-    VAddr: 0x300C
-    Sections:
-      - Section: sectionC
-      - Section: blobB
-      - Section: sectionD
+  - Type:     0x6ABCDEF0
+    VAddr:    0x300C
+    FirstSec: sectionC
+    LastSec:  sectionD
   # Eleventh segment contains two sections with space between and at ends and is nested.
-  - Type:  0x6ABCDEF0
-    VAddr: 0x3018
-    Sections:
-      - Section: blobC
-      - Section: sectionE
-      - Section: blobD
-      - Section: sectionF
-      - Section: blobE
+  - Type:     0x6ABCDEF0
+    VAddr:    0x3018
+    FirstSec: blobC
+    LastSec:  blobE
   # Twelfth segment contains one section with space at ends adjacent to space in parent segment.
   - Type:     0x6ABCDEF0
     VAddr:    0x302E
     Offset:   0x302E
     FileSize: 8
-    Sections:
-      - Section: sectionG
+    FirstSec: sectionG
+    LastSec:  sectionG
   # Thirteenth segment contains overlaps sections at either end in parent segment.
   - Type:     0x6ABCDEF0
     VAddr:    0x303A
     Offset:   0x303A
     FileSize: 0x8
-    Sections:
-      - Section: blobH
+    FirstSec: blobH
+    LastSec:  blobH
 
   # The next batch of segments are segments that only partially overlap other segments.
 
   # Segment14: |-unlabelled-|-Sec-|
   # Segment15:           |--|-Sec-|-unlabelled-|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x4000
-    Sections:
-      - Section: blobz
-      - Section: sectionz
-  - Type:   0x6ABCDEF0
-    VAddr:  0x4002
-    Offset: 0x4002
-    Sections:
-      - Section: sectionz
-      - Section: bloby
+  - Type:     0x6ABCDEF0
+    VAddr:    0x4000
+    FirstSec: blobz
+    LastSec:  sectionz
+  - Type:     0x6ABCDEF0
+    VAddr:    0x4002
+    Offset:   0x4002
+    FirstSec: sectionz
+    LastSec:  bloby
 
   # Segment16: |-Sec-|--|
   # Segment17:    |--|----unlabelled---|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x400C
+  - Type:     0x6ABCDEF0
+    VAddr:    0x400C
     FileSize: 6
-    Sections:
-      - Section: sectiony
-  - Type:   0x6ABCDEF0
-    VAddr:  0x400E
-    Offset: 0x400E
-    Sections:
-      - Section: blobx
+    FirstSec: sectiony
+    LastSec:  sectiony
+  - Type:     0x6ABCDEF0
+    VAddr:    0x400E
+    Offset:   0x400E
+    FirstSec: blobx
+    LastSec:  blobx
 
   # Segment18: |-unlabelled-|-Sec-|
   # Segment19:              |-Sec-|-unlabelled-|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x4014
-    Sections:
-      - Section: blobw
-      - Section: sectionx
-  - Type:  0x6ABCDEF0
-    VAddr: 0x4018
-    Sections:
-      - Section: sectionx
-      - Section: blobv
+  - Type:     0x6ABCDEF0
+    VAddr:    0x4014
+    FirstSec: blobw
+    LastSec:  sectionx
+  - Type:     0x6ABCDEF0
+    VAddr:    0x4018
+    FirstSec: sectionx
+    LastSec:  blobv
 
   # Segment20: |-Sec-|
   # Segment21:    |--|-unlabelled-|-Sec-|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x4020
-    Sections:
-      - Section: sectionw
+  - Type:     0x6ABCDEF0
+    VAddr:    0x4020
+    FirstSec: sectionw
+    LastSec:  sectionw
+
   - Type:   0x6ABCDEF0
     VAddr:  0x4022
     Offset: 0x4022
-    Sections:
-      - Section: blobu
-      - Section: sectionv
+    FirstSec: blobu
+    LastSec:  sectionv
 
   # Segment22: |-Sec-|
   # Segment23:    |--|-Sec-|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x402C
-    Sections:
-      - Section: sectionu
-  - Type:   0x6ABCDEF0
-    VAddr:  0x402E
-    Offset: 0x402E
-    Sections:
-      - Section: sectiont
+  - Type:     0x6ABCDEF0
+    VAddr:    0x402C
+    FirstSec: sectionu
+    LastSec:  sectionu
+  - Type:     0x6ABCDEF0
+    VAddr:    0x402E
+    Offset:   0x402E
+    FirstSec: sectiont
+    LastSec:  sectiont
 
   # Segment24: |-unlabelled-|--|
   # Segment25:              |--Sec--|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x4034
+  - Type:     0x6ABCDEF0
+    VAddr:    0x4034
     FileSize: 6
-    Sections:
-      - Section: blobt
-  - Type:  0x6ABCDEF0
-    VAddr: 0x4038
-    Sections:
-      - Section: sections
+    FirstSec: blobt
+    LastSec:  blobt
+  - Type:     0x6ABCDEF0
+    VAddr:    0x4038
+    FirstSec: sections
+    LastSec:  sections
 
   # The next batch of segments represent groups of three nested/overlapping segments,
   # with one parent segment containing two overlapping segments.
@@ -500,100 +465,85 @@ ProgramHeaders:
   # Segment26: |-unlabelled-|-Sec-|-unlabelled-|
   # Segment27: |------------|--|
   # Segment28:              |-Sec-|------------|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5000
-    Align: 0x1000
-    Sections:
-      - Section: bloba
-      - Section: sectiona
-      - Section: blobb
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5000
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5000
+    Align:    0x1000
+    FirstSec: bloba
+    LastSec:  blobb
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5000
     FileSize: 6
-    Sections:
-      - Section: bloba
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5004
-    Sections:
-      - Section: sectiona
-      - Section: blobb
+    FirstSec: bloba
+    LastSec:  bloba
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5004
+    FirstSec: sectiona
+    LastSec:  blobb
 
   # Segment29: |-Sec-|-unlabelled-|-Sec-|
   # Segment30: |-Sec-|--------|
   # Segment31:          |---------|-Sec-|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x500C
-    Sections:
-      - Section: sectionb
-      - Section: blobc
-      - Section: sectionc
-  - Type:  0x6ABCDEF0
-    VAddr: 0x500C
+  - Type:     0x6ABCDEF0
+    VAddr:    0x500C
+    FirstSec: sectionb
+    LastSec:  sectionc
+  - Type:     0x6ABCDEF0
+    VAddr:    0x500C
     FileSize: 7
-    Sections:
-      - Section: sectionb
-  - Type:   0x6ABCDEF0
-    VAddr:  0x5011
-    Offset: 0x5011
-    Sections:
-      - Section: sectionc
+    FirstSec: sectionb
+    LastSec:  sectionb
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5011
+    Offset:   0x5011
+    FirstSec: sectionc
+    LastSec:  sectionc
 
   # Segment32: |-Sec-|-unlabelled-|-Sec-|
   # Segment33: |-Sec-|------------|
   # Segment34:       |------------|-Sec-|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5018
-    Sections:
-      - Section: sectiond
-      - Section: blobd
-      - Section: sectione
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5018
-    Sections:
-      - Section: sectiond
-      - Section: blobd
-  - Type:  0x6ABCDEF0
-    VAddr: 0x501C
-    Sections:
-      - Section: blobd
-      - Section: sectione
+  - Type:    0x6ABCDEF0
+    VAddr:   0x5018
+    FirstSec: sectiond
+    LastSec:  sectione
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5018
+    FirstSec: sectiond
+    LastSec:  blobd
+  - Type:     0x6ABCDEF0
+    VAddr:    0x501C
+    FirstSec: blobd
+    LastSec:  sectione
 
   # Segment35: |-unlabelled-|-Sec-|-unlabelled-|
   # Segment36: |------------|-Sec-|
   # Segment37:              |-Sec-|------------|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5024
-    Sections:
-      - Section: blobe
-      - Section: sectionf
-      - Section: blobf
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5024
-    Sections:
-      - Section: blobe
-      - Section: sectionf
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5028
-    Sections:
-      - Section: sectionf
-      - Section: blobf
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5024
+    FirstSec: blobe
+    LastSec:  blobf
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5024
+    FirstSec: blobe
+    LastSec:  sectionf
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5028
+    FirstSec: sectionf
+    LastSec:  blobf
 
   # Segment38: |-unlabelled-|-Sec-|-unlabelled-|
   # Segment39: |------------|---|
   # Segment40:                |---|------------|
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5030
-    Sections:
-      - Section: blobg
-      - Section: sectiong
-      - Section: blobh
-  - Type:  0x6ABCDEF0
-    VAddr: 0x5030
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5030
+    FirstSec: blobg
+    LastSec:  blobh
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5030
     FileSize: 7
-    Sections:
-      - Section: blobg
-  - Type:   0x6ABCDEF0
-    VAddr:  0x5035
-    Offset: 0x5035
-    Sections:
-      - Section: blobh
+    FirstSec: blobg
+    LastSec:  blobg
+  - Type:     0x6ABCDEF0
+    VAddr:    0x5035
+    Offset:   0x5035
+    FirstSec: blobh
+    LastSec:  blobh

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/program-headers.test b/llvm/test/tools/llvm-objcopy/ELF/program-headers.test
index 9c123d215470..4835d88caca2 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/program-headers.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/program-headers.test
@@ -28,19 +28,18 @@ Sections:
     Address:         0xAAAA2000
     AddressAlign:    0x0000000000001000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0xAAAA1000
-    PAddr: 0xFFFF1000
-    Sections:
-      - Section: .text
-      - Section: .init
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0xAAAA2000
-    PAddr: 0xFFFF2000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0xAAAA1000
+    PAddr:    0xFFFF1000
+    FirstSec: .text
+    LastSec:  .init
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0xAAAA2000
+    PAddr:    0xFFFF2000
+    FirstSec: .data
+    LastSec:  .data
 
 #CHECK:     ProgramHeaders [
 #CHECK-NEXT:   ProgramHeader {

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-segment.test b/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-segment.test
index 036c9541f300..4aa9264f988a 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-segment.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-segment.test
@@ -42,6 +42,5 @@ Sections:
 ProgramHeaders:
   # Use an arbitrary segment type to show that the segment type is unimportant.
   - Type: 0x61234567
-    Sections:
-      - Section: shf_alloc
-      - Section: non_alloc
+    FirstSec: shf_alloc
+    LastSec:  non_alloc

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test b/llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test
index 7a9f4cdd42b8..adf512fec789 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test
@@ -28,16 +28,16 @@ Sections:
     AddressAlign:    0x1000
     Size:            0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x3000
-    Sections:
-      - Section: .text3
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x3000
+    FirstSec: .text3
+    LastSec:  .text3
 ## TODO (grimar): without the following line (i.e. without an empty symbol table),
 ## llvm-objcopy adds an empty .strtab section. It doesn't look correct.
 Symbols: []

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/segment-shift.test b/llvm/test/tools/llvm-objcopy/ELF/segment-shift.test
index 303edaf7a1d3..d03bee452172 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/segment-shift.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/segment-shift.test
@@ -28,16 +28,16 @@ Sections:
     AddressAlign:    0x1000
     Size:            0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x3000
-    Sections:
-      - Section: .text3
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x3000
+    FirstSec: .text3
+    LastSec:  .text3
 
 # CHECK:     ProgramHeaders [
 # CHECK-NEXT:  ProgramHeader {

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test b/llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test
index ca83e58f53a9..ce310af5ae22 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test
@@ -36,12 +36,10 @@ Sections:
     AddressAlign:    0x1000
     Size:            4096
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text
-      - Section: .text2
-      - Section: .text3
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text3
 ## TODO (grimar): without the following line (i.e. without an empty symbol table),
 ## llvm-objcopy adds an empty .strtab section. It doesn't look correct.
 Symbols: []

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/strip-all-gnu.test b/llvm/test/tools/llvm-objcopy/ELF/strip-all-gnu.test
index 7df3d3b3c91a..74acdc40ac39 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/strip-all-gnu.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/strip-all-gnu.test
@@ -56,9 +56,9 @@ Sections:
     Info:            .text
 ProgramHeaders:
   # Use an arbitrary segment type to show that the segment type is unimportant.
-  - Type: 0x61234567
-    Sections:
-      - Section: .debug_in_segment
+  - Type:     0x61234567
+    FirstSec: .debug_in_segment
+    LastSec:  .debug_in_segment
 
 # CHECK: SectionHeaderCount: 8
 

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/strip-all.test b/llvm/test/tools/llvm-objcopy/ELF/strip-all.test
index cba3f1490184..20f3c9addf55 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/strip-all.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/strip-all.test
@@ -70,9 +70,9 @@ Sections:
     Type:            SHT_PROGBITS
 ProgramHeaders:
   # Use an arbitrary segment type to show that the segment type is unimportant.
-  - Type: 0x61234567
-    Sections:
-      - Section: non_alloc_in_segment
+  - Type:     0x61234567
+    FirstSec: non_alloc_in_segment
+    LastSec:  non_alloc_in_segment
 
 # CHECK: SectionHeaderCount: 6
 

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test b/llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test
index 1cfb596ea5cf..9c74084ac904 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/strip-non-alloc.test
@@ -27,9 +27,9 @@ Sections:
     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
 ProgramHeaders:
   # Use an arbitrary segment type to show that the segment type is unimportant.
-  - Type: 0x61234567
-    Sections:
-      - Section: non_alloc_in_segment
+  - Type:     0x61234567
+    FirstSec: non_alloc_in_segment
+    LastSec:  non_alloc_in_segment
 
 # RUN: yaml2obj --docnum=2 %s -o %t2
 # RUN: llvm-objcopy --strip-non-alloc %t2 %t2.out
@@ -57,6 +57,6 @@ Sections:
     Type:    SHT_PROGBITS
     Content: 00
 ProgramHeaders:
-  - Type: 0x61234567
-    Sections:
-      - Section: .text
+  - Type:     0x61234567
+    FirstSec: .text
+    LastSec:  .text

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/strip-sections.test b/llvm/test/tools/llvm-objcopy/ELF/strip-sections.test
index 68bc07fcde06..2fd826712f12 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/strip-sections.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/strip-sections.test
@@ -34,11 +34,10 @@ Sections:
     Flags:           [ ]
     Content:         "FEEDFACE"
 ProgramHeaders:
-- Type: PT_LOAD
-  Flags: [ PF_X, PF_R ]
-  Sections:
-    - Section: .text
-    - Section: .non_alloc_in_segment
+- Type:     PT_LOAD
+  Flags:    [ PF_X, PF_R ]
+  FirstSec: .text
+  LastSec:  .non_alloc_in_segment
 
 # DATA: {{^[^[:blank:]]+}} de ad be ef ca fe ba be
 # DATA-NOT: fe ed fa ce

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/triple-overlap.test b/llvm/test/tools/llvm-objcopy/ELF/triple-overlap.test
index 503a9075f4a0..d6d44f1e287a 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/triple-overlap.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/triple-overlap.test
@@ -40,32 +40,22 @@ Sections:
     AddressAlign:    0x1000
     Size:            4096
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text4
-      - Section: .text5
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text3
-      - Section: .text4
-      - Section: .text5
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text
-      - Section: .text2
-      - Section: .text3
-      - Section: .text4
-      - Section: .text5
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text2
-      - Section: .text3
-      - Section: .text4
-      - Section: .text5
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text4
+    LastSec:  .text5
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text3
+    LastSec:  .text5
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text5
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text2
+    LastSec:  .text5
 
 #CHECK:     ProgramHeaders [
 #CHECK-NEXT:  ProgramHeader {

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-end.test b/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-end.test
index 2ad3a761a9a8..72e6badbf78e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-end.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-end.test
@@ -39,18 +39,16 @@ Sections:
     Content:         "FFFFFFFF"
     Size:            0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .text2
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x3000
-    Sections:
-      - Section: .text3
-      - Section: .text4
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text2
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x3000
+    FirstSec: .text3
+    LastSec:  .text4
 
 # CHECK: 000000 c3 c3 c3 c3
 # CHECK: 001000 de ad be ef

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-first.test b/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-first.test
index 6b58363ad250..4f5ecaa6e81d 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-first.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-first.test
@@ -39,18 +39,16 @@ Sections:
     Content:         "FFFFFFFF"
     Size:            0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .text2
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x3000
-    Sections:
-      - Section: .text3
-      - Section: .text4
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text2
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x3000
+    FirstSec: .text3
+    LastSec:  .text4
 
 # CHECK: 000000 de ad be ef
 # CHECK: 001000 32 32 32 32

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-third-sec.test b/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-third-sec.test
index 54eef2690ba5..7053d200bf48 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-third-sec.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/two-seg-remove-third-sec.test
@@ -39,18 +39,16 @@ Sections:
     Content:         "FFFFFFFF"
     Size:            0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .text2
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x3000
-    Sections:
-      - Section: .text3
-      - Section: .text4
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text2
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x3000
+    FirstSec: .text3
+    LastSec:  .text4
 
 # CHECK: 000000 c3 c3 c3 c3
 # CHECK: 001000 de ad be ef

diff  --git a/llvm/test/tools/llvm-objdump/ELF/dynamic-section-machine-specific.test b/llvm/test/tools/llvm-objdump/ELF/dynamic-section-machine-specific.test
index 49d3e89b702f..2f3b7cb1ce84 100644
--- a/llvm/test/tools/llvm-objdump/ELF/dynamic-section-machine-specific.test
+++ b/llvm/test/tools/llvm-objdump/ELF/dynamic-section-machine-specific.test
@@ -28,12 +28,12 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 2: Test that MIPS machine-specific tags can be dumped.
 ##         MIPS has a few long tag names. Show that we indent columns properly.
@@ -190,12 +190,12 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 3: Test that PPC machine-specific tags can be dumped.
 # RUN: yaml2obj --docnum=3 -o %t.ppc %s
@@ -222,12 +222,12 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 4: Test that PPC64 machine-specific tags can be dumped.
 # RUN: yaml2obj --docnum=4 -o %t.ppc64 %s
@@ -251,12 +251,12 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:      PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 5: Test that AARCH64 machine-specific tags can be dumped.
 # RUN: yaml2obj --docnum=5 -o %t.aarch64 %s
@@ -283,9 +283,9 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-objdump/ELF/dynamic-section.test b/llvm/test/tools/llvm-objdump/ELF/dynamic-section.test
index 0a99145d977a..5205c5a3876d 100644
--- a/llvm/test/tools/llvm-objdump/ELF/dynamic-section.test
+++ b/llvm/test/tools/llvm-objdump/ELF/dynamic-section.test
@@ -205,15 +205,14 @@ Sections:
      - Tag:   DT_NULL
        Value: 0x0
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1010
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1010
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # RUN: yaml2obj --docnum=2 %s -o %t2
 # RUN: llvm-objdump -p %t2 | FileCheck %s --strict-whitespace --match-full-lines --check-prefix=ELF32
@@ -421,15 +420,14 @@ Sections:
      - Tag:   DT_NULL
        Value: 0x0
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1010
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1010
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## When printing the value column we want to have the minimal possible indentation.
 ## Use an arbitrary dynamic tag to demonstrate that.

diff  --git a/llvm/test/tools/llvm-objdump/X86/elf-disassemble-dynamic-symbols.test b/llvm/test/tools/llvm-objdump/X86/elf-disassemble-dynamic-symbols.test
index d4442a46d803..95e0c3d0f28a 100644
--- a/llvm/test/tools/llvm-objdump/X86/elf-disassemble-dynamic-symbols.test
+++ b/llvm/test/tools/llvm-objdump/X86/elf-disassemble-dynamic-symbols.test
@@ -56,10 +56,10 @@ Sections:
     Address: 0x1000
     Content: 909090909090909090909090
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text
 Symbols:
   - Name:    both_static
     Value:   0x1001

diff  --git a/llvm/test/tools/llvm-objdump/X86/elf-dynamic-relocs.test b/llvm/test/tools/llvm-objdump/X86/elf-dynamic-relocs.test
index 557650ff496a..37ed0555437b 100644
--- a/llvm/test/tools/llvm-objdump/X86/elf-dynamic-relocs.test
+++ b/llvm/test/tools/llvm-objdump/X86/elf-dynamic-relocs.test
@@ -94,17 +94,13 @@ ProgramHeaders:
   - Type:     PT_LOAD
     VAddr:    0x100000
     Align:    0x100
-    Sections:
-      - Section: .foo
-      - Section: .rela.dyn
-      - Section: .rela.plt
-      - Section: .rel.dyn
-      - Section: .dynamic
+    FirstSec: .foo
+    LastSec:  .dynamic
   - Type:     PT_DYNAMIC
     VAddr:    0x100500
     Align:    0x100
-    Sections:
-      - Section: .dynamic
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 DynamicSymbols:
   - Name:    foo
     Section: .foo

diff  --git a/llvm/test/tools/llvm-objdump/X86/phdrs-lma.test b/llvm/test/tools/llvm-objdump/X86/phdrs-lma.test
index c83373a3014a..006db51db7b5 100644
--- a/llvm/test/tools/llvm-objdump/X86/phdrs-lma.test
+++ b/llvm/test/tools/llvm-objdump/X86/phdrs-lma.test
@@ -33,16 +33,15 @@ Sections:
     Content:         "00000000"
     Address:         0x00002000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x00001000
-    PAddr: 0x00002000
-    Sections:
-      - Section: .text
-      - Section: .init
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x00002000
-    PAddr: 0x00003000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x00001000
+    PAddr:    0x00002000
+    FirstSec: .text
+    LastSec:  .init
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x00002000
+    PAddr:    0x00003000
+    FirstSec: .data
+    LastSec:  .data

diff  --git a/llvm/test/tools/llvm-objdump/X86/phdrs-lma2.test b/llvm/test/tools/llvm-objdump/X86/phdrs-lma2.test
index a8f3e2ca6157..b2831ef8feae 100644
--- a/llvm/test/tools/llvm-objdump/X86/phdrs-lma2.test
+++ b/llvm/test/tools/llvm-objdump/X86/phdrs-lma2.test
@@ -45,14 +45,13 @@ Sections:
     Content:         "00000000"
     Address:         0x00002000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x00001000
-    Sections:
-      - Section: .text
-      - Section: .init
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x00002000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x00001000
+    FirstSec: .text
+    LastSec:  .init
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x00002000
+    FirstSec: .data
+    LastSec:  .data

diff  --git a/llvm/test/tools/llvm-objdump/section-filter.test b/llvm/test/tools/llvm-objdump/section-filter.test
index 6a93856d13b6..77506320c20f 100644
--- a/llvm/test/tools/llvm-objdump/section-filter.test
+++ b/llvm/test/tools/llvm-objdump/section-filter.test
@@ -40,22 +40,21 @@ Sections:
     AddressAlign: 0x10
     Size:         1
 ProgramHeaders:
-  - Type:  PT_LOAD
-    VAddr: 0x400
-    PAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .text2
-  - Type:  PT_LOAD
-    VAddr: 0x410
-    PAddr: 0x2000
-    Sections:
-      - Section: .data
-  - Type:  PT_LOAD
-    VAddr: 0x420
-    PAddr: 0x3000
-    Sections:
-      - Section: .bss
+  - Type:     PT_LOAD
+    VAddr:    0x400
+    PAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text2
+  - Type:     PT_LOAD
+    VAddr:    0x410
+    PAddr:    0x2000
+    FirstSec: .data
+    LastSec:  .data
+  - Type:     PT_LOAD
+    VAddr:    0x420
+    PAddr:    0x3000
+    FirstSec: .bss
+    LastSec:  .bss
 
 ## Test that --section works with --fault-map-section.
 # RUN: yaml2obj %s --docnum=2 -o %t.o

diff  --git a/llvm/test/tools/llvm-objdump/warn-on-out-of-range-start-stop-address.test b/llvm/test/tools/llvm-objdump/warn-on-out-of-range-start-stop-address.test
index 797a48b20ca3..6f0912e704ac 100644
--- a/llvm/test/tools/llvm-objdump/warn-on-out-of-range-start-stop-address.test
+++ b/llvm/test/tools/llvm-objdump/warn-on-out-of-range-start-stop-address.test
@@ -151,9 +151,8 @@ ProgramHeaders:
     Flags:    [ PF_X, PF_R ]
     VAddr:    0x1000
     FileSize: 0x500
-    Sections:
-      - Section: .text
-      - Section: .text2
+    FirstSec: .text
+    LastSec:  .text2
 
 --- !ELF
 FileHeader:
@@ -172,8 +171,8 @@ ProgramHeaders:
     Flags:    [ PF_X, PF_R ]
     VAddr:    0x1000
     FileSize: 0x4
-    Sections:
-      - Section: .text
+    FirstSec: .text
+    LastSec:  .text
 
 --- !ELF
 FileHeader:

diff  --git a/llvm/test/tools/llvm-readobj/ELF/all.test b/llvm/test/tools/llvm-readobj/ELF/all.test
index 501c480f23df..3d452d8b60f8 100644
--- a/llvm/test/tools/llvm-readobj/ELF/all.test
+++ b/llvm/test/tools/llvm-readobj/ELF/all.test
@@ -97,20 +97,19 @@ Sections:
 ## An arbitrary linker-generated valid content.
     Content: 040000001000000003000000474E55004FCB712AA6387724A9F465A32CD8C14B
 ProgramHeaders:
-  - Type:  PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .hash
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
-  - Type: PT_GNU_EH_FRAME
-    Sections:
-      - Section: .eh_frame_hdr
-  - Type: PT_NOTE
-    Sections:
-      - Section: .note.gnu.build-id
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .hash
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_GNU_EH_FRAME
+    FirstSec: .eh_frame_hdr
+    LastSec:  .eh_frame_hdr
+  - Type:     PT_NOTE
+    FirstSec: .note.gnu.build-id
+    LastSec:  .note.gnu.build-id
 Symbols: []
 DynamicSymbols:
   - Name: foo

diff  --git a/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test b/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test
index 8ac862d12a6d..bd7916a91fc1 100644
--- a/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test
+++ b/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test
@@ -44,10 +44,9 @@ Sections:
 DynamicSymbols:
   - StName: 0x1234
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .rela.dyn
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .rela.dyn
+    LastSec:  .dynamic
 
 ## Show we print a warning for an invalid relocation table size stored in a DT_RELASZ entry.
 # RUN: yaml2obj --docnum=2 -DRELTYPE=RELA -DTAG1=DT_RELASZ -DTAG1VAL=0xFF -DTAG2=DT_RELAENT %s -o %t2
@@ -77,10 +76,9 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .relx.dyn
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .relx.dyn
+    LastSec:  .dynamic
 
 ## Show we print a warning for an invalid relocation table entry size stored in a DT_RELAENT entry.
 # RUN: yaml2obj --docnum=2 -DRELTYPE=RELA -DTAG1=DT_RELASZ -DTAG2=DT_RELAENT -DTAG2VAL=0xFF %s -o %t3
@@ -158,10 +156,9 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .rela.plt
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .rela.plt
+    LastSec:  .dynamic
 
 ## Show we print a warning when dumping dynamic relocations if there is no dynamic symbol table.
 # RUN: yaml2obj --docnum=4 %s -o %t11
@@ -207,10 +204,9 @@ Sections:
       - Tag:   DT_NULL
         Value: 0x0
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .rela.dyn
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .rela.dyn
+    LastSec:  .dynamic
 
 ## Show we print a warning when the symbol index of a dynamic relocation is too
 ## large (goes past the end of the dynamic symbol table).
@@ -254,10 +250,9 @@ Sections:
 DynamicSymbols:
   - Name: foo
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .rela.dyn
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .rela.dyn
+    LastSec:  .dynamic
 
 ## Show that when we have both REL and RELA relocations, we dump both sets.
 # RUN: yaml2obj --docnum=6 %s -o %t13
@@ -314,11 +309,9 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .rela.dyn
-      - Section: .rel.dyn
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .rela.dyn
+    LastSec:  .dynamic
 
 ## Check that llvm-readobj/llvm-readelf reports a warning when dumping a relocation
 ## which refers to a symbol past the end of the file.
@@ -402,14 +395,12 @@ Sections:
 DynamicSymbols:
   - Name: foo
 ProgramHeaders:
-  - Type:   PT_LOAD
-    Offset: 0x0
-    Sections:
-      - Section: .dynamic
-      - Section: .rela.dyn
-      - Section: .dynsym
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Offset:   0x0
+    FirstSec: .dynamic
+    LastSec:  .dynsym
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 SectionHeaderTable:
   NoHeaders: true

diff  --git a/llvm/test/tools/llvm-readobj/ELF/check-output-order.test b/llvm/test/tools/llvm-readobj/ELF/check-output-order.test
index 855299e36639..0b241fee5f43 100644
--- a/llvm/test/tools/llvm-readobj/ELF/check-output-order.test
+++ b/llvm/test/tools/llvm-readobj/ELF/check-output-order.test
@@ -40,6 +40,6 @@ Sections:
         Value: 0
 Symbols: []
 ProgramHeaders:
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/demangle.test b/llvm/test/tools/llvm-readobj/ELF/demangle.test
index 94a77cc2a982..4369a9e94812 100644
--- a/llvm/test/tools/llvm-readobj/ELF/demangle.test
+++ b/llvm/test/tools/llvm-readobj/ELF/demangle.test
@@ -216,17 +216,13 @@ DynamicSymbols:
   - Name:    _Z3fooi
     Binding: STB_GLOBAL
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    VAddr: 0x0
-    Sections:
-      - Section: .dynstr
-      - Section: .dynsym
-      - Section: .rela.dyn
-      - Section: .dynamic
-      - Section: .text.foo
-  - Type:  PT_DYNAMIC
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    VAddr:    0x0
+    FirstSec: .dynstr
+    LastSec:  .text.foo
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test
index dc421c14eae9..f23c62a054f0 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test
@@ -123,22 +123,18 @@ DynamicSymbols:
     Section: .data
     Value:   0x200
 ProgramHeaders:
-  - Type:  PT_LOAD
-    VAddr: 0
-    Sections:
-      - Section: .text
-      - Section: .data
-  - Type:  PT_LOAD
-    VAddr: 0x400
-    Sections:
-      - Section: .dynsym
-      - Section: .hash
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type:  PT_DYNAMIC
-    VAddr: 0xA00
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0
+    FirstSec: .text
+    LastSec:  .data
+  - Type:     PT_LOAD
+    VAddr:    0x400
+    FirstSec: .dynsym
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0xA00
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 2: Table size from DT_HASH does not match size from section header.
 # RUN: yaml2obj --docnum=2 %s -o %t2-smaller -DCHAIN="[1, 2]"
@@ -290,22 +286,18 @@ DynamicSymbols:
     Section: .data
     Value:   0x300
 ProgramHeaders:
-  - Type:  PT_LOAD
-    VAddr: 0
-    Sections:
-      - Section: .text
-      - Section: .data
-  - Type:  PT_LOAD
-    VAddr: 0x400
-    Sections:
-      - Section: .dynsym
-      - Section: .hash
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type:  PT_DYNAMIC
-    VAddr: 0xA00
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0
+    FirstSec: .text
+    LastSec:  .data
+  - Type:     PT_LOAD
+    VAddr:    0x400
+    FirstSec: .dynsym
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0xA00
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 3: DT_HASH is missing.
 ## Show that no warning occurs if there are section headers.
@@ -409,9 +401,7 @@ Sections:
     NChain: 0xFFFFFFFF
 DynamicSymbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .rela.plt
-      - Section: .dynamic
-      - Section: .hash
+  - Type:     PT_LOAD
+    FirstSec: .rela.plt
+    LastSec:  .hash
     VAddr: 0x1000

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
index 2581e6430041..0ccb24a2f4bd 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
@@ -63,10 +63,10 @@ DynamicSymbols:
   - Name: foo
   - Name: bar
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x100
-    Sections:
-      - Section: .dynsym
+  - Type:     PT_LOAD
+    VAddr:    0x100
+    FirstSec: .dynsym
+    LastSec:  .dynsym
 
 ## Case 2: Check the output for aliases.
 ## a) Check the two-letter alias --dt is equivalent to the --dyn-symbols
@@ -201,10 +201,10 @@ Sections:
 DynamicSymbols:
   - Name: foo
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x0000
-    Sections:
-      - Section: .dynsym
+  - Type:     PT_LOAD
+    VAddr:    0x0000
+    FirstSec: .dynsym
+    LastSec:  .dynsym
 
 ## Case 6: Check that if we can get the location of the dynamic symbol table using both the DT_SYMTAB value
 ## and the section headers table then we prefer the former and report a warning.
@@ -238,10 +238,10 @@ Sections:
 DynamicSymbols:
   - Name: foo
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x0000
-    Sections:
-      - Section: .mydynsym
+  - Type:     PT_LOAD
+    VAddr:    0x0000
+    FirstSec: .mydynsym
+    LastSec:  .mydynsym
 
 ## Case 7: Check how we dump versioned symbols. Use both -V and --dyn-symbols
 ## to check that printed version is consistent.
@@ -488,10 +488,10 @@ Sections:
     Address: 0x100
     Size:    0x1
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x100
-    Sections:
-      - Section: .dynsym
+  - Type:     PT_LOAD
+    VAddr:    0x100
+    FirstSec: .dynsym
+    LastSec:  .dynsym
 
 --- !ELF
 FileHeader:
@@ -582,11 +582,10 @@ DynamicSymbols:
 ## An arbitrary valid symbol to document we report an error before dumping it.
   - StName:  0x1
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .dynstr
+    LastSec:  .dynamic
 
 ## Case 11: check various warnings we report when fields of the SHT_DYNSYM section are broken.
 

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-empty.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-empty.test
index 307180fb23f0..5522b7e4a6a7 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-empty.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-empty.test
@@ -18,11 +18,11 @@ Sections:
     Type:         SHT_DYNAMIC
     Address:      0x1000
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-malformed.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-malformed.test
index 35927097f160..48ab1d914c3b 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-malformed.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-malformed.test
@@ -35,14 +35,14 @@ Sections:
     Content: "01234567"
 Symbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Test handling of a .dynamic section with an invalid entsize (i.e. not 2 * sizeof(Elf_Dyn)).
 # RUN: yaml2obj %s --docnum=2 -o %t.bad-entsize
@@ -77,14 +77,14 @@ Sections:
         Value: 0
 Symbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Test handling of string references pointing past the end of the dynamic string table.
 # RUN: yaml2obj %s --docnum=3 -o %t.bad-string
@@ -171,15 +171,14 @@ Sections:
         Value: 0
 Symbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1010
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1010
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Test handling of DT_STRTAB pointing outside the file's address space.
 # RUN: yaml2obj %s --docnum=4 -o %t.bad-strtab
@@ -226,14 +225,14 @@ Sections:
         Value: 0x0
 Symbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Test handling of other d_ptr tags pointing outside the file's address space.
 # RUN: yaml2obj %s --docnum=5 -o %t.bad-rela
@@ -268,14 +267,14 @@ Sections:
         Value: 0x0
 Symbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Check how we handle cases when the dynamic string table is not null-terminated.
 
@@ -365,15 +364,14 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1100
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1100
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Check that we emit an appropriate warning when the dynamic string table ends past the end of the file.
 

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-no-pt-dynamic.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-no-pt-dynamic.test
index f5c95d7d66d0..c578835f9e3b 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-no-pt-dynamic.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-no-pt-dynamic.test
@@ -32,7 +32,7 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-not-in-pt-dynamic.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-not-in-pt-dynamic.test
index 20dd7c0ef630..7022866f685d 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-not-in-pt-dynamic.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-not-in-pt-dynamic.test
@@ -50,15 +50,14 @@ Sections:
     AddressAlign: 0x100
     Content: "00"
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .text
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .text
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text
 
 ## Case 2: The dynamic table found using the dynamic program header is 
diff erent from the
 ##         table found using the section header table.
@@ -104,15 +103,14 @@ Sections:
     AddressAlign: 0x100
     Content: "00000000000000000000000000000000"
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .text
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
+  - Type:      PT_LOAD
+    VAddr:     0x1000
+    FirstSec:  .dynamic
+    LastSec:   .text
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text
 
 ## Case 3: Both dynamic tables found using SHT_DYNAMIC/PT_DYNAMIC are corrupted.
 
@@ -145,12 +143,11 @@ Sections:
     AddressAlign: 0x100
     Content: "00"
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .text
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .text
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .text

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc-no-section-headers.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc-no-section-headers.test
index b6c6f102c9c1..ae99d76b8f8b 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc-no-section-headers.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc-no-section-headers.test
@@ -53,14 +53,11 @@ Sections:
 DynamicSymbols:
   - Name: foo
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .rela.dyn
-      - Section: .dynamic
-        Section: .dynsym
-        Section: .dynstr
-  - Type:  PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .rela.dyn
+    LastSec:  .dynstr
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 SectionHeaderTable:
   NoHeaders: true

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test
index 44fe4348e1e7..221e0b80058e 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test
@@ -125,10 +125,6 @@ Symbols:
 DynamicSymbols:
   - Name: foo
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .rela.dyn
-      - Section: .rel.dyn
-      - Section: .relr.dyn
-      - Section: .plt
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .rela.dyn
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-table-dtnull.s b/llvm/test/tools/llvm-readobj/ELF/dynamic-table-dtnull.s
index a38a61896849..bd55f3904ec0 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-table-dtnull.s
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-table-dtnull.s
@@ -25,12 +25,12 @@ Sections:
       - Tag:   DT_DEBUG
         Value: 0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # Sometimes .dynamic section content length can be greater than the
 # length of its entries. In this case, we should not try to dump anything
@@ -67,9 +67,9 @@ Sections:
       - Tag:   DT_NULL
         Value: 0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test
index 4a7780815764..53a661a427d8 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test
@@ -39,12 +39,12 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 2: Test that MIPS machine-specific tags can be dumped.
 # RUN: yaml2obj --docnum=2 %s -o %t.mips
@@ -259,12 +259,12 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 3: Test that PPC machine-specific tags can be dumped.
 # RUN: yaml2obj --docnum=3 %s -o %t.ppc
@@ -301,12 +301,12 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 4: Test that PPC64 machine-specific tags can be dumped.
 # RUN: yaml2obj --docnum=4 %s -o %t.ppc64
@@ -339,12 +339,12 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Case 5: Test that AARCH64 machine-specific tags can be dumped.
 # RUN: yaml2obj --docnum=5 %s -o %t.aarch64
@@ -381,9 +381,9 @@ Sections:
       - Tag:   DT_NULL
         Value: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
index 04f6fd02b78d..f1d7b6c4f494 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
@@ -281,15 +281,14 @@ Sections:
       - Tag:   DT_NULL
         Value: 0x0
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1010
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynstr
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1010
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 # RUN: yaml2obj %s --docnum=1 -DBITS=32 -DSYMBOLIC=0x12345678 -DDEBUG=0xfedcba09 \
 # RUN:   -DTEXTREL=0x11223344 -DBINDNOW=0x88776655 -DFLAGS=0xffffffff \

diff  --git a/llvm/test/tools/llvm-readobj/ELF/gnu-notes.test b/llvm/test/tools/llvm-readobj/ELF/gnu-notes.test
index 7a152969046c..efc7f6e57094 100644
--- a/llvm/test/tools/llvm-readobj/ELF/gnu-notes.test
+++ b/llvm/test/tools/llvm-readobj/ELF/gnu-notes.test
@@ -104,10 +104,10 @@ Sections:
     AddressAlign: 0x0000000000000004
     Content:      040000000900000004000000474E5500676F6C6420312E3131000000
 ProgramHeaders:
-  - Type: PT_NOTE
+  - Type:     PT_NOTE
     FileSize: 0x20
-    Sections:
-      - Section: .note.gnu.build-id
+    FirstSec: .note.gnu.build-id
+    LastSec:  .note.gnu.build-id
 
 ## Test tools report an error if a note section has an invalid offset
 ## that goes past the end of file.
@@ -186,10 +186,10 @@ Sections:
     Type:  SHT_NOTE
     Notes: []
 ProgramHeaders:
-  - Type: PT_NOTE
+  - Type:     PT_NOTE
     FileSize: 0xffff0000
-    Sections:
-      - Section: .note
+    FirstSec: .note
+    LastSec:  .note
 
 ## Check we report a warning when we are unable to locate the PT_NOTE
 ## segment because of broken program headers.

diff  --git a/llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test b/llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test
index b10b3ec4563d..24eb004a8a47 100644
--- a/llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test
+++ b/llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test
@@ -39,19 +39,17 @@ Sections:
     Size:    0x4
 ProgramHeaders:
 ## Case 1: an arbitrary segment with sections.
-  - Type:  PT_PHDR
-    Flags: [ PF_W ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     PT_PHDR
+    Flags:    [ PF_W ]
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 2: another segment with 
diff erent sections.
-  - Type:  PT_PHDR
-    Flags: [ PF_X ]
-    VAddr: 0x2000
-    Sections:
-      - Section: .bar.begin
-      - Section: .bar.end
+  - Type:     PT_PHDR
+    Flags:    [ PF_X ]
+    VAddr:    0x2000
+    FirstSec: .bar.begin
+    LastSec:  .bar.end
 
 ## Check that --section-mapping=false --program-headers produces just program headers.
 # RUN: llvm-readelf --section-mapping=false --program-headers %t64.elf \

diff  --git a/llvm/test/tools/llvm-readobj/ELF/gnuhash.test b/llvm/test/tools/llvm-readobj/ELF/gnuhash.test
index 9ae439f65eb9..a8c3b98cf6d3 100644
--- a/llvm/test/tools/llvm-readobj/ELF/gnuhash.test
+++ b/llvm/test/tools/llvm-readobj/ELF/gnuhash.test
@@ -57,11 +57,10 @@ DynamicSymbols:
   - Name:    ddd
     Binding: STB_GLOBAL
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Check we report a warning if there is no dynamic symbol section in the object.
 
@@ -103,11 +102,10 @@ Sections:
       - Tag:   DT_NULL
         Value: 0x0
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Check what we do when the index of the first symbol in the dynamic symbol table
 ## included in the hash table is larger than the number of dynamic symbols.
@@ -156,11 +154,10 @@ DynamicSymbols:
   - Name:    aaa
     Binding: STB_GLOBAL
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Check we emit a warning when the dynamic symbol table is empty.
 ## A valid dynamic symbol table should have at least one symbol: the symbol with index 0.
@@ -209,11 +206,10 @@ Sections:
     Type: SHT_DYNSYM
     Size: 0
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Linkers might produce an empty no-op SHT_GNU_HASH section when
 ## there are no dynamic symbols or when all dynamic symbols are undefined.
@@ -277,11 +273,10 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Check we report a proper warning when a hash table goes past the end of the file.
 

diff  --git a/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test b/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test
index 933440dd29f5..cc187f477aa0 100644
--- a/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test
+++ b/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test
@@ -63,11 +63,9 @@ DynamicSymbols:
   - Name: c
   - Name: d
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Show that we report a warning for a hash table which contains an entry of
 ## the bucket array pointing to a cycle.
@@ -106,10 +104,9 @@ Sections:
 DynamicSymbols:
   - Name: foo
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Each SHT_HASH section starts with two 32-bit fields: nbucket and nchain.
 ## Check we report an error when a DT_HASH value points to data that has size less than 8 bytes.
@@ -142,9 +139,8 @@ DynamicSymbols: []
 ProgramHeaders:
   - Type:     PT_LOAD
     FileSize: 0x23a
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Check we report a warning when the hash table goes past the end of the file.
 
@@ -201,10 +197,9 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Check we dump a histogram for the .gnu.hash table even when the .hash table is skipped.
 
@@ -258,11 +253,9 @@ Sections:
 DynamicSymbols:
   - Name: foo
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Check we report a proper warning when the GNU hash table goes past the end of the file.
 
@@ -308,10 +301,9 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Linkers might produce an empty no-op SHT_GNU_HASH section when
 ## there are no dynamic symbols or when all dynamic symbols are undefined.
@@ -369,10 +361,9 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Check we report warnings when the dynamic symbol table is absent or empty.
 
@@ -416,6 +407,6 @@ Sections:
     Type: [[TYPE]]
     Size: 0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .gnu.hash
+  - Type:     PT_LOAD
+    FirstSec: .gnu.hash
+    LastSec:  .gnu.hash

diff  --git a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
index 788c265b69ec..49db87e04ddb 100644
--- a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
@@ -104,12 +104,10 @@ DynamicSymbols:
     Value:   0x0000000000001001
     Type:    [[TYPE=STT_NOTYPE]]
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .hash
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:      PT_LOAD
+    Flags:     [ PF_R, PF_X ]
+    FirstSec:  .hash
+    LastSec:   .dynamic
 
 ## Check what we print for unnamed section symbols.
 # RUN: yaml2obj --docnum=1 -DBITS=64 -DTYPE=STT_SECTION -DNAME="''" %s -o %t1-sec-syms.so
@@ -188,11 +186,10 @@ DynamicSymbols:
     Binding: STB_WEAK
     Value:   0x0000000000001001
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Check the output when only .gnu.hash section is present.
 
@@ -252,11 +249,10 @@ DynamicSymbols:
     Binding: STB_WEAK
     Value:   0x0000000000001001
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Show that if there are no hash sections, we do not print anything.
 # RUN: yaml2obj --docnum=4 %s -o %t4.so
@@ -317,19 +313,16 @@ DynamicSymbols:
   - Name:    _Z3fooi
     Binding: STB_GLOBAL
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    VAddr: 0x0
-    Sections:
-      - Section: .dynstr
-      - Section: .dynsym
-      - Section: .dynamic
-      - Section: .text.foo
-  - Type:  PT_DYNAMIC
-    Flags: [ PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    VAddr:    0x0
+    FirstSec: .dynstr
+    LastSec:  .text.foo
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_R ]
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Show that we report a warning for a hash table which contains an entry of
 ## the bucket array pointing to a cycle.
@@ -365,10 +358,9 @@ DynamicSymbols:
   - Name:    aaa
   - Name:    bbb
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Each SHT_HASH section starts with two 32-bit fields: nbucket and nchain.
 ## Check we report an error when a DT_HASH value points to data that has size less than 8 bytes.
@@ -401,9 +393,8 @@ DynamicSymbols: []
 ProgramHeaders:
   - Type:     PT_LOAD
     FileSize: 0x23a
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Check we report a warning when the hash table goes past the end of the file.
 
@@ -465,10 +456,9 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Check we report a proper warning when a GNU hash table goes past the end of the file.
 
@@ -524,11 +514,10 @@ DynamicSymbols:
   - Name:    ddd
     Binding: STB_GLOBAL
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## Check the behavior when the dynamic symbol table is empty or not found.
 
@@ -576,12 +565,10 @@ Sections:
     Flags: [ SHF_ALLOC ]
     Size:  0
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
-      - Section: .dynstr
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .hash
+    LastSec:  .dynstr
 
 ## Case A.2: similar to A.1, but now check that we report a warning when the dynamic symbol table was not found.
 ##           To do that, set the type of the .dynsym to SHT_PROGBITS to hide it.
@@ -649,12 +636,10 @@ Sections:
     Flags: [ SHF_ALLOC ]
     Size:  0
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
-      - Section: .dynstr
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynstr
 
 ## In this case we have a broken value in the hash buckets array. Normally it contains an
 ## index into the dynamic symbol table and also is used to get a hash value from the hash values array.
@@ -699,11 +684,10 @@ DynamicSymbols:
   - Name:    foo
     Binding: STB_GLOBAL
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R, PF_X ]
-    Sections:
-      - Section: .gnu.hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    FirstSec: .gnu.hash
+    LastSec:  .dynamic
 
 ## In this case we are unable to read a hash value for a symbol with
 ## an index that is less than the index of the first hashed symbol.

diff  --git a/llvm/test/tools/llvm-readobj/ELF/hash-table.test b/llvm/test/tools/llvm-readobj/ELF/hash-table.test
index 025a6932f958..ad52a98639be 100644
--- a/llvm/test/tools/llvm-readobj/ELF/hash-table.test
+++ b/llvm/test/tools/llvm-readobj/ELF/hash-table.test
@@ -38,10 +38,9 @@ Sections:
       - Tag:   DT_NULL
         Value: 0x0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Document that we ignore the sh_entsize value when dumping the hash section.
 ## Implementation assumes that the size of entries is 4, matching the ELF specification.
@@ -117,14 +116,13 @@ Sections:
 SectionHeaderTable:
   NoHeaders: [[NOHEADERS=false]]
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x10
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x10
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 
 ## Document we don't report a warning when the value of the sh_entsize field of the SHT_HASH section is not 4.
 
@@ -179,9 +177,8 @@ DynamicSymbols: []
 ProgramHeaders:
   - Type:     PT_LOAD
     FileSize: 0x23a
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+    FirstSec: .hash
+    LastSec:  .dynamic
 
 ## Check we report a warning when the hash table goes past the end of the file.
 
@@ -274,10 +271,9 @@ Sections:
         Value: 0x0
 DynamicSymbols: []
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .hash
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    FirstSec: .hash
+    LastSec: .dynamic
 
 ## Show we do not duplicate warnings when printing both the hash table and the hash histogram.
 ## Note that --elf-hash-histogram is only implemented for llvm-readelf currently.

diff  --git a/llvm/test/tools/llvm-readobj/ELF/loadname.test b/llvm/test/tools/llvm-readobj/ELF/loadname.test
index 5fda41107284..b0a028d3d641 100644
--- a/llvm/test/tools/llvm-readobj/ELF/loadname.test
+++ b/llvm/test/tools/llvm-readobj/ELF/loadname.test
@@ -47,9 +47,8 @@ ProgramHeaders:
     Flags:    [ PF_R ]
     VAddr:    0x0000
     FileSize: [[PHDRFILESIZE]]
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
+    FirstSec: .dynstr
+    LastSec:  .dynamic
 
 ## Check we do not crash when an object contains a DT_STRTAB entry whose address
 ## is past the end of the object.

diff  --git a/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test b/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test
index 68da95b29ce0..02df7117a832 100644
--- a/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test
+++ b/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test
@@ -140,7 +140,7 @@ Sections:
 ProgramHeaders:
   - Type:     PT_DYNAMIC
     FileSize: [[FILESIZE=<none>]]
-    Sections:
-      - Section: .dynamic
+    FirstSec: .dynamic
+    LastSec:  .dynamic
 SectionHeaderTable:
   NoHeaders: [[NOHEADERS=false]]

diff  --git a/llvm/test/tools/llvm-readobj/ELF/needed-libs.test b/llvm/test/tools/llvm-readobj/ELF/needed-libs.test
index ec2c1178c5ac..d37ab6238e13 100644
--- a/llvm/test/tools/llvm-readobj/ELF/needed-libs.test
+++ b/llvm/test/tools/llvm-readobj/ELF/needed-libs.test
@@ -51,9 +51,8 @@ Sections:
 ProgramHeaders:
   - Type: PT_LOAD
     VAddr: 0x0
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
+    FirstSec: .dynstr
+    LastSec:  .dynamic
 
 ## Check what we print when the dynamic string table is empty.
 # RUN: yaml2obj %s --docnum=2 -o %t2
@@ -94,8 +93,7 @@ Sections:
       - Tag:   DT_NULL
         Value: 0x0
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x0
-    Sections:
-      - Section: .dynstr
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x0
+    FirstSec: .dynstr
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/non-dynamic-in-pt-dynamic.test b/llvm/test/tools/llvm-readobj/ELF/non-dynamic-in-pt-dynamic.test
index 12bcdf6b7216..eec6d7a9fbe4 100644
--- a/llvm/test/tools/llvm-readobj/ELF/non-dynamic-in-pt-dynamic.test
+++ b/llvm/test/tools/llvm-readobj/ELF/non-dynamic-in-pt-dynamic.test
@@ -48,16 +48,14 @@ Sections:
       - Tag:   DT_NULL
         Value: 0x0
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .text
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .text
+    LastSec:  .dynamic
 
 ## In this case .text goes after .dynamic and we don't display any warnings,
 ## though the content of the .text is used for dumping the dynamic table.
@@ -102,16 +100,14 @@ Sections:
     AddressAlign: 0x100
     Content: "00000000000000000000000000000000"
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .text
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .text
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .text
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .text
 
 ## In this case .text goes after .dynamic, but (PT_DYNAMIC segment size % dynamic entry size != 0)
 ## and we have to use the information from the section header instead.
@@ -157,13 +153,11 @@ Sections:
     AddressAlign: 0x100
     Content: "00"
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .text
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .text
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .text
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .text

diff  --git a/llvm/test/tools/llvm-readobj/ELF/note-core-ntfile-bad.test b/llvm/test/tools/llvm-readobj/ELF/note-core-ntfile-bad.test
index eedfaa795acd..ca3033c7248a 100644
--- a/llvm/test/tools/llvm-readobj/ELF/note-core-ntfile-bad.test
+++ b/llvm/test/tools/llvm-readobj/ELF/note-core-ntfile-bad.test
@@ -32,9 +32,9 @@ Sections:
     Type:    SHT_NOTE
     Content: 0500000008000000454C4946434F5245000000000000000000000000
 ProgramHeaders:
-  - Type:        PT_NOTE
-    Sections:
-      - Section: .note.foo
+  - Type:     PT_NOTE
+    FirstSec: .note.foo
+    LastSec:  .note.foo
 
 # RUN: yaml2obj --docnum=2 %s -o %t2.o
 # RUN: llvm-readelf -n %t2.o 2>&1 | FileCheck -DFILE=%t2.o %s --check-prefix=ERR-NULL-TERM
@@ -66,9 +66,9 @@ Sections:
     Type:    SHT_NOTE
     Content: 050000002C000000454C4946434F5245000000000100000000000000001000000000000000100000000000000020000000000000003000000000000078787878
 ProgramHeaders:
-  - Type:        PT_NOTE
-    Sections:
-      - Section: .note.foo
+  - Type:     PT_NOTE
+    FirstSec: .note.foo
+    LastSec:  .note.foo
 
 # RUN: yaml2obj --docnum=3 %s -o %t3.o
 # RUN: llvm-readelf -n %t3.o 2>&1 | FileCheck -DFILE=%t3.o %s --check-prefix=ERR-FILE-COUNT
@@ -100,9 +100,9 @@ Sections:
     Type:    SHT_NOTE
     Content: 050000002C000000454C4946434F5245000000000200000000000000001000000000000000100000000000000020000000000000003000000000000078797A00
 ProgramHeaders:
-  - Type:        PT_NOTE
-    Sections:
-      - Section: .note.foo
+  - Type:     PT_NOTE
+    FirstSec: .note.foo
+    LastSec:  .note.foo
 
 # RUN: yaml2obj --docnum=4 %s -o %t4.o
 # RUN: llvm-readelf -n %t4.o 2>&1 | FileCheck -DFILE=%t4.o %s --check-prefix=ERR-FILE-END-EARLY
@@ -137,6 +137,6 @@ Sections:
     Type:    SHT_NOTE
     Content: 0500000044000000454C4946434F5245000000000200000000000000001000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000078797A00
 ProgramHeaders:
-  - Type:        PT_NOTE
-    Sections:
-      - Section: .note.foo
+  - Type:     PT_NOTE
+    FirstSec: .note.foo
+    LastSec:  .note.foo

diff  --git a/llvm/test/tools/llvm-readobj/ELF/note-core-ntfile.test b/llvm/test/tools/llvm-readobj/ELF/note-core-ntfile.test
index 01aa4643aef1..53b1c1c4f239 100644
--- a/llvm/test/tools/llvm-readobj/ELF/note-core-ntfile.test
+++ b/llvm/test/tools/llvm-readobj/ELF/note-core-ntfile.test
@@ -45,9 +45,9 @@ Sections:
     Type:        SHT_NOTE
     Content:     0500000080000000454C4946434F524500000000030000000000000000100000000000000010000000000000002000000000000000300000000000000040000000000000005000000000000000600000000000000070000000000000008000000000000000900000000000002F706174682F746F2F612E6F7574002F706174682F746F2F6C6962632E736F005B737461636B5D00
 ProgramHeaders:
-  - Type:        PT_NOTE
-    Sections:
-      - Section: .note.foo
+  - Type:     PT_NOTE
+    FirstSec: .note.foo
+    LastSec:  .note.foo
 
 # GNU:      Displaying notes found
 # GNU-NEXT:   Owner                 Data size       Description

diff  --git a/llvm/test/tools/llvm-readobj/ELF/note-core.test b/llvm/test/tools/llvm-readobj/ELF/note-core.test
index d7ec0c39ca4c..3c7216027d74 100644
--- a/llvm/test/tools/llvm-readobj/ELF/note-core.test
+++ b/llvm/test/tools/llvm-readobj/ELF/note-core.test
@@ -271,6 +271,6 @@ Sections:
       - Name: CORE
         Type: [[TYPE]]
 ProgramHeaders:
-  - Type: PT_NOTE
-    Sections:
-      - Section: .note.foo
+  - Type:     PT_NOTE
+    FirstSec: .note.foo
+    LastSec:  .note.foo

diff  --git a/llvm/test/tools/llvm-readobj/ELF/program-headers.test b/llvm/test/tools/llvm-readobj/ELF/program-headers.test
index 17fbaa8ce1d4..d876a239ba68 100644
--- a/llvm/test/tools/llvm-readobj/ELF/program-headers.test
+++ b/llvm/test/tools/llvm-readobj/ELF/program-headers.test
@@ -445,146 +445,125 @@ Sections:
     Size:    0x1
 ProgramHeaders:
 ## Case 1: an arbitrary segment with sections.
-  - Type:  PT_PHDR
-    Flags: [ PF_W ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     PT_PHDR
+    Flags:    [ PF_W ]
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 2: another segment with 
diff erent sections.
-  - Type:  PT_PHDR
-    Flags: [ PF_X ]
-    VAddr: 0x2000
-    Sections:
-      - Section: .bar.begin
-      - Section: .bar.end
+  - Type:     PT_PHDR
+    Flags:    [ PF_X ]
+    VAddr:    0x2000
+    FirstSec: .bar.begin
+    LastSec:  .bar.end
 ## Case 3: the PT_NULL segment.
-  - Type:  PT_NULL
-    Flags: [ PF_X ]
-    VAddr: 0x2000
-    Sections:
-      - Section: .bar.begin
-      - Section: .bar.end
+  - Type:     PT_NULL
+    Flags:    [ PF_X ]
+    VAddr:    0x2000
+    FirstSec: .bar.begin
+    LastSec:  .bar.end
 ## Case 4: the PT_DYNAMIC segment.
-  - Type:  PT_DYNAMIC
-    Flags: [ PF_R, PF_W, PF_X ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_R, PF_W, PF_X ]
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 5: the PT_INTERP segment.
-  - Type:  PT_INTERP
-    Flags: [ PF_R, PF_W ]
-    VAddr: 0x3000
-    Sections:
-      - Section: .interp
+  - Type:     PT_INTERP
+    Flags:    [ PF_R, PF_W ]
+    VAddr:    0x3000
+    FirstSec: .interp
+    LastSec:  .interp
 ## Case 6: the PT_NOTE segment.
-  - Type: PT_NOTE
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     PT_NOTE
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 7: the PT_SHLIB segment.
-  - Type: PT_SHLIB
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
+  - Type:     PT_SHLIB
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.begin
 ## Case 8: the PT_TLS segment.
-  - Type: PT_TLS
-    VAddr: 0x4000
-    Sections:
-      - Section: .tls
+  - Type:     PT_TLS
+    VAddr:    0x4000
+    FirstSec: .tls
+    LastSec:  .tls
 ## Case 9: the PT_LOOS segment.
-  - Type:  0x60000000 ## PT_LOOS
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x60000000 ## PT_LOOS
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 10: the PT_GNU_EH_FRAME segment.
-  - Type: PT_GNU_EH_FRAME
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     PT_GNU_EH_FRAME
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 11: the PT_SUNW_UNWIND segment.
-  - Type: 0x6464e550 ## PT_SUNW_UNWIND
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x6464e550 ## PT_SUNW_UNWIND
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 12: the PT_GNU_STACK segment.
-  - Type: PT_GNU_STACK
-    Sections:
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     PT_GNU_STACK
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 13: the PT_GNU_RELRO segment.
-  - Type: PT_GNU_RELRO
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     PT_GNU_RELRO
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 14: the PT_GNU_PROPERTY segment.
-  - Type: PT_GNU_PROPERTY
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     PT_GNU_PROPERTY
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 15: the PT_OPENBSD_RANDOMIZE segment.
-  - Type: 0x65a3dbe6 ## PT_OPENBSD_RANDOMIZE
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x65a3dbe6 ## PT_OPENBSD_RANDOMIZE
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 16: the PT_OPENBSD_WXNEEDED segment.
-  - Type: 0x65a3dbe7 ## PT_OPENBSD_WXNEEDED
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x65a3dbe7 ## PT_OPENBSD_WXNEEDED
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 17: the PT_OPENBSD_BOOTDATA segment.
-  - Type: 0x65a41be6 ## PT_OPENBSD_BOOTDATA
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x65a41be6 ## PT_OPENBSD_BOOTDATA
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 18: the PT_HIOS segment.
-  - Type: 0x6fffffff ## PT_HIOS
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x6fffffff ## PT_HIOS
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 19: the PT_LOPROC/PT_ARM_ARCHEXT/PT_MIPS_REGINFO segment.
-  - Type: 0x70000000 ## PT_LOPROC/PT_ARM_ARCHEXT/PT_MIPS_REGINFO
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x70000000 ## PT_LOPROC/PT_ARM_ARCHEXT/PT_MIPS_REGINFO
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 20: the PT_ARM_EXIDX/PT_MIPS_RTPROC segment.
-  - Type: 0x70000001 ## PT_ARM_EXIDX, PT_MIPS_RTPROC
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x70000001 ## PT_ARM_EXIDX, PT_MIPS_RTPROC
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 20: the PT_MIPS_OPTIONS segment.
-  - Type: 0x70000002 ## PT_MIPS_OPTIONS
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x70000002 ## PT_MIPS_OPTIONS
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 21: the PT_MIPS_ABIFLAGS segment.
-  - Type: 0x70000003 ## PT_MIPS_ABIFLAGS
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x70000003 ## PT_MIPS_ABIFLAGS
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec:  .foo.end
 ## Case 22: the PT_HIPROC segment.
-  - Type: 0x7fffffff ## PT_HIPROC
-    VAddr: 0x1000
-    Sections:
-      - Section: .foo.begin
-      - Section: .foo.end
+  - Type:     0x7fffffff ## PT_HIPROC
+    VAddr:    0x1000
+    FirstSec: .foo.begin
+    LastSec: .foo.end
 
 ## Check how we dump ARM specific program headers.
 # RUN: yaml2obj --docnum=1 -DBITS=64 -DMACHINE=EM_ARM %s -o %tarm.elf
@@ -702,9 +681,9 @@ Sections:
   - Name: .foo
     Type: SHT_PROGBITS
 ProgramHeaders:
-  - Type: PT_PHDR
-    Sections:
-      - Section: .foo
+  - Type:     PT_PHDR
+    FirstSec: .foo
+    LastSec:  .foo
 
 ## Case B: the value of the e_phoff field is invalid.
 

diff  --git a/llvm/test/tools/llvm-readobj/ELF/reloc-negative-addend-no-sym.test b/llvm/test/tools/llvm-readobj/ELF/reloc-negative-addend-no-sym.test
index 58bc1f35c243..7e00de88605e 100644
--- a/llvm/test/tools/llvm-readobj/ELF/reloc-negative-addend-no-sym.test
+++ b/llvm/test/tools/llvm-readobj/ELF/reloc-negative-addend-no-sym.test
@@ -62,12 +62,11 @@ DynamicSymbols:
   - Name:    force_dynsym
     Binding: STB_GLOBAL
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .rela.dyn
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .rela.dyn
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/reloc-zero-name-or-value.test b/llvm/test/tools/llvm-readobj/ELF/reloc-zero-name-or-value.test
index 24e83ad6598d..30743cfa7be7 100644
--- a/llvm/test/tools/llvm-readobj/ELF/reloc-zero-name-or-value.test
+++ b/llvm/test/tools/llvm-readobj/ELF/reloc-zero-name-or-value.test
@@ -133,12 +133,11 @@ DynamicSymbols:
     Section: .text
     Binding: STB_GLOBAL
 ProgramHeaders:
-  - Type: PT_LOAD
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
-      - Section: .rela.dyn
-  - Type: PT_DYNAMIC
-    VAddr: 0x1000
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .rela.dyn
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/llvm-readobj/ELF/unwind.test b/llvm/test/tools/llvm-readobj/ELF/unwind.test
index 1bdf0997c231..2deb1a587d24 100644
--- a/llvm/test/tools/llvm-readobj/ELF/unwind.test
+++ b/llvm/test/tools/llvm-readobj/ELF/unwind.test
@@ -217,16 +217,16 @@ ProgramHeaders:
     Flags:    [ PF_X, PF_R ]
     VAddr:    0x00400000
     PAddr:    0x00400000
-    Sections:
-      - Section: .text
-  - Type: PT_GNU_EH_FRAME
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x004013C0
-    PAddr: 0x004013C0
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_GNU_EH_FRAME
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x004013C0
+    PAddr:    0x004013C0
     MemSize:  [[MEMSIZE]]
     FileSize: [[FILESIZE]]
-    Sections:
-      - Section: .eh_frame_hdr
+    FirstSec: .eh_frame_hdr
+    LastSec:  .eh_frame_hdr
 
 ## Document we report a error when the memory size of the PT_GNU_EH_FRAME does not match its file size.
 ## TODO: we want to report a warning and continue dumping instead.
@@ -326,11 +326,10 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_EXEC
 ProgramHeaders:
-  - Type: PT_GNU_EH_FRAME
+  - Type:     PT_GNU_EH_FRAME
     MemSize:  [[SIZE]]
     FileSize: [[SIZE]]
     Offset:   [[OFFSET]]
-    Sections: []
 
 ## Case B: test we report an error when the file size of the PT_GNU_EH_FRAME
 ##         is invalid (goes past the end of the file).

diff  --git a/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test b/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test
index 79f743f1dbde..51694df32b73 100644
--- a/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test
+++ b/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test
@@ -17,24 +17,23 @@ FileHeader:
   Flags:           [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
   Entry:           0x00000000000012B0
 ProgramHeaders:
-  - Type:            PT_LOAD
-    Flags:           [ PF_R ]
-    Sections:
-      - Section:         .rel.dyn
-    Align:           0x0000000000001000
-  - Type:            PT_LOAD
-    Flags:           [ PF_X, PF_R ]
-    Sections:
-      - Section:         .text
-    VAddr:           0x00000000000012B0
-    Align:           0x0000000000001000
-  - Type:            PT_LOAD
-    Flags:           [ PF_W, PF_R ]
-    Sections:
-      - Section:         xray_instr_map
-      - Section:         xray_fn_idx
-    VAddr:           0x00000000000033CC
-    Align:           0x0000000000001000
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .rel.dyn
+    LastSec:  .rel.dyn
+    Align:    0x0000000000001000
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .text
+    LastSec:  .text
+    VAddr:    0x00000000000012B0
+    Align:    0x0000000000001000
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: xray_instr_map
+    LastSec:  xray_fn_idx
+    VAddr:    0x00000000000033CC
+    Align:    0x0000000000001000
 Sections:
   - Name:            .rel.dyn
     Type:            SHT_REL

diff  --git a/llvm/test/tools/obj2yaml/ELF/program-headers.yaml b/llvm/test/tools/obj2yaml/ELF/program-headers.yaml
index b3ef3c787f2a..6a7841a045e3 100644
--- a/llvm/test/tools/obj2yaml/ELF/program-headers.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/program-headers.yaml
@@ -37,59 +37,53 @@
 # RUN: obj2yaml %t1 | FileCheck %s --check-prefix=YAML
 
 # YAML:      ProgramHeaders:
-# YAML-NEXT:  - Type:  PT_LOAD
-# YAML-NEXT:    Flags: [ PF_R ]
-# YAML-NEXT:    Sections:
-# YAML-NEXT:      - Section: .hash
-# YAML-NEXT:      - Section: .gnu.hash
-# YAML-NEXT:      - Section: .dynsym
-# YAML-NEXT:      - Section: .dynstr
-# YAML-NEXT:    Align: 0x0000000000001000
-# YAML-NEXT:  - Type:  PT_LOAD
-# YAML-NEXT:    Flags: [ PF_X, PF_R ]
-# YAML-NEXT:    Sections:
-# YAML-NEXT:      - Section: .foo
-# YAML-NEXT:      - Section: .zed
-# YAML-NEXT:    VAddr: 0x0000000000001000
-# YAML-NEXT:    Align: 0x0000000000001000
-# YAML-NEXT:  - Type:  PT_LOAD
-# YAML-NEXT:    Flags: [ PF_R ]
-# YAML-NEXT:    Sections:
-# YAML-NEXT:      - Section: '.foo (1)'
-# YAML-NEXT:      - Section: .baz
-# YAML-NEXT:    VAddr: 0x0000000000002000
-# YAML-NEXT:    Align: 0x0000000000001000
-# YAML-NEXT:  - Type:  PT_LOAD
-# YAML-NEXT:    Flags: [ PF_W, PF_R ]
-# YAML-NEXT:    Sections:
-# YAML-NEXT:      - Section: .dynamic
-# YAML-NEXT:      - Section: .dynamic.tail
-# YAML-NEXT:    VAddr: 0x0000000000003EF0
-# YAML-NEXT:    Align: 0x0000000000001000
-# YAML-NEXT:  - Type:  PT_DYNAMIC
-# YAML-NEXT:    Flags: [ PF_W, PF_R ]
-# YAML-NEXT:    Sections:
-# YAML-NEXT:      - Section: .dynamic
-# YAML-NEXT:    VAddr: 0x0000000000003EF0
-# YAML-NEXT:    Align: 0x0000000000000008
-# YAML-NEXT:  - Type:  PT_GNU_RELRO
-# YAML-NEXT:    Flags: [ PF_R ]
-# YAML-NEXT:    Sections:
-# YAML-NEXT:      - Section: .dynamic
-# YAML-NEXT:    VAddr: 0x0000000000003EF0
+# YAML-NEXT:  - Type:     PT_LOAD
+# YAML-NEXT:    Flags:    [ PF_R ]
+# YAML-NEXT:    FirstSec: .hash
+# YAML-NEXT:    LastSec:  .dynstr
+# YAML-NEXT:    Align:    0x0000000000001000
+# YAML-NEXT:  - Type:     PT_LOAD
+# YAML-NEXT:    Flags:    [ PF_X, PF_R ]
+# YAML-NEXT:    FirstSec: .foo
+# YAML-NEXT:    LastSec:  .zed
+# YAML-NEXT:    VAddr:    0x0000000000001000
+# YAML-NEXT:    Align:    0x0000000000001000
+# YAML-NEXT:  - Type:     PT_LOAD
+# YAML-NEXT:    Flags:    [ PF_R ]
+# YAML-NEXT:    FirstSec: '.foo (1)'
+# YAML-NEXT:    LastSec:  .baz
+# YAML-NEXT:    VAddr:    0x0000000000002000
+# YAML-NEXT:    Align:    0x0000000000001000
+# YAML-NEXT:  - Type:     PT_LOAD
+# YAML-NEXT:    Flags:    [ PF_W, PF_R ]
+# YAML-NEXT:    FirstSec: .dynamic
+# YAML-NEXT:    LastSec:  .dynamic.tail
+# YAML-NEXT:    VAddr:    0x0000000000003EF0
+# YAML-NEXT:    Align:    0x0000000000001000
+# YAML-NEXT:  - Type:     PT_DYNAMIC
+# YAML-NEXT:    Flags:    [ PF_W, PF_R ]
+# YAML-NEXT:    FirstSec: .dynamic
+# YAML-NEXT:    LastSec:  .dynamic
+# YAML-NEXT:    VAddr:    0x0000000000003EF0
+# YAML-NEXT:    Align:    0x0000000000000008
+# YAML-NEXT:  - Type:     PT_GNU_RELRO
+# YAML-NEXT:    Flags:    [ PF_R ]
+# YAML-NEXT:    FirstSec: .dynamic
+# YAML-NEXT:    LastSec:  .dynamic
+# YAML-NEXT:    VAddr:    0x0000000000003EF0
 # YAML-NEXT:  - Type:  PT_LOAD
 # YAML-NEXT:    Flags: [ PF_R ]
 # YAML-NEXT:    VAddr: 0x0000000000004000
-# YAML-NEXT:  - Type:  PT_LOAD
-# YAML-NEXT:    Flags: [ PF_R ]
-# YAML-NEXT:    Sections:
-# YAML-NEXT:      - Section: .gnu.hash
-# YAML-NEXT:    VAddr: 0x00000000000001A0
-# YAML-NEXT:  - Type:  PT_LOAD
-# YAML-NEXT:    Flags: [ PF_R ]
-# YAML-NEXT:    Sections:
-# YAML-NEXT:      - Section: .gnu.hash
-# YAML-NEXT:    VAddr: 0x00000000000001A0
+# YAML-NEXT:  - Type:     PT_LOAD
+# YAML-NEXT:    Flags:    [ PF_R ]
+# YAML-NEXT:    FirstSec: .gnu.hash
+# YAML-NEXT:    LastSec:  .gnu.hash
+# YAML-NEXT:    VAddr:    0x00000000000001A0
+# YAML-NEXT:  - Type:     PT_LOAD
+# YAML-NEXT:    Flags:    [ PF_R ]
+# YAML-NEXT:    FirstSec: .gnu.hash
+# YAML-NEXT:    LastSec:  .gnu.hash
+# YAML-NEXT:    VAddr:    0x00000000000001A0
 # YAML-NEXT: Sections:
 
 --- !ELF
@@ -101,82 +95,75 @@ ProgramHeaders:
 ## Check we can create a PT_LOAD with arbitrary (we used .hash, .gnu.hash)
 ## and implicit sections (we use .dynsym, .dynstr). It also checks that the
 ## SHT_NULL section at index 0 is not included in the segment.
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .hash
-      - Section: .gnu.hash
-      - Section: .dynsym
-      - Section: .dynstr
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .hash
+    LastSec:  .dynstr
     Align:  0x1000
     Offset: 0x0
 ## Check we can create a PT_LOAD with a 
diff erent set of properties and sections.
-  - Type:  PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .foo
-      - Section: .zed
-    VAddr: 0x1000
-    Align: 0x1000
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    FirstSec: .foo
+    LastSec:  .zed
+    VAddr:    0x1000
+    Align:    0x1000
 ## Create a PT_LOAD to demonstate we are able to refer to output sections with the same name.
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: '.foo (1)'
-      - Section: .baz
-    VAddr: 0x2000
-    Align: 0x1000
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: '.foo (1)'
+    LastSec:  .baz
+    VAddr:    0x2000
+    Align:    0x1000
 ## Show we can create a writeable PT_LOAD segment and put an arbitrary section into it.
 ## Here we test both regular (SHT_PROGBITS) and a special section (SHT_DYNAMIC).
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .dynamic
-      - Section: .dynamic.tail
-    VAddr: 0x3EF0
-    Align: 0x1000
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .dynamic
+    LastSec:  .dynamic.tail
+    VAddr:    0x3EF0
+    Align:    0x1000
 ## Show we can create a nested dynamic segment and put a section into it.
-  - Type:  PT_DYNAMIC
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .dynamic
-    VAddr: 0x3EF0
-    Align: 0x8
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+    VAddr:    0x3EF0
+    Align:    0x8
 ## Show we can create a relro segment and put a section into it.
 ## We used .dynamic here and in tests above to demonstrate that
 ## we can place a section in any number of segments.
 ## Also, we explicitly set the "Align" property to 1 to demonstate
 ## that we do not dump it, because it is the default alignment
 ## value set by yaml2obj.
-  - Type:  PT_GNU_RELRO
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .dynamic
-    VAddr: 0x3EF0
-    Align: 0x1
+  - Type:     PT_GNU_RELRO
+    Flags:    [ PF_R ]
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+    VAddr:    0x3EF0
+    Align:    0x1
 ## Show we can dump a standalone empty segment.
   - Type:  PT_LOAD
     Flags: [ PF_R ]
-    Sections: [ ]
     VAddr: 0x4000
     Align: 0x1
 ## ELF specification says that loadable segment entries in the
 ## program header are sorted by virtual address.
 ## Show we can dump an out of order segment.
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .gnu.hash
-    VAddr: 0x1A0
-    Align: 0x1
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .gnu.hash
+    LastSec:  .gnu.hash
+    VAddr:    0x1A0
+    Align:    0x1
 ## Test we are able to dump duplicated segments.
 ## We use a segment that is the same as the previous one for this.
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .gnu.hash
-    VAddr: 0x1A0
-    Align: 0x1
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .gnu.hash
+    LastSec:  .gnu.hash
+    VAddr:    0x1A0
+    Align:    0x1
 Sections:
   - Name:    .hash
     Type:    SHT_PROGBITS
@@ -240,31 +227,27 @@ DynamicSymbols: []
 # RUN: yaml2obj --docnum=2 %s -o %t2
 # RUN: obj2yaml %t2 | FileCheck %s --check-prefix=EMPTY
 
-# EMPTY:      - Type:  PT_LOAD
-# EMPTY-NEXT:   Flags: [ PF_W, PF_R ]
-# EMPTY-NEXT:   Sections:
-# EMPTY-NEXT:     - Section: .empty.tls.start
-# EMPTY-NEXT:     - Section: .section.1
-# EMPTY-NEXT:     - Section: .empty.tls.middle
-# EMPTY-NEXT:     - Section: .section.2
-# EMPTY-NEXT:     - Section: .empty.tls.end
+# EMPTY:      - Type:     PT_LOAD
+# EMPTY-NEXT:   Flags:    [ PF_W, PF_R ]
+# EMPTY-NEXT:   FirstSec: .empty.tls.start
+# EMPTY-NEXT:   LastSec:  .empty.tls.end
 # EMPTY-NEXT:   VAddr: 0x0000000000001000
 # EMPTY-NEXT:   Align: 0x0000000000001000
-# EMPTY-NEXT: - Type:            PT_TLS
-# EMPTY-NEXT:   Flags:           [ PF_W, PF_R ]
-# EMPTY-NEXT:   Sections:
-# EMPTY-NEXT:     - Section:         .empty.tls.start
-# EMPTY-NEXT:   VAddr:           0x0000000000001000
-# EMPTY-NEXT: - Type:            PT_TLS
-# EMPTY-NEXT:   Flags:           [ PF_W, PF_R ]
-# EMPTY-NEXT:   Sections:
-# EMPTY-NEXT:     - Section:         .empty.tls.middle
-# EMPTY-NEXT:   VAddr:           0x0000000000001100
-# EMPTY-NEXT: - Type:            PT_TLS
-# EMPTY-NEXT:   Flags:           [ PF_W, PF_R ]
-# EMPTY-NEXT:   Sections:
-# EMPTY-NEXT:     - Section:         .empty.tls.end
-# EMPTY-NEXT:   VAddr:           0x0000000000001200
+# EMPTY-NEXT: - Type:     PT_TLS
+# EMPTY-NEXT:   Flags:    [ PF_W, PF_R ]
+# EMPTY-NEXT:   FirstSec: .empty.tls.start
+# EMPTY-NEXT:   LastSec:  .empty.tls.start
+# EMPTY-NEXT:   VAddr:    0x0000000000001000
+# EMPTY-NEXT: - Type:     PT_TLS
+# EMPTY-NEXT:   Flags:    [ PF_W, PF_R ]
+# EMPTY-NEXT:   FirstSec: .empty.tls.middle
+# EMPTY-NEXT:   LastSec:  .empty.tls.middle
+# EMPTY-NEXT:   VAddr:    0x0000000000001100
+# EMPTY-NEXT: - Type:     PT_TLS
+# EMPTY-NEXT:   Flags:    [ PF_W, PF_R ]
+# EMPTY-NEXT:   FirstSec: .empty.tls.end
+# EMPTY-NEXT:   LastSec:  .empty.tls.end
+# EMPTY-NEXT:   VAddr:    0x0000000000001200
 # EMPTY-NEXT: Sections:
 
 --- !ELF
@@ -273,34 +256,30 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_DYN
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .empty.tls.start
-      - Section: .section.1
-      - Section: .empty.tls.middle
-      - Section: .section.2
-      - Section: .empty.tls.end
-    VAddr: 0x1000
-    Align: 0x1000
-  - Type:  PT_TLS
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .empty.tls.start
-    VAddr: 0x1000
-    Align: 0x1
-  - Type:  PT_TLS
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .empty.tls.middle
-    VAddr: 0x1100
-    Align: 0x1
-  - Type:  PT_TLS
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .empty.tls.end
-    VAddr: 0x1200
-    Align: 0x1
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .empty.tls.start
+    LastSec:  .empty.tls.end
+    VAddr:    0x1000
+    Align:    0x1000
+  - Type:     PT_TLS
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .empty.tls.start
+    LastSec:  .empty.tls.start
+    VAddr:    0x1000
+    Align:    0x1
+  - Type:     PT_TLS
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .empty.tls.middle
+    LastSec:  .empty.tls.middle
+    VAddr:    0x1100
+    Align:    0x1
+  - Type:     PT_TLS
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .empty.tls.end
+    LastSec:  .empty.tls.end
+    VAddr:    0x1200
+    Align:    0x1
 Sections:
   - Name:    .empty.tls.start
     Type:    SHT_PROGBITS
@@ -337,12 +316,12 @@ Sections:
 # MISALIGNED-READELF-NEXT: LOAD 0x000077 0x0000000000001000 0x0000000000001000 0x000078 0x000078 R   0x1000
 
 # MISALIGNED-YAML:      ProgramHeaders:
-# MISALIGNED-YAML-NEXT:  - Type:  PT_LOAD
-# MISALIGNED-YAML-NEXT:    Flags: [ PF_R ]
-# MISALIGNED-YAML-NEXT:    Sections:
-# MISALIGNED-YAML-NEXT:     - Section: .foo
-# MISALIGNED-YAML-NEXT:    VAddr: 0x0000000000001000
-# MISALIGNED-YAML-NEXT:    Align: 0x0000000000001000
+# MISALIGNED-YAML-NEXT:  - Type:     PT_LOAD
+# MISALIGNED-YAML-NEXT:    Flags:    [ PF_R ]
+# MISALIGNED-YAML-NEXT:    FirstSec: .foo
+# MISALIGNED-YAML-NEXT:    LastSec:  .foo
+# MISALIGNED-YAML-NEXT:    VAddr:    0x0000000000001000
+# MISALIGNED-YAML-NEXT:    Align:    0x0000000000001000
 # MISALIGNED-YAML-NEXT: Sections:
 
 --- !ELF
@@ -351,13 +330,13 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_DYN
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .foo
-    VAddr:  0x1000
-    Align:  0x1000
-    Offset: 0x000077
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .foo
+    LastSec:  .foo
+    VAddr:    0x1000
+    Align:    0x1000
+    Offset:   0x000077
 Sections:
   - Name:    .foo
     Type:    SHT_PROGBITS
@@ -371,13 +350,22 @@ Sections:
 # RUN: obj2yaml %t4 | FileCheck %s --check-prefix=NON-ALLOC
 
 # NON-ALLOC:      ProgramHeaders:
-# NON-ALLOC-NEXT:   - Type:  PT_LOAD
-# NON-ALLOC-NEXT:     Flags: [ PF_R ]
-# NON-ALLOC-NEXT:     Sections:
-# NON-ALLOC-NEXT:      - Section: .alloc.1
-# NON-ALLOC-NEXT:      - Section: .non-alloc.1
-# NON-ALLOC-NEXT:      - Section: .alloc.2
-# NON-ALLOC-NEXT:     VAddr: 0x0000000000001000
+# NON-ALLOC-NEXT: - Type:     PT_LOAD
+# NON-ALLOC-NEXT:   Flags:    [ PF_R ]
+# NON-ALLOC-NEXT:   FirstSec: .alloc.1
+# NON-ALLOC-NEXT:   LastSec:  .non-alloc.1
+# NON-ALLOC-NEXT: - Type:     PT_LOAD
+# NON-ALLOC-NEXT:   Flags:    [ PF_R ]
+# NON-ALLOC-NEXT:   FirstSec: .alloc.1
+# NON-ALLOC-NEXT:   LastSec:  .non-alloc.1
+# NON-ALLOC-NEXT: - Type:     PT_LOAD
+# NON-ALLOC-NEXT:   Flags:    [ PF_R ]
+# NON-ALLOC-NEXT:   FirstSec: .alloc.2
+# NON-ALLOC-NEXT:   LastSec:  .alloc.2
+# NON-ALLOC-NEXT: - Type:     PT_LOAD
+# NON-ALLOC-NEXT:   Flags:    [ PF_R ]
+# NON-ALLOC-NEXT:   FirstSec: .alloc.1
+# NON-ALLOC-NEXT:   LastSec:  .alloc.2
 # NON-ALLOC-NEXT: Sections:
 
 --- !ELF
@@ -386,12 +374,22 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_DYN
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .alloc.1
-      - Section: .alloc.2
-    VAddr:  0x1000
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .alloc.1
+    LastSec:  .non-alloc.1
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .alloc.1
+    LastSec:  .non-alloc.2
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .non-alloc.2
+    LastSec:  .alloc.2
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .alloc.1
+    LastSec:  .alloc.2
 Sections:
   - Name:    .alloc.1
     Type:    SHT_PROGBITS
@@ -416,31 +414,26 @@ Sections:
 # RUN: obj2yaml %t5 | FileCheck %s --check-prefix=NOBITS
 
 # NOBITS:      ProgramHeaders:
-# NOBITS-NEXT:   - Type:  PT_LOAD
-# NOBITS-NEXT:     Flags: [ PF_W, PF_R ]
-# NOBITS-NEXT:     Sections:
-# NOBITS-NEXT:       - Section: .bss
-# NOBITS-NEXT:   - Type:  PT_LOAD
-# NOBITS-NEXT:     Flags: [ PF_W, PF_R ]
-# NOBITS-NEXT:     Sections:
-# NOBITS-NEXT:       - Section: .data.1
-# NOBITS-NEXT:       - Section: .bss
-# NOBITS-NEXT:   - Type:  PT_LOAD
-# NOBITS-NEXT:     Flags: [ PF_W, PF_R ]
-# NOBITS-NEXT:     Sections:
-# NOBITS-NEXT:       - Section: .data.1
-# NOBITS-NEXT:       - Section: .bss
-# NOBITS-NEXT:       - Section: .data.2
-# NOBITS-NEXT:   - Type:  PT_LOAD
-# NOBITS-NEXT:     Flags: [ PF_W, PF_R ]
-# NOBITS-NEXT:     Sections:
-# NOBITS-NEXT:       - Section: .bss
-# NOBITS-NEXT:       - Section: .data.2
-# NOBITS-NEXT:   - Type:  PT_LOAD
-# NOBITS-NEXT:     Flags: [ PF_W, PF_R ]
-# NOBITS-NEXT:     Sections:
-# NOBITS-NEXT:       - Section: .foo.bss
-# NOBITS-NEXT:       - Section: .bar.bss
+# NOBITS-NEXT:   - Type:     PT_LOAD
+# NOBITS-NEXT:     Flags:    [ PF_W, PF_R ]
+# NOBITS-NEXT:     FirstSec: .bss
+# NOBITS-NEXT:     LastSec:  .bss
+# NOBITS-NEXT:   - Type:     PT_LOAD
+# NOBITS-NEXT:     Flags:    [ PF_W, PF_R ]
+# NOBITS-NEXT:     FirstSec: .data.1
+# NOBITS-NEXT:     LastSec:  .bss
+# NOBITS-NEXT:   - Type:     PT_LOAD
+# NOBITS-NEXT:     Flags:    [ PF_W, PF_R ]
+# NOBITS-NEXT:     FirstSec: .data.1
+# NOBITS-NEXT:     LastSec:  .data.2
+# NOBITS-NEXT:   - Type:     PT_LOAD
+# NOBITS-NEXT:     Flags:    [ PF_W, PF_R ]
+# NOBITS-NEXT:     FirstSec: .bss
+# NOBITS-NEXT:     LastSec:  .data.2
+# NOBITS-NEXT:   - Type:     PT_LOAD
+# NOBITS-NEXT:     Flags:    [ PF_W, PF_R ]
+# NOBITS-NEXT:     FirstSec: .foo.bss
+# NOBITS-NEXT:     LastSec:  .bar.bss
 # NOBITS-NEXT:     VAddr: 0x0000000200000000
 # NOBITS-NEXT: Sections:
 
@@ -451,36 +444,31 @@ FileHeader:
   Type:  ET_EXEC
 ProgramHeaders:
 ## Case 1: the segment contains a single SHT_NOBITS section.
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .bss
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .bss
+    LastSec:  .bss
 ## Case 2: the SHT_NOBITS section is the last section in the segment.
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .data.1
-      - Section: .bss
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .data.1
+    LastSec:  .bss
 ## Case 3: the SHT_NOBITS section is in the middle of the segment.
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .data.1
-      - Section: .bss
-      - Section: .data.2
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .data.1
+    LastSec:  .data.2
 ## Case 4: the SHT_NOBITS section is the first section in the segment.
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .bss
-      - Section: .data.2
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .bss
+    LastSec:  .data.2
 ## Case 5: another two SHT_NOBITS sections in a 
diff erent segment.
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .foo.bss
-      - Section: .bar.bss
-    VAddr: 0x200000000
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .foo.bss
+    LastSec:  .bar.bss
+    VAddr:    0x200000000
 Sections:
   - Name:    .data.1
     Type:    SHT_PROGBITS
@@ -518,7 +506,7 @@ Sections:
 # RUN: not yaml2obj --docnum=6 %s -o %t6 2>&1 | \
 # RUN:   FileCheck %s --check-prefix=UNSORTED --implicit-check-not="error:"
 
-# UNSORTED:      error: sections in the program header with index 1 are not sorted by their file offset
+# UNSORTED:      error: program header with index 0: the section index of .bar is greater than the index of .foo
 # UNSORTED-NEXT: error: sections in the program header with index 3 are not sorted by their file offset
 
 --- !ELF
@@ -529,30 +517,27 @@ FileHeader:
 ProgramHeaders:
 ## Case 1: the .bar section is placed after the .foo section in the file.
 ##         Check we report an error about the violation of the order.
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .bar
-      - Section: .foo
-    VAddr:  0x1000
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .bar
+    LastSec:  .foo
+    VAddr:    0x1000
 ## There is nothing wrong with this segment. We have it to show that
 ## we report correct program header indices in error messages.
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .foo
-      - Section: .bar
-    VAddr:  0x1000
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .foo
+    LastSec:  .bar
+    VAddr:    0x1000
 ## Case 2: the .bar section is placed before the .zed section in the file,
 ##         but the sh_offset of .zed is less than the sh_offset of
 ##         the .bar section because of the "ShOffset" property.
 ##         Document we report an error for such a case.
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .bar
-      - Section: .zed
-    VAddr:  0x1001
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .bar
+    LastSec:  .zed
+    VAddr:    0x1001
 Sections:
   - Name:    .foo
     Type:    SHT_PROGBITS
@@ -591,13 +576,11 @@ Sections:
 # RUN: obj2yaml %t7 | FileCheck %s --check-prefix=ZERO-SIZE
 
 # ZERO-SIZE:      ProgramHeaders:
-# ZERO-SIZE-NEXT:   - Type:  PT_LOAD
-# ZERO-SIZE-NEXT:     Flags: [ PF_W, PF_R ]
-# ZERO-SIZE-NEXT:     Sections:
-# ZERO-SIZE-NEXT:       - Section: .empty.bar1
-# ZERO-SIZE-NEXT:       - Section: .bar
-# ZERO-SIZE-NEXT:       - Section: .empty.bar2
-# ZERO-SIZE-NEXT:     VAddr: 0x0000000000002000
+# ZERO-SIZE-NEXT:   - Type:     PT_LOAD
+# ZERO-SIZE-NEXT:     Flags:    [ PF_W, PF_R ]
+# ZERO-SIZE-NEXT:     FirstSec: .empty.bar1
+# ZERO-SIZE-NEXT:     LastSec:  .empty.bar2
+# ZERO-SIZE-NEXT:     VAddr:    0x0000000000002000
 # ZERO-SIZE-NEXT: Sections:
 
 --- !ELF
@@ -606,11 +589,11 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_EXEC
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    Sections:
-      - Section: .bar
-    VAddr: 0x2000
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    FirstSec: .bar
+    LastSec:  .bar
+    VAddr:    0x2000
 Sections:
   - Name:    .empty.foo
     Type:    SHT_PROGBITS
@@ -642,11 +625,11 @@ Sections:
 # RUN: obj2yaml %t8 | FileCheck %s --check-prefix=BROKEN-VA
 
 # BROKEN-VA:      ProgramHeaders:
-# BROKEN-VA-NEXT:  - Type:  PT_LOAD
-# BROKEN-VA-NEXT:    Flags: [ PF_W, PF_R ]
-# BROKEN-VA-NEXT:    Sections:
-# BROKEN-VA-NEXT:      - Section: .empty_middle
-# BROKEN-VA-NEXT:    VAddr: 0x0000000000001000
+# BROKEN-VA-NEXT:  - Type:     PT_LOAD
+# BROKEN-VA-NEXT:    Flags:    [ PF_W, PF_R ]
+# BROKEN-VA-NEXT:    FirstSec: .empty_middle
+# BROKEN-VA-NEXT:    LastSec:  .empty_middle
+# BROKEN-VA-NEXT:    VAddr:    0x0000000000001000
 
 --- !ELF
 FileHeader:
@@ -654,13 +637,11 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_EXEC
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_W, PF_R ]
-    VAddr: 0x1000
-    Sections:
-      - Section: .empty_begin
-      - Section: .empty_middle
-      - Section: .empty_end
+  - Type:     PT_LOAD
+    Flags:    [ PF_W, PF_R ]
+    VAddr:    0x1000
+    FirstSec: .empty_begin
+    LastSec:  .empty_end
 Sections:
   - Name:    .empty_begin
     Type:    SHT_PROGBITS

diff  --git a/llvm/test/tools/yaml2obj/ELF/custom-fill.yaml b/llvm/test/tools/yaml2obj/ELF/custom-fill.yaml
index 064f817d1ac1..d770fdb98253 100644
--- a/llvm/test/tools/yaml2obj/ELF/custom-fill.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/custom-fill.yaml
@@ -119,16 +119,14 @@ Sections:
     Pattern: ""
     Size:    0x45
 ProgramHeaders:
-  - Type:  PT_LOAD
-    VAddr: 0x100
-    Sections:
-      - Section: fill1
-      - Section: .bar
-      - Section: fill2
-  - Type:  PT_GNU_RELRO
-    VAddr: 0x105
-    Sections:
-      - Section: fill2
+  - Type:     PT_LOAD
+    VAddr:    0x100
+    FirstSec: fill1
+    LastSec:  fill2
+  - Type:     PT_GNU_RELRO
+    VAddr:    0x105
+    FirstSec: fill2
+    LastSec:  fill2
 
 ## Check that the "Pattern" field is not mandatory.
 # RUN: yaml2obj --docnum=4 2>&1 -o %t4 %s
@@ -269,7 +267,8 @@ Sections:
 ## an unknown section or fill and have at least one Fill defined.
 
 # RUN: not yaml2obj --docnum=10 2>&1 %s | FileCheck %s --check-prefix=UNKNOWN-ERR
-# UNKNOWN-ERR: error: unknown section or fill referenced: 'fill' by program header
+# UNKNOWN-ERR: error: unknown section or fill referenced: 'fill' by the 'FirstSec' key of the program header with index 0
+# UNKNOWN-ERR: error: unknown section or fill referenced: 'fill' by the 'LastSec' key of the program header with index 0
 
 --- !ELF
 FileHeader:
@@ -281,9 +280,9 @@ Sections:
     Pattern: ""
     Size:    0
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: fill
+  - Type:     PT_LOAD
+    FirstSec: fill
+    LastSec:  fill
 
 ## Show that we can use the "Offset" key to set an arbitrary offset for a Fill.
 

diff  --git a/llvm/test/tools/yaml2obj/ELF/dynamic-section-i386.yaml b/llvm/test/tools/yaml2obj/ELF/dynamic-section-i386.yaml
index 38609d4c01d8..f6bec2398a4d 100644
--- a/llvm/test/tools/yaml2obj/ELF/dynamic-section-i386.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/dynamic-section-i386.yaml
@@ -27,14 +27,14 @@ Sections:
       - Tag:             DT_NULL
         Value:           0x0000000000000000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0x0000
-    Align: 8
-    Sections:
-      - Section: .dynamic
-  - Type: PT_DYNAMIC
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0x0008
-    Sections:
-      - Section: .dynamic
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x0000
+    Align:    8
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+  - Type:     PT_DYNAMIC
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x0008
+    FirstSec: .dynamic
+    LastSec:  .dynamic

diff  --git a/llvm/test/tools/yaml2obj/ELF/header-sh-fields.yaml b/llvm/test/tools/yaml2obj/ELF/header-sh-fields.yaml
index 9c95d771300d..03df36b96fdb 100644
--- a/llvm/test/tools/yaml2obj/ELF/header-sh-fields.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/header-sh-fields.yaml
@@ -20,10 +20,8 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_REL
 ProgramHeaders:
-  - Type:     PT_LOAD
-    Sections: []
-  - Type:     PT_LOAD
-    Sections: []
+  - Type: PT_LOAD
+  - Type: PT_LOAD
 
 ## Check we can override all default values using the same values
 ## and that this does not change the output.
@@ -43,10 +41,8 @@ FileHeader:
   EPhEntSize: [[PHENTSIZE=56]]
   EPhNum:     [[PHNUM=2]]
 ProgramHeaders:
-  - Type:     PT_LOAD
-    Sections: []
-  - Type:     PT_LOAD
-    Sections: []
+  - Type: PT_LOAD
+  - Type: PT_LOAD
 
 ## Override 
diff erent fields to check the output produced.
 

diff  --git a/llvm/test/tools/yaml2obj/ELF/program-header-address.yaml b/llvm/test/tools/yaml2obj/ELF/program-header-address.yaml
index 83832bd94444..a43253f7095b 100644
--- a/llvm/test/tools/yaml2obj/ELF/program-header-address.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/program-header-address.yaml
@@ -28,28 +28,27 @@ Sections:
 ProgramHeaders:
 ## Show what virtual and physical address we set by default for the case where
 ## a program header has no sections.
-  - Type:     PT_LOAD
-    Flags:    [ PF_X, PF_R ]
-    Sections: []
+  - Type:  PT_LOAD
+    Flags: [ PF_X, PF_R ]
 ## Show what virtual and physical address we set by default for the case
 ## where a program header includes a section with a virtual address that
 ## is explicitly set.
   - Type:     PT_LOAD
     Flags:    [ PF_X, PF_R ]
-    Sections:
-      - Section: .foo
+    FirstSec: .foo
+    LastSec:  .foo
 ## Now we have a program header that has a virtual address 
diff erent to
 ## the address of the section included. Show that the default physical address
 ## is equal to the program header's virtual address.
-  - Type:  PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0xAAAA1000
-    Sections:
-      - Section: .foo
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0xAAAA1000
+    FirstSec: .foo
+    LastSec:  .foo
 ## Show that we are able to set 
diff erent virtual and physical addresses.
-  - Type:  PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0xAAAA1000
-    PAddr: 0xBBBB2000
-    Sections:
-      - Section: .foo
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0xAAAA1000
+    PAddr:    0xBBBB2000
+    FirstSec: .foo
+    LastSec:  .foo

diff  --git a/llvm/test/tools/yaml2obj/ELF/program-header-align.yaml b/llvm/test/tools/yaml2obj/ELF/program-header-align.yaml
index c23a5a5e4ad5..d405eb1b6dc9 100644
--- a/llvm/test/tools/yaml2obj/ELF/program-header-align.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/program-header-align.yaml
@@ -25,9 +25,8 @@ Sections:
 ProgramHeaders:
   - Type:  PT_TLS
     Align: 16
-    Sections:
-      - Section: .tdata
-      - Section: .tbss
+    FirstSec: .tdata
+    LastSec:  .tbss
 
 ## If Align is not specified, p_align is inferred from the maximum alignment
 ## of contained sections.
@@ -48,7 +47,6 @@ Sections:
     Type:         SHT_PROGBITS
     AddressAlign: 16
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .text
-      - Section: .text.hot
+  - Type:     PT_LOAD
+    FirstSec: .text
+    LastSec:  .text.hot

diff  --git a/llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml b/llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
index a06922ce7c7e..6c77cdd17bfd 100644
--- a/llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
@@ -86,16 +86,14 @@ ProgramHeaders:
 ## We have 2 segments, the first is predefined and the second can be customized.
 ## We want to have more than one segment to show we check all of them when
 ## trying to find a non-nobits section after a nobits one.
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .data.before
-      - Section: .nobits.1
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: [[SEC1]]
-      - Section: [[SEC2]]
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .data.before
+    LastSec:  .nobits.1
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: [[SEC1]]
+    LastSec:  [[SEC2]]
 
 ## Case D. We have a segment with SHT_NOBITS sections on its borders and one
 ##         non-nobits in the middle. Check we allocate the file space only for
@@ -132,9 +130,7 @@ Sections:
     Flags: [ SHF_ALLOC ]
     Size:  0x100
 ProgramHeaders:
-  - Type:  PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .nobits.1
-      - Section: .data
-      - Section: .nobits.2
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    FirstSec: .nobits.1
+    LastSec:  .nobits.2

diff  --git a/llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml b/llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml
index 2441aafb25a7..add260d5972e 100644
--- a/llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml
@@ -73,25 +73,25 @@ ProgramHeaders:
   # Program header with only file size set.
   - Type:     0x6abcdef0
     FileSize: 6
-    Sections:
-      - Section: .rodata
+    FirstSec: .rodata
+    LastSec:  .rodata
   # Program header with only mem size set.
   - Type:     0x6abcdef0
-    MemSize: 6
-    Sections:
-      - Section: .rodata
+    MemSize:  6
+    FirstSec: .rodata
+    LastSec:  .rodata
   # Program header with only offset set.
   - Type:     0x6abcdef0
     Offset:   0x1fff
-    Sections:
-      - Section: .rodata
+    FirstSec: .rodata
+    LastSec:  .rodata
   # Program header with sections, valid properties.
   - Type:     0x6abcdef0
     Offset:   0xffe
     FileSize: 7
     MemSize:  9
-    Sections:
-      - Section: .text
+    FirstSec: .text
+    LastSec:  .text
   # Program header with invalid properties.
   - Type:     0x6abcdef0
     Offset:   0x3000
@@ -100,10 +100,8 @@ ProgramHeaders:
   # Program header with 2 SHT_NOBITS sections.
   - Type:     0x6abcdef0
     Offset:   0x2004
-    Sections:
-      - Section: .data
-      - Section: .nobits1
-      - Section: .nobits2
+    FirstSec: .data
+    LastSec:  .nobits2
 
 ## Test the "Offset" property.
 
@@ -137,13 +135,12 @@ Sections:
     Flags: [ SHF_ALLOC ]
     Size:  0x1
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .foo
-      - Section: .bar
-  - Type: PT_LOAD
-    Sections:
-      - Section: .bar
+  - Type:     PT_LOAD
+    FirstSec: .foo
+    LastSec:  .bar
+  - Type:     PT_LOAD
+    FirstSec: .bar
+    LastSec:  .bar
 
 ## Check we can set the "Offset" value explicitly to be less than or equal to
 ## the offset of a section in the segment.
@@ -172,10 +169,10 @@ Sections:
     Flags: [ SHF_ALLOC ]
     Size:  0x1
 ProgramHeaders:
-  - Type: PT_LOAD
-    Offset: [[OFFSET]]
-    Sections:
-      - Section: .foo
+  - Type:    PT_LOAD
+    Offset:  [[OFFSET]]
+    FirstSec: .foo
+    LastSec:  .foo
 
 ## Check we report an error when the "Offset" value is larger than the offset of a section in the segment.
 # RUN: not yaml2obj --docnum=3 -DOFFSET=0x79 %s -o /dev/null 2>&1 | \
@@ -207,7 +204,7 @@ Sections:
 ##       0xFFFFFF00, but no error is reported.
     ShOffset: 0xFFFFFFFF
 ProgramHeaders:
-  - Type:   PT_LOAD
-    Offset: 0xFFFFFF00
-    Sections:
-      - Section: .foo
+  - Type:     PT_LOAD
+    Offset:   0xFFFFFF00
+    FirstSec: .foo
+    LastSec:  .foo

diff  --git a/llvm/test/tools/yaml2obj/ELF/program-header.yaml b/llvm/test/tools/yaml2obj/ELF/program-header.yaml
index 39d721cf066b..4899102346af 100644
--- a/llvm/test/tools/yaml2obj/ELF/program-header.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/program-header.yaml
@@ -23,19 +23,18 @@ Sections:
     Content:         "00000000"
     AddressAlign:    0x0000000000001000
 ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    VAddr: 0xAAAA1000
-    PAddr: 0xFFFF1000
-    Sections:
-      - Section: .text
-      - Section: .init
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    VAddr: 0xAAAA2000
-    PAddr: 0xFFFF2000
-    Sections:
-      - Section: .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0xAAAA1000
+    PAddr:    0xFFFF1000
+    FirstSec: .text
+    LastSec:  .init
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0xAAAA2000
+    PAddr:    0xFFFF2000
+    FirstSec: .data
+    LastSec:  .data
   - Type: PT_GNU_EH_FRAME
   - Type: PT_GNU_STACK
   - Type: PT_GNU_RELRO
@@ -82,18 +81,92 @@ ProgramHeaders:
 #CHECK-NEXT:]
 
 ## Check we do not allow referencing sections that do not exist.
-# RUN: not yaml2obj --docnum=2 %s -o %t 2>&1 | FileCheck %s --check-prefix=ERR
+# RUN: not yaml2obj -DFIRST=".unknown1" -DLAST=".unknown2" --docnum=2 %s 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=UNKNOWN-ERR
 
-# ERR: error: unknown section or fill referenced: '.foo' by program header
-# ERR: error: unknown section or fill referenced: '.bar' by program header
+# UNKNOWN-ERR: error: unknown section or fill referenced: '.unknown1' by the 'FirstSec' key of the program header with index 0
+# UNKNOWN-ERR: error: unknown section or fill referenced: '.unknown2' by the 'LastSec' key of the program header with index 0
 
 --- !ELF
 FileHeader:
   Class: ELFCLASS64
   Data:  ELFDATA2LSB
   Type:  ET_EXEC
+Sections:
+  - Name:   .foo
+    Type:   SHT_PROGBITS
+    Offset: 0x100
+    Size:   0x10
+  - Name:   .bar
+    Type:   SHT_PROGBITS
+    Offset: 0x200
+    Size:   0x20
+  - Name:   .zed
+    Type:   SHT_PROGBITS
+    Offset: 0x300
+    Size:   0x30
+  - Name:   .fill1
+    Type:   Fill
+    Offset: 0x400
+    Size:   0x40
+  - Name:   .fill2
+    Type:   Fill
+    Offset: 0x500
+    Size:   0x50
 ProgramHeaders:
-  - Type: PT_LOAD
-    Sections:
-      - Section: .foo
-      - Section: .bar
+  - Type:     PT_LOAD
+    FirstSec: [[FIRST=<none>]]
+    LastSec:  [[LAST=<none>]]
+
+## Check we report an error when the index of the section specified by the "FirstSec" key
+## is greater than the index of the section specified by the "LastSec" key.
+
+# RUN: not yaml2obj -DFIRST=".bar" -DLAST=".foo" --docnum=2 %s 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ORDER-ERR
+
+# ORDER-ERR: error: program header with index 0: the section index of .bar is greater than the index of .foo
+
+## Check that we can't use the "LastSec" key without the "FirstSec" key.
+
+# RUN: not yaml2obj -DLAST=".foo" --docnum=2 %s 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ONLY-LAST-ERR
+
+# ONLY-LAST-ERR: error: the "LastSec" key can't be used without the "FirstSec" key
+
+## Check that we can't use the "FirstSec" key without the "LastSec" key.
+
+# RUN: not yaml2obj -DFIRST=".foo" --docnum=2 %s 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ONLY-FIRST-ERR
+
+# ONLY-FIRST-ERR: error: the "FirstSec" key can't be used without the "LastSec" key
+
+## Check we create an empty segment when neither "FirstSec" nor "LastSec" are specified.
+
+# RUN: yaml2obj --docnum=2 %s -o %t3
+# RUN: llvm-readelf --program-headers %t3 | FileCheck %s --check-prefix=EMPTY-SEGMENT
+
+# EMPTY-SEGMENT:       Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
+# EMPTY-SEGMENT:       LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000
+# EMPTY-SEGMENT-EMPTY:
+
+## Check that we include all sections between FirstSec and LastSec in the segment when both keys are used.
+
+# RUN: yaml2obj --docnum=2 -DFIRST=".foo" -DLAST=".zed" %s -o %t4
+# RUN: llvm-readelf --program-headers %t4 | FileCheck %s --check-prefix=BOTH
+
+# BOTH:      Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
+# BOTH-NEXT: LOAD 0x000100 0x0000000000000000 0x0000000000000000 0x000230 0x000230
+
+## Check that we include fills that are between FirstSec and LastSec in the segment when both keys are used.
+
+# RUN: yaml2obj --docnum=2 -DFIRST=".foo" -DLAST=".fill1" %s -o %t5a
+# RUN: llvm-readelf --program-headers %t5a | FileCheck %s --check-prefix=FILL1
+
+# FILL1: Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
+# FILL1: LOAD 0x000100 0x0000000000000000 0x0000000000000000 0x000340 0x000340
+
+# RUN: yaml2obj --docnum=2 -DFIRST=".foo" -DLAST=".fill2" %s -o %t5b
+# RUN: llvm-readelf --program-headers %t5b | FileCheck %s --check-prefix=FILL2
+
+# FILL2: Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
+# FILL2: LOAD 0x000100 0x0000000000000000 0x0000000000000000 0x000450 0x000450

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index ba1bacd6b7a0..4f5ff19806ff 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -393,8 +393,11 @@ ELFDumper<ELFT>::dumpProgramHeaders(
     // obj2yaml does not create Fill chunks.
     for (const std::unique_ptr<ELFYAML::Chunk> &C : Chunks) {
       ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
-      if (isInSegment<ELFT>(S, Sections[S.OriginalSecNdx], Phdr))
-        PH.Sections.push_back({S.Name});
+      if (isInSegment<ELFT>(S, Sections[S.OriginalSecNdx], Phdr)) {
+        if (!PH.FirstSec)
+          PH.FirstSec = S.Name;
+        PH.LastSec = S.Name;
+      }
     }
 
     Ret.push_back(PH);


        


More information about the llvm-commits mailing list