This was discussed in D93678 thread.
Currently we have one special chunk - Fill.
This patch re implements the "SectionHeaderTable" key to become a special chunk too.
With that we are able to place the section header table at any location,
just like we place sections.
Differential revision: https://reviews.llvm.org/D95140
StringRef Name;
};
-struct SectionHeaderTable {
- Optional<std::vector<SectionHeader>> Sections;
- Optional<std::vector<SectionHeader>> Excluded;
- Optional<bool> NoHeaders;
-};
-
struct Symbol {
StringRef Name;
ELF_STT Type;
ARMIndexTable,
MipsABIFlags,
Addrsig,
- Fill,
LinkerOptions,
DependentLibraries,
CallGraphProfile,
- BBAddrMap
+ BBAddrMap,
+
+ // Special chunks.
+ SpecialChunksStart,
+ Fill = SpecialChunksStart,
+ SectionHeaderTable,
};
ChunkKind Kind;
StringRef Name;
Optional<llvm::yaml::Hex64> 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();
};
Optional<yaml::BinaryRef> Content;
Optional<llvm::yaml::Hex64> 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 <entry name, is used> pairs. It is used for section
Optional<yaml::BinaryRef> 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<std::vector<SectionHeader>> Sections;
+ Optional<std::vector<SectionHeader>> Excluded;
+ Optional<bool> 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<std::vector<BBAddrMapEntry>> Entries;
struct Object {
FileHeader Header;
- Optional<SectionHeaderTable> SectionHeaders;
std::vector<ProgramHeader> ProgramHeaders;
// An object might contain output section descriptions as well as
return Ret;
}
+ const SectionHeaderTable &getSectionHeaderTable() const {
+ for (const std::unique_ptr<Chunk> &C : Chunks)
+ if (auto *S = dyn_cast<ELFYAML::SectionHeaderTable>(C.get()))
+ return *S;
+ llvm_unreachable("the section header table chunk must always be present");
+ }
+
unsigned getMachine() const;
};
static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr);
};
-template <> struct MappingTraits<ELFYAML::SectionHeaderTable> {
- static void mapping(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable);
- static std::string validate(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable);
-};
-
template <> struct MappingTraits<ELFYAML::SectionHeader> {
static void mapping(IO &IO, ELFYAML::SectionHeader &SHdr);
};
if (checkLimit(sizeof(T)))
support::endian::write<T>(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
ArrayRef<typename ELFT::Shdr> SHeaders);
void finalizeStrings();
- void writeELFHeader(raw_ostream &OS, Optional<uint64_t> SHOff);
+ void writeELFHeader(raw_ostream &OS);
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::NoBitsSection &Section,
ContiguousBlobAccumulator &CBA);
std::make_unique<ELFYAML::Section>(
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<ELFYAML::Chunk> &C = Doc.Chunks[I];
+
+ // We might have an explicit section header table declaration.
+ if (auto S = dyn_cast<ELFYAML::SectionHeaderTable>(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));
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
std::unique_ptr<ELFYAML::Chunk> Sec = std::make_unique<ELFYAML::Section>(
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<ELFYAML::SectionHeaderTable>(/*IsImplicit=*/true));
}
template <class ELFT>
-void ELFState<ELFT>::writeELFHeader(raw_ostream &OS, Optional<uint64_t> SHOff) {
+void ELFState<ELFT>::writeELFHeader(raw_ostream &OS) {
using namespace llvm::ELF;
Elf_Ehdr Header;
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;
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 +
continue;
}
+ if (ELFYAML::SectionHeaderTable *S =
+ dyn_cast<ELFYAML::SectionHeaderTable>(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<ELFYAML::Section>(D.get());
- bool IsFirstUndefSection = D == Doc.Chunks.front();
+ bool IsFirstUndefSection = Sec == Doc.getSections().front();
if (IsFirstUndefSection && Sec->IsImplicit)
continue;
template <class ELFT>
DenseMap<StringRef, size_t> ELFState<ELFT>::buildSectionHeaderReorderMap() {
- if (!Doc.SectionHeaders || Doc.SectionHeaders->NoHeaders)
+ const ELFYAML::SectionHeaderTable &SectionHeaders =
+ Doc.getSectionHeaderTable();
+ if (SectionHeaders.IsImplicit || SectionHeaders.NoHeaders)
return DenseMap<StringRef, size_t>();
DenseMap<StringRef, size_t> Ret;
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()) {
// Build excluded section headers map.
std::vector<ELFYAML::Section *> 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) {
// 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<uint64_t> 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));
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;
}
IO.mapRequired("Name", SHdr.Name);
}
-void MappingTraits<ELFYAML::SectionHeaderTable>::mapping(
- IO &IO, ELFYAML::SectionHeaderTable &SectionHeader) {
- IO.mapOptional("Sections", SectionHeader.Sections);
- IO.mapOptional("Excluded", SectionHeader.Excluded);
- IO.mapOptional("NoHeaders", SectionHeader.NoHeaders);
-}
-
-std::string MappingTraits<ELFYAML::SectionHeaderTable>::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<ELFYAML::FileHeader>::mapping(IO &IO,
ELFYAML::FileHeader &FileHdr) {
IO.mapRequired("Class", FileHdr.Class);
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);
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<std::unique_ptr<ELFYAML::Chunk>>::mapping(
IO &IO, std::unique_ptr<ELFYAML::Chunk> &Section) {
ELFYAML::ELF_SHT Type;
+ StringRef TypeStr;
if (IO.outputting()) {
- Type = cast<ELFYAML::Section>(Section.get())->Type;
+ if (auto *S = dyn_cast<ELFYAML::Section>(Section.get()))
+ Type = S->Type;
+ else if (auto *SHT = dyn_cast<ELFYAML::SectionHeaderTable>(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<ELFYAML::Fill>(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<ELFYAML::Fill>(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<ELFYAML::SectionHeaderTable>(Section.get()));
+ return;
}
const auto &Obj = *static_cast<ELFYAML::Object *>(IO.getContext());
return "";
}
+ if (const auto *SHT = dyn_cast<ELFYAML::SectionHeaderTable>(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<ELFYAML::Section>(C.get());
if (Sec.Size && Sec.Content &&
(uint64_t)(*Sec.Size) < Sec.Content->binary_size())
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);
# 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
# 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
# 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
# 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
Flags: [ SHF_ALLOC ]
Address: 0x300
Offset: 0x300
+ - Type: SectionHeaderTable
+ NoHeaders: true
DynamicSymbols:
- Name: foo
ProgramHeaders:
- Type: PT_DYNAMIC
FirstSec: .dynamic
LastSec: .dynamic
-SectionHeaderTable:
- NoHeaders: true
Value: 0x0
- Name: .dynsym
Type: SHT_DYNSYM
+ - Type: SectionHeaderTable
+ NoHeaders: true
DynamicSymbols:
- Name: foo
ProgramHeaders:
- Type: PT_DYNAMIC
FirstSec: .dynamic
LastSec: .dynamic
-SectionHeaderTable:
- NoHeaders: true
## 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.
Value: 0x0
- Tag: DT_NULL
Value: 0x0
-SectionHeaderTable:
- NoHeaders: [[NOHEADERS=false]]
+ - Type: SectionHeaderTable
+ NoHeaders: [[NOHEADERS=false]]
ProgramHeaders:
- Type: PT_LOAD
FirstSec: .hash
Entries:
- Tag: DT_NULL
Value: 0
+ - Type: SectionHeaderTable
+ NoHeaders: [[NOHEADERS=false]]
ProgramHeaders:
- Type: PT_DYNAMIC
FileSize: [[FILESIZE=<none>]]
FirstSec: .dynamic
LastSec: .dynamic
-SectionHeaderTable:
- NoHeaders: [[NOHEADERS=false]]
Entries: [ 0, 1 ]
Offset: 0x2000
Address: 0x2000
+ - Type: SectionHeaderTable
+ NoHeaders: true
DynamicSymbols:
- Name: dynsym1
Index: SHN_XINDEX
VAddr: 0x1000
FirstSec: .dynamic
LastSec: .dynamic
-SectionHeaderTable:
- NoHeaders: true
# 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
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.
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.
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.
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
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
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.
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
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
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.
- 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.
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.
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 | \
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.
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.
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.
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.
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:
- 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.
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: []
- 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"
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
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.
# 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:
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
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.
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.
- 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
## 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=<none>]]
+ 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
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
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
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
cast<ELFYAML::Section>(B.get())->OriginalSecNdx;
});
if (!SectionsSorted) {
- Y->SectionHeaders.emplace();
- Y->SectionHeaders->Sections.emplace();
+ std::unique_ptr<ELFYAML::SectionHeaderTable> SHT =
+ std::make_unique<ELFYAML::SectionHeaderTable>(/*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<ELFYAML::Chunk> &C) {
+ if (isa<ELFYAML::SectionHeaderTable>(*C.get()))
+ return false;
+
const ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF);
});