From 5918b7a03d4d6a52e18f7c102250c9cfd6ae52dd Mon Sep 17 00:00:00 2001 From: Sean Silva Date: Mon, 10 Jun 2013 23:44:15 +0000 Subject: [PATCH] [yaml2obj] Initial ELF support. Currently, only emitting the ELF header is supported (no sections or segments). The ELFYAML code organization is broadly similar to the COFFYAML code. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@183711 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/ELFYAML.h | 92 +++++++++ lib/Object/CMakeLists.txt | 1 + lib/Object/ELFYAML.cpp | 228 ++++++++++++++++++++++ test/Object/Inputs/ELF/BE32.yaml | 6 + test/Object/Inputs/ELF/BE64.yaml | 6 + test/Object/Inputs/ELF/Header.yaml | 7 + test/Object/Inputs/ELF/LE32.yaml | 6 + test/Object/Inputs/ELF/LE64.yaml | 6 + test/Object/yaml2obj-elf-basic.test | 32 +++ test/Object/yaml2obj-elf-bits-endian.test | 16 ++ tools/yaml2obj/CMakeLists.txt | 1 + tools/yaml2obj/yaml2elf.cpp | 78 ++++++++ tools/yaml2obj/yaml2obj.cpp | 6 +- tools/yaml2obj/yaml2obj.h | 1 + 14 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 include/llvm/Object/ELFYAML.h create mode 100644 lib/Object/ELFYAML.cpp create mode 100644 test/Object/Inputs/ELF/BE32.yaml create mode 100644 test/Object/Inputs/ELF/BE64.yaml create mode 100644 test/Object/Inputs/ELF/Header.yaml create mode 100644 test/Object/Inputs/ELF/LE32.yaml create mode 100644 test/Object/Inputs/ELF/LE64.yaml create mode 100644 test/Object/yaml2obj-elf-basic.test create mode 100644 test/Object/yaml2obj-elf-bits-endian.test create mode 100644 tools/yaml2obj/yaml2elf.cpp diff --git a/include/llvm/Object/ELFYAML.h b/include/llvm/Object/ELFYAML.h new file mode 100644 index 00000000000..18eacce707f --- /dev/null +++ b/include/llvm/Object/ELFYAML.h @@ -0,0 +1,92 @@ +//===- ELFYAML.h - ELF YAMLIO implementation --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file declares classes for handling the YAML representation +/// of ELF. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ELFYAML_H +#define LLVM_OBJECT_ELFYAML_H + +#include "llvm/Object/YAML.h" +#include "llvm/Support/ELF.h" + +namespace llvm { +namespace ELFYAML { + +// These types are invariant across 32/64-bit ELF, so for simplicity just +// directly give them their exact sizes. We don't need to worry about +// endianness because these are just the types in the YAMLIO structures, +// and are appropriately converted to the necessary endianness when +// reading/generating binary object files. +// The naming of these types is intended to be ELF_PREFIX, where PREFIX is +// the common prefix of the respective constants. E.g. ELF_EM corresponds +// to the `e_machine` constants, like `EM_X86_64`. +// 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_EM); +LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFCLASS); +LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFDATA); + +// For now, hardcode 64 bits everywhere that 32 or 64 would be needed +// since 64-bit can hold 32-bit values too. +struct Header { + ELF_ELFCLASS Class; + ELF_ELFDATA Data; + ELF_ET Type; + ELF_EM Machine; + llvm::yaml::Hex64 Entry; +}; +struct Object { + Header Header; +}; + +} // end namespace ELFYAML +} // end namespace llvm + +namespace llvm { +namespace yaml { + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, ELFYAML::ELF_ET &Value); +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, ELFYAML::ELF_EM &Value); +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, ELFYAML::ELF_ELFCLASS &Value); +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, ELFYAML::ELF_ELFDATA &Value); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::Header &Header); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::Object &Object); +}; + +} // end namespace yaml +} // end namespace llvm + +#endif diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt index e24f78a598d..cec0e283379 100644 --- a/lib/Object/CMakeLists.txt +++ b/lib/Object/CMakeLists.txt @@ -4,6 +4,7 @@ add_llvm_library(LLVMObject COFFObjectFile.cpp COFFYAML.cpp ELFObjectFile.cpp + ELFYAML.cpp Error.cpp MachOObjectFile.cpp Object.cpp diff --git a/lib/Object/ELFYAML.cpp b/lib/Object/ELFYAML.cpp new file mode 100644 index 00000000000..c4f3fc187ac --- /dev/null +++ b/lib/Object/ELFYAML.cpp @@ -0,0 +1,228 @@ +//===- ELFYAML.cpp - ELF YAMLIO implementation ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines classes for handling the YAML representation of ELF. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/ELFYAML.h" + +namespace llvm { +namespace yaml { + +void +ScalarEnumerationTraits::enumeration(IO &IO, + ELFYAML::ELF_ET &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + ECase(ET_NONE) + ECase(ET_REL) + ECase(ET_EXEC) + ECase(ET_DYN) + ECase(ET_CORE) +#undef ECase +} + +void +ScalarEnumerationTraits::enumeration(IO &IO, + ELFYAML::ELF_EM &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + ECase(EM_NONE) + ECase(EM_M32) + ECase(EM_SPARC) + ECase(EM_386) + ECase(EM_68K) + ECase(EM_88K) + ECase(EM_486) + ECase(EM_860) + ECase(EM_MIPS) + ECase(EM_S370) + ECase(EM_MIPS_RS3_LE) + ECase(EM_PARISC) + ECase(EM_VPP500) + ECase(EM_SPARC32PLUS) + ECase(EM_960) + ECase(EM_PPC) + ECase(EM_PPC64) + ECase(EM_S390) + ECase(EM_SPU) + ECase(EM_V800) + ECase(EM_FR20) + ECase(EM_RH32) + ECase(EM_RCE) + ECase(EM_ARM) + ECase(EM_ALPHA) + ECase(EM_SH) + ECase(EM_SPARCV9) + ECase(EM_TRICORE) + ECase(EM_ARC) + ECase(EM_H8_300) + ECase(EM_H8_300H) + ECase(EM_H8S) + ECase(EM_H8_500) + ECase(EM_IA_64) + ECase(EM_MIPS_X) + ECase(EM_COLDFIRE) + ECase(EM_68HC12) + ECase(EM_MMA) + ECase(EM_PCP) + ECase(EM_NCPU) + ECase(EM_NDR1) + ECase(EM_STARCORE) + ECase(EM_ME16) + ECase(EM_ST100) + ECase(EM_TINYJ) + ECase(EM_X86_64) + ECase(EM_PDSP) + ECase(EM_PDP10) + ECase(EM_PDP11) + ECase(EM_FX66) + ECase(EM_ST9PLUS) + ECase(EM_ST7) + ECase(EM_68HC16) + ECase(EM_68HC11) + ECase(EM_68HC08) + ECase(EM_68HC05) + ECase(EM_SVX) + ECase(EM_ST19) + ECase(EM_VAX) + ECase(EM_CRIS) + ECase(EM_JAVELIN) + ECase(EM_FIREPATH) + ECase(EM_ZSP) + ECase(EM_MMIX) + ECase(EM_HUANY) + ECase(EM_PRISM) + ECase(EM_AVR) + ECase(EM_FR30) + ECase(EM_D10V) + ECase(EM_D30V) + ECase(EM_V850) + ECase(EM_M32R) + ECase(EM_MN10300) + ECase(EM_MN10200) + ECase(EM_PJ) + ECase(EM_OPENRISC) + ECase(EM_ARC_COMPACT) + ECase(EM_XTENSA) + ECase(EM_VIDEOCORE) + ECase(EM_TMM_GPP) + ECase(EM_NS32K) + ECase(EM_TPC) + ECase(EM_SNP1K) + ECase(EM_ST200) + ECase(EM_IP2K) + ECase(EM_MAX) + ECase(EM_CR) + ECase(EM_F2MC16) + ECase(EM_MSP430) + ECase(EM_BLACKFIN) + ECase(EM_SE_C33) + ECase(EM_SEP) + ECase(EM_ARCA) + ECase(EM_UNICORE) + ECase(EM_EXCESS) + ECase(EM_DXP) + ECase(EM_ALTERA_NIOS2) + ECase(EM_CRX) + ECase(EM_XGATE) + ECase(EM_C166) + ECase(EM_M16C) + ECase(EM_DSPIC30F) + ECase(EM_CE) + ECase(EM_M32C) + ECase(EM_TSK3000) + ECase(EM_RS08) + ECase(EM_SHARC) + ECase(EM_ECOG2) + ECase(EM_SCORE7) + ECase(EM_DSP24) + ECase(EM_VIDEOCORE3) + ECase(EM_LATTICEMICO32) + ECase(EM_SE_C17) + ECase(EM_TI_C6000) + ECase(EM_TI_C2000) + ECase(EM_TI_C5500) + ECase(EM_MMDSP_PLUS) + ECase(EM_CYPRESS_M8C) + ECase(EM_R32C) + ECase(EM_TRIMEDIA) + ECase(EM_HEXAGON) + ECase(EM_8051) + ECase(EM_STXP7X) + ECase(EM_NDS32) + ECase(EM_ECOG1) + ECase(EM_ECOG1X) + ECase(EM_MAXQ30) + ECase(EM_XIMO16) + ECase(EM_MANIK) + ECase(EM_CRAYNV2) + ECase(EM_RX) + ECase(EM_METAG) + ECase(EM_MCST_ELBRUS) + ECase(EM_ECOG16) + ECase(EM_CR16) + ECase(EM_ETPU) + ECase(EM_SLE9X) + ECase(EM_L10M) + ECase(EM_K10M) + ECase(EM_AARCH64) + ECase(EM_AVR32) + ECase(EM_STM8) + ECase(EM_TILE64) + ECase(EM_TILEPRO) + ECase(EM_MICROBLAZE) + ECase(EM_CUDA) + ECase(EM_TILEGX) + ECase(EM_CLOUDSHIELD) + ECase(EM_COREA_1ST) + ECase(EM_COREA_2ND) + ECase(EM_ARC_COMPACT2) + ECase(EM_OPEN8) + ECase(EM_RL78) + ECase(EM_VIDEOCORE5) + ECase(EM_78KOR) + ECase(EM_56800EX) + ECase(EM_MBLAZE) +#undef ECase +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, ELFYAML::ELF_ELFCLASS &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + // Since the semantics of ELFCLASSNONE is "invalid", just don't accept it + // here. + ECase(ELFCLASS32) + ECase(ELFCLASS64) +#undef ECase +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, ELFYAML::ELF_ELFDATA &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + // Since the semantics of ELFDATANONE is "invalid", just don't accept it + // here. + ECase(ELFDATA2LSB) + ECase(ELFDATA2MSB) +#undef ECase +} + +void MappingTraits::mapping(IO &IO, ELFYAML::Header &Header) { + IO.mapRequired("Class", Header.Class); + IO.mapRequired("Data", Header.Data); + IO.mapRequired("Type", Header.Type); + IO.mapRequired("Machine", Header.Machine); + IO.mapOptional("Entry", Header.Entry, Hex64(0)); +} + +void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { + IO.mapRequired("Header", Object.Header); +} + +} // end namespace yaml +} // end namespace llvm diff --git a/test/Object/Inputs/ELF/BE32.yaml b/test/Object/Inputs/ELF/BE32.yaml new file mode 100644 index 00000000000..3709ff70cd3 --- /dev/null +++ b/test/Object/Inputs/ELF/BE32.yaml @@ -0,0 +1,6 @@ +!ELF +Header: !Header + Class: ELFCLASS32 + Data: ELFDATA2MSB + Type: ET_EXEC + Machine: EM_PPC diff --git a/test/Object/Inputs/ELF/BE64.yaml b/test/Object/Inputs/ELF/BE64.yaml new file mode 100644 index 00000000000..d1c4401c0c0 --- /dev/null +++ b/test/Object/Inputs/ELF/BE64.yaml @@ -0,0 +1,6 @@ +!ELF +Header: !Header + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_EXEC + Machine: EM_PPC64 diff --git a/test/Object/Inputs/ELF/Header.yaml b/test/Object/Inputs/ELF/Header.yaml new file mode 100644 index 00000000000..085b12077d9 --- /dev/null +++ b/test/Object/Inputs/ELF/Header.yaml @@ -0,0 +1,7 @@ +!ELF +Header: !Header + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x400000 diff --git a/test/Object/Inputs/ELF/LE32.yaml b/test/Object/Inputs/ELF/LE32.yaml new file mode 100644 index 00000000000..a4f30fbb803 --- /dev/null +++ b/test/Object/Inputs/ELF/LE32.yaml @@ -0,0 +1,6 @@ +!ELF +Header: !Header + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 diff --git a/test/Object/Inputs/ELF/LE64.yaml b/test/Object/Inputs/ELF/LE64.yaml new file mode 100644 index 00000000000..cd0ca2545b9 --- /dev/null +++ b/test/Object/Inputs/ELF/LE64.yaml @@ -0,0 +1,6 @@ +!ELF +Header: !Header + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 diff --git a/test/Object/yaml2obj-elf-basic.test b/test/Object/yaml2obj-elf-basic.test new file mode 100644 index 00000000000..e97ad2013bf --- /dev/null +++ b/test/Object/yaml2obj-elf-basic.test @@ -0,0 +1,32 @@ +RUN: yaml2obj -format=elf %p/Inputs/ELF/Header.yaml | llvm-readobj -file-headers - | FileCheck %s + +// CHECK: File: +// CHECK-NEXT: Format: ELF64-x86-64 +// CHECK-NEXT: Arch: x86_64 +// CHECK-NEXT: AddressSize: 64bit +// CHECK-NEXT: LoadName: +// CHECK-NEXT: ElfHeader { +// CHECK-NEXT: Ident { +// CHECK-NEXT: Magic: (7F 45 4C 46) +// CHECK-NEXT: Class: 64-bit (0x2) +// CHECK-NEXT: DataEncoding: LittleEndian (0x1) +// CHECK-NEXT: FileVersion: 1 +// CHECK-NEXT: OS/ABI: SystemV (0x0) +// CHECK-NEXT: ABIVersion: 0 +// CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +// CHECK-NEXT: } +// CHECK-NEXT: Type: Executable (0x2) +// CHECK-NEXT: Machine: EM_X86_64 (0x3E) +// CHECK-NEXT: Version: 1 +// CHECK-NEXT: Entry: 0x400000 +// CHECK-NEXT: ProgramHeaderOffset: 0x0 +// CHECK-NEXT: SectionHeaderOffset: 0x0 +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: HeaderSize: 64 +// CHECK-NEXT: ProgramHeaderEntrySize: 0 +// CHECK-NEXT: ProgramHeaderCount: 0 +// CHECK-NEXT: SectionHeaderEntrySize: 0 +// CHECK-NEXT: SectionHeaderCount: 0 +// CHECK-NEXT: StringTableSectionIndex: 0 +// CHECK-NEXT: } diff --git a/test/Object/yaml2obj-elf-bits-endian.test b/test/Object/yaml2obj-elf-bits-endian.test new file mode 100644 index 00000000000..4be9a4465b8 --- /dev/null +++ b/test/Object/yaml2obj-elf-bits-endian.test @@ -0,0 +1,16 @@ +RUN: yaml2obj -format=elf %p/Inputs/ELF/LE64.yaml | llvm-readobj -file-headers - | FileCheck %s --check-prefix LE64 +RUN: yaml2obj -format=elf %p/Inputs/ELF/BE64.yaml | llvm-readobj -file-headers - | FileCheck %s --check-prefix BE64 +RUN: yaml2obj -format=elf %p/Inputs/ELF/LE32.yaml | llvm-readobj -file-headers - | FileCheck %s --check-prefix LE32 +RUN: yaml2obj -format=elf %p/Inputs/ELF/BE32.yaml | llvm-readobj -file-headers - | FileCheck %s --check-prefix BE32 + +LE64: Class: 64-bit (0x2) +LE64-NEXT: DataEncoding: LittleEndian (0x1) + +BE64: Class: 64-bit (0x2) +BE64-NEXT: DataEncoding: BigEndian (0x2) + +LE32: Class: 32-bit (0x1) +LE32-NEXT: DataEncoding: LittleEndian (0x1) + +BE32: Class: 32-bit (0x1) +BE32-NEXT: DataEncoding: BigEndian (0x2) diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt index 5cccf9330ed..8d9d6522469 100644 --- a/tools/yaml2obj/CMakeLists.txt +++ b/tools/yaml2obj/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS object) add_llvm_utility(yaml2obj yaml2obj.cpp yaml2coff.cpp + yaml2elf.cpp ) target_link_libraries(yaml2obj LLVMSupport) diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp new file mode 100644 index 00000000000..d59594236f9 --- /dev/null +++ b/tools/yaml2obj/yaml2elf.cpp @@ -0,0 +1,78 @@ +//===- yaml2elf - Convert YAML to a ELF object file -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief The ELF component of yaml2obj. +/// +//===----------------------------------------------------------------------===// + +#include "yaml2obj.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFYAML.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +template +static void writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { + const ELFYAML::Header &Hdr = Doc.Header; + using namespace llvm::ELF; + using namespace llvm::object; + typename ELFObjectFile::Elf_Ehdr Header; + memset(&Header, 0, sizeof(Header)); + Header.e_ident[EI_MAG0] = 0x7f; + Header.e_ident[EI_MAG1] = 'E'; + Header.e_ident[EI_MAG2] = 'L'; + Header.e_ident[EI_MAG3] = 'F'; + Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; + bool IsLittleEndian = ELFT::TargetEndianness == support::little; + Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; + + Header.e_ident[EI_VERSION] = EV_CURRENT; + + // TODO: Implement ELF_ELFOSABI enum. + Header.e_ident[EI_OSABI] = ELFOSABI_NONE; + // TODO: Implement ELF_ABIVERSION enum. + Header.e_ident[EI_ABIVERSION] = 0; + Header.e_type = Hdr.Type; + Header.e_machine = Hdr.Machine; + Header.e_version = EV_CURRENT; + Header.e_entry = Hdr.Entry; + Header.e_ehsize = sizeof(Header); + + // TODO: Section headers and program headers. + + OS.write((const char *)&Header, sizeof(Header)); +} + +int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { + yaml::Input YIn(Buf->getBuffer()); + ELFYAML::Object Doc; + YIn >> Doc; + if (YIn.error()) { + errs() << "yaml2obj: Failed to parse YAML file!\n"; + return 1; + } + if (Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64)) { + if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB)) + writeELF >(outs(), Doc); + else + writeELF >(outs(), Doc); + } else { + if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB)) + writeELF >(outs(), Doc); + else + writeELF >(outs(), Doc); + } + + return 0; +} diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp index a9ac78bce48..6d1107c8581 100644 --- a/tools/yaml2obj/yaml2obj.cpp +++ b/tools/yaml2obj/yaml2obj.cpp @@ -38,7 +38,8 @@ static cl::opt // them appropriately requires some work in the YAML parser and the YAMLIO // library. enum YAMLObjectFormat { - YOF_COFF + YOF_COFF, + YOF_ELF }; cl::opt Format( @@ -46,6 +47,7 @@ cl::opt Format( cl::desc("Interpret input as this type of object file"), cl::values( clEnumValN(YOF_COFF, "coff", "COFF object file format"), + clEnumValN(YOF_ELF, "elf", "ELF object file format"), clEnumValEnd)); @@ -60,6 +62,8 @@ int main(int argc, char **argv) { return 1; if (Format == YOF_COFF) { return yaml2coff(outs(), Buf.get()); + } else if (Format == YOF_ELF) { + return yaml2elf(outs(), Buf.get()); } else { errs() << "Not yet implemented\n"; return 1; diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h index 7197410b268..095435c5498 100644 --- a/tools/yaml2obj/yaml2obj.h +++ b/tools/yaml2obj/yaml2obj.h @@ -17,5 +17,6 @@ namespace llvm { class MemoryBuffer; } int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf); +int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf); #endif -- 2.34.1