Index: include/llvm/Object/Binary.h =================================================================== --- include/llvm/Object/Binary.h +++ include/llvm/Object/Binary.h @@ -59,6 +59,8 @@ ID_MachO64L, // MachO 64-bit, little endian ID_MachO64B, // MachO 64-bit, big endian + ID_Wasm, + ID_EndObjects }; @@ -115,6 +117,10 @@ return TypeID == ID_COFF; } + bool isWasm() const { + return TypeID == ID_Wasm; + } + bool isCOFFImportFile() const { return TypeID == ID_COFFImportFile; } Index: include/llvm/Object/ObjectFile.h =================================================================== --- include/llvm/Object/ObjectFile.h +++ include/llvm/Object/ObjectFile.h @@ -29,6 +29,7 @@ class ObjectFile; class COFFObjectFile; class MachOObjectFile; +class WasmObjectFile; class SymbolRef; class symbol_iterator; @@ -304,6 +305,8 @@ uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0); + static Expected> + createWasmObjectFile(MemoryBufferRef Object); }; // Inline function definitions. Index: include/llvm/Object/Wasm.h =================================================================== --- /dev/null +++ include/llvm/Object/Wasm.h @@ -0,0 +1,129 @@ +//===- WasmObjectFile.h - Wasm object file implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the WasmObjectFile class, which implements the ObjectFile +// interface for Wasm files. +// +// See: https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_WASM_H +#define LLVM_OBJECT_WASM_H + +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Wasm.h" + +namespace llvm { +namespace object { + +class WasmObjectFile : public ObjectFile { +public: + WasmObjectFile(MemoryBufferRef Object, Error &Err); + const wasm::WasmObjectHeader &getHeader() const; + const wasm::WasmSection *getWasmSection(const SectionRef &Section) const; + static inline bool classof(const Binary *v) { return v->isWasm(); } + + const std::vector types() const { return Signatures; } + const std::vector functions() const { return Functions; } + const std::vector imports() const { return Imports; } + const std::vector tables() const { return Tables; } + const std::vector memories() const { return Memories; } + const std::vector exports() const { return Exports; } + const std::vector elements() const { return ElemSegments; } + const std::vector dataSegments() const { return DataSegments; } + +protected: + // Overrides from ObjectFile. + void moveSymbolNext(DataRefImpl &Symb) const override; + + std::error_code printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const override; + + uint32_t getSymbolFlags(DataRefImpl Symb) const override; + + basic_symbol_iterator symbol_begin_impl() const override; + + basic_symbol_iterator symbol_end_impl() const override; + Expected getSymbolName(DataRefImpl Symb) const override; + + Expected getSymbolAddress(DataRefImpl Symb) const override; + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + uint32_t getSymbolAlignment(DataRefImpl Symb) const override; + uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; + Expected getSymbolType(DataRefImpl Symb) const override; + Expected + getSymbolSection(DataRefImpl Symb) const override; + + // Overrides from SectionRef. + friend class SectionRef; + void moveSectionNext(DataRefImpl &Sec) const override; + std::error_code getSectionName(DataRefImpl Sec, + StringRef &Res) const override; + uint64_t getSectionAddress(DataRefImpl Sec) const override; + uint64_t getSectionSize(DataRefImpl Sec) const override; + std::error_code getSectionContents(DataRefImpl Sec, + StringRef &Res) const override; + uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; + bool isSectionText(DataRefImpl Sec) const override; + bool isSectionData(DataRefImpl Sec) const override; + bool isSectionBSS(DataRefImpl Sec) const override; + bool isSectionVirtual(DataRefImpl Sec) const override; + bool isSectionBitcode(DataRefImpl Sec) const override; + relocation_iterator section_rel_begin(DataRefImpl Sec) const override; + relocation_iterator section_rel_end(DataRefImpl Sec) const override; + section_iterator getRelocatedSection(DataRefImpl Sec) const override; + + // Overrides from RelocationRef. + friend class RelocationRef; + void moveRelocationNext(DataRefImpl &Rel) const override; + uint64_t getRelocationOffset(DataRefImpl Rel) const override; + symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; + uint64_t getRelocationType(DataRefImpl Rel) const override; + void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl &Result) const override; + + section_iterator section_begin() const override; + section_iterator section_end() const override; + uint8_t getBytesInAddress() const override; + StringRef getFileFormatName() const override; + unsigned getArch() const override; + SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } + bool isRelocatableObject() const override; + +private: + const uint8_t *getPtr(size_t Offset) const; + Error parseTypeSection(const uint8_t *Ptr, size_t Length); + Error parseImportSection(const uint8_t *Ptr, size_t Length); + Error parseFunctionSection(const uint8_t *Ptr, size_t Length); + Error parseTableSection(const uint8_t *Ptr, size_t Length); + Error parseMemorySection(const uint8_t *Ptr, size_t Length); + Error parseExportSection(const uint8_t *Ptr, size_t Length); + Error parseElemSection(const uint8_t *Ptr, size_t Length); + Error parseDataSection(const uint8_t *Ptr, size_t Length); + + wasm::WasmObjectHeader Header; + std::vector Sections; + std::vector Signatures; + std::vector Functions; + std::vector Tables; + std::vector Memories; + std::vector Imports; + std::vector Exports; + std::vector ElemSegments; + std::vector DataSegments; +}; + +// The iterator function section + +} +} + +#endif Index: include/llvm/ObjectYAML/ObjectYAML.h =================================================================== --- include/llvm/ObjectYAML/ObjectYAML.h +++ include/llvm/ObjectYAML/ObjectYAML.h @@ -14,6 +14,7 @@ #include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/ObjectYAML/COFFYAML.h" #include "llvm/ObjectYAML/MachOYAML.h" +#include "llvm/ObjectYAML/WasmYAML.h" namespace llvm { namespace yaml { @@ -23,6 +24,7 @@ std::unique_ptr Coff; std::unique_ptr MachO; std::unique_ptr FatMachO; + std::unique_ptr Wasm; }; template <> struct MappingTraits { Index: include/llvm/ObjectYAML/WasmYAML.h =================================================================== --- /dev/null +++ include/llvm/ObjectYAML/WasmYAML.h @@ -0,0 +1,272 @@ +//===- WasmYAML.h - Wasm 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 wasm binaries. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_WASMYAML_H +#define LLVM_OBJECTYAML_WASMYAML_H + +#include "llvm/Support/Wasm.h" +#include "llvm/ObjectYAML/YAML.h" + +namespace llvm { +namespace WasmYAML { + +LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionType) +LLVM_YAML_STRONG_TYPEDEF(int32_t, ValueType) +LLVM_YAML_STRONG_TYPEDEF(int32_t, TableType) +LLVM_YAML_STRONG_TYPEDEF(int32_t, SignatureForm) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, ExportKind) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, Opcode) + +struct FileHeader { + yaml::Hex32 Version; +}; + +struct Import { + StringRef Module; + StringRef Field; + ExportKind Kind; + yaml::Hex32 SigIndex; +}; + +struct Limits { + yaml::Hex32 Flags; + yaml::Hex32 Initial; + yaml::Hex32 Maximum; +}; + +struct Table { + TableType ElemType; + Limits TableLimits; +}; + +struct Export { + StringRef Name; + ExportKind Kind; + yaml::Hex32 Index; +}; + +struct ElemSegment { + uint32_t TableIndex; + wasm::WasmInitExpr Offset; + std::vector Functions; +}; + +struct DataSegment { + yaml::Hex32 Index; + wasm::WasmInitExpr Offset; + yaml::BinaryRef Content; +}; + +struct Signature { + Signature() : Form(wasm::WASM_TYPE_FUNC) {} + + SignatureForm Form; + std::vector ParamTypes; + ValueType ReturnType; +}; + +struct Section { + Section(SectionType SecType) : Type(SecType) {} + + SectionType Type; +}; + +struct TypeSection : Section { + TypeSection() : Section(wasm::WASM_SEC_TYPE) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_TYPE; + } + + std::vector Signatures; +}; + +struct ImportSection : Section { + ImportSection() : Section(wasm::WASM_SEC_IMPORT) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_IMPORT; + } + + std::vector Imports; +}; + +struct FunctionSection : Section { + FunctionSection() : Section(wasm::WASM_SEC_FUNCTION) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_FUNCTION; + } + + std::vector FunctionTypes; +}; + +struct TableSection : Section { + TableSection() : Section(wasm::WASM_SEC_TABLE) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_TABLE; + } + + std::vector Tables; +}; + +struct MemorySection : Section { + MemorySection() : Section(wasm::WASM_SEC_MEMORY) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_MEMORY; + } + + std::vector Memories; +}; + +struct ExportSection : Section { + ExportSection() : Section(wasm::WASM_SEC_EXPORT) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_EXPORT; + } + + std::vector Exports; +}; + +struct ElemSection : Section { + ElemSection() : Section(wasm::WASM_SEC_ELEM) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_ELEM; + } + + std::vector Segments; +}; + +struct CodeSection : Section { + CodeSection() : Section(wasm::WASM_SEC_CODE) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_CODE; + } + + yaml::BinaryRef Content; +}; + +struct DataSection : Section { + DataSection() : Section(wasm::WASM_SEC_DATA) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_DATA; + } + + std::vector Segments; +}; + +struct Object { + FileHeader Header; + std::vector> Sections; +}; + +} // end namespace WasmYAML +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Signature) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ValueType) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Table) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Import) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Export) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ElemSegment) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Limits) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::DataSegment) +LLVM_YAML_IS_SEQUENCE_VECTOR(uint32_t) + +namespace llvm { +namespace yaml { + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::FileHeader &FileHdr); +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &Section); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Object &Object); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Import &Import); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Export &Export); +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, WasmYAML::SectionType &Type); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Signature &Signature); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Table &Table); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Limits &Limits); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, wasm::WasmInitExpr &Expr); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::DataSegment &Segment); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, WasmYAML::ElemSegment &Segment); +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, WasmYAML::ValueType &Type); +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, WasmYAML::ExportKind &Kind); +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, WasmYAML::TableType &Type); +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, WasmYAML::Opcode &Opcode); +}; + +} // end namespace yaml +} // end namespace llvm + +#endif Index: include/llvm/Support/FileSystem.h =================================================================== --- include/llvm/Support/FileSystem.h +++ include/llvm/Support/FileSystem.h @@ -261,7 +261,8 @@ coff_object, ///< COFF object file coff_import_library, ///< COFF import library pecoff_executable, ///< PECOFF executable file - windows_resource ///< Windows compiled resource file (.rc) + windows_resource, ///< Windows compiled resource file (.rc) + wasm_object ///< WebAssembly Object file }; bool is_object() const { Index: include/llvm/Support/Wasm.h =================================================================== --- /dev/null +++ include/llvm/Support/Wasm.h @@ -0,0 +1,136 @@ +//===- Wasm.h - Wasm object file format -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines manifest constants for the wasm object file format. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_WASM_H +#define LLVM_SUPPORT_WASM_H + +#include "llvm/ADT/ArrayRef.h" + +namespace llvm { +namespace wasm { + +const char WasmMagic[] = { '\0', 'a', 's', 'm' }; +const uint32_t WasmVersion = 0xd; + +struct WasmObjectHeader { + StringRef Magic; + uint32_t Version; +}; + +struct WasmSection { + uint32_t Type; + uint32_t Offset; + ArrayRef Content; +}; + +struct WasmSignature { + std::vector ParamTypes; + int32_t ReturnType; +}; + +struct WasmImport { + StringRef Module; + StringRef Field; + uint32_t Kind; + uint32_t SigIndex; +}; + +struct WasmExport { + StringRef Name; + uint32_t Kind; + uint32_t Index; +}; + +struct WasmLimits { + uint32_t Flags; + uint32_t Initial; + uint32_t Maximum; +}; + +struct WasmTable { + int32_t ElemType; + WasmLimits Limits; +}; + +struct WasmInitExpr { + uint8_t Opcode; + union { + uint32_t Int32; + uint64_t Int64; + uint32_t Float32; + uint64_t Float64; + uint32_t Global; + } Value; +}; + +struct WasmDataSegment { + uint32_t Index; + WasmInitExpr Offset; + ArrayRef Content; +}; + +struct WasmElemSegment { + uint32_t TableIndex; + WasmInitExpr Offset; + std::vector Functions; +}; + +enum : unsigned { + WASM_SEC_USER = 0, + WASM_SEC_TYPE = 1, + WASM_SEC_IMPORT = 2, + WASM_SEC_FUNCTION = 3, + WASM_SEC_TABLE = 4, + WASM_SEC_MEMORY = 5, + WASM_SEC_GLOBAL = 6, + WASM_SEC_EXPORT = 7, + WASM_SEC_START = 8, + WASM_SEC_ELEM = 9, + WASM_SEC_CODE = 10, + WASM_SEC_DATA = 11 +}; + +enum : signed { + WASM_TYPE_I32 = -0x01, + WASM_TYPE_I64 = -0x02, + WASM_TYPE_F32 = -0x03, + WASM_TYPE_F64 = -0x04, + WASM_TYPE_ANYFUNC = -0x10, + WASM_TYPE_FUNC = -0x20, + WASM_TYPE_VOID = -0x40, +}; + +enum : unsigned { + WASM_OP_END = 0x0b, + WASM_OP_I32_CONST = 0x41, + WASM_OP_I64_CONST = 0x42, + WASM_OP_F64_CONST = 0x43, + WASM_OP_F32_CONST = 0x44, + WASM_OP_GET_GLOBAL = 0x23, +}; + +enum : unsigned { + WASM_LIMITS_FLAG_HAS_MAX = 0x1, +}; + +enum : unsigned { + WASM_EXTERNAL_FUNC = 0, + WASM_EXTERNAL_TABLE = 1, + WASM_EXTERNAL_MEMORY = 2, + WASM_EXTERNAL_GLOBAL = 3, +}; + +} // end namespace wasm +} // end namespace llvm + +#endif Index: lib/Object/Binary.cpp =================================================================== --- lib/Object/Binary.cpp +++ lib/Object/Binary.cpp @@ -63,6 +63,7 @@ case sys::fs::file_magic::coff_import_library: case sys::fs::file_magic::pecoff_executable: case sys::fs::file_magic::bitcode: + case sys::fs::file_magic::wasm_object: return ObjectFile::createSymbolicFile(Buffer, Type, Context); case sys::fs::file_magic::macho_universal_binary: return MachOUniversalBinary::create(Buffer); Index: lib/Object/CMakeLists.txt =================================================================== --- lib/Object/CMakeLists.txt +++ lib/Object/CMakeLists.txt @@ -15,6 +15,7 @@ RecordStreamer.cpp SymbolicFile.cpp SymbolSize.cpp + WasmObjectFile.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Object Index: lib/Object/ObjectFile.cpp =================================================================== --- lib/Object/ObjectFile.cpp +++ lib/Object/ObjectFile.cpp @@ -13,6 +13,7 @@ #include "llvm/Object/COFF.h" #include "llvm/Object/MachO.h" +#include "llvm/Object/Wasm.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -104,6 +105,8 @@ case sys::fs::file_magic::coff_import_library: case sys::fs::file_magic::pecoff_executable: return errorOrToExpected(createCOFFObjectFile(Object)); + case sys::fs::file_magic::wasm_object: + return createWasmObjectFile(Object); } llvm_unreachable("Unexpected Object File Type"); } Index: lib/Object/SymbolicFile.cpp =================================================================== --- lib/Object/SymbolicFile.cpp +++ lib/Object/SymbolicFile.cpp @@ -57,6 +57,7 @@ case sys::fs::file_magic::macho_dsym_companion: case sys::fs::file_magic::macho_kext_bundle: case sys::fs::file_magic::pecoff_executable: + case sys::fs::file_magic::wasm_object: return ObjectFile::createObjectFile(Object, Type); case sys::fs::file_magic::coff_import_library: return std::unique_ptr(new COFFImportFile(Object)); Index: lib/Object/WasmObjectFile.cpp =================================================================== --- /dev/null +++ lib/Object/WasmObjectFile.cpp @@ -0,0 +1,541 @@ +//===- WasmObjectFile.cpp - Wasm object file implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Wasm.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/LEB128.h" + +#include + +namespace llvm { +namespace object { + +Expected> +ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) { + Error Err; + std::unique_ptr ObjectFile; + + ObjectFile.reset(new WasmObjectFile(Buffer, Err)); + if (Err) + return std::move(Err); + + return std::move(ObjectFile); +} + +namespace { + +uint8_t readUint8(const uint8_t *&Ptr) { + return *Ptr++; +} + +uint32_t readUint32(const uint8_t *&Ptr) { + uint32_t Result = 0; + memcpy(&Result, Ptr, sizeof(Result)); + if (!sys::IsLittleEndianHost) + sys::swapByteOrder(Result); + Ptr += sizeof(Result); + return Result; +} + +float readFloat32(const uint8_t *&Ptr) { + float Result = 0; + memcpy(&Result, Ptr, sizeof(Result)); + Ptr += sizeof(Result); + return Result; +} + +double readFloat64(const uint8_t *&Ptr) { + double Result = 0; + memcpy(&Result, Ptr, sizeof(Result)); + Ptr += sizeof(Result); + return Result; +} + +uint64_t readULEB128(const uint8_t *&Ptr) { + unsigned Count; + uint64_t Result = decodeULEB128(Ptr, &Count); + Ptr += Count; + return Result; +} + +int64_t readLEB128(const uint8_t *&Ptr) { + unsigned Count; + uint64_t Result = decodeSLEB128(Ptr, &Count); + Ptr += Count; + return Result; +} + +Error readInitExpr(wasm::WasmInitExpr &Expr, const uint8_t *&Ptr) { + Expr.Opcode = readUint8(Ptr); + + switch (Expr.Opcode) { + case wasm::WASM_OP_I32_CONST: + Expr.Value.Int32 = readLEB128(Ptr); + break; + case wasm::WASM_OP_I64_CONST: + Expr.Value.Int64 = readLEB128(Ptr); + break; + case wasm::WASM_OP_F32_CONST: + Expr.Value.Float32 = readFloat32(Ptr); + break; + case wasm::WASM_OP_F64_CONST: + Expr.Value.Float64 = readFloat64(Ptr); + break; + case wasm::WASM_OP_GET_GLOBAL: + Expr.Value.Global = readULEB128(Ptr); + break; + default: + return make_error("Invalid opcode in init_expr", + object_error::invalid_file_type); + } + + uint8_t EndOpcode = readUint8(Ptr); + if (EndOpcode != wasm::WASM_OP_END) { + return make_error("Invalid init_expr", + object_error::invalid_file_type); + } + return Error::success(); +} + +static wasm::WasmLimits readLimits(const uint8_t *&Ptr) { + wasm::WasmLimits Result; + Result.Flags = readULEB128(Ptr); + Result.Initial = readULEB128(Ptr); + if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) + Result.Maximum = readULEB128(Ptr); + return Result; +} + +StringRef readString(const uint8_t *&Ptr) { + uint32_t StringLen = readULEB128(Ptr); + StringRef Return = StringRef(reinterpret_cast(Ptr), StringLen); + Ptr += StringLen; + return Return; +} + +Error readSection(wasm::WasmSection &Section, const uint8_t *&Ptr, + const uint8_t *Start) { + // TODO(sbc): Avoid reading past EOF in the case of malformed files. + Section.Offset = Ptr - Start; + Section.Type = readULEB128(Ptr); + uint32_t Size = readULEB128(Ptr); + Section.Content = ArrayRef(Ptr, Size); + Ptr += Size; + return Error::success(); +} + +} + +WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) + : ObjectFile(Binary::ID_Wasm, Buffer) { + ErrorAsOutParameter ErrAsOutParam(&Err); + Header.Magic = getData().substr(0, 4); + if (Header.Magic != StringRef("\0asm", 4)) { + Err = make_error("Bad magic number", + object_error::invalid_file_type); + return; + } + const uint8_t* Ptr = getPtr(4); + Header.Version = readUint32(Ptr); + if (Header.Version != wasm::WasmVersion) { + Err = make_error("Bad version number", + object_error::invalid_file_type); + return; + } + + const uint8_t* Eof = getPtr(getData().size()); + wasm::WasmSection Sec; + while (Ptr < Eof) { + if ((Err = readSection(Sec, Ptr, getPtr(0)))) + return; + Sections.push_back(Sec); + switch (Sec.Type) { + case wasm::WASM_SEC_TYPE: + if ((Err = parseTypeSection(Sec.Content.data(), Sec.Content.size()))) + return; + break; + case wasm::WASM_SEC_IMPORT: + if ((Err = parseImportSection(Sec.Content.data(), Sec.Content.size()))) + return; + break; + case wasm::WASM_SEC_FUNCTION: + if ((Err = parseFunctionSection(Sec.Content.data(), Sec.Content.size()))) + return; + break; + case wasm::WASM_SEC_TABLE: + if ((Err = parseTableSection(Sec.Content.data(), Sec.Content.size()))) + return; + break; + case wasm::WASM_SEC_MEMORY: + if ((Err = parseMemorySection(Sec.Content.data(), Sec.Content.size()))) + return; + break; + case wasm::WASM_SEC_EXPORT: + if ((Err = parseExportSection(Sec.Content.data(), Sec.Content.size()))) + return; + break; + case wasm::WASM_SEC_ELEM: + if ((Err = parseElemSection(Sec.Content.data(), Sec.Content.size()))) + return; + break; + case wasm::WASM_SEC_CODE: + // Nothing to parse, we just store the raw binary content + break; + case wasm::WASM_SEC_DATA: + if ((Err = parseDataSection(Sec.Content.data(), Sec.Content.size()))) + return; + break; + default: + Err = make_error("Bad section type", + object_error::invalid_file_type); + break; + } + } +} + +Error WasmObjectFile::parseTypeSection(const uint8_t *Ptr, size_t Length) { + uint32_t Count = readULEB128(Ptr); + while (Count--) { + wasm::WasmSignature Sig; + Sig.ReturnType = wasm::WASM_TYPE_VOID; + int32_t Form = readLEB128(Ptr); + if (Form != wasm::WASM_TYPE_FUNC) { + return make_error("Invalid signature type", + object_error::invalid_file_type); + } + uint32_t ParamCount = readULEB128(Ptr); + while (ParamCount--) { + uint32_t ParamType = readLEB128(Ptr); + Sig.ParamTypes.push_back(ParamType); + } + uint32_t ReturnCount = readULEB128(Ptr); + if (ReturnCount) { + if (ReturnCount != 1) { + return make_error( + "Multiple return types not supported", + object_error::invalid_file_type); + } + Sig.ReturnType = readLEB128(Ptr); + } + Signatures.push_back(Sig); + } + return Error::success(); +} + +Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, size_t Length) { + uint32_t Count = readULEB128(Ptr); + while (Count--) { + wasm::WasmImport Im; + Im.Module = readString(Ptr); + Im.Field = readString(Ptr); + Im.Kind = readULEB128(Ptr); + Im.SigIndex = readULEB128(Ptr); + Imports.push_back(Im); + } + return Error::success(); +} + +Error WasmObjectFile::parseFunctionSection(const uint8_t *Ptr, size_t Length) { + uint32_t Count = readULEB128(Ptr); + while (Count--) { + Functions.push_back(readULEB128(Ptr)); + } + return Error::success(); +} + +Error WasmObjectFile::parseTableSection(const uint8_t *Ptr, size_t Length) { + uint32_t Count = readULEB128(Ptr); + while (Count--) { + wasm::WasmTable Table; + Table.ElemType = readLEB128(Ptr); + if (Table.ElemType != wasm::WASM_TYPE_ANYFUNC) { + return make_error("Invalid table element type", + object_error::invalid_file_type); + } + Table.Limits = readLimits(Ptr); + Tables.push_back(Table); + } + return Error::success(); +} + +Error WasmObjectFile::parseMemorySection(const uint8_t *Ptr, size_t Length) { + uint32_t Count = readULEB128(Ptr); + while (Count--) { + Memories.push_back(readLimits(Ptr)); + } + return Error::success(); +} + +Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, size_t Length) { + uint32_t Count = readULEB128(Ptr); + while (Count--) { + wasm::WasmExport Ex; + Ex.Name = readString(Ptr); + Ex.Kind = readULEB128(Ptr); + Ex.Index = readULEB128(Ptr); + Exports.push_back(Ex); + } + return Error::success(); +} + +Error WasmObjectFile::parseElemSection(const uint8_t *Ptr, size_t Length) { + uint32_t SegCount = readULEB128(Ptr); + while (SegCount--) { + wasm::WasmElemSegment Segment; + Segment.TableIndex = readULEB128(Ptr); + if (Segment.TableIndex != 0) { + return make_error("Invalid TableIndex", + object_error::invalid_file_type); + } + if (Error Err = readInitExpr(Segment.Offset, Ptr)) + return Err; + int NumElems = readULEB128(Ptr); + while (NumElems--) { + Segment.Functions.push_back(readULEB128(Ptr)); + } + ElemSegments.push_back(Segment); + } + return Error::success(); +} + +Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, size_t Length) { + uint32_t SegCount = readULEB128(Ptr); + while (SegCount--) { + wasm::WasmDataSegment Segment; + Segment.Index = readULEB128(Ptr); + if (Error Err = readInitExpr(Segment.Offset, Ptr)) + return Err; + uint32_t Size = readULEB128(Ptr); + Segment.Content = ArrayRef(Ptr, Size); + Ptr += Size; + DataSegments.push_back(Segment); + } + return Error::success(); +} + +const uint8_t *WasmObjectFile::getPtr(size_t Offset) const { + return reinterpret_cast(getData().substr(Offset, 1).data()); +} + +const wasm::WasmObjectHeader& WasmObjectFile::getHeader() const { + return Header; +} + +void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { + llvm_unreachable("not yet implemented"); +} + +std::error_code WasmObjectFile::printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return object_error::invalid_file_type; +} + +uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return 0; +} + +basic_symbol_iterator WasmObjectFile::symbol_begin_impl() const { + return BasicSymbolRef(DataRefImpl(), this); +} + +basic_symbol_iterator WasmObjectFile::symbol_end_impl() const { + return BasicSymbolRef(DataRefImpl(), this); +} + +Expected WasmObjectFile::getSymbolName(DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return errorCodeToError(object_error::invalid_file_type); +} + +Expected WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return errorCodeToError(object_error::invalid_file_type); +} + +uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return 0; +} + +uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return 0; +} + +uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return 0; +} + +Expected +WasmObjectFile::getSymbolType(DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return errorCodeToError(object_error::invalid_file_type); +} + +Expected +WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { + llvm_unreachable("not yet implemented"); + return errorCodeToError(object_error::invalid_file_type); +} + +void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { + Sec.d.a++; +} + +std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, + StringRef &Res) const { + const wasm::WasmSection& S = Sections[Sec.d.a]; +#define ECase(X) case wasm::WASM_SEC_##X: Res = #X; break + switch (S.Type) { + ECase(USER); + ECase(TYPE); + ECase(IMPORT); + ECase(FUNCTION); + ECase(TABLE); + ECase(MEMORY); + ECase(GLOBAL); + ECase(EXPORT); + ECase(START); + ECase(ELEM); + ECase(CODE); + ECase(DATA); + default: + return object_error::invalid_file_type; + } + return std::error_code(); +} + +uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { + return 0; +} + +uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const { + const wasm::WasmSection& S = Sections[Sec.d.a]; + return S.Content.size(); +} + +std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec, + StringRef &Res) const { + const wasm::WasmSection& S = Sections[Sec.d.a]; + Res = StringRef(reinterpret_cast(S.Content.data()), + S.Content.size()); + return std::error_code(); +} + +uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const { + return 1; +} + +bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const { + return false; +} + +bool WasmObjectFile::isSectionText(DataRefImpl Sec) const { + const wasm::WasmSection& S = Sections[Sec.d.a]; + return S.Type == wasm::WASM_SEC_CODE; +} + +bool WasmObjectFile::isSectionData(DataRefImpl Sec) const { + const wasm::WasmSection& S = Sections[Sec.d.a]; + return S.Type == wasm::WASM_SEC_DATA; +} + +bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { + return false; +} + +bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { + return false; +} + +bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { + return false; +} + +relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Sec) const { + llvm_unreachable("not yet implemented"); + RelocationRef Rel; + return relocation_iterator(Rel); +} + +relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Sec) const { + llvm_unreachable("not yet implemented"); + RelocationRef Rel; + return relocation_iterator(Rel); +} + +section_iterator WasmObjectFile::getRelocatedSection(DataRefImpl Sec) const { + llvm_unreachable("not yet implemented"); + SectionRef Ref; + return section_iterator(Ref); +} + +void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { + llvm_unreachable("not yet implemented"); +} + +uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Rel) const { + llvm_unreachable("not yet implemented"); + return 0; +} + +symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const { + llvm_unreachable("not yet implemented"); + SymbolRef Ref; + return symbol_iterator(Ref); +} + +uint64_t WasmObjectFile::getRelocationType(DataRefImpl Rel) const { + llvm_unreachable("not yet implemented"); + return 0; +} + +void WasmObjectFile::getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl &Result) const { + llvm_unreachable("not yet implemented"); +} + +section_iterator WasmObjectFile::section_begin() const { + DataRefImpl Ref; + Ref.d.a = 0; + return section_iterator(SectionRef(Ref, this)); +} + +section_iterator WasmObjectFile::section_end() const { + DataRefImpl Ref; + Ref.d.a = Sections.size(); + return section_iterator(SectionRef(Ref, this)); +} + +uint8_t WasmObjectFile::getBytesInAddress() const { + return 4; +} + +StringRef WasmObjectFile::getFileFormatName() const { + return "WASM"; +} + +unsigned WasmObjectFile::getArch() const { + return Triple::wasm32; +} + +bool WasmObjectFile::isRelocatableObject() const { + return false; +} + +const wasm::WasmSection * +WasmObjectFile::getWasmSection(const SectionRef &Section) const { + return &Sections[Section.getRawDataRefImpl().d.a]; +} + +} // end namespace object +} // end namespace llvm Index: lib/ObjectYAML/CMakeLists.txt =================================================================== --- lib/ObjectYAML/CMakeLists.txt +++ lib/ObjectYAML/CMakeLists.txt @@ -4,4 +4,5 @@ ELFYAML.cpp MachOYAML.cpp ObjectYAML.cpp + WasmYAML.cpp ) Index: lib/ObjectYAML/ObjectYAML.cpp =================================================================== --- lib/ObjectYAML/ObjectYAML.cpp +++ lib/ObjectYAML/ObjectYAML.cpp @@ -43,6 +43,9 @@ ObjectFile.FatMachO.reset(new MachOYAML::UniversalBinary()); MappingTraits::mapping(IO, *ObjectFile.FatMachO); + } else if (IO.mapTag("!WASM")) { + ObjectFile.Wasm.reset(new WasmYAML::Object()); + MappingTraits::mapping(IO, *ObjectFile.Wasm); } else { Input &In = (Input &)IO; std::string Tag = In.getCurrentNode()->getRawTag(); Index: lib/ObjectYAML/WasmYAML.cpp =================================================================== --- /dev/null +++ lib/ObjectYAML/WasmYAML.cpp @@ -0,0 +1,273 @@ +//===- WasmYAML.cpp - Wasm 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 wasm. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Wasm.h" +#include "llvm/ObjectYAML/WasmYAML.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/MipsABIFlags.h" + +namespace llvm { +namespace yaml { + +void MappingTraits::mapping(IO &IO, + WasmYAML::FileHeader &FileHdr) { + IO.mapRequired("Version", FileHdr.Version); +} + +void MappingTraits::mapping(IO &IO, + WasmYAML::Object &Object) { + IO.setContext(&Object); + IO.mapTag("!WASM", true); + IO.mapRequired("FileHeader", Object.Header); + IO.mapOptional("Sections", Object.Sections); + IO.setContext(nullptr); +} + +static void commonSectionMapping(IO &IO, WasmYAML::Section &Section) { + IO.mapRequired("Type", Section.Type); +} + +static void sectionMapping(IO &IO, WasmYAML::TypeSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Signatures", Section.Signatures); +} + +static void sectionMapping(IO &IO, WasmYAML::ImportSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Imports", Section.Imports); +} + +static void sectionMapping(IO &IO, WasmYAML::FunctionSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("FunctionTypes", Section.FunctionTypes); +} + +static void sectionMapping(IO &IO, WasmYAML::TableSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Tables", Section.Tables); +} + +static void sectionMapping(IO &IO, WasmYAML::MemorySection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Memories", Section.Memories); +} + +static void sectionMapping(IO &IO, WasmYAML::ExportSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Exports", Section.Exports); +} + +static void sectionMapping(IO &IO, WasmYAML::ElemSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Segments", Section.Segments); +} + +static void sectionMapping(IO &IO, WasmYAML::CodeSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Content", Section.Content); +} + +static void sectionMapping(IO &IO, WasmYAML::DataSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Segments", Section.Segments); +} + +void MappingTraits>::mapping( + IO &IO, std::unique_ptr &Section) { + WasmYAML::SectionType SectionType; + if (IO.outputting()) + SectionType = Section->Type; + else + IO.mapRequired("Type", SectionType); + + switch (SectionType) { + case wasm::WASM_SEC_TYPE: + if (!IO.outputting()) + Section.reset(new WasmYAML::TypeSection()); + sectionMapping(IO, *cast(Section.get())); + break; + case wasm::WASM_SEC_IMPORT: + if (!IO.outputting()) + Section.reset(new WasmYAML::ImportSection()); + sectionMapping(IO, *cast(Section.get())); + break; + case wasm::WASM_SEC_FUNCTION: + if (!IO.outputting()) + Section.reset(new WasmYAML::FunctionSection()); + sectionMapping(IO, *cast(Section.get())); + break; + case wasm::WASM_SEC_TABLE: + if (!IO.outputting()) + Section.reset(new WasmYAML::TableSection()); + sectionMapping(IO, *cast(Section.get())); + break; + case wasm::WASM_SEC_MEMORY: + if (!IO.outputting()) + Section.reset(new WasmYAML::MemorySection()); + sectionMapping(IO, *cast(Section.get())); + break; + case wasm::WASM_SEC_EXPORT: + if (!IO.outputting()) + Section.reset(new WasmYAML::ExportSection()); + sectionMapping(IO, *cast(Section.get())); + break; + case wasm::WASM_SEC_ELEM: + if (!IO.outputting()) + Section.reset(new WasmYAML::ElemSection()); + sectionMapping(IO, *cast(Section.get())); + break; + case wasm::WASM_SEC_CODE: + if (!IO.outputting()) + Section.reset(new WasmYAML::CodeSection()); + sectionMapping(IO, *cast(Section.get())); + break; + case wasm::WASM_SEC_DATA: + if (!IO.outputting()) + Section.reset(new WasmYAML::DataSection()); + sectionMapping(IO, *cast(Section.get())); + break; + } +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::SectionType &Type) { +#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_SEC_##X); + ECase(USER); + ECase(TYPE); + ECase(IMPORT); + ECase(FUNCTION); + ECase(TABLE); + ECase(MEMORY); + ECase(GLOBAL); + ECase(EXPORT); + ECase(START); + ECase(ELEM); + ECase(CODE); + ECase(DATA); +#undef ECase +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::Signature &Signature) { + IO.mapRequired("ReturnType", Signature.ReturnType); + IO.mapRequired("ParamTypes", Signature.ParamTypes); +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::Table &Table) { + IO.mapRequired("ElemType", Table.ElemType); + IO.mapRequired("Limits", Table.TableLimits); +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::Limits &Limits) { + if (!IO.outputting() || Limits.Flags) + IO.mapOptional("Flags", Limits.Flags); + IO.mapRequired("Initial", Limits.Initial); + if (!IO.outputting() || Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) + IO.mapOptional("Maximum", Limits.Maximum); +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::ElemSegment &Segment) { + IO.mapRequired("Offset", Segment.Offset); + IO.mapRequired("Functions", Segment.Functions); +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::Import &Import) { + IO.mapRequired("Module", Import.Module); + IO.mapRequired("Field", Import.Field); + IO.mapRequired("Kind", Import.Kind); + IO.mapRequired("SigIndex", Import.SigIndex); +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::Export &Export) { + IO.mapRequired("Name", Export.Name); + IO.mapRequired("Kind", Export.Kind); + IO.mapRequired("Index", Export.Index); +} + +void MappingTraits::mapping( + IO &IO, wasm::WasmInitExpr &Expr) { + WasmYAML::Opcode Op = Expr.Opcode; + IO.mapRequired("Opcode", Op); + Expr.Opcode = Op; + switch (Expr.Opcode) { + case wasm::WASM_OP_I32_CONST: + IO.mapRequired("Value", Expr.Value.Int32); + break; + case wasm::WASM_OP_I64_CONST: + IO.mapRequired("Value", Expr.Value.Int64); + break; + case wasm::WASM_OP_F32_CONST: + IO.mapRequired("Value", Expr.Value.Float32); + break; + case wasm::WASM_OP_F64_CONST: + IO.mapRequired("Value", Expr.Value.Float64); + break; + } +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::DataSegment &Segment) { + IO.mapRequired("Index", Segment.Index); + IO.mapRequired("Offset", Segment.Offset); + IO.mapRequired("Content", Segment.Content); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::ValueType &Type) { +#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); + ECase(I32); + ECase(I64); + ECase(F32); + ECase(F64); + ECase(FUNC); + ECase(ANYFUNC); + ECase(VOID); +#undef ECase +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::ExportKind &Kind) { +#define ECase(X) IO.enumCase(Kind, #X, wasm::WASM_EXTERNAL_##X); + ECase(FUNC); + ECase(TABLE); + ECase(MEMORY); + ECase(GLOBAL); +#undef ECase +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::Opcode &Code) { +#define ECase(X) IO.enumCase(Code, #X, wasm::WASM_OP_##X); + ECase(END); + ECase(I32_CONST); + ECase(I64_CONST); + ECase(F64_CONST); + ECase(F32_CONST); + ECase(GET_GLOBAL); +#undef ECase +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::TableType &Type) { +#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); + ECase(ANYFUNC); +#undef ECase +} + +} // end namespace yaml +} // end namespace llvm Index: lib/Support/Path.cpp =================================================================== --- lib/Support/Path.cpp +++ lib/Support/Path.cpp @@ -1011,6 +1011,8 @@ // 0x0000 = COFF unknown machine type if (Magic[1] == 0) return file_magic::coff_object; + if (Magic[1] == 'a' && Magic[2] == 's' && Magic[3] == 'm') + return file_magic::wasm_object; break; } case 0xDE: // 0x0B17C0DE = BC wraper Index: test/ObjectYAML/Wasm/data_section.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/data_section.yaml @@ -0,0 +1,28 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +Sections: + - Type: MEMORY + Memories: + - Initial: 0x00000003 + - Type: DATA + Segments: + - Index: 0x00000000 + Offset: + Opcode: I32_CONST + Value: 4 + Content: '10001000' +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: Sections: +# CHECK: - Type: DATA +# CHECK: Segments: +# CHECK: - Index: 0x00000000 +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 4 +# CHECK: Content: '10001000' +# CHECK: ... Index: test/ObjectYAML/Wasm/elem_section.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/elem_section.yaml @@ -0,0 +1,42 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +Sections: + - Type: TABLE + Tables: + - ElemType: ANYFUNC + Limits: + Flags: 0x00000001 + Initial: 0x00000010 + Maximum: 0x00000011 + - Type: ELEM + Segments: + - Offset: + Opcode: I32_CONST + Value: 3 + Functions: + - 1 + - Offset: + Opcode: I32_CONST + Value: 5 + Functions: + - 4 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: Sections: +# CHECK: - Type: ELEM +# CHECK: Segments: +# CHECK: - Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 3 +# CHECK: Functions: +# CHECK: - 1 +# CHECK: - Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 5 +# CHECK: Functions: +# CHECK: - 4 +# CHECK: ... Index: test/ObjectYAML/Wasm/export_section.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/export_section.yaml @@ -0,0 +1,27 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +Sections: + - Type: EXPORT + Exports: + - Name: foo + Kind: FUNC + Index: 0x00000000 + - Name: bar + Kind: FUNC + Index: 0x00000001 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: Sections: +# CHECK: - Type: EXPORT +# CHECK: Exports: +# CHECK: - Name: foo +# CHECK: Kind: FUNC +# CHECK: Index: 0x00000000 +# CHECK: - Name: bar +# CHECK: Kind: FUNC +# CHECK: Index: 0x00000001 +# CHECK: ... Index: test/ObjectYAML/Wasm/function_section.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/function_section.yaml @@ -0,0 +1,19 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +Sections: + - Type: FUNCTION + FunctionTypes: + - 1 + - 0 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: Sections: +# CHECK: - Type: FUNCTION +# CHECK: FunctionTypes: +# CHECK: - 1 +# CHECK: - 0 +# CHECK: ... Index: test/ObjectYAML/Wasm/header.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/header.yaml @@ -0,0 +1,9 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: ... Index: test/ObjectYAML/Wasm/header_invalid_version.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/header_invalid_version.yaml @@ -0,0 +1,8 @@ +# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s + +--- !WASM +FileHeader: + Version: 0x0000000B +... + +# CHECK: Error: 'The file was not recognized as a valid object file' Index: test/ObjectYAML/Wasm/import_section.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/import_section.yaml @@ -0,0 +1,31 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +Sections: + - Type: IMPORT + Imports: + - Module: foo + Field: bar + Kind: FUNC + SigIndex: 0x00000000 + - Module: fiz + Field: baz + Kind: FUNC + SigIndex: 0x00000007 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: Sections: +# CHECK: - Type: IMPORT +# CHECK: Imports: +# CHECK: - Module: foo +# CHECK: Field: bar +# CHECK: Kind: FUNC +# CHECK: SigIndex: 0x00000000 +# CHECK: - Module: fiz +# CHECK: Field: baz +# CHECK: Kind: FUNC +# CHECK: SigIndex: 0x00000007 +# CHECK: ... Index: test/ObjectYAML/Wasm/memory_section.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/memory_section.yaml @@ -0,0 +1,23 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +Sections: + - Type: MEMORY + Memories: + - Flags: 0x00000001 + Initial: 0x00000002 + Maximum: 0x000000FF + - Initial: 0x00000003 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: Sections: +# CHECK: - Type: MEMORY +# CHECK: Memories: +# CHECK: - Flags: 0x00000001 +# CHECK: Initial: 0x00000002 +# CHECK: Maximum: 0x000000FF +# CHECK: - Initial: 0x00000003 +# CHECK: ... Index: test/ObjectYAML/Wasm/table_section.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/table_section.yaml @@ -0,0 +1,25 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +Sections: + - Type: TABLE + Tables: + - ElemType: ANYFUNC + Limits: + Flags: 0x00000001 + Initial: 0x00000010 + Maximum: 0x00000011 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: Sections: +# CHECK: - Type: TABLE +# CHECK: Tables: +# CHECK: - ElemType: ANYFUNC +# CHECK: Limits: +# CHECK: Flags: 0x00000001 +# CHECK: Initial: 0x00000010 +# CHECK: Maximum: 0x00000011 +# CHECK: ... Index: test/ObjectYAML/Wasm/type_section.yaml =================================================================== --- /dev/null +++ test/ObjectYAML/Wasm/type_section.yaml @@ -0,0 +1,31 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x0000000D +Sections: + - Type: TYPE + Signatures: + - ReturnType: I32 + ParamTypes: + - F32 + - F32 + - ReturnType: I64 + ParamTypes: + - F64 + - F64 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x0000000D +# CHECK: Sections: +# CHECK: - Type: TYPE +# CHECK: Signatures: +# CHECK: - ReturnType: I32 +# CHECK: ParamTypes: +# CHECK: - F32 +# CHECK: - F32 +# CHECK: - ReturnType: I64 +# CHECK: ParamTypes: +# CHECK: - F64 +# CHECK: - F64 +# CHECK: ... Index: test/tools/llvm-objdump/wasm.txt =================================================================== --- /dev/null +++ test/tools/llvm-objdump/wasm.txt @@ -0,0 +1,11 @@ +# RUN: llvm-objdump -p %p/Inputs/test.wasm | FileCheck %s + +# CHECK: Version: 0xd +# CHECK: Sections: +# CHECK: TYPE size 0x00000015 off 0x00000008 +# CHECK: IMPORT size 0x00000011 off 0x00000025 +# CHECK: FUNCTION size 0x00000003 off 0x00000038 +# CHECK: TABLE size 0x00000005 off 0x00000043 +# CHECK: EXPORT size 0x00000014 off 0x00000050 +# CHECK: ELEM size 0x00000007 off 0x00000066 +# CHECK: FUNCTION size 0x00000042 off 0x00000075 Index: test/tools/llvm-readobj/file-headers.test =================================================================== --- test/tools/llvm-readobj/file-headers.test +++ test/tools/llvm-readobj/file-headers.test @@ -26,6 +26,8 @@ RUN: | FileCheck %s -check-prefix COFF-IMPORTLIB RUN: llvm-readobj -h %p/Inputs/trivial.obj.elf-lanai \ RUN: | FileCheck %s -check-prefix ELF-LANAI +RUN: llvm-readobj -h %p/Inputs/trivial.obj.wasm \ +RUN: | FileCheck %s -check-prefix WASM COFF-ARM: File: {{(.*[/\\])?}}trivial.obj.coff-arm COFF-ARM-NEXT: Format: COFF-ARM @@ -367,3 +369,9 @@ ELF-LANAI-NEXT: SectionHeaderCount: 8 ELF-LANAI-NEXT: StringTableSectionIndex: 1 ELF-LANAI-NEXT: } + +WASM: Format: WASM +WASM: Arch: wasm32 +WASM: AddressSize: 32bit +WASM: Version: 0xD + Index: test/tools/llvm-readobj/sections.test =================================================================== --- test/tools/llvm-readobj/sections.test +++ test/tools/llvm-readobj/sections.test @@ -14,6 +14,8 @@ RUN: | FileCheck %s -check-prefix MACHO-PPC64 RUN: llvm-readobj -s %p/Inputs/trivial.obj.macho-arm \ RUN: | FileCheck %s -check-prefix MACHO-ARM +RUN: llvm-readobj -s %p/Inputs/trivial.obj.wasm \ +RUN: | FileCheck %s -check-prefix WASM COFF: Sections [ COFF-NEXT: Section { @@ -490,3 +492,41 @@ MACHO-ARM-NEXT: Reserved2: 0x0 MACHO-ARM-NEXT: } MACHO-ARM-NEXT:] + +WASM: Sections [ +WASM: Section { +WASM: Type: TYPE (0x1) +WASM: Size: 15 +WASM: Offset: 8 +WASM: } +WASM: Section { +WASM: Type: IMPORT (0x2) +WASM: Size: 11 +WASM: Offset: 25 +WASM: } +WASM: Section { +WASM: Type: FUNCTION (0x3) +WASM: Size: 3 +WASM: Offset: 38 +WASM: } +WASM: Section { +WASM: Type: TABLE (0x4) +WASM: Size: 5 +WASM: Offset: 43 +WASM: } +WASM: Section { +WASM: Type: EXPORT (0x7) +WASM: Size: 14 +WASM: Offset: 50 +WASM: } +WASM: Section { +WASM: Type: ELEM (0x9) +WASM: Size: 7 +WASM: Offset: 66 +WASM: } +WASM: Section { +WASM: Type: CODE (0xA) +WASM: Size: 42 +WASM: Offset: 75 +WASM: } +WASM: ] Index: tools/llvm-nm/llvm-nm.cpp =================================================================== --- tools/llvm-nm/llvm-nm.cpp +++ tools/llvm-nm/llvm-nm.cpp @@ -29,6 +29,7 @@ #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" #include "llvm/Support/COFF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -275,6 +276,8 @@ } if (isa(Obj)) return false; + if (isa(Obj)) + return false; if (MachOObjectFile *MachO = dyn_cast(&Obj)) return MachO->is64Bit(); return cast(Obj).getBytesInAddress() == 8; Index: tools/llvm-objdump/CMakeLists.txt =================================================================== --- tools/llvm-objdump/CMakeLists.txt +++ tools/llvm-objdump/CMakeLists.txt @@ -19,6 +19,7 @@ COFFDump.cpp ELFDump.cpp MachODump.cpp + WasmDump.cpp ) if(HAVE_LIBXAR) Index: tools/llvm-objdump/WasmDump.cpp =================================================================== --- /dev/null +++ tools/llvm-objdump/WasmDump.cpp @@ -0,0 +1,77 @@ +//===-- WasmDump.cpp - wasm-specific dumper ---------------------*- 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 implements the wasm-specific dumper for llvm-objdump. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-objdump.h" +#include "llvm/Object/Wasm.h" + +using namespace llvm; +using namespace object; + +void llvm::printWasmFileHeader(const object::ObjectFile *Obj) { + const WasmObjectFile *File = dyn_cast(Obj); + + outs() << "Version: 0x"; + outs().write_hex(File->getHeader().Version); + outs() << "\n"; + outs() << "\n"; + outs() << "Sections:\n"; + + for (auto &Section : File->sections()) { + const wasm::WasmSection* WasmSec = File->getWasmSection(Section); + switch (WasmSec->Type) { + case wasm::WASM_SEC_USER: + outs() << " USER"; + break; + case wasm::WASM_SEC_TYPE: + outs() << " TYPE"; + break; + case wasm::WASM_SEC_IMPORT: + outs() << " IMPORT"; + break; + case wasm::WASM_SEC_FUNCTION: + outs() << " FUNCTION"; + break; + case wasm::WASM_SEC_TABLE: + outs() << " TABLE"; + break; + case wasm::WASM_SEC_MEMORY: + outs() << " MEMORY"; + break; + case wasm::WASM_SEC_GLOBAL: + outs() << " GLOBAL"; + break; + case wasm::WASM_SEC_EXPORT: + outs() << " EXPORT"; + break; + case wasm::WASM_SEC_START: + outs() << " START"; + break; + case wasm::WASM_SEC_ELEM: + outs() << " ELEM"; + break; + case wasm::WASM_SEC_CODE: + outs() << " FUNCTION"; + break; + case wasm::WASM_SEC_DATA: + outs() << " FUNCTION"; + break; + default: + outs() << " UNKNOWN"; + break; + } + outs() << " size " << format("0x%08d", WasmSec->Content.size()); + outs() << " off " << format("0x%08d", WasmSec->Offset); + outs() << "\n"; + } +} Index: tools/llvm-objdump/llvm-objdump.h =================================================================== --- tools/llvm-objdump/llvm-objdump.h +++ tools/llvm-objdump/llvm-objdump.h @@ -79,6 +79,7 @@ void printCOFFSymbolTable(const object::COFFObjectFile *o); void printMachOFileHeader(const object::ObjectFile *o); void printMachOLoadCommands(const object::ObjectFile *o); +void printWasmFileHeader(const object::ObjectFile *o); void printExportsTrie(const object::ObjectFile *o); void printRebaseTable(const object::ObjectFile *o); void printBindTable(const object::ObjectFile *o); Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -1896,6 +1896,8 @@ return printELFFileHeader(o); if (o->isCOFF()) return printCOFFFileHeader(o); + if (o->isWasm()) + return printWasmFileHeader(o); if (o->isMachO()) { printMachOFileHeader(o); if (!onlyFirst) Index: tools/llvm-readobj/CMakeLists.txt =================================================================== --- tools/llvm-readobj/CMakeLists.txt +++ tools/llvm-readobj/CMakeLists.txt @@ -16,5 +16,6 @@ llvm-readobj.cpp MachODumper.cpp ObjDumper.cpp + WasmDumper.cpp Win64EHDumper.cpp ) Index: tools/llvm-readobj/MachODumper.cpp =================================================================== --- tools/llvm-readobj/MachODumper.cpp +++ tools/llvm-readobj/MachODumper.cpp @@ -1,4 +1,4 @@ -//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// +//===-- MachODumper.cpp - Object file dumping utility for llvm ------------===// // // The LLVM Compiler Infrastructure // Index: tools/llvm-readobj/ObjDumper.h =================================================================== --- tools/llvm-readobj/ObjDumper.h +++ tools/llvm-readobj/ObjDumper.h @@ -94,6 +94,10 @@ ScopedPrinter &Writer, std::unique_ptr &Result); +std::error_code createWasmDumper(const object::ObjectFile *Obj, + ScopedPrinter &Writer, + std::unique_ptr &Result); + void dumpCOFFImportFile(const object::COFFImportFile *File); void dumpCodeViewMergedTypes(ScopedPrinter &Writer, Index: tools/llvm-readobj/WasmDumper.cpp =================================================================== --- /dev/null +++ tools/llvm-readobj/WasmDumper.cpp @@ -0,0 +1,88 @@ +//===-- WasmDumper.cpp - Object file dumping utility for llvm --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Wasm-specific dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "ObjDumper.h" +#include "llvm/Object/Wasm.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace object; + +namespace { + +const char* wasmSectionTypeToString(uint32_t Type) { + switch (Type) { + case wasm::WASM_SEC_USER: return "USER"; + case wasm::WASM_SEC_TYPE: return "TYPE"; + case wasm::WASM_SEC_IMPORT: return "IMPORT"; + case wasm::WASM_SEC_FUNCTION: return "FUNCTION"; + case wasm::WASM_SEC_TABLE: return "TABLE"; + case wasm::WASM_SEC_MEMORY: return "MEMORY"; + case wasm::WASM_SEC_GLOBAL: return "GLOBAL"; + case wasm::WASM_SEC_EXPORT: return "EXPORT"; + case wasm::WASM_SEC_START: return "START"; + case wasm::WASM_SEC_ELEM: return "ELEM"; + case wasm::WASM_SEC_CODE: return "CODE"; + case wasm::WASM_SEC_DATA: return "DATA"; + } + return ""; +} + +class WasmDumper : public ObjDumper { +public: + WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer) + : ObjDumper(Writer), Obj(Obj) {} + + void printFileHeaders() override { + W.printHex("Version", Obj->getHeader().Version); + } + + void printSections() override { + ListScope Group(W, "Sections"); + for (const SectionRef &Section : Obj->sections()) { + const wasm::WasmSection* WasmSec = Obj->getWasmSection(Section); + DictScope SectionD(W, "Section"); + const char* Type = wasmSectionTypeToString(WasmSec->Type); + W.printHex("Type", Type, WasmSec->Type); + W.printNumber("Size", WasmSec->Content.size()); + W.printNumber("Offset", WasmSec->Offset); + } + } + void printRelocations() override { assert(0); } + void printSymbols() override { assert(0); } + void printDynamicSymbols() override { assert(0); } + void printUnwindInfo() override { assert(0); } + void printStackMap() const override { assert(0); } + +private: + + const WasmObjectFile *Obj; +}; + +} + +namespace llvm { + +std::error_code createWasmDumper(const object::ObjectFile *Obj, + ScopedPrinter &Writer, + std::unique_ptr &Result) { + const WasmObjectFile *WasmObj = dyn_cast(Obj); + if (!WasmObj) + return readobj_error::unsupported_obj_file_format; + + Result.reset(new WasmDumper(WasmObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm Index: tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- tools/llvm-readobj/llvm-readobj.cpp +++ tools/llvm-readobj/llvm-readobj.cpp @@ -354,6 +354,8 @@ return createELFDumper(Obj, Writer, Result); if (Obj->isMachO()) return createMachODumper(Obj, Writer, Result); + if (Obj->isWasm()) + return createWasmDumper(Obj, Writer, Result); return readobj_error::unsupported_obj_file_format; } Index: tools/obj2yaml/CMakeLists.txt =================================================================== --- tools/obj2yaml/CMakeLists.txt +++ tools/obj2yaml/CMakeLists.txt @@ -9,5 +9,6 @@ coff2yaml.cpp elf2yaml.cpp macho2yaml.cpp + wasm2yaml.cpp Error.cpp ) Index: tools/obj2yaml/coff2yaml.cpp =================================================================== --- tools/obj2yaml/coff2yaml.cpp +++ tools/obj2yaml/coff2yaml.cpp @@ -1,4 +1,4 @@ -//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// +//===------ utils/coff2yaml.cpp - obj2yaml conversion tool ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // Index: tools/obj2yaml/obj2yaml.h =================================================================== --- tools/obj2yaml/obj2yaml.h +++ tools/obj2yaml/obj2yaml.h @@ -14,6 +14,7 @@ #define LLVM_TOOLS_OBJ2YAML_OBJ2YAML_H #include "llvm/Object/COFF.h" +#include "llvm/Object/Wasm.h" #include "llvm/Support/raw_ostream.h" #include @@ -23,5 +24,7 @@ const llvm::object::ObjectFile &Obj); std::error_code macho2yaml(llvm::raw_ostream &Out, const llvm::object::Binary &Obj); +std::error_code wasm2yaml(llvm::raw_ostream &Out, + const llvm::object::WasmObjectFile &Obj); #endif Index: tools/obj2yaml/obj2yaml.cpp =================================================================== --- tools/obj2yaml/obj2yaml.cpp +++ tools/obj2yaml/obj2yaml.cpp @@ -24,6 +24,8 @@ return coff2yaml(outs(), cast(Obj)); if (Obj.isELF()) return elf2yaml(outs(), Obj); + if (Obj.isWasm()) + return wasm2yaml(outs(), cast(Obj)); return obj2yaml_error::unsupported_obj_file_format; } Index: tools/obj2yaml/wasm2yaml.cpp =================================================================== --- /dev/null +++ tools/obj2yaml/wasm2yaml.cpp @@ -0,0 +1,161 @@ +//===------ utils/wasm2yaml.cpp - obj2yaml conversion tool ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "obj2yaml.h" +#include "llvm/Object/COFF.h" +#include "llvm/ObjectYAML/WasmYAML.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace llvm; + +namespace { + +class WasmDumper { + const object::WasmObjectFile &Obj; + +public: + WasmDumper(const object::WasmObjectFile &O) : Obj(O) {} + ErrorOr dump(); +}; + +ErrorOr WasmDumper::dump() { + auto Y = make_unique(); + + // Dump header + Y->Header.Version = Obj.getHeader().Version; + + // Dump sections + for (const auto &Sec : Obj.sections()) { + const wasm::WasmSection* WasmSec = Obj.getWasmSection(Sec); + std::unique_ptr S; + switch (WasmSec->Type) { + case wasm::WASM_SEC_TYPE: { + WasmYAML::TypeSection* TypeSec = new WasmYAML::TypeSection; + for (const auto &FunctionSig : Obj.types()) { + WasmYAML::Signature Sig; + Sig.ReturnType = FunctionSig.ReturnType; + for (const auto &ParamType : FunctionSig.ParamTypes) + Sig.ParamTypes.push_back(ParamType); + TypeSec->Signatures.push_back(Sig); + } + S.reset(TypeSec); + break; + } + case wasm::WASM_SEC_IMPORT: { + WasmYAML::ImportSection* ImportSec = new WasmYAML::ImportSection; + for (auto &Import : Obj.imports()) { + WasmYAML::Import Ex; + Ex.Module = Import.Module; + Ex.Field = Import.Field; + Ex.Kind = Import.Kind; + Ex.SigIndex = Import.SigIndex; + ImportSec->Imports.push_back(Ex); + } + S.reset(ImportSec); + break; + } + case wasm::WASM_SEC_FUNCTION: { + WasmYAML::FunctionSection* FuncSec = new WasmYAML::FunctionSection; + for (const auto &Func : Obj.functions()) { + FuncSec->FunctionTypes.push_back(Func); + } + S.reset(FuncSec); + break; + } + case wasm::WASM_SEC_TABLE: { + WasmYAML::TableSection* TableSec = new WasmYAML::TableSection; + for (auto &Table : Obj.tables()) { + WasmYAML::Table T; + T.ElemType = Table.ElemType; + T.TableLimits.Flags = Table.Limits.Flags; + T.TableLimits.Initial = Table.Limits.Initial; + T.TableLimits.Maximum = Table.Limits.Maximum; + TableSec->Tables.push_back(T); + } + S.reset(TableSec); + break; + } + case wasm::WASM_SEC_MEMORY: { + WasmYAML::MemorySection* MemorySec = new WasmYAML::MemorySection; + for (auto &Memory : Obj.memories()) { + WasmYAML::Limits L; + L.Flags = Memory.Flags; + L.Initial = Memory.Initial; + L.Maximum = Memory.Maximum; + MemorySec->Memories.push_back(L); + } + S.reset(MemorySec); + break; + } + case wasm::WASM_SEC_EXPORT: { + WasmYAML::ExportSection* ExportSec = new WasmYAML::ExportSection; + for (auto &Export : Obj.exports()) { + WasmYAML::Export Ex; + Ex.Name = Export.Name; + Ex.Kind = Export.Kind; + Ex.Index = Export.Index; + ExportSec->Exports.push_back(Ex); + } + S.reset(ExportSec); + break; + } + case wasm::WASM_SEC_ELEM: { + WasmYAML::ElemSection* ElemSec = new WasmYAML::ElemSection; + for (auto &Segment : Obj.elements()) { + WasmYAML::ElemSegment Seg; + Seg.TableIndex = Segment.TableIndex; + Seg.Offset = Segment.Offset; + for (auto &Func : Segment.Functions) { + Seg.Functions.push_back(Func); + } + ElemSec->Segments.push_back(Seg); + } + S.reset(ElemSec); + break; + } + case wasm::WASM_SEC_CODE: { + WasmYAML::CodeSection* CodeSec = new WasmYAML::CodeSection(); + CodeSec->Content = yaml::BinaryRef(WasmSec->Content); + S.reset(CodeSec); + break; + } + case wasm::WASM_SEC_DATA: { + WasmYAML::DataSection* DataSec = new WasmYAML::DataSection(); + for (auto &Segment : Obj.dataSegments()) { + WasmYAML::DataSegment Seg; + Seg.Index = Segment.Index; + Seg.Offset = Segment.Offset; + Seg.Content = yaml::BinaryRef(Segment.Content); + DataSec->Segments.push_back(Seg); + } + S.reset(DataSec); + break; + } + } + Y->Sections.push_back(std::move(S)); + } + + return Y.release(); +} + +} + +std::error_code wasm2yaml(raw_ostream &Out, const object::WasmObjectFile &Obj) { + WasmDumper Dumper(Obj); + ErrorOr YAMLOrErr = Dumper.dump(); + if (std::error_code EC = YAMLOrErr.getError()) + return EC; + + std::unique_ptr YAML(YAMLOrErr.get()); + yaml::Output Yout(Out); + Yout << *YAML; + + return std::error_code(); +} Index: tools/yaml2obj/CMakeLists.txt =================================================================== --- tools/yaml2obj/CMakeLists.txt +++ tools/yaml2obj/CMakeLists.txt @@ -10,4 +10,5 @@ yaml2coff.cpp yaml2elf.cpp yaml2macho.cpp + yaml2wasm.cpp ) Index: tools/yaml2obj/yaml2obj.h =================================================================== --- tools/yaml2obj/yaml2obj.h +++ tools/yaml2obj/yaml2obj.h @@ -23,6 +23,10 @@ struct Object; } +namespace WasmYAML { +struct Object; +} + namespace yaml { class Input; struct YamlObjectFile; @@ -32,5 +36,6 @@ int yaml2coff(llvm::COFFYAML::Object &Doc, llvm::raw_ostream &Out); int yaml2elf(llvm::ELFYAML::Object &Doc, llvm::raw_ostream &Out); int yaml2macho(llvm::yaml::YamlObjectFile &Doc, llvm::raw_ostream &Out); +int yaml2wasm(llvm::WasmYAML::Object &Doc, llvm::raw_ostream &Out); #endif Index: tools/yaml2obj/yaml2obj.cpp =================================================================== --- tools/yaml2obj/yaml2obj.cpp +++ tools/yaml2obj/yaml2obj.cpp @@ -57,6 +57,8 @@ return yaml2coff(*Doc.Coff, Out); if (Doc.MachO || Doc.FatMachO) return yaml2macho(Doc, Out); + if (Doc.Wasm) + return yaml2wasm(*Doc.Wasm, Out); errs() << "yaml2obj: Unknown document type!\n"; return 1; } @@ -80,7 +82,7 @@ std::unique_ptr Out( new tool_output_file(OutputFilename, EC, sys::fs::F_None)); if (EC) { - errs() << EC.message() << '\n'; + errs() << "Error: '" << EC.message() << "'\n"; return 1; } Index: tools/yaml2obj/yaml2wasm.cpp =================================================================== --- /dev/null +++ tools/yaml2obj/yaml2wasm.cpp @@ -0,0 +1,271 @@ +//===- yaml2wasm - Convert YAML to a Wasm 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 Wasm component of yaml2obj. +/// +//===----------------------------------------------------------------------===// +// +#include "yaml2obj.h" +#include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/Object/Wasm.h" +#include "llvm/Support/LEB128.h" + +using namespace llvm; + +/// This parses a yaml stream that represents a Wasm object file. +/// See docs/yaml2obj for the yaml scheema. +class WasmWriter { +public: + WasmWriter(WasmYAML::Object &Obj) : Obj(Obj) {} + int writeWasm(raw_ostream &OS); + int writeSectionContent(raw_ostream &OS, WasmYAML::TypeSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::ImportSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::FunctionSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section); +private: + WasmYAML::Object &Obj; +}; + +static int writeUint64(raw_ostream &OS, uint64_t Value) { + char Data[sizeof(Value)]; + if (!sys::IsLittleEndianHost) + sys::swapByteOrder(Value); + memcpy(Data, &Value, sizeof(Data)); + OS.write(Data, sizeof(Data)); + return 0; +} + +static int writeUint32(raw_ostream &OS, uint32_t Value) { + char Data[sizeof(Value)]; + if (!sys::IsLittleEndianHost) + sys::swapByteOrder(Value); + memcpy(Data, &Value, sizeof(Data)); + OS.write(Data, sizeof(Data)); + return 0; +} + +static int writeUint8(raw_ostream &OS, uint8_t Value) { + char Data[sizeof(Value)]; + memcpy(Data, &Value, sizeof(Data)); + OS.write(Data, sizeof(Data)); + return 0; +} + +static int writeStringRef(StringRef &Str, raw_ostream &OS) { + encodeULEB128(Str.size(), OS); + OS << Str; + return 0; +} + +static int writeLimits(WasmYAML::Limits Lim, raw_ostream &OS) { + encodeULEB128(Lim.Flags, OS); + encodeULEB128(Lim.Initial, OS); + if (Lim.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) + encodeULEB128(Lim.Maximum, OS); + return 0; +} + +static int writeInitExpr(wasm::WasmInitExpr InitExpr, raw_ostream &OS) { + writeUint8(OS, InitExpr.Opcode); + switch (InitExpr.Opcode) { + case wasm::WASM_OP_I32_CONST: + encodeSLEB128(InitExpr.Value.Int32, OS); + break; + case wasm::WASM_OP_I64_CONST: + encodeSLEB128(InitExpr.Value.Int64, OS); + break; + case wasm::WASM_OP_F32_CONST: + writeUint32(OS, InitExpr.Value.Float32); + break; + case wasm::WASM_OP_F64_CONST: + writeUint64(OS, InitExpr.Value.Float64); + break; + case wasm::WASM_OP_GET_GLOBAL: + encodeULEB128(InitExpr.Value.Global, OS); + break; + default: + errs() << "Unknown opcode in init_expr: " << InitExpr.Opcode; + return 1; + } + writeUint8(OS, wasm::WASM_OP_END); + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::TypeSection &Section) { + encodeULEB128(Section.Signatures.size(), OS); + for (auto &Sig : Section.Signatures) { + encodeSLEB128(Sig.Form, OS); + encodeULEB128(Sig.ParamTypes.size(), OS); + for (auto ParamType : Sig.ParamTypes) + encodeSLEB128(ParamType, OS); + if (Sig.ReturnType == wasm::WASM_TYPE_VOID) { + encodeULEB128(0, OS); + } else { + encodeULEB128(1, OS); + encodeSLEB128(Sig.ReturnType, OS); + } + } + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::ImportSection &Section) { + encodeULEB128(Section.Imports.size(), OS); + for (auto &Import : Section.Imports) { + writeStringRef(Import.Module, OS); + writeStringRef(Import.Field, OS); + encodeULEB128(Import.Kind, OS); + switch (Import.Kind) { + case wasm::WASM_EXTERNAL_FUNC: + encodeULEB128(Import.SigIndex, OS); + break; + default: + errs() << "Unknown import type: " << Import.Kind; + return 1; + } + } + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::FunctionSection &Section) { + encodeULEB128(Section.FunctionTypes.size(), OS); + for (uint32_t FuncType : Section.FunctionTypes) { + encodeULEB128(FuncType, OS); + } + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::ExportSection &Section) { + encodeULEB128(Section.Exports.size(), OS); + for (auto &Export : Section.Exports) { + writeStringRef(Export.Name, OS); + encodeULEB128(Export.Kind, OS); + encodeULEB128(Export.Index, OS); + } + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::TableSection &Section) { + encodeULEB128(Section.Tables.size(), OS); + for (auto &Table : Section.Tables) { + encodeSLEB128(Table.ElemType, OS); + writeLimits(Table.TableLimits, OS); + } + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::MemorySection &Section) { + encodeULEB128(Section.Memories.size(), OS); + for (auto &Mem : Section.Memories) { + writeLimits(Mem, OS); + } + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::ElemSection &Section) { + encodeULEB128(Section.Segments.size(), OS); + for (auto &Segment : Section.Segments) { + encodeULEB128(Segment.TableIndex, OS); + writeInitExpr(Segment.Offset, OS); + + encodeULEB128(Segment.Functions.size(), OS); + for (auto &Function : Segment.Functions) { + encodeULEB128(Function, OS); + } + } + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::CodeSection &Section) { + Section.Content.writeAsBinary(OS); + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::DataSection &Section) { + encodeULEB128(Section.Segments.size(), OS); + for (auto &Segment : Section.Segments) { + encodeULEB128(Segment.Index, OS); + writeInitExpr(Segment.Offset, OS); + encodeULEB128(Segment.Content.binary_size(), OS); + Segment.Content.writeAsBinary(OS); + } + return 0; +} + +int WasmWriter::writeWasm(raw_ostream &OS) { + // Write headers + OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic)); + writeUint32(OS, Obj.Header.Version); + + // Write each section + for (const std::unique_ptr &Sec : Obj.Sections) { + encodeULEB128(Sec->Type, OS); + + std::string OutString; + raw_string_ostream StringStream(OutString); + if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else if (auto S = dyn_cast(Sec.get())) { + if (auto Err = writeSectionContent(StringStream, *S)) + return Err; + } else { + errs() << "Unknown section type: " << Sec->Type << "\n"; + return 1; + } + StringStream.flush(); + + // Write the section size followed by the content + encodeULEB128(OutString.size(), OS); + OS << OutString; + } + + return 0; +} + +int yaml2wasm(llvm::WasmYAML::Object &Doc, raw_ostream &Out) { + WasmWriter Writer(Doc); + + return Writer.writeWasm(Out); +}