Optional<llvm::yaml::Hex16> SHStrNdx;
};
+struct SectionHeader {
+ StringRef Name;
+};
+
+struct SectionHeaderTable {
+ std::vector<SectionHeader> Sections;
+};
+
struct SectionName {
StringRef Section;
};
struct Object {
FileHeader Header;
+ Optional<SectionHeaderTable> SectionHeaders;
std::vector<ProgramHeader> ProgramHeaders;
// An object might contain output section descriptions as well as
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::CallGraphEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::NoteEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionHeader)
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Chunk>)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerdefEntry)
static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr);
};
+template <> struct MappingTraits<ELFYAML::SectionHeaderTable> {
+ static void mapping(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable);
+};
+
+template <> struct MappingTraits<ELFYAML::SectionHeader> {
+ static void mapping(IO &IO, ELFYAML::SectionHeader &SHdr);
+};
+
template <> struct MappingTraits<ELFYAML::ProgramHeader> {
static void mapping(IO &IO, ELFYAML::ProgramHeader &FileHdr);
};
void assignSectionAddress(Elf_Shdr &SHeader, ELFYAML::Section *YAMLSec);
+ DenseMap<StringRef, size_t> buildSectionHeaderReorderMap();
+
BumpPtrAllocator StringAlloc;
uint64_t alignToOffset(ContiguousBlobAccumulator &CBA, uint64_t Align,
llvm::Optional<llvm::yaml::Hex64> Offset);
// other sections to the end of the file.
uint64_t SHOff =
alignToOffset(CBA, sizeof(typename ELFT::uint), /*Offset=*/None);
- Header.e_shoff =
- Doc.Header.SHOff ? typename ELFT::uint(*Doc.Header.SHOff) : SHOff;
- Header.e_shnum =
- Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : Doc.getSections().size();
- Header.e_shstrndx = Doc.Header.SHStrNdx ? (uint16_t)*Doc.Header.SHStrNdx
- : SN2I.get(".shstrtab");
+
+ if (Doc.Header.SHOff)
+ Header.e_shoff = *Doc.Header.SHOff;
+ else if (Doc.SectionHeaders && Doc.SectionHeaders->Sections.empty())
+ Header.e_shoff = 0;
+ else
+ Header.e_shoff = SHOff;
+
+ if (Doc.Header.SHNum)
+ Header.e_shnum = *Doc.Header.SHNum;
+ else if (!Doc.SectionHeaders)
+ Header.e_shnum = Doc.getSections().size();
+ else if (Doc.SectionHeaders->Sections.empty())
+ Header.e_shnum = 0;
+ else
+ Header.e_shnum = Doc.SectionHeaders->Sections.size() + /*Null section*/ 1;
+
+ if (Doc.Header.SHStrNdx)
+ Header.e_shstrndx = *Doc.Header.SHStrNdx;
+ else if (!Doc.SectionHeaders || !Doc.SectionHeaders->Sections.empty())
+ Header.e_shstrndx = SN2I.get(".shstrtab");
+ else
+ Header.e_shstrndx = 0;
OS.write((const char *)&Header, sizeof(Header));
}
Fill.Pattern->writeAsBinary(OS, Fill.Size - Written);
}
+template <class ELFT>
+DenseMap<StringRef, size_t> ELFState<ELFT>::buildSectionHeaderReorderMap() {
+ if (!Doc.SectionHeaders || Doc.SectionHeaders->Sections.empty())
+ return DenseMap<StringRef, size_t>();
+
+ DenseMap<StringRef, size_t> Ret;
+ size_t SecNdx = 0;
+ StringSet<> Seen;
+ for (const ELFYAML::SectionHeader &Hdr : Doc.SectionHeaders->Sections) {
+ if (!Ret.try_emplace(Hdr.Name, ++SecNdx).second)
+ reportError("repeated section name: '" + Hdr.Name +
+ "' in the section header description");
+ Seen.insert(Hdr.Name);
+ }
+
+ for (const ELFYAML::Section *S : Doc.getSections()) {
+ // Ignore special first SHT_NULL section.
+ if (S == Doc.getSections().front())
+ continue;
+ if (!Seen.count(S->Name))
+ reportError("section '" + S->Name +
+ "' should be present in the 'Sections' list");
+ Seen.erase(S->Name);
+ }
+
+ for (const auto &It : Seen)
+ reportError("section header contains undefined section '" + It.getKey() +
+ "'");
+ return Ret;
+}
+
template <class ELFT> void ELFState<ELFT>::buildSectionIndex() {
+ // A YAML description can have an explicit section header declaration that allows
+ // to change the order of section headers.
+ DenseMap<StringRef, size_t> ReorderMap = buildSectionHeaderReorderMap();
+
size_t SecNdx = -1;
for (const std::unique_ptr<ELFYAML::Chunk> &C : Doc.Chunks) {
if (!isa<ELFYAML::Section>(C.get()))
continue;
++SecNdx;
- if (!SN2I.addName(C->Name, SecNdx))
+ size_t Index = ReorderMap.empty() ? SecNdx : ReorderMap.lookup(C->Name);
+ if (!SN2I.addName(C->Name, Index))
llvm_unreachable("buildSectionIndex() failed");
DotShStrtab.add(ELFYAML::dropUniqueSuffix(C->Name));
}
#undef BCase
}
+void MappingTraits<ELFYAML::SectionHeader>::mapping(
+ IO &IO, ELFYAML::SectionHeader &SHdr) {
+ IO.mapRequired("Name", SHdr.Name);
+}
+
+void MappingTraits<ELFYAML::SectionHeaderTable>::mapping(
+ IO &IO, ELFYAML::SectionHeaderTable &SectionHeader) {
+ IO.mapRequired("Sections", SectionHeader.Sections);
+}
+
void MappingTraits<ELFYAML::FileHeader>::mapping(IO &IO,
ELFYAML::FileHeader &FileHdr) {
IO.mapRequired("Class", FileHdr.Class);
IO.setContext(&Object);
IO.mapTag("!ELF", true);
IO.mapRequired("FileHeader", Object.Header);
+ IO.mapOptional("SectionHeaderTable", Object.SectionHeaders);
IO.mapOptional("ProgramHeaders", Object.ProgramHeaders);
IO.mapOptional("Sections", Object.Chunks);
IO.mapOptional("Symbols", Object.Symbols);
--- /dev/null
+## Check we can use "SectionHeaderTable" tag to reorder section header entries.
+
+## This is a general test that has sections with unique prefixes, a fill and a
+## section without the unique prefix. The section header table describes sections
+## in the same order they are listed in the YAML.
+# RUN: yaml2obj %s --docnum=1 -o %t1 -DSEC1=".section (1)" -DSEC2=".section (2)" -DSEC3=".section.foo"
+# RUN: llvm-readelf --section-headers %t1 | FileCheck %s --check-prefix=NO-OP
+
+# NO-OP: Section Headers:
+# NO-OP-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
+# NO-OP-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
+# NO-OP-NEXT: [ 1] .section PROGBITS 0000000000000000 000040 000010 00 0 0 0
+# NO-OP-NEXT: [ 2] .section PROGBITS 0000000000000000 000050 000020 00 0 0 0
+# NO-OP-NEXT: [ 3] .section.foo PROGBITS 0000000000000000 0000a0 000040 00 0 0 0
+# NO-OP-NEXT: [ 4] .strtab STRTAB 0000000000000000 0000e0 000001 00 0 0 1
+# NO-OP-NEXT: [ 5] .shstrtab STRTAB 0000000000000000 0000e1 000029 00 0 0 1
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .section (1)
+ Type: SHT_PROGBITS
+ Size: 0x10
+ - Name: .section (2)
+ Type: SHT_PROGBITS
+ Size: 0x20
+ - Type: Fill
+ Name: .filler
+ Size: 0x30
+ Pattern: ""
+ - Name: .section.foo
+ Type: SHT_PROGBITS
+ Size: 0x40
+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"
+# RUN: llvm-readelf --section-headers %t2 | FileCheck %s --check-prefix=REORDERED
+
+# REORDERED: Section Headers:
+# REORDERED-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
+# REORDERED-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
+# REORDERED-NEXT: [ 1] .section.foo PROGBITS 0000000000000000 0000a0 000040 00 0 0 0
+# REORDERED-NEXT: [ 2] .section PROGBITS 0000000000000000 000050 000020 00 0 0 0
+# REORDERED-NEXT: [ 3] .section PROGBITS 0000000000000000 000040 000010 00 0 0 0
+# REORDERED-NEXT: [ 4] .strtab STRTAB 0000000000000000 0000e0 000001 00 0 0 1
+# REORDERED-NEXT: [ 5] .shstrtab STRTAB 0000000000000000 0000e1 000029 00 0 0 1
+
+## Show we report proper errors when the section header description:
+## a) contains a repeated section name.
+## b) omits any section that exists.
+## c) contains a non-existent section.
+# RUN: not yaml2obj %s -o /dev/null -DSEC1=".section.foo" -DSEC2="unknown" -DSEC3=".section.foo" 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR1
+# d) contains a repeated implicit section name.
+# e) contains a fill name.
+# RUN: not yaml2obj %s -o /dev/null -DSEC1=".strtab" -DSEC2=".shstrtab" -DSEC3=".filler" 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR2
+
+# ERR1: error: repeated section name: '.section.foo' in the section header description
+# ERR1-NEXT: error: section '.section (1)' should be present in the 'Sections' list
+# ERR1-NEXT: error: section '.section (2)' should be present in the 'Sections' list
+# ERR1-NEXT: error: section header contains undefined section 'unknown'
+
+# ERR2: error: repeated section name: '.strtab' in the section header description
+# ERR2-NEXT: error: repeated section name: '.shstrtab' in the section header description
+# ERR2-NEXT: error: section '.section (1)' should be present in the 'Sections' list
+# ERR2-NEXT: error: section '.section (2)' should be present in the 'Sections' list
+# ERR2-NEXT: error: section '.section.foo' should be present in the 'Sections' list
+# ERR2-NEXT: error: section header contains undefined section '.filler'
+
+## Test that we are able to specify an empty sections list for
+## the "SectionHeaderTable" tag to produce no section header.
+# RUN: yaml2obj %s --docnum=2 -o %t3
+# RUN: llvm-readelf --file-headers %t3 | FileCheck %s --check-prefix=NO-HEADERS
+
+# NO-HEADERS: Start of section headers: 0 (bytes into file)
+# NO-HEADERS: Size of section headers: 64 (bytes)
+# NO-HEADERS: Number of section headers: 0
+# NO-HEADERS: Section header string table index: 0
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .foo
+ Type: SHT_PROGBITS
+SectionHeaderTable:
+ Sections: []
+
+## Test that we are still able to override e_shoff, e_shnum and e_shstrndx
+## fields even when we do not produce section headers.
+# RUN: yaml2obj %s --docnum=3 -o %t4
+# RUN: llvm-readelf --file-headers %t4 | FileCheck %s --check-prefix=NO-HEADERS-OVERRIDE
+
+# NO-HEADERS-OVERRIDE: Start of section headers: 2 (bytes into file)
+# NO-HEADERS-OVERRIDE: Number of section headers: 3
+# NO-HEADERS-OVERRIDE: Section header string table index: 4
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+ SHOff: 0x2
+ SHNum: 0x3
+ SHStrNdx: 0x4
+Sections:
+ - Name: .foo
+ Type: SHT_PROGBITS
+SectionHeaderTable:
+ Sections: []
+
+## Check that section indices are updated properly in other places when we
+## reorder sections in the section header table.
+# RUN: yaml2obj %s --docnum=4 -o %t5 -DSEC1=".foo" -DSEC2=".bar"
+# RUN: llvm-readelf --section-headers --symbols %t5 | FileCheck %s --check-prefix=INDICES-A
+# RUN: yaml2obj %s --docnum=4 -o %t6 -DSEC2=".foo" -DSEC1=".bar"
+# RUN: llvm-readelf --section-headers --symbols %t6 | FileCheck %s --check-prefix=INDICES-B
+
+# INDICES-A: [Nr] Name Type Address Off Size ES Flg Lk
+# INDICES-A: [ 1] .foo PROGBITS 0000000000000000 000040 000000 00 0
+# INDICES-A-NEXT: [ 2] .bar PROGBITS 0000000000000000 000040 000000 00 0
+# INDICES-A-NEXT: [ 3] .another.1 PROGBITS 0000000000000000 000040 000000 00 1
+# INDICES-A-NEXT: [ 4] .another.2 PROGBITS 0000000000000000 000040 000000 00 2
+
+# INDICES-A: Num: Value Size Type Bind Vis Ndx Name
+# INDICES-A: 1: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 foo
+# INDICES-A-NEXT: 2: 0000000000000000 0 NOTYPE LOCAL DEFAULT 2 bar
+
+# INDICES-B: [ 1] .bar PROGBITS 0000000000000000 000040 000000 00 0
+# INDICES-B-NEXT: [ 2] .foo PROGBITS 0000000000000000 000040 000000 00 0
+# INDICES-B-NEXT: [ 3] .another.1 PROGBITS 0000000000000000 000040 000000 00 2
+# INDICES-B-NEXT: [ 4] .another.2 PROGBITS 0000000000000000 000040 000000 00 1
+
+# INDICES-B: Num: Value Size Type Bind Vis Ndx Name
+# INDICES-B: 1: 0000000000000000 0 NOTYPE LOCAL DEFAULT 2 foo
+# INDICES-B-NEXT: 2: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 bar
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .foo
+ Type: SHT_PROGBITS
+ - Name: .bar
+ Type: SHT_PROGBITS
+ - Name: .another.1
+ Link: .foo
+ Type: SHT_PROGBITS
+ - 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
+Symbols:
+ - Name: foo
+ Section: .foo
+ - Name: bar
+ Section: .bar