forked from OSchip/llvm-project
[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:
parent
d283fc4f9d
commit
ad07d5f394
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue