1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[yaml2obj][ELF] Add support for program headers

This change adds basic support for program headers.

I need to do some testing which requires generating program headers but
I can't use ld.lld or clang to produce programs that have headers. I'd
also like to test some strange things that those programs may never
produce.

Patch by Jake Ehrlich

Differential Revision: https://reviews.llvm.org/D35276

llvm-svn: 308520
This commit is contained in:
Petr Hosek 2017-07-19 20:38:46 +00:00
parent 992aad1a5d
commit 5fac88383c
5 changed files with 270 additions and 5 deletions

View File

@ -37,12 +37,14 @@ namespace ELFYAML {
// In the future, these would probably be better suited by C++11 enum
// class's with appropriate fixed underlying type.
LLVM_YAML_STRONG_TYPEDEF(uint16_t, ELF_ET)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_PT)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_EM)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFCLASS)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFDATA)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFOSABI)
// Just use 64, since it can hold 32-bit values too.
LLVM_YAML_STRONG_TYPEDEF(uint64_t, ELF_EF)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_PF)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_SHT)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_REL)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_RSS)
@ -71,6 +73,18 @@ struct FileHeader {
llvm::yaml::Hex64 Entry;
};
struct SectionName {
StringRef Section;
};
struct ProgramHeader {
ELF_PT Type;
ELF_PF Flags;
llvm::yaml::Hex64 VAddr;
llvm::yaml::Hex64 PAddr;
std::vector<SectionName> Sections;
};
struct Symbol {
StringRef Name;
ELF_STT Type;
@ -183,6 +197,7 @@ struct MipsABIFlags : Section {
struct Object {
FileHeader Header;
std::vector<ProgramHeader> ProgramHeaders;
std::vector<std::unique_ptr<Section>> Sections;
// Although in reality the symbols reside in a section, it is a lot
// cleaner and nicer if we read them from the YAML as a separate
@ -194,10 +209,12 @@ struct Object {
} // end namespace ELFYAML
} // end namespace llvm
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Section>)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionOrType)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName)
namespace llvm {
namespace yaml {
@ -207,6 +224,10 @@ struct ScalarEnumerationTraits<ELFYAML::ELF_ET> {
static void enumeration(IO &IO, ELFYAML::ELF_ET &Value);
};
template <> struct ScalarEnumerationTraits<ELFYAML::ELF_PT> {
static void enumeration(IO &IO, ELFYAML::ELF_PT &Value);
};
template <>
struct ScalarEnumerationTraits<ELFYAML::ELF_EM> {
static void enumeration(IO &IO, ELFYAML::ELF_EM &Value);
@ -232,6 +253,10 @@ struct ScalarBitSetTraits<ELFYAML::ELF_EF> {
static void bitset(IO &IO, ELFYAML::ELF_EF &Value);
};
template <> struct ScalarBitSetTraits<ELFYAML::ELF_PF> {
static void bitset(IO &IO, ELFYAML::ELF_PF &Value);
};
template <>
struct ScalarEnumerationTraits<ELFYAML::ELF_SHT> {
static void enumeration(IO &IO, ELFYAML::ELF_SHT &Value);
@ -302,6 +327,10 @@ struct MappingTraits<ELFYAML::FileHeader> {
static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr);
};
template <> struct MappingTraits<ELFYAML::ProgramHeader> {
static void mapping(IO &IO, ELFYAML::ProgramHeader &FileHdr);
};
template <>
struct MappingTraits<ELFYAML::Symbol> {
static void mapping(IO &IO, ELFYAML::Symbol &Symbol);
@ -331,6 +360,10 @@ template <> struct MappingTraits<ELFYAML::SectionOrType> {
static void mapping(IO &IO, ELFYAML::SectionOrType &sectionOrType);
};
template <> struct MappingTraits<ELFYAML::SectionName> {
static void mapping(IO &IO, ELFYAML::SectionName &sectionName);
};
} // end namespace yaml
} // end namespace llvm

View File

@ -39,6 +39,21 @@ void ScalarEnumerationTraits<ELFYAML::ELF_ET>::enumeration(
IO.enumFallback<Hex16>(Value);
}
void ScalarEnumerationTraits<ELFYAML::ELF_PT>::enumeration(
IO &IO, ELFYAML::ELF_PT &Value) {
#define ECase(X) IO.enumCase(Value, #X, ELF::X)
ECase(PT_NULL);
ECase(PT_LOAD);
ECase(PT_DYNAMIC);
ECase(PT_INTERP);
ECase(PT_NOTE);
ECase(PT_SHLIB);
ECase(PT_PHDR);
ECase(PT_TLS);
#undef ECase
IO.enumFallback<Hex32>(Value);
}
void ScalarEnumerationTraits<ELFYAML::ELF_EM>::enumeration(
IO &IO, ELFYAML::ELF_EM &Value) {
#define ECase(X) IO.enumCase(Value, #X, ELF::X)
@ -412,6 +427,14 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration(
#undef ECase
}
void ScalarBitSetTraits<ELFYAML::ELF_PF>::bitset(IO &IO,
ELFYAML::ELF_PF &Value) {
#define BCase(X) IO.bitSetCase(Value, #X, ELF::X)
BCase(PF_X);
BCase(PF_W);
BCase(PF_R);
}
void ScalarBitSetTraits<ELFYAML::ELF_SHF>::bitset(IO &IO,
ELFYAML::ELF_SHF &Value) {
const auto *Object = static_cast<ELFYAML::Object *>(IO.getContext());
@ -649,6 +672,15 @@ void MappingTraits<ELFYAML::FileHeader>::mapping(IO &IO,
IO.mapOptional("Entry", FileHdr.Entry, Hex64(0));
}
void MappingTraits<ELFYAML::ProgramHeader>::mapping(
IO &IO, ELFYAML::ProgramHeader &Phdr) {
IO.mapRequired("Type", Phdr.Type);
IO.mapOptional("Flags", Phdr.Flags, ELFYAML::ELF_PF(0));
IO.mapOptional("Sections", Phdr.Sections);
IO.mapOptional("VAddr", Phdr.VAddr, Hex64(0));
IO.mapOptional("PAddr", Phdr.PAddr, Hex64(0));
}
namespace {
struct NormalizedOther {
@ -720,6 +752,11 @@ void MappingTraits<ELFYAML::SectionOrType>::mapping(
IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
}
void MappingTraits<ELFYAML::SectionName>::mapping(
IO &IO, ELFYAML::SectionName &sectionName) {
IO.mapRequired("Section", sectionName.Section);
}
static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) {
commonSectionMapping(IO, Section);
IO.mapOptional("Version", Section.Version, Hex16(0));
@ -837,6 +874,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("ProgramHeaders", Object.ProgramHeaders);
IO.mapOptional("Sections", Object.Sections);
IO.mapOptional("Symbols", Object.Symbols);
IO.setContext(nullptr);

View File

@ -0,0 +1,39 @@
# RUN: yaml2obj %s -o %t
# RUN: llvm-readobj -program-headers %t | FileCheck %s
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .data
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Content: "00000000"
- Name: .after
Type: SHT_NOBITS
Flags: [ SHF_ALLOC ]
Size: 64
ProgramHeaders:
- Type: PT_LOAD
Flags: [ PF_R ]
Sections:
- Section: .data
- Section: .after
#CHECK: ProgramHeaders [
#CHECK-NEXT: ProgramHeader {
#CHECK-NEXT: Type: PT_LOAD
#CHECK-NEXT: Offset:
#CHECK-NEXT: VirtualAddress:
#CHECK-NEXT: PhysicalAddress:
#CHECK-NEXT: FileSize: 4
#CHECK-NEXT: MemSize: 68
#CHECK-NEXT: Flags [
#CHECK-NEXT: PF_R
#CHECK-NEXT: ]
#CHECK-NEXT: Alignment:
#CHECK-NEXT: }
#CHECK-NEXT:]

View File

@ -0,0 +1,67 @@
# RUN: yaml2obj %s -o %t
# RUN: llvm-readobj -program-headers %t | FileCheck %s
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x0000000000001000
Content: "00000000"
- Name: .init
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Content: "00000000"
AddressAlign: 0x0000000000000010
- Name: .data
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Content: "00000000"
AddressAlign: 0x0000000000001000
ProgramHeaders:
- Type: PT_LOAD
Flags: [ PF_X, PF_R ]
VAddr: 0xAAAA1000
PAddr: 0xFFFF1000
Sections:
- Section: .text
- Section: .init
- Type: PT_LOAD
Flags: [ PF_R ]
VAddr: 0xAAAA2000
PAddr: 0xFFFF2000
Sections:
- Section: .data
#CHECK: ProgramHeaders [
#CHECK-NEXT: ProgramHeader {
#CHECK-NEXT: Type: PT_LOAD
#CHECK-NEXT: Offset: 0x1000
#CHECK-NEXT: VirtualAddress: 0xAAAA1000
#CHECK-NEXT: PhysicalAddress: 0xFFFF1000
#CHECK-NEXT: FileSize: 20
#CHECK-NEXT: MemSize: 20
#CHECK-NEXT: Flags [
#CHECK-NEXT: PF_R
#CHECK-NEXT: PF_X
#CHECK-NEXT: ]
#CHECK-NEXT: Alignment: 4096
#CHECK-NEXT: }
#CHECK-NEXT: ProgramHeader {
#CHECK-NEXT: Type: PT_LOAD
#CHECK-NEXT: Offset: 0x2000
#CHECK-NEXT: VirtualAddress: 0xAAAA2000
#CHECK-NEXT: PhysicalAddress: 0xFFFF2000
#CHECK-NEXT: FileSize: 4
#CHECK-NEXT: MemSize: 4
#CHECK-NEXT: Flags [
#CHECK-NEXT: PF_R
#CHECK-NEXT: ]
#CHECK-NEXT: Alignment: 4096
#CHECK-NEXT: }
#CHECK-NEXT:]

View File

@ -99,6 +99,7 @@ namespace {
template <class ELFT>
class ELFState {
typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
typedef typename object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
@ -118,6 +119,7 @@ class ELFState {
bool buildSymbolIndex(std::size_t &StartIndex,
const std::vector<ELFYAML::Symbol> &Symbols);
void initELFHeader(Elf_Ehdr &Header);
void initProgramHeaders(std::vector<Elf_Phdr> &PHeaders);
bool initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
ContiguousBlobAccumulator &CBA);
void initSymtabSectionHeader(Elf_Shdr &SHeader,
@ -125,6 +127,8 @@ class ELFState {
void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name,
StringTableBuilder &STB,
ContiguousBlobAccumulator &CBA);
void setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
std::vector<Elf_Shdr> &SHeaders);
void addSymbols(const std::vector<ELFYAML::Symbol> &Symbols,
std::vector<Elf_Sym> &Syms, unsigned SymbolBinding);
void writeSectionContent(Elf_Shdr &SHeader,
@ -173,15 +177,31 @@ void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) {
Header.e_machine = Doc.Header.Machine;
Header.e_version = EV_CURRENT;
Header.e_entry = Doc.Header.Entry;
Header.e_phoff = sizeof(Header);
Header.e_flags = Doc.Header.Flags;
Header.e_ehsize = sizeof(Elf_Ehdr);
Header.e_phentsize = sizeof(Elf_Phdr);
Header.e_phnum = Doc.ProgramHeaders.size();
Header.e_shentsize = sizeof(Elf_Shdr);
// Immediately following the ELF header.
Header.e_shoff = sizeof(Header);
// Immediately following the ELF header and program headers.
Header.e_shoff =
sizeof(Header) + sizeof(Elf_Phdr) * Doc.ProgramHeaders.size();
Header.e_shnum = getSectionCount();
Header.e_shstrndx = getDotShStrTabSecNo();
}
template <class ELFT>
void ELFState<ELFT>::initProgramHeaders(std::vector<Elf_Phdr> &PHeaders) {
for (const auto &YamlPhdr : Doc.ProgramHeaders) {
Elf_Phdr Phdr;
Phdr.p_type = YamlPhdr.Type;
Phdr.p_flags = YamlPhdr.Flags;
Phdr.p_vaddr = YamlPhdr.VAddr;
Phdr.p_paddr = YamlPhdr.PAddr;
PHeaders.push_back(Phdr);
}
}
template <class ELFT>
bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
ContiguousBlobAccumulator &CBA) {
@ -310,6 +330,67 @@ void ELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name,
SHeader.sh_addralign = 1;
}
template <class ELFT>
void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
std::vector<Elf_Shdr> &SHeaders) {
uint32_t PhdrIdx = 0;
for (auto &YamlPhdr : Doc.ProgramHeaders) {
auto &PHeader = PHeaders[PhdrIdx++];
if (YamlPhdr.Sections.size())
PHeader.p_offset = UINT32_MAX;
else
PHeader.p_offset = 0;
// Find the minimum offset for the program header.
for (auto SecName : YamlPhdr.Sections) {
uint32_t Index = 0;
SN2I.lookup(SecName.Section, Index);
const auto &SHeader = SHeaders[Index];
PHeader.p_offset = std::min(PHeader.p_offset, SHeader.sh_offset);
}
// Find the maximum offset of the end of a section in order to set p_filesz.
PHeader.p_filesz = 0;
for (auto SecName : YamlPhdr.Sections) {
uint32_t Index = 0;
SN2I.lookup(SecName.Section, Index);
const auto &SHeader = SHeaders[Index];
uint64_t EndOfSection;
if (SHeader.sh_type == llvm::ELF::SHT_NOBITS)
EndOfSection = SHeader.sh_offset;
else
EndOfSection = SHeader.sh_offset + SHeader.sh_size;
uint64_t EndOfSegment = PHeader.p_offset + PHeader.p_filesz;
EndOfSegment = std::max(EndOfSegment, EndOfSection);
PHeader.p_filesz = EndOfSegment - PHeader.p_offset;
}
// Find the memory size by adding the size of sections at the end of the
// segment. These should be empty (size of zero) and NOBITS sections.
PHeader.p_memsz = PHeader.p_filesz;
for (auto SecName : YamlPhdr.Sections) {
uint32_t Index = 0;
SN2I.lookup(SecName.Section, Index);
const auto &SHeader = SHeaders[Index];
if (SHeader.sh_offset == PHeader.p_offset + PHeader.p_filesz)
PHeader.p_memsz += SHeader.sh_size;
}
// Set the alignment of the segment to be the same as the maximum alignment
// of the the sections with the same offset so that by default the segment
// has a valid and sensible alignment.
PHeader.p_align = 1;
for (auto SecName : YamlPhdr.Sections) {
uint32_t Index = 0;
SN2I.lookup(SecName.Section, Index);
const auto &SHeader = SHeaders[Index];
if (SHeader.sh_offset == PHeader.p_offset)
PHeader.p_align = std::max(PHeader.p_align, SHeader.sh_addralign);
}
}
}
template <class ELFT>
void ELFState<ELFT>::addSymbols(const std::vector<ELFYAML::Symbol> &Symbols,
std::vector<Elf_Sym> &Syms,
@ -508,12 +589,15 @@ int ELFState<ELFT>::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) {
State.initELFHeader(Header);
// TODO: Flesh out section header support.
// TODO: Program headers.
std::vector<Elf_Phdr> PHeaders;
State.initProgramHeaders(PHeaders);
// XXX: This offset is tightly coupled with the order that we write
// things to `OS`.
const size_t SectionContentBeginOffset =
Header.e_ehsize + Header.e_shentsize * Header.e_shnum;
const size_t SectionContentBeginOffset = Header.e_ehsize +
Header.e_phentsize * Header.e_phnum +
Header.e_shentsize * Header.e_shnum;
ContiguousBlobAccumulator CBA(SectionContentBeginOffset);
// Doc might not contain .symtab, .strtab and .shstrtab sections,
@ -543,7 +627,11 @@ int ELFState<ELFT>::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) {
CBA);
SHeaders.push_back(ShStrTabSHeader);
// Now we can decide segment offsets
State.setProgramHeaderLayout(PHeaders, SHeaders);
OS.write((const char *)&Header, sizeof(Header));
writeArrayData(OS, makeArrayRef(PHeaders));
writeArrayData(OS, makeArrayRef(SHeaders));
CBA.writeBlobToStream(OS);
return 0;