diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/ObjectYAML/ELFYAML.h | 33 | ||||
-rw-r--r-- | llvm/lib/ObjectYAML/ELFYAML.cpp | 38 | ||||
-rw-r--r-- | llvm/test/tools/yaml2obj/program-header-nobits.yaml | 39 | ||||
-rw-r--r-- | llvm/test/tools/yaml2obj/program-header.yaml | 67 | ||||
-rw-r--r-- | llvm/tools/yaml2obj/yaml2elf.cpp | 98 |
5 files changed, 270 insertions, 5 deletions
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h index ed455311696..c4a1fe2ce39 100644 --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -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 §ionOrType); }; +template <> struct MappingTraits<ELFYAML::SectionName> { + static void mapping(IO &IO, ELFYAML::SectionName §ionName); +}; + } // end namespace yaml } // end namespace llvm diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 39741dab327..fd0aa49445f 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -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 §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>::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); diff --git a/llvm/test/tools/yaml2obj/program-header-nobits.yaml b/llvm/test/tools/yaml2obj/program-header-nobits.yaml new file mode 100644 index 00000000000..4664753a4b1 --- /dev/null +++ b/llvm/test/tools/yaml2obj/program-header-nobits.yaml @@ -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:] diff --git a/llvm/test/tools/yaml2obj/program-header.yaml b/llvm/test/tools/yaml2obj/program-header.yaml new file mode 100644 index 00000000000..f07e393f512 --- /dev/null +++ b/llvm/test/tools/yaml2obj/program-header.yaml @@ -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:] diff --git a/llvm/tools/yaml2obj/yaml2elf.cpp b/llvm/tools/yaml2obj/yaml2elf.cpp index c89f768ed6f..1d28a1abffc 100644 --- a/llvm/tools/yaml2obj/yaml2elf.cpp +++ b/llvm/tools/yaml2obj/yaml2elf.cpp @@ -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_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) { // Ensure SHN_UNDEF entry is present. An all-zero section header is a @@ -311,6 +331,67 @@ void ELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, } 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 &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; |