Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -100,10 +100,6 @@ Optional NoHeaders; }; -struct SectionName { - StringRef Section; -}; - struct Symbol { StringRef Name; ELF_STT Type; @@ -602,9 +598,10 @@ Optional FileSize; Optional MemSize; Optional Offset; + Optional FirstSec; + Optional LastSec; - std::vector Sections; - // This vector is parallel to Sections and contains corresponding chunks. + // This vector contains all chunks from [FirstSec, LastSec]. std::vector Chunks; }; @@ -653,7 +650,6 @@ 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 { @@ -789,6 +785,7 @@ template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::ProgramHeader &FileHdr); + static std::string validate(IO &IO, ELFYAML::ProgramHeader &FileHdr); }; template <> @@ -855,10 +852,6 @@ static void mapping(IO &IO, ELFYAML::SectionOrType §ionOrType); }; -template <> struct MappingTraits { - static void mapping(IO &IO, ELFYAML::SectionName §ionName); -}; - } // end namespace yaml } // end namespace llvm Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -464,12 +464,16 @@ template void ELFState::initProgramHeaders(std::vector &PHeaders) { DenseMap NameToFill; - for (const std::unique_ptr &D : Doc.Chunks) - if (auto S = dyn_cast(D.get())) + DenseMap NameToIndex; + for (size_t I = 0, E = Doc.Chunks.size(); I != E; ++I) { + if (auto S = dyn_cast(Doc.Chunks[I].get())) NameToFill[S->Name] = S; + NameToIndex[Doc.Chunks[I]->Name] = I + 1; + } std::vector 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; @@ -478,22 +482,28 @@ 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) + continue; - unsigned Index; - if (SN2I.lookup(SecName.Section, Index)) { - YamlPhdr.Chunks.push_back(Sections[Index]); - continue; - } + 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 = YamlPhdr.LastSec ? NameToIndex[*YamlPhdr.LastSec] : First; + if (!Last && YamlPhdr.LastSec) + reportError("unknown section or fill referenced: '" + *YamlPhdr.LastSec + + "' by the 'LastSec' key of the program header with index " + + Twine(I)); + if (First && Last && First > Last) + reportError("program header with index " + Twine(I) + + ": the section index of " + *YamlPhdr.FirstSec + + " is greater than the index of " + *YamlPhdr.LastSec); + if (HasError) + continue; - reportError("unknown section or fill referenced: '" + SecName.Section + - "' by program header"); - } + for (size_t I = First; I <= Last; ++I) + YamlPhdr.Chunks.push_back(Doc.Chunks[I - 1].get()); } } Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -901,7 +901,8 @@ 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); @@ -910,6 +911,13 @@ IO.mapOptional("Offset", Phdr.Offset); } +std::string MappingTraits::validate( + IO &IO, ELFYAML::ProgramHeader &FileHdr) { + if (!FileHdr.FirstSec && FileHdr.LastSec) + return "the \"LastSec\" can't be used without the \"LastSec\" key"; + return ""; +} + LLVM_YAML_STRONG_TYPEDEF(StringRef, StOtherPiece) template <> struct ScalarTraits { @@ -1251,11 +1259,6 @@ IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType); } -void MappingTraits::mapping( - IO &IO, ELFYAML::SectionName §ionName) { - IO.mapRequired("Section", sectionName.Section); -} - static void sectionMapping(IO &IO, ELFYAML::ARMIndexTableSection &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Entries", Section.Entries); Index: llvm/test/tools/obj2yaml/ELF/program-headers.yaml =================================================================== --- llvm/test/tools/obj2yaml/ELF/program-headers.yaml +++ llvm/test/tools/obj2yaml/ELF/program-headers.yaml @@ -37,59 +37,49 @@ # 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: VAddr: 0x0000000000003EF0 +# YAML-NEXT: Align: 0x0000000000000008 +# YAML-NEXT: - Type: PT_GNU_RELRO +# YAML-NEXT: Flags: [ PF_R ] +# YAML-NEXT: FirstSec: .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: VAddr: 0x00000000000001A0 +# YAML-NEXT: - Type: PT_LOAD +# YAML-NEXT: Flags: [ PF_R ] +# YAML-NEXT: FirstSec: .gnu.hash +# YAML-NEXT: VAddr: 0x00000000000001A0 # YAML-NEXT: Sections: --- !ELF @@ -101,82 +91,71 @@ ## 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 different 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 + 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 + 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 + 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 + VAddr: 0x1A0 + Align: 0x1 Sections: - Name: .hash Type: SHT_PROGBITS @@ -240,31 +219,24 @@ # 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: VAddr: 0x0000000000001000 +# EMPTY-NEXT: - Type: PT_TLS +# EMPTY-NEXT: Flags: [ PF_W, PF_R ] +# EMPTY-NEXT: FirstSec: .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: VAddr: 0x0000000000001200 # EMPTY-NEXT: Sections: --- !ELF @@ -273,34 +245,27 @@ 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 + VAddr: 0x1000 + Align: 0x1 + - Type: PT_TLS + Flags: [ PF_W, PF_R ] + FirstSec: .empty.tls.middle + VAddr: 0x1100 + Align: 0x1 + - Type: PT_TLS + Flags: [ PF_W, PF_R ] + FirstSec: .empty.tls.end + VAddr: 0x1200 + Align: 0x1 Sections: - Name: .empty.tls.start Type: SHT_PROGBITS @@ -337,12 +302,11 @@ # 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: VAddr: 0x0000000000001000 +# MISALIGNED-YAML-NEXT: Align: 0x0000000000001000 # MISALIGNED-YAML-NEXT: Sections: --- !ELF @@ -351,13 +315,12 @@ 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 + VAddr: 0x1000 + Align: 0x1000 + Offset: 0x000077 Sections: - Name: .foo Type: SHT_PROGBITS @@ -371,13 +334,11 @@ # 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: .alloc.2 +# NON-ALLOC-NEXT: VAddr: 0x0000000000001000 # NON-ALLOC-NEXT: Sections: --- !ELF @@ -386,12 +347,11 @@ 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: .alloc.2 + VAddr: 0x1000 Sections: - Name: .alloc.1 Type: SHT_PROGBITS @@ -416,31 +376,25 @@ # 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: - 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 +405,30 @@ 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 ## 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 different 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 +466,7 @@ # 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 +477,27 @@ 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 +536,11 @@ # 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 +549,10 @@ 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 + VAddr: 0x2000 Sections: - Name: .empty.foo Type: SHT_PROGBITS @@ -642,11 +584,10 @@ # 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: VAddr: 0x0000000000001000 --- !ELF FileHeader: @@ -654,13 +595,11 @@ 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 Index: llvm/test/tools/yaml2obj/ELF/custom-fill.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/custom-fill.yaml +++ llvm/test/tools/yaml2obj/ELF/custom-fill.yaml @@ -119,16 +119,13 @@ 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 ## Check that the "Pattern" field is not mandatory. # RUN: yaml2obj --docnum=4 2>&1 -o %t4 %s @@ -269,7 +266,7 @@ ## 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 --- !ELF FileHeader: @@ -281,9 +278,8 @@ Pattern: "" Size: 0 ProgramHeaders: - - Type: PT_LOAD - Sections: - - Section: fill + - Type: PT_LOAD + FirstSec: fill ## Show that we can use the "Offset" key to set an arbitrary offset for a Fill. Index: llvm/test/tools/yaml2obj/ELF/dynamic-section-i386.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/dynamic-section-i386.yaml +++ llvm/test/tools/yaml2obj/ELF/dynamic-section-i386.yaml @@ -27,14 +27,12 @@ - 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 + - Type: PT_DYNAMIC + Flags: [ PF_X, PF_R ] + VAddr: 0x0008 + FirstSec: .dynamic Index: llvm/test/tools/yaml2obj/ELF/header-sh-fields.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/header-sh-fields.yaml +++ llvm/test/tools/yaml2obj/ELF/header-sh-fields.yaml @@ -20,10 +20,8 @@ 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 @@ EPhEntSize: [[PHENTSIZE=56]] EPhNum: [[PHNUM=2]] ProgramHeaders: - - Type: PT_LOAD - Sections: [] - - Type: PT_LOAD - Sections: [] + - Type: PT_LOAD + - Type: PT_LOAD ## Override different fields to check the output produced. Index: llvm/test/tools/yaml2obj/ELF/program-header-address.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/program-header-address.yaml +++ llvm/test/tools/yaml2obj/ELF/program-header-address.yaml @@ -28,28 +28,24 @@ 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 ## Now we have a program header that has a virtual address different 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 ## Show that we are able to set different 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 Index: llvm/test/tools/yaml2obj/ELF/program-header-align.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/program-header-align.yaml +++ llvm/test/tools/yaml2obj/ELF/program-header-align.yaml @@ -25,9 +25,8 @@ 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 @@ Type: SHT_PROGBITS AddressAlign: 16 ProgramHeaders: - - Type: PT_LOAD - Sections: - - Section: .text - - Section: .text.hot + - Type: PT_LOAD + FirstSec: .text + LastSec: .text.hot Index: llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml +++ llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml @@ -86,16 +86,14 @@ ## 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 @@ 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 Index: llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml +++ llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml @@ -73,25 +73,21 @@ # Program header with only file size set. - Type: 0x6abcdef0 FileSize: 6 - Sections: - - Section: .rodata + FirstSec: .rodata # Program header with only mem size set. - Type: 0x6abcdef0 - MemSize: 6 - Sections: - - Section: .rodata + MemSize: 6 + FirstSec: .rodata # Program header with only offset set. - Type: 0x6abcdef0 Offset: 0x1fff - Sections: - - Section: .rodata + FirstSec: .rodata # Program header with sections, valid properties. - Type: 0x6abcdef0 Offset: 0xffe FileSize: 7 MemSize: 9 - Sections: - - Section: .text + FirstSec: .text # Program header with invalid properties. - Type: 0x6abcdef0 Offset: 0x3000 @@ -100,10 +96,8 @@ # 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 +131,11 @@ 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 ## 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 +164,9 @@ Flags: [ SHF_ALLOC ] Size: 0x1 ProgramHeaders: - - Type: PT_LOAD - Offset: [[OFFSET]] - Sections: - - Section: .foo + - Type: PT_LOAD + Offset: [[OFFSET]] + FirstSec: .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 +198,6 @@ ## 0xFFFFFF00, but no error is reported. ShOffset: 0xFFFFFFFF ProgramHeaders: - - Type: PT_LOAD - Offset: 0xFFFFFF00 - Sections: - - Section: .foo + - Type: PT_LOAD + Offset: 0xFFFFFF00 + FirstSec: .foo Index: llvm/test/tools/yaml2obj/ELF/program-header.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/program-header.yaml +++ llvm/test/tools/yaml2obj/ELF/program-header.yaml @@ -23,19 +23,17 @@ 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 - Type: PT_GNU_EH_FRAME - Type: PT_GNU_STACK - Type: PT_GNU_RELRO @@ -84,8 +82,8 @@ ## 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 -# ERR: error: unknown section or fill referenced: '.foo' by program header -# ERR: error: unknown section or fill referenced: '.bar' by program header +# ERR: error: unknown section or fill referenced: '.foo' by the 'FirstSec' key of the program header with index 0 +# ERR: error: unknown section or fill referenced: '.bar' by the 'LastSec' key of the program header with index 0 --- !ELF FileHeader: @@ -93,7 +91,6 @@ Data: ELFDATA2LSB Type: ET_EXEC ProgramHeaders: - - Type: PT_LOAD - Sections: - - Section: .foo - - Section: .bar + - Type: PT_LOAD + FirstSec: .foo + LastSec: .bar Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -392,8 +392,12 @@ // obj2yaml does not create Fill chunks. for (const std::unique_ptr &C : Chunks) { ELFYAML::Section &S = cast(*C.get()); - if (isInSegment(S, Sections[S.OriginalSecNdx], Phdr)) - PH.Sections.push_back({S.Name}); + if (isInSegment(S, Sections[S.OriginalSecNdx], Phdr)) { + if (!PH.FirstSec) + PH.FirstSec = S.Name; + if (S.Name != *PH.FirstSec) + PH.LastSec = S.Name; + } } Ret.push_back(PH);