diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -128,12 +128,6 @@ StringRef Name; }; -struct SectionHeaderTable { - Optional> Sections; - Optional> Excluded; - Optional NoHeaders; -}; - struct Symbol { StringRef Name; ELF_STT Type; @@ -196,18 +190,26 @@ ARMIndexTable, MipsABIFlags, Addrsig, - Fill, LinkerOptions, DependentLibraries, CallGraphProfile, - BBAddrMap + BBAddrMap, + + // Special chunks. + SpecialChunksStart, + Fill = SpecialChunksStart, + SectionHeaderTable, }; ChunkKind Kind; StringRef Name; Optional Offset; - Chunk(ChunkKind K) : Kind(K) {} + // Usually chunks are not created implicitly, but rather loaded from YAML. + // This flag is used to signal whether this is the case or not. + bool IsImplicit; + + Chunk(ChunkKind K, bool Implicit) : Kind(K), IsImplicit(Implicit) {} virtual ~Chunk(); }; @@ -222,17 +224,14 @@ Optional Content; Optional Size; - // Usually sections are not created implicitly, but loaded from YAML. - // When they are, this flag is used to signal about that. - bool IsImplicit; - // Holds the original section index. unsigned OriginalSecNdx; - Section(ChunkKind Kind, bool IsImplicit = false) - : Chunk(Kind), IsImplicit(IsImplicit) {} + Section(ChunkKind Kind, bool IsImplicit = false) : Chunk(Kind, IsImplicit) {} - static bool classof(const Chunk *S) { return S->Kind != ChunkKind::Fill; } + static bool classof(const Chunk *S) { + return S->Kind < ChunkKind::SpecialChunksStart; + } // Some derived sections might have their own special entries. This method // returns a vector of pairs. It is used for section @@ -276,11 +275,34 @@ Optional Pattern; llvm::yaml::Hex64 Size; - Fill() : Chunk(ChunkKind::Fill) {} + Fill() : Chunk(ChunkKind::Fill, /*Implicit=*/false) {} static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Fill; } }; +struct SectionHeaderTable : Chunk { + SectionHeaderTable(bool IsImplicit) + : Chunk(ChunkKind::SectionHeaderTable, IsImplicit) {} + + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::SectionHeaderTable; + } + + Optional> Sections; + Optional> Excluded; + Optional NoHeaders; + + size_t getNumHeaders(size_t SectionsNum) const { + if (IsImplicit) + return SectionsNum; + if (NoHeaders) + return (*NoHeaders) ? 0 : SectionsNum; + return (Sections ? Sections->size() : 0) + /*Null section*/ 1; + } + + static constexpr StringRef TypeStr = "SectionHeaderTable"; +}; + struct BBAddrMapSection : Section { Optional> Entries; @@ -665,7 +687,6 @@ struct Object { FileHeader Header; - Optional SectionHeaders; std::vector ProgramHeaders; // An object might contain output section descriptions as well as @@ -688,6 +709,13 @@ return Ret; } + const SectionHeaderTable &getSectionHeaderTable() const { + for (const std::unique_ptr &C : Chunks) + if (auto *S = dyn_cast(C.get())) + return *S; + llvm_unreachable("the section header table chunk must always be present"); + } + unsigned getMachine() const; }; @@ -837,11 +865,6 @@ static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr); }; -template <> struct MappingTraits { - static void mapping(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable); - static std::string validate(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable); -}; - template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::SectionHeader &SHdr); }; diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -124,6 +124,11 @@ if (checkLimit(sizeof(T))) support::endian::write(OS, Val, E); } + + void updateDataAt(uint64_t Pos, void *Data, size_t Size) { + assert(Pos >= InitialOffset && Pos + Size <= getOffset()); + memcpy(&Buf[Pos - InitialOffset], Data, Size); + } }; // Used to keep track of section and symbol names, so that in the YAML file @@ -224,7 +229,7 @@ ArrayRef SHeaders); void finalizeStrings(); - void writeELFHeader(raw_ostream &OS, Optional SHOff); + void writeELFHeader(raw_ostream &OS); void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::NoBitsSection &Section, ContiguousBlobAccumulator &CBA); @@ -330,12 +335,22 @@ std::make_unique( ELFYAML::Chunk::ChunkKind::RawContent, /*IsImplicit=*/true)); - // We add a technical suffix for each unnamed section/fill. It does not affect - // the output, but allows us to map them by name in the code and report better - // error messages. StringSet<> DocSections; + ELFYAML::SectionHeaderTable *SecHdrTable = nullptr; for (size_t I = 0; I < Doc.Chunks.size(); ++I) { const std::unique_ptr &C = Doc.Chunks[I]; + + // We might have an explicit section header table declaration. + if (auto S = dyn_cast(C.get())) { + if (SecHdrTable) + reportError("multiple section header tables are not allowed"); + SecHdrTable = S; + continue; + } + + // We add a technical suffix for each unnamed section/fill. It does not + // affect the output, but allows us to map them by name in the code and + // report better error messages. if (C->Name.empty()) { std::string NewName = ELFYAML::appendUniqueSuffix( /*Name=*/"", "index " + Twine(I)); @@ -359,7 +374,7 @@ ImplicitSections.push_back(StringRef(SecName).copy(StringAlloc)); } ImplicitSections.insert(ImplicitSections.end(), {".strtab"}); - if (!Doc.SectionHeaders || !Doc.SectionHeaders->NoHeaders.getValueOr(false)) + if (!SecHdrTable || !SecHdrTable->NoHeaders.getValueOr(false)) ImplicitSections.insert(ImplicitSections.end(), {".shstrtab"}); // Insert placeholders for implicit sections that are not @@ -371,12 +386,27 @@ std::unique_ptr Sec = std::make_unique( ELFYAML::Chunk::ChunkKind::RawContent, true /*IsImplicit*/); Sec->Name = SecName; - Doc.Chunks.push_back(std::move(Sec)); + + // When the section header table is explicitly defined at the end of the + // sections list, it is reasonable to assume that the user wants to reorder + // section headers, but still wants to place the section header table after + // all sections, like it normally happens. In this case we want to insert + // other implicit sections right before the section header table. + if (Doc.Chunks.back().get() == SecHdrTable) + Doc.Chunks.insert(Doc.Chunks.end() - 1, std::move(Sec)); + else + Doc.Chunks.push_back(std::move(Sec)); } + + // Insert the section header table implicitly at the end, when it is not + // explicitly defined. + if (!SecHdrTable) + Doc.Chunks.push_back( + std::make_unique(/*IsImplicit=*/true)); } template -void ELFState::writeELFHeader(raw_ostream &OS, Optional SHOff) { +void ELFState::writeELFHeader(raw_ostream &OS) { using namespace llvm::ELF; Elf_Ehdr Header; @@ -426,29 +456,24 @@ Header.e_shentsize = Doc.Header.EShEntSize ? (uint16_t)*Doc.Header.EShEntSize : sizeof(Elf_Shdr); + const ELFYAML::SectionHeaderTable &SectionHeaders = + Doc.getSectionHeaderTable(); + if (Doc.Header.EShOff) Header.e_shoff = *Doc.Header.EShOff; - else if (SHOff) - Header.e_shoff = *SHOff; + else if (SectionHeaders.Offset) + Header.e_shoff = *SectionHeaders.Offset; else Header.e_shoff = 0; if (Doc.Header.EShNum) Header.e_shnum = *Doc.Header.EShNum; - else if (!Doc.SectionHeaders || - (Doc.SectionHeaders->NoHeaders && !*Doc.SectionHeaders->NoHeaders)) - Header.e_shnum = Doc.getSections().size(); - else if (!SHOff) - Header.e_shnum = 0; else - Header.e_shnum = - (Doc.SectionHeaders->Sections ? Doc.SectionHeaders->Sections->size() - : 0) + - /*Null section*/ 1; + Header.e_shnum = SectionHeaders.getNumHeaders(Doc.getSections().size()); if (Doc.Header.EShStrNdx) Header.e_shstrndx = *Doc.Header.EShStrNdx; - else if (SHOff && !ExcludedSectionHeaders.count(".shstrtab")) + else if (SectionHeaders.Offset && !ExcludedSectionHeaders.count(".shstrtab")) Header.e_shstrndx = SN2I.get(".shstrtab"); else Header.e_shstrndx = 0; @@ -520,14 +545,16 @@ return 0; } - if (!Doc.SectionHeaders || (Doc.SectionHeaders->NoHeaders && - !Doc.SectionHeaders->NoHeaders.getValue())) + const ELFYAML::SectionHeaderTable &SectionHeaders = + Doc.getSectionHeaderTable(); + if (SectionHeaders.IsImplicit || + (SectionHeaders.NoHeaders && !SectionHeaders.NoHeaders.getValue())) return Index; - assert(!Doc.SectionHeaders->NoHeaders.getValueOr(false) || - !Doc.SectionHeaders->Sections); + assert(!SectionHeaders.NoHeaders.getValueOr(false) || + !SectionHeaders.Sections); size_t FirstExcluded = - Doc.SectionHeaders->Sections ? Doc.SectionHeaders->Sections->size() : 0; + SectionHeaders.Sections ? SectionHeaders.Sections->size() : 0; if (Index >= FirstExcluded) { if (LocSym.empty()) reportError("unable to link '" + LocSec + "' to excluded section '" + S + @@ -670,8 +697,27 @@ continue; } + if (ELFYAML::SectionHeaderTable *S = + dyn_cast(D.get())) { + if (S->NoHeaders.getValueOr(false)) + continue; + + if (!S->Offset) + S->Offset = alignToOffset(CBA, sizeof(typename ELFT::uint), + /*Offset=*/None); + else + S->Offset = alignToOffset(CBA, /*Align=*/1, S->Offset); + + uint64_t Size = S->getNumHeaders(SHeaders.size()) * sizeof(Elf_Shdr); + // The full section header information might be not available here, so + // fill the space with zeroes as a placeholder. + CBA.writeZeros(Size); + LocationCounter += Size; + continue; + } + ELFYAML::Section *Sec = cast(D.get()); - bool IsFirstUndefSection = D == Doc.Chunks.front(); + bool IsFirstUndefSection = Sec == Doc.getSections().front(); if (IsFirstUndefSection && Sec->IsImplicit) continue; @@ -1742,7 +1788,9 @@ template DenseMap ELFState::buildSectionHeaderReorderMap() { - if (!Doc.SectionHeaders || Doc.SectionHeaders->NoHeaders) + const ELFYAML::SectionHeaderTable &SectionHeaders = + Doc.getSectionHeaderTable(); + if (SectionHeaders.IsImplicit || SectionHeaders.NoHeaders) return DenseMap(); DenseMap Ret; @@ -1756,12 +1804,12 @@ Seen.insert(Hdr.Name); }; - if (Doc.SectionHeaders->Sections) - for (const ELFYAML::SectionHeader &Hdr : *Doc.SectionHeaders->Sections) + if (SectionHeaders.Sections) + for (const ELFYAML::SectionHeader &Hdr : *SectionHeaders.Sections) AddSection(Hdr); - if (Doc.SectionHeaders->Excluded) - for (const ELFYAML::SectionHeader &Hdr : *Doc.SectionHeaders->Excluded) + if (SectionHeaders.Excluded) + for (const ELFYAML::SectionHeader &Hdr : *SectionHeaders.Excluded) AddSection(Hdr); for (const ELFYAML::Section *S : Doc.getSections()) { @@ -1790,17 +1838,17 @@ // Build excluded section headers map. std::vector Sections = Doc.getSections(); - if (Doc.SectionHeaders) { - if (Doc.SectionHeaders->Excluded) - for (const ELFYAML::SectionHeader &Hdr : *Doc.SectionHeaders->Excluded) - if (!ExcludedSectionHeaders.insert(Hdr.Name).second) - llvm_unreachable("buildSectionIndex() failed"); - - if (Doc.SectionHeaders->NoHeaders.getValueOr(false)) - for (const ELFYAML::Section *S : Sections) - if (!ExcludedSectionHeaders.insert(S->Name).second) - llvm_unreachable("buildSectionIndex() failed"); - } + const ELFYAML::SectionHeaderTable &SectionHeaders = + Doc.getSectionHeaderTable(); + if (SectionHeaders.Excluded) + for (const ELFYAML::SectionHeader &Hdr : *SectionHeaders.Excluded) + if (!ExcludedSectionHeaders.insert(Hdr.Name).second) + llvm_unreachable("buildSectionIndex() failed"); + + if (SectionHeaders.NoHeaders.getValueOr(false)) + for (const ELFYAML::Section *S : Sections) + if (!ExcludedSectionHeaders.insert(S->Name).second) + llvm_unreachable("buildSectionIndex() failed"); size_t SecNdx = -1; for (const ELFYAML::Section *S : Sections) { @@ -1903,17 +1951,7 @@ // Now we can decide segment offsets. State.setProgramHeaderLayout(PHeaders, SHeaders); - // If needed, align the start of the section header table, which is written - // after all section data. - const bool HasSectionHeaders = - !Doc.SectionHeaders || !Doc.SectionHeaders->NoHeaders.getValueOr(false); - Optional SHOff; - if (HasSectionHeaders) - SHOff = State.alignToOffset(CBA, sizeof(typename ELFT::uint), - /*Offset=*/None); - bool ReachedLimit = SHOff.getValueOr(CBA.getOffset()) + - arrayDataSize(makeArrayRef(SHeaders)) > - MaxSize; + bool ReachedLimit = CBA.getOffset() > MaxSize; if (Error E = CBA.takeLimitError()) { // We report a custom error message instead below. consumeError(std::move(E)); @@ -1928,11 +1966,15 @@ if (State.HasError) return false; - State.writeELFHeader(OS, SHOff); + State.writeELFHeader(OS); writeArrayData(OS, makeArrayRef(PHeaders)); + + const ELFYAML::SectionHeaderTable &SHT = Doc.getSectionHeaderTable(); + if (!SHT.NoHeaders.getValueOr(false)) + CBA.updateDataAt(*SHT.Offset, SHeaders.data(), + SHT.getNumHeaders(SHeaders.size()) * sizeof(Elf_Shdr)); + CBA.writeBlobToStream(OS); - if (HasSectionHeaders) - writeArrayData(OS, makeArrayRef(SHeaders)); return true; } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -860,23 +860,6 @@ IO.mapRequired("Name", SHdr.Name); } -void MappingTraits::mapping( - IO &IO, ELFYAML::SectionHeaderTable &SectionHeader) { - IO.mapOptional("Sections", SectionHeader.Sections); - IO.mapOptional("Excluded", SectionHeader.Excluded); - IO.mapOptional("NoHeaders", SectionHeader.NoHeaders); -} - -std::string MappingTraits::validate( - IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable) { - if (SecHdrTable.NoHeaders && (SecHdrTable.Sections || SecHdrTable.Excluded)) - return "NoHeaders can't be used together with Sections/Excluded"; - if (!SecHdrTable.NoHeaders && !SecHdrTable.Sections && !SecHdrTable.Excluded) - return "SectionHeaderTable can't be empty. Use 'NoHeaders' key to drop the " - "section header table"; - return ""; -} - void MappingTraits::mapping(IO &IO, ELFYAML::FileHeader &FileHdr) { IO.mapRequired("Class", FileHdr.Class); @@ -1252,6 +1235,14 @@ IO.mapRequired("Size", Fill.Size); } +static void sectionHeaderTableMapping(IO &IO, + ELFYAML::SectionHeaderTable &SHT) { + IO.mapOptional("Offset", SHT.Offset); + IO.mapOptional("Sections", SHT.Sections); + IO.mapOptional("Excluded", SHT.Excluded); + IO.mapOptional("NoHeaders", SHT.NoHeaders); +} + static void sectionMapping(IO &IO, ELFYAML::LinkerOptionsSection &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Options", Section.Options); @@ -1304,22 +1295,48 @@ return Val; } +static void setStringValue(IO &IO, const char *Key, StringRef Val) { + IO.mapRequired(Key, Val); +} + +static bool isInteger(StringRef Val) { + APInt Tmp; + return !Val.getAsInteger(0, Tmp); +} + void MappingTraits>::mapping( IO &IO, std::unique_ptr &Section) { ELFYAML::ELF_SHT Type; + StringRef TypeStr; if (IO.outputting()) { - Type = cast(Section.get())->Type; + if (auto *S = dyn_cast(Section.get())) + Type = S->Type; + else if (auto *SHT = dyn_cast(Section.get())) + TypeStr = SHT->TypeStr; } else { // When the Type string does not have a "SHT_" prefix, we know it is not a - // description of a regular ELF output section. Currently, we have one - // special type named "Fill". See comments for Fill. - if (getStringValue(IO, "Type") == "Fill") { - Section.reset(new ELFYAML::Fill()); - fillMapping(IO, *cast(Section.get())); - return; - } + // description of a regular ELF output section. + TypeStr = getStringValue(IO, "Type"); + if (TypeStr.startswith("SHT_") || isInteger(TypeStr)) + IO.mapRequired("Type", Type); + } + + if (TypeStr == "Fill") { + assert(!IO.outputting()); // We don't dump fills currently. + Section.reset(new ELFYAML::Fill()); + fillMapping(IO, *cast(Section.get())); + return; + } + + if (TypeStr == ELFYAML::SectionHeaderTable::TypeStr) { + if (IO.outputting()) + setStringValue(IO, "Type", TypeStr); + else + Section.reset(new ELFYAML::SectionHeaderTable(/*IsImplicit=*/false)); - IO.mapRequired("Type", Type); + sectionHeaderTableMapping( + IO, *cast(Section.get())); + return; } const auto &Obj = *static_cast(IO.getContext()); @@ -1452,6 +1469,15 @@ return ""; } + if (const auto *SHT = dyn_cast(C.get())) { + if (SHT->NoHeaders && (SHT->Sections || SHT->Excluded || SHT->Offset)) + return "NoHeaders can't be used together with Offset/Sections/Excluded"; + if (!SHT->NoHeaders && !SHT->Sections && !SHT->Excluded) + return "SectionHeaderTable can't be empty. Use 'NoHeaders' key to drop " + "the section header table"; + return ""; + } + const ELFYAML::Section &Sec = *cast(C.get()); if (Sec.Size && Sec.Content && (uint64_t)(*Sec.Size) < Sec.Content->binary_size()) @@ -1656,7 +1682,6 @@ IO.mapOptional("Symbols", Object.Symbols); IO.mapOptional("DynamicSymbols", Object.DynamicSymbols); IO.mapOptional("DWARF", Object.DWARF); - IO.mapOptional("SectionHeaderTable", Object.SectionHeaders); if (Object.DWARF) { Object.DWARF->IsLittleEndian = Object.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); diff --git a/llvm/test/Object/obj2yaml.test b/llvm/test/Object/obj2yaml.test --- a/llvm/test/Object/obj2yaml.test +++ b/llvm/test/Object/obj2yaml.test @@ -415,6 +415,19 @@ # ELF-MIPSEL-NEXT: - Offset: 0x2C # ELF-MIPSEL-NEXT: Symbol: SomeOtherFunction # ELF-MIPSEL-NEXT: Type: R_MIPS_CALL16 +# ELF-MIPSEL-NEXT: - Type: SectionHeaderTable +# ELF-MIPSEL-NEXT: Sections: +# ELF-MIPSEL-NEXT: - Name: .text +# ELF-MIPSEL-NEXT: - Name: .rel.text +# ELF-MIPSEL-NEXT: - Name: .data +# ELF-MIPSEL-NEXT: - Name: .bss +# ELF-MIPSEL-NEXT: - Name: .mdebug.abi32 +# ELF-MIPSEL-NEXT: - Name: .rodata.str1.1 +# ELF-MIPSEL-NEXT: - Name: .reginfo +# ELF-MIPSEL-NEXT: - Name: .MIPS.abiflags +# ELF-MIPSEL-NEXT: - Name: .shstrtab +# ELF-MIPSEL-NEXT: - Name: .symtab +# ELF-MIPSEL-NEXT: - Name: .strtab # ELF-MIPSEL-NEXT: Symbols: # ELF-MIPSEL-NEXT: - Name: trivial.ll # ELF-MIPSEL-NEXT: Type: STT_FILE @@ -460,19 +473,6 @@ # ELF-MIPSEL-NEXT: Binding: STB_GLOBAL # ELF-MIPSEL-NEXT: - Name: puts # ELF-MIPSEL-NEXT: Binding: STB_GLOBAL -# ELF-MIPSEL-NEXT: SectionHeaderTable: -# ELF-MIPSEL-NEXT: Sections: -# ELF-MIPSEL-NEXT: - Name: .text -# ELF-MIPSEL-NEXT: - Name: .rel.text -# ELF-MIPSEL-NEXT: - Name: .data -# ELF-MIPSEL-NEXT: - Name: .bss -# ELF-MIPSEL-NEXT: - Name: .mdebug.abi32 -# ELF-MIPSEL-NEXT: - Name: .rodata.str1.1 -# ELF-MIPSEL-NEXT: - Name: .reginfo -# ELF-MIPSEL-NEXT: - Name: .MIPS.abiflags -# ELF-MIPSEL-NEXT: - Name: .shstrtab -# ELF-MIPSEL-NEXT: - Name: .symtab -# ELF-MIPSEL-NEXT: - Name: .strtab # ELF-MIPSEL-NEXT: ... # RUN: obj2yaml %p/Inputs/trivial-object-test.elf-mips64el | FileCheck %s --check-prefix ELF-MIPS64EL @@ -514,6 +514,17 @@ # ELF-MIPS64EL-NEXT: Relocations: # ELF-MIPS64EL-NEXT: - Symbol: zed # ELF-MIPS64EL-NEXT: Type: R_MIPS_64 +# ELF-MIPS64EL-NEXT: - Type: SectionHeaderTable +# ELF-MIPS64EL-NEXT: Sections: +# ELF-MIPS64EL-NEXT: - Name: .text +# ELF-MIPS64EL-NEXT: - Name: .data +# ELF-MIPS64EL-NEXT: - Name: .rela.data +# ELF-MIPS64EL-NEXT: - Name: .bss +# ELF-MIPS64EL-NEXT: - Name: .MIPS.options +# ELF-MIPS64EL-NEXT: - Name: .pdr +# ELF-MIPS64EL-NEXT: - Name: .shstrtab +# ELF-MIPS64EL-NEXT: - Name: .symtab +# ELF-MIPS64EL-NEXT: - Name: .strtab # ELF-MIPS64EL-NEXT: Symbols: # ELF-MIPS64EL-NEXT: - Name: .text # ELF-MIPS64EL-NEXT: Type: STT_SECTION @@ -534,17 +545,6 @@ # ELF-MIPS64EL-NEXT: Section: .pdr # ELF-MIPS64EL-NEXT: - Name: zed # ELF-MIPS64EL-NEXT: Binding: STB_GLOBAL -# ELF-MIPS64EL-NEXT: SectionHeaderTable: -# ELF-MIPS64EL-NEXT: Sections: -# ELF-MIPS64EL-NEXT: - Name: .text -# ELF-MIPS64EL-NEXT: - Name: .data -# ELF-MIPS64EL-NEXT: - Name: .rela.data -# ELF-MIPS64EL-NEXT: - Name: .bss -# ELF-MIPS64EL-NEXT: - Name: .MIPS.options -# ELF-MIPS64EL-NEXT: - Name: .pdr -# ELF-MIPS64EL-NEXT: - Name: .shstrtab -# ELF-MIPS64EL-NEXT: - Name: .symtab -# ELF-MIPS64EL-NEXT: - Name: .strtab # ELF-MIPS64EL-NEXT: ... # RUN: yaml2obj %s -o %t-x86-64 diff --git a/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test b/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test --- a/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test +++ b/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test @@ -447,6 +447,8 @@ Flags: [ SHF_ALLOC ] Address: 0x300 Offset: 0x300 + - Type: SectionHeaderTable + NoHeaders: true DynamicSymbols: - Name: foo ProgramHeaders: @@ -457,5 +459,3 @@ - Type: PT_DYNAMIC FirstSec: .dynamic LastSec: .dynamic -SectionHeaderTable: - NoHeaders: true 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 --- 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 @@ -50,6 +50,8 @@ Value: 0x0 - Name: .dynsym Type: SHT_DYNSYM + - Type: SectionHeaderTable + NoHeaders: true DynamicSymbols: - Name: foo ProgramHeaders: @@ -59,5 +61,3 @@ - Type: PT_DYNAMIC FirstSec: .dynamic LastSec: .dynamic -SectionHeaderTable: - NoHeaders: true diff --git a/llvm/test/tools/llvm-readobj/ELF/file-headers.test b/llvm/test/tools/llvm-readobj/ELF/file-headers.test --- a/llvm/test/tools/llvm-readobj/ELF/file-headers.test +++ b/llvm/test/tools/llvm-readobj/ELF/file-headers.test @@ -215,8 +215,9 @@ ## The index of the section name string table is too large. ## The section would be past the EOF. EShStrNdx: [[SHSTRNDX=0x3000]] -SectionHeaderTable: - NoHeaders: true +Sections: + - Type: SectionHeaderTable + NoHeaders: true ## Check we don't dump anything except the file header when the section header table can't be read. diff --git a/llvm/test/tools/llvm-readobj/ELF/hash-table.test b/llvm/test/tools/llvm-readobj/ELF/hash-table.test --- a/llvm/test/tools/llvm-readobj/ELF/hash-table.test +++ b/llvm/test/tools/llvm-readobj/ELF/hash-table.test @@ -113,8 +113,8 @@ Value: 0x0 - Tag: DT_NULL Value: 0x0 -SectionHeaderTable: - NoHeaders: [[NOHEADERS=false]] + - Type: SectionHeaderTable + NoHeaders: [[NOHEADERS=false]] ProgramHeaders: - Type: PT_LOAD FirstSec: .hash diff --git a/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test b/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test --- a/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test +++ b/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test @@ -137,10 +137,10 @@ Entries: - Tag: DT_NULL Value: 0 + - Type: SectionHeaderTable + NoHeaders: [[NOHEADERS=false]] ProgramHeaders: - Type: PT_DYNAMIC FileSize: [[FILESIZE=]] FirstSec: .dynamic LastSec: .dynamic -SectionHeaderTable: - NoHeaders: [[NOHEADERS=false]] diff --git a/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test --- a/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test +++ b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test @@ -313,6 +313,8 @@ Entries: [ 0, 1 ] Offset: 0x2000 Address: 0x2000 + - Type: SectionHeaderTable + NoHeaders: true DynamicSymbols: - Name: dynsym1 Index: SHN_XINDEX @@ -327,5 +329,3 @@ VAddr: 0x1000 FirstSec: .dynamic LastSec: .dynamic -SectionHeaderTable: - NoHeaders: true diff --git a/llvm/test/tools/obj2yaml/ELF/offset.yaml b/llvm/test/tools/obj2yaml/ELF/offset.yaml --- a/llvm/test/tools/obj2yaml/ELF/offset.yaml +++ b/llvm/test/tools/obj2yaml/ELF/offset.yaml @@ -36,17 +36,17 @@ # BASIC-NEXT: Type: SHT_PROGBITS # BASIC-NEXT: AddressAlign: 0x100000000 # BASIC-NEXT: Offset: 0x210 -# HEADERS-NEXT: SectionHeaderTable: -# HEADERS-NEXT: Sections: -# HEADERS-NEXT: - Name: .bar4 -# HEADERS-NEXT: - Name: .bar3 -# HEADERS-NEXT: - Name: .bar2 -# HEADERS-NEXT: - Name: .bar1 -# HEADERS-NEXT: - Name: .foo3 -# HEADERS-NEXT: - Name: .foo2 -# HEADERS-NEXT: - Name: .foo1 -# HEADERS-NEXT: - Name: .strtab -# HEADERS-NEXT: - Name: .shstrtab +# HEADERS-NEXT: - Type: SectionHeaderTable +# HEADERS-NEXT: Sections: +# HEADERS-NEXT: - Name: .bar4 +# HEADERS-NEXT: - Name: .bar3 +# HEADERS-NEXT: - Name: .bar2 +# HEADERS-NEXT: - Name: .bar1 +# HEADERS-NEXT: - Name: .foo3 +# HEADERS-NEXT: - Name: .foo2 +# HEADERS-NEXT: - Name: .foo1 +# HEADERS-NEXT: - Name: .strtab +# HEADERS-NEXT: - Name: .shstrtab # BASIC-NEXT: ... --- !ELF @@ -103,18 +103,18 @@ Type: SHT_PROGBITS AddressAlign: 0x100000000 Offset: 0x210 -SectionHeaderTable: - Sections: + - Type: SectionHeaderTable + Sections: ## By default we have the same order of sections as defined by the "Sections" key. - - Name: [[SEC1=.foo1]] - - Name: [[SEC2=.foo2]] - - Name: [[SEC3=.foo3]] - - Name: [[SEC4=.bar1]] - - Name: [[SEC5=.bar2]] - - Name: [[SEC6=.bar3]] - - Name: [[SEC7=.bar4]] - - Name: .strtab - - Name: .shstrtab + - Name: [[SEC1=.foo1]] + - Name: [[SEC2=.foo2]] + - Name: [[SEC3=.foo3]] + - Name: [[SEC4=.bar1]] + - Name: [[SEC5=.bar2]] + - Name: [[SEC6=.bar3]] + - Name: [[SEC7=.bar4]] + - Name: .strtab + - Name: .shstrtab ## In this case we change the order of sections in the section header table. ## Check that we still dump offsets correctly. diff --git a/llvm/test/tools/yaml2obj/ELF/section-headers-exclude.yaml b/llvm/test/tools/yaml2obj/ELF/section-headers-exclude.yaml --- a/llvm/test/tools/yaml2obj/ELF/section-headers-exclude.yaml +++ b/llvm/test/tools/yaml2obj/ELF/section-headers-exclude.yaml @@ -32,13 +32,13 @@ Type: SHT_PROGBITS - Name: .bar Type: SHT_PROGBITS -SectionHeaderTable: - Sections: - - Name: [[INCLUDED]] - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: [[EXCLUDED]] + - Type: SectionHeaderTable + Sections: + - Name: [[INCLUDED]] + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: [[EXCLUDED]] ## Check we report an error when a section is in both the "Sections" and "Excluded" lists at the same time. ## Also check that we report an error if a section is missing from the lists. @@ -66,13 +66,14 @@ Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_REL -SectionHeaderTable: - Sections: - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .strtab - - Name: .strtab +Sections: + - Type: SectionHeaderTable + Sections: + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .strtab + - Name: .strtab ## Check that we are able to exclude all sections, except the implicit ## null section, with the use of the "Excluded" key. @@ -91,11 +92,12 @@ Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_REL -SectionHeaderTable: - Sections: [] - Excluded: - - Name: .strtab - - Name: .shstrtab +Sections: + - Type: SectionHeaderTable + Sections: [] + Excluded: + - Name: .strtab + - Name: .shstrtab ## Case B: the "Sections" key is not present. # RUN: yaml2obj %s --docnum=4 -o %t4 @@ -106,10 +108,11 @@ Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_REL -SectionHeaderTable: - Excluded: - - Name: .strtab - - Name: .shstrtab +Sections: + - Type: SectionHeaderTable + Excluded: + - Name: .strtab + - Name: .shstrtab ## Check how we handle cases when a section is excluded, but its section index is needed. ## The general rule is: when a section is explicitly linked with another section, which is @@ -134,13 +137,13 @@ Link: .bar - Name: .bar Type: SHT_PROGBITS -SectionHeaderTable: - Sections: - - Name: .foo - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .bar + - Type: SectionHeaderTable + Sections: + - Name: .foo + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .bar ## Case B.1: check we report an error when a symbol table section has a Link field which ## points to an excluded section. @@ -160,13 +163,13 @@ Link: .foo - Name: .foo Type: SHT_PROGBITS -SectionHeaderTable: - Sections: - - Name: [[NAME]] - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .foo + - Type: SectionHeaderTable + Sections: + - Name: [[NAME]] + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .foo ## Case B.2: check we do not link .dynsym with .dynstr implicitly when the latter is excluded. # RUN: yaml2obj %s --docnum=7 -o %t5 @@ -185,13 +188,13 @@ Type: SHT_DYNSYM - Name: .dynstr Type: SHT_PROGBITS -SectionHeaderTable: - Sections: - - Name: .dynsym - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .dynstr + - Type: SectionHeaderTable + Sections: + - Name: .dynsym + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .dynstr ## Case B.3: check we do not link .symtab with .strtab implicitly when the latter is excluded. # RUN: yaml2obj %s --docnum=8 -o %t6 @@ -210,12 +213,12 @@ Type: SHT_SYMTAB - Name: .strtab Type: SHT_PROGBITS -SectionHeaderTable: - Sections: - - Name: .symtab - - Name: .shstrtab - Excluded: - - Name: .strtab + - Type: SectionHeaderTable + Sections: + - Name: .symtab + - Name: .shstrtab + Excluded: + - Name: .strtab ## Case C: check we report an error when a debug section has a Link field which ## points to an excluded section. @@ -231,12 +234,12 @@ - Name: .debug_unknown Type: SHT_PROGBITS Link: .strtab -SectionHeaderTable: - Sections: - - Name: .debug_unknown - - Name: .shstrtab - Excluded: - - Name: .strtab + - Type: SectionHeaderTable + Sections: + - Name: .debug_unknown + - Name: .shstrtab + Excluded: + - Name: .strtab ## Case D.1: check we report an error when a relocatable section has an Info field which ## points to an excluded section. @@ -253,12 +256,12 @@ Type: SHT_RELA Info: .strtab Relocations: [] -SectionHeaderTable: - Sections: - - Name: .rela - - Name: .shstrtab - Excluded: - - Name: .strtab + - Type: SectionHeaderTable + Sections: + - Name: .rela + - Name: .shstrtab + Excluded: + - Name: .strtab ## Case D.2: check we report an error when the SHT_REL[A] section is linked ## with an excluded section explicitly. @@ -277,13 +280,13 @@ Relocations: [] - Name: .symtab Type: SHT_PROGBITS -SectionHeaderTable: - Sections: - - Name: .rela - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .symtab + - Type: SectionHeaderTable + Sections: + - Name: .rela + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .symtab ## Case E: check we report an error when a symbol references an excluded section. # RUN: not yaml2obj %s --docnum=12 -o /dev/null 2>&1 | \ @@ -299,17 +302,17 @@ Sections: - Name: .foo Type: SHT_PROGBITS + - Type: SectionHeaderTable + Sections: + - Name: .symtab + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .foo Symbols: - Name: foo Type: STT_OBJECT Section: .foo -SectionHeaderTable: - Sections: - - Name: .symtab - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .foo ## Case F.1: check we report an error when a group section ## contains an excluded section member. @@ -326,12 +329,12 @@ Type: SHT_GROUP Members: - SectionOrType: .strtab -SectionHeaderTable: - Sections: - - Name: .group - - Name: .shstrtab - Excluded: - - Name: .strtab + - Type: SectionHeaderTable + Sections: + - Name: .group + - Name: .shstrtab + Excluded: + - Name: .strtab ## Case F.2: check we report an error when the group section is linked ## to an excluded section explicitly. @@ -350,13 +353,13 @@ Members: [] - Name: .symtab Type: SHT_SYMTAB -SectionHeaderTable: - Sections: - - Name: .group - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .symtab + - Type: SectionHeaderTable + Sections: + - Name: .group + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .symtab ## Case G: check we do not link SHT_LLVM_CALL_GRAPH_PROFILE/SHT_LLVM_ADDRSIG/SHT_GROUP/SHT_REL[A] sections ## with .symtab implicitly when the latter is excluded. @@ -389,16 +392,16 @@ Relocations: [] - Name: .symtab Type: SHT_SYMTAB -SectionHeaderTable: - Sections: - - Name: .cgp - - Name: .llvm_addrsig - - Name: .group - - Name: .rela - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .symtab + - Type: SectionHeaderTable + Sections: + - Name: .cgp + - Name: .llvm_addrsig + - Name: .group + - Name: .rela + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .symtab ## Case H: check we do not link SHT_HASH/SHT_GNU_HASH sections with .dynsym ## implicitly when the latter is excluded. @@ -423,14 +426,14 @@ Content: "" - Name: .dynsym Type: SHT_DYNSYM -SectionHeaderTable: - Sections: - - Name: .hash - - Name: .gnu_hash - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .dynsym + - Type: SectionHeaderTable + Sections: + - Name: .hash + - Name: .gnu_hash + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .dynsym ## Case I: document the case when an excluded section is explicitly linked to another excluded section. ## We report an error in this case, because: @@ -454,13 +457,13 @@ - Name: .bar Type: SHT_PROGBITS Link: .foo -SectionHeaderTable: - Sections: - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .foo - - Name: .bar + - Type: SectionHeaderTable + Sections: + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .foo + - Name: .bar ## Check we set e_shstrndx field to 0 when the section header string table is excluded. ## Check that the e_shnum field is adjusted properly when a section is removed. @@ -475,22 +478,24 @@ Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_REL -SectionHeaderTable: - Sections: - - Name: .strtab - Excluded: - - Name: .shstrtab +Sections: + - Type: SectionHeaderTable + Sections: + - Name: .strtab + Excluded: + - Name: .shstrtab ## Check we do not allow using "Excluded" together with "NoHeaders". # RUN: not yaml2obj %s --docnum=19 -DNOHEADERS=true -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOHEADERS # RUN: not yaml2obj %s --docnum=19 -DNOHEADERS=false -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOHEADERS -# NOHEADERS: NoHeaders can't be used together with Sections/Excluded +# NOHEADERS: NoHeaders can't be used together with Offset/Sections/Excluded --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_REL -SectionHeaderTable: - NoHeaders: [[NOHEADERS]] - Excluded: [] +Sections: + - Type: SectionHeaderTable + NoHeaders: [[NOHEADERS]] + Excluded: [] diff --git a/llvm/test/tools/yaml2obj/ELF/section-headers.yaml b/llvm/test/tools/yaml2obj/ELF/section-headers.yaml --- a/llvm/test/tools/yaml2obj/ELF/section-headers.yaml +++ b/llvm/test/tools/yaml2obj/ELF/section-headers.yaml @@ -34,13 +34,13 @@ - Name: .section.foo Type: SHT_PROGBITS Size: 0x40 -SectionHeaderTable: - Sections: - - Name: [[SEC1]] - - Name: [[SEC2]] - - Name: [[SEC3]] - - Name: .strtab - - Name: .shstrtab + - Type: SectionHeaderTable + Sections: + - Name: [[SEC1]] + - Name: [[SEC2]] + - Name: [[SEC3]] + - Name: .strtab + - Name: .shstrtab ## Show we are able to reorder sections. # RUN: yaml2obj %s -o %t2 -DSEC3=".section (1)" -DSEC2=".section (2)" -DSEC1=".section.foo" @@ -93,8 +93,8 @@ Sections: - Name: .foo Type: SHT_PROGBITS -SectionHeaderTable: - Sections: [] + - Type: SectionHeaderTable + Sections: [] ## Test that we are able to use "NoHeaders" property to produce an empty section header table. # RUN: yaml2obj %s --docnum=3 -DNOHEADERS=true -o %t3.1 @@ -113,8 +113,8 @@ Sections: - Name: .foo Type: SHT_PROGBITS -SectionHeaderTable: - NoHeaders: [[NOHEADERS]] + - Type: SectionHeaderTable + NoHeaders: [[NOHEADERS]] ## Test that we are able to set NoHeaders to false. In this case the tool produces an output ## as if there were no `SectionHeaderTable` key at all. @@ -137,7 +137,7 @@ # RUN: not yaml2obj %s --docnum=4 -DNOHEADERS=true -o /dev/null 2>&1 | FileCheck %s --check-prefix=SECTIONS-NO-HEADERS # RUN: not yaml2obj %s --docnum=4 -DNOHEADERS=false -o /dev/null 2>&1 | FileCheck %s --check-prefix=SECTIONS-NO-HEADERS -# SECTIONS-NO-HEADERS: error: NoHeaders can't be used together with Sections/Excluded +# SECTIONS-NO-HEADERS: error: NoHeaders can't be used together with Offset/Sections/Excluded --- !ELF FileHeader: @@ -147,12 +147,12 @@ Sections: - Name: .foo Type: SHT_PROGBITS -SectionHeaderTable: - Sections: [] - NoHeaders: [[NOHEADERS]] + - Type: SectionHeaderTable + Sections: [] + NoHeaders: [[NOHEADERS]] ## Check that we do not allow an empty SectionHeaderTable tag and suggest to use an explicit syntax instead. -# RUN: not yaml2obj %s --docnum=5 -DVAL="" -o /dev/null 2>&1 | FileCheck %s --check-prefix=NO-VALUE +# RUN: not yaml2obj %s --docnum=5 -o /dev/null 2>&1 | FileCheck %s --check-prefix=NO-VALUE # NO-VALUE: SectionHeaderTable can't be empty. Use 'NoHeaders' key to drop the section header table @@ -164,12 +164,7 @@ Sections: - Name: .foo Type: SHT_PROGBITS -SectionHeaderTable: [[VAL]] - -## An empty mapping is also not allowed for the SectionHeaderTable tag. -# RUN: not yaml2obj %s --docnum=5 -DVAL="[]" -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOT-A-MAPPING - -# NOT-A-MAPPING: error: not a mapping + - Type: SectionHeaderTable ## Test that we are still able to override e_shoff, e_shnum and e_shstrndx ## fields even when we do not produce section headers. @@ -188,8 +183,9 @@ EShOff: 0x2 EShNum: 0x3 EShStrNdx: 0x4 -SectionHeaderTable: - NoHeaders: true +Sections: + - Type: SectionHeaderTable + NoHeaders: true ## Check that section indices are updated properly in other places when we ## reorder sections in the section header table. @@ -233,15 +229,15 @@ - Name: .another.2 Link: .bar Type: SHT_PROGBITS -SectionHeaderTable: - Sections: - - Name: [[SEC1]] - - Name: [[SEC2]] - - Name: .another.1 - - Name: .another.2 - - Name: .symtab - - Name: .strtab - - Name: .shstrtab + - Type: SectionHeaderTable + Sections: + - Name: [[SEC1]] + - Name: [[SEC2]] + - Name: .another.1 + - Name: .another.2 + - Name: .symtab + - Name: .strtab + - Name: .shstrtab Symbols: - Name: foo Section: .foo @@ -275,5 +271,142 @@ ## for writing the section header table. Size: 0xFF Offset: 0x100 -SectionHeaderTable: - NoHeaders: true + - Type: SectionHeaderTable + NoHeaders: true + +## Check we do not allow using "Offset" together with "NoHeaders". +# RUN: not yaml2obj %s --docnum=9 -DNOHEADERS=true -o /dev/null 2>&1 | FileCheck %s --check-prefix=NO-HEADERS-OFFSET +# RUN: not yaml2obj %s --docnum=9 -DNOHEADERS=false -o /dev/null 2>&1 | FileCheck %s --check-prefix=NO-HEADERS-OFFSET + +# NO-HEADERS-OFFSET: error: NoHeaders can't be used together with Offset/Sections/Excluded + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Type: SectionHeaderTable + Offset: 0x1000 + NoHeaders: [[NOHEADERS]] + +## Check we can place the section header table before other sections. + +# RUN: yaml2obj %s --docnum=10 -o %t10 +# RUN: llvm-readelf --file-headers --sections %t10 | FileCheck %s --check-prefix=PLACE-BEFORE + +# PLACE-BEFORE: Start of section headers: 64 (bytes into file) +# PLACE-BEFORE: Size of section headers: 64 (bytes) +# PLACE-BEFORE: Number of section headers: 4 + +# PLACE-BEFORE: Section Headers: +# PLACE-BEFORE: [Nr] Name Type Address Off Size +## 0x140 == Start of section headers (64) + Size of section headers (64) * Number of section headers (4); +# PLACE-BEFORE: [ 1] .foo PROGBITS 0000000000000000 000140 000000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Type: SectionHeaderTable + Offset: [[OFFSET=]] + Sections: + - Name: .foo + - Name: .strtab + - Name: .shstrtab + - Name: .foo + Type: SHT_PROGBITS + +## Check we can use the Offset key to place the section header table at a different location. + +# RUN: yaml2obj %s --docnum=10 -DOFFSET=0x1000 -o %t10.offset +# RUN: llvm-readelf --file-headers --sections %t10.offset | \ +# RUN: FileCheck %s --check-prefix=PLACE-BEFORE-OFFSET + +# PLACE-BEFORE-OFFSET: Start of section headers: 4096 (bytes into file) +# PLACE-BEFORE-OFFSET: Size of section headers: 64 (bytes) +# PLACE-BEFORE-OFFSET: Number of section headers: 4 + +# PLACE-BEFORE-OFFSET: Section Headers: +# PLACE-BEFORE-OFFSET: [Nr] Name Type Address Off Size +## 0x1100 == Start of section headers (0x1000) + Size of section headers (64) * Number of section headers (4); +# PLACE-BEFORE-OFFSET: [ 1] .foo PROGBITS 0000000000000000 001100 000000 + +## Check we can place the section header table somewhere in the middle of the sections list. + +# RUN: yaml2obj %s --docnum=11 -o %t11 +# RUN: llvm-readelf --sections %t11 | FileCheck %s --check-prefix=PLACE-AT-MIDDLE + +# PLACE-AT-MIDDLE: There are 5 section headers, starting at offset 0x140: +# PLACE-AT-MIDDLE: [Nr] Name Type Address Off Size +# PLACE-AT-MIDDLE: [ 1] .foo PROGBITS 0000000000000000 000040 000100 +## The section header table is placed here, at 0x40 + 0x100 == 0x140. +## The size of the table is 5 * 64 == 320 == 0x140. +## 0x140 + 0x140 == offset of the .bar section. +# PLACE-AT-MIDDLE-NEXT: [ 2] .bar PROGBITS 0000000000000000 000280 000200 +# PLACE-AT-MIDDLE-NEXT: [ 3] .strtab STRTAB 0000000000000000 000480 000001 +# PLACE-AT-MIDDLE-NEXT: [ 4] .shstrtab STRTAB 0000000000000000 000481 00001d + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .foo + Type: SHT_PROGBITS + Size: 0x100 + - Type: SectionHeaderTable + Sections: + - Name: .foo + - Name: .bar + - Name: .strtab + - Name: .shstrtab + - Name: .bar + Type: SHT_PROGBITS + Size: 0x200 + +## Check we don`t allow having multiple SectionHeaderTable chunks. + +# RUN: not yaml2obj %s --docnum=12 -o /dev/null 2>&1 | FileCheck %s --check-prefix=MULTIPLE + +# MULTIPLE: error: multiple section header tables are not allowed + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Type: SectionHeaderTable + Sections: [] + - Type: SectionHeaderTable + Sections: [] + +## Check that we place implicit sections before the section header table +## when it is placed at the end explicitly. + +# RUN: yaml2obj %s --docnum=13 -o %t13 +# RUN: llvm-readelf --sections %t13 | FileCheck %s --check-prefix=IMPLICIT + +# IMPLICIT: There are 3 section headers, starting at offset 0x58: +# IMPLICIT: [Nr] Name Type Address Off Size +# IMPLICIT: [ 1] .strtab STRTAB 0000000000000000 000040 000001 +# IMPLICIT-NEXT: [ 2] .shstrtab STRTAB 0000000000000000 000041 000013 +## The section header table is placed here, at 0x58. +## alignTo(8, 0x41 + 0x13) == 0x58. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Type: SectionHeaderTable + Sections: + - Name: .strtab + - Name: .shstrtab diff --git a/llvm/test/tools/yaml2obj/ELF/verdef-section.yaml b/llvm/test/tools/yaml2obj/ELF/verdef-section.yaml --- a/llvm/test/tools/yaml2obj/ELF/verdef-section.yaml +++ b/llvm/test/tools/yaml2obj/ELF/verdef-section.yaml @@ -241,10 +241,10 @@ Type: SHT_GNU_verdef - Name: .dynstr Type: SHT_STRTAB -SectionHeaderTable: - Sections: - - Name: .gnu.version_d - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .dynstr + - Type: SectionHeaderTable + Sections: + - Name: .gnu.version_d + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .dynstr diff --git a/llvm/test/tools/yaml2obj/ELF/verneed-section.yaml b/llvm/test/tools/yaml2obj/ELF/verneed-section.yaml --- a/llvm/test/tools/yaml2obj/ELF/verneed-section.yaml +++ b/llvm/test/tools/yaml2obj/ELF/verneed-section.yaml @@ -182,10 +182,10 @@ Type: SHT_GNU_verneed - Name: .dynstr Type: SHT_STRTAB -SectionHeaderTable: - Sections: - - Name: .gnu.version_r - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .dynstr + - Type: SectionHeaderTable + Sections: + - Name: .gnu.version_r + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .dynstr diff --git a/llvm/test/tools/yaml2obj/ELF/versym-section.yaml b/llvm/test/tools/yaml2obj/ELF/versym-section.yaml --- a/llvm/test/tools/yaml2obj/ELF/versym-section.yaml +++ b/llvm/test/tools/yaml2obj/ELF/versym-section.yaml @@ -194,10 +194,10 @@ Type: SHT_GNU_versym - Name: .dynsym Type: SHT_DYNSYM -SectionHeaderTable: - Sections: - - Name: .gnu.version - - Name: .strtab - - Name: .shstrtab - Excluded: - - Name: .dynsym + - Type: SectionHeaderTable + Sections: + - Name: .gnu.version + - Name: .strtab + - Name: .shstrtab + Excluded: + - Name: .dynsym diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -382,13 +382,18 @@ cast(B.get())->OriginalSecNdx; }); if (!SectionsSorted) { - Y->SectionHeaders.emplace(); - Y->SectionHeaders->Sections.emplace(); + std::unique_ptr SHT = + std::make_unique(/*IsImplicit=*/false); + SHT->Sections.emplace(); for (ELFYAML::Section *S : OriginalOrder) - Y->SectionHeaders->Sections->push_back({S->Name}); + SHT->Sections->push_back({S->Name}); + Chunks.push_back(std::move(SHT)); } llvm::erase_if(Chunks, [this, &Y](const std::unique_ptr &C) { + if (isa(*C.get())) + return false; + const ELFYAML::Section &S = cast(*C.get()); return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF); });