[llvm] r308520 - [yaml2obj][ELF] Add support for program headers
Petr Hosek via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 19 13:38:46 PDT 2017
Author: phosek
Date: Wed Jul 19 13:38:46 2017
New Revision: 308520
URL: http://llvm.org/viewvc/llvm-project?rev=308520&view=rev
Log:
[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
Added:
llvm/trunk/test/tools/yaml2obj/program-header-nobits.yaml
llvm/trunk/test/tools/yaml2obj/program-header.yaml
Modified:
llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h
llvm/trunk/lib/ObjectYAML/ELFYAML.cpp
llvm/trunk/tools/yaml2obj/yaml2elf.cpp
Modified: llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h?rev=308520&r1=308519&r2=308520&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h (original)
+++ llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h Wed Jul 19 13:38:46 2017
@@ -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::
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_E
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
static void mapping(IO &IO, ELFYAML::SectionOrType §ionOrType);
};
+template <> struct MappingTraits<ELFYAML::SectionName> {
+ static void mapping(IO &IO, ELFYAML::SectionName §ionName);
+};
+
} // end namespace yaml
} // end namespace llvm
Modified: llvm/trunk/lib/ObjectYAML/ELFYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ObjectYAML/ELFYAML.cpp?rev=308520&r1=308519&r2=308520&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/ELFYAML.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/ELFYAML.cpp Wed Jul 19 13:38:46 2017
@@ -39,6 +39,21 @@ void ScalarEnumerationTraits<ELFYAML::EL
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::EL
#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>:
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::SectionOrTyp
IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
}
+void MappingTraits<ELFYAML::SectionName>::mapping(
+ IO &IO, ELFYAML::SectionName §ionName) {
+ 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>::map
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);
Added: llvm/trunk/test/tools/yaml2obj/program-header-nobits.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/yaml2obj/program-header-nobits.yaml?rev=308520&view=auto
==============================================================================
--- llvm/trunk/test/tools/yaml2obj/program-header-nobits.yaml (added)
+++ llvm/trunk/test/tools/yaml2obj/program-header-nobits.yaml Wed Jul 19 13:38:46 2017
@@ -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:]
Added: llvm/trunk/test/tools/yaml2obj/program-header.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/yaml2obj/program-header.yaml?rev=308520&view=auto
==============================================================================
--- llvm/trunk/test/tools/yaml2obj/program-header.yaml (added)
+++ llvm/trunk/test/tools/yaml2obj/program-header.yaml Wed Jul 19 13:38:46 2017
@@ -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:]
Modified: llvm/trunk/tools/yaml2obj/yaml2elf.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/yaml2obj/yaml2elf.cpp?rev=308520&r1=308519&r2=308520&view=diff
==============================================================================
--- llvm/trunk/tools/yaml2obj/yaml2elf.cpp (original)
+++ llvm/trunk/tools/yaml2obj/yaml2elf.cpp Wed Jul 19 13:38:46 2017
@@ -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,16 +177,32 @@ void ELFState<ELFT>::initELFHeader(Elf_E
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) {
// Ensure SHN_UNDEF entry is present. An all-zero section header is a
@@ -311,6 +331,67 @@ void ELFState<ELFT>::initStrtabSectionHe
}
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,
unsigned SymbolBinding) {
@@ -508,12 +589,15 @@ int ELFState<ELFT>::writeELF(raw_ostream
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
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;
More information about the llvm-commits
mailing list