[yaml2obj] - Implement the "SectionHeaderTable" tag.

With the "SectionHeaderTable" it is now possible to reorder
entries in the section header table.

It also allows to stop emitting the table.

Differential revision: https://reviews.llvm.org/D80002
This commit is contained in:
Georgii Rymar 2020-05-14 14:15:40 +03:00
parent d283fc4f9d
commit ad07d5f394
4 changed files with 275 additions and 7 deletions

View File

@ -86,6 +86,14 @@ struct FileHeader {
Optional<llvm::yaml::Hex16> SHStrNdx;
};
struct SectionHeader {
StringRef Name;
};
struct SectionHeaderTable {
std::vector<SectionHeader> Sections;
};
struct SectionName {
StringRef Section;
};
@ -508,6 +516,7 @@ struct ProgramHeader {
struct Object {
FileHeader Header;
Optional<SectionHeaderTable> SectionHeaders;
std::vector<ProgramHeader> ProgramHeaders;
// An object might contain output section descriptions as well as
@ -539,6 +548,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::LinkerOption)
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)
@ -670,6 +680,14 @@ struct MappingTraits<ELFYAML::FileHeader> {
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);
};

View File

@ -218,6 +218,8 @@ template <class ELFT> class ELFState {
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);
@ -318,12 +320,29 @@ void ELFState<ELFT>::writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream
// 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));
}
@ -1447,14 +1466,50 @@ void ELFState<ELFT>::writeFill(ELFYAML::Fill &Fill,
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));
}

View File

@ -832,6 +832,16 @@ void ScalarBitSetTraits<ELFYAML::MIPS_AFL_FLAGS1>::bitset(
#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);
@ -1638,6 +1648,7 @@ void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
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);

View File

@ -0,0 +1,184 @@
## 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