Index: llvm/trunk/include/llvm/Object/Wasm.h =================================================================== --- llvm/trunk/include/llvm/Object/Wasm.h +++ llvm/trunk/include/llvm/Object/Wasm.h @@ -29,21 +29,64 @@ namespace llvm { namespace object { +class WasmSymbol { +public: + enum class SymbolType { + FUNCTION_IMPORT, + FUNCTION_EXPORT, + GLOBAL_IMPORT, + GLOBAL_EXPORT, + DEBUG_FUNCTION_NAME, + }; + + WasmSymbol(StringRef Name, SymbolType Type) : Name(Name), Type(Type) {} + + StringRef Name; + SymbolType Type; +}; + +class WasmSection { +public: + WasmSection() : Type(0), Offset(0) {} + + uint32_t Type; // Section type (See below) + uint32_t Offset; // Offset with in the file + StringRef Name; // Section name (User-defined sections only) + ArrayRef Content; // Section content + std::vector Relocations; // Relocations for this section +}; + class WasmObjectFile : public ObjectFile { public: WasmObjectFile(MemoryBufferRef Object, Error &Err); const wasm::WasmObjectHeader &getHeader() const; - const wasm::WasmSection *getWasmSection(const SectionRef &Section) const; + const WasmSymbol &getWasmSymbol(DataRefImpl Symb) const; + const WasmSection &getWasmSection(const SectionRef &Section) const; + const wasm::WasmRelocation &getWasmRelocation(const RelocationRef& Ref) const; static bool classof(const Binary *v) { return v->isWasm(); } + const std::vector& types() const { return Signatures; } + const std::vector& functionTypes() const { return FunctionTypes; } + const std::vector& imports() const { return Imports; } + const std::vector& tables() const { return Tables; } + const std::vector& memories() const { return Memories; } + const std::vector& globals() const { return Globals; } + const std::vector& exports() const { return Exports; } + const std::vector& elements() const { + return ElemSegments; + } + const std::vector& dataSegments() const { + return DataSegments; + } + const std::vector& functions() const { return Functions; } + const ArrayRef& code() const { return CodeSection; } + uint32_t startFunction() const { return StartFunction; } + protected: 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() const override; @@ -75,7 +118,6 @@ 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. void moveRelocationNext(DataRefImpl &Rel) const override; @@ -94,12 +136,50 @@ bool isRelocatableObject() const override; private: + const WasmSection &getWasmSection(DataRefImpl Ref) const; + const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; + + WasmSection* findCustomSectionByName(StringRef Name); + WasmSection* findSectionByType(uint32_t Type); + const uint8_t *getPtr(size_t Offset) const; - Error parseCustomSection(wasm::WasmSection &Sec, const uint8_t *Ptr, - size_t Length); + Error parseSection(WasmSection &Sec); + Error parseCustomSection(WasmSection &Sec, const uint8_t *Ptr, + const uint8_t *End); + + // Standard section types + Error parseTypeSection(const uint8_t *Ptr, const uint8_t *End); + Error parseImportSection(const uint8_t *Ptr, const uint8_t *End); + Error parseFunctionSection(const uint8_t *Ptr, const uint8_t *End); + Error parseTableSection(const uint8_t *Ptr, const uint8_t *End); + Error parseMemorySection(const uint8_t *Ptr, const uint8_t *End); + Error parseGlobalSection(const uint8_t *Ptr, const uint8_t *End); + Error parseExportSection(const uint8_t *Ptr, const uint8_t *End); + Error parseStartSection(const uint8_t *Ptr, const uint8_t *End); + Error parseElemSection(const uint8_t *Ptr, const uint8_t *End); + Error parseCodeSection(const uint8_t *Ptr, const uint8_t *End); + Error parseDataSection(const uint8_t *Ptr, const uint8_t *End); + + // Custom section types + Error parseNameSection(const uint8_t *Ptr, const uint8_t *End); + Error parseRelocSection(StringRef Name, const uint8_t *Ptr, + const uint8_t *End); wasm::WasmObjectHeader Header; - std::vector Sections; + std::vector Sections; + std::vector Signatures; + std::vector FunctionTypes; + std::vector Tables; + std::vector Memories; + std::vector Globals; + std::vector Imports; + std::vector Exports; + std::vector ElemSegments; + std::vector DataSegments; + std::vector Symbols; + std::vector Functions; + ArrayRef CodeSection; + uint32_t StartFunction; }; } // end namespace object Index: llvm/trunk/include/llvm/ObjectYAML/ObjectYAML.h =================================================================== --- llvm/trunk/include/llvm/ObjectYAML/ObjectYAML.h +++ llvm/trunk/include/llvm/ObjectYAML/ObjectYAML.h @@ -10,10 +10,11 @@ #ifndef LLVM_OBJECTYAML_OBJECTYAML_H #define LLVM_OBJECTYAML_OBJECTYAML_H -#include "llvm/Support/YAMLTraits.h" -#include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/ObjectYAML/COFFYAML.h" +#include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/ObjectYAML/MachOYAML.h" +#include "llvm/ObjectYAML/WasmYAML.h" +#include "llvm/Support/YAMLTraits.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: llvm/trunk/include/llvm/ObjectYAML/WasmYAML.h =================================================================== --- llvm/trunk/include/llvm/ObjectYAML/WasmYAML.h +++ llvm/trunk/include/llvm/ObjectYAML/WasmYAML.h @@ -0,0 +1,338 @@ +//===- 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/ObjectYAML/YAML.h" +#include "llvm/Support/Wasm.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) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, RelocType) + +struct FileHeader { + yaml::Hex32 Version; +}; + +struct Import { + StringRef Module; + StringRef Field; + ExportKind Kind; + union { + uint32_t SigIndex; + ValueType GlobalType; + }; + bool GlobalMutable; +}; + +struct Limits { + yaml::Hex32 Flags; + yaml::Hex32 Initial; + yaml::Hex32 Maximum; +}; + +struct Table { + TableType ElemType; + Limits TableLimits; +}; + +struct Export { + StringRef Name; + ExportKind Kind; + uint32_t Index; +}; + +struct ElemSegment { + uint32_t TableIndex; + wasm::WasmInitExpr Offset; + std::vector Functions; +}; + +struct Global { + ValueType Type; + bool Mutable; + wasm::WasmInitExpr InitExpr; +}; + +struct LocalDecl { + ValueType Type; + uint32_t Count; +}; + +struct Function { + std::vector Locals; + yaml::BinaryRef Body; +}; + +struct Relocation { + RelocType Type; + uint32_t Index; + yaml::Hex32 Offset; + yaml::Hex32 Addend; +}; + +struct DataSegment { + uint32_t Index; + wasm::WasmInitExpr Offset; + yaml::BinaryRef Content; +}; + +struct Signature { + Signature() : Form(wasm::WASM_TYPE_FUNC) {} + + uint32_t Index; + SignatureForm Form; + std::vector ParamTypes; + ValueType ReturnType; +}; + +struct Section { + Section(SectionType SecType) : Type(SecType) {} + + SectionType Type; + std::vector Relocations; +}; + +struct CustomSection : Section { + CustomSection() : Section(wasm::WASM_SEC_CUSTOM) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_CUSTOM; + } + + StringRef Name; + yaml::BinaryRef Payload; +}; + +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 GlobalSection : Section { + GlobalSection() : Section(wasm::WASM_SEC_GLOBAL) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_GLOBAL; + } + + std::vector Globals; +}; + +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 StartSection : Section { + StartSection() : Section(wasm::WASM_SEC_START) {} + static bool classof(const Section *S) { + return S->Type == wasm::WASM_SEC_START; + } + + uint32_t StartFunction; +}; + +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; + } + + std::vector Functions; +}; + +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(llvm::WasmYAML::Global) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Function) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::LocalDecl) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Relocation) +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 MappingTraits { + static void mapping(IO &IO, WasmYAML::Global &Global); +}; + +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, WasmYAML::Function &Function); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Relocation &Relocation); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::LocalDecl &LocalDecl); +}; + +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); +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, WasmYAML::RelocType &Kind); +}; + +} // end namespace yaml +} // end namespace llvm + +#endif Index: llvm/trunk/include/llvm/Support/Wasm.h =================================================================== --- llvm/trunk/include/llvm/Support/Wasm.h +++ llvm/trunk/include/llvm/Support/Wasm.h @@ -30,11 +30,83 @@ uint32_t Version; }; -struct WasmSection { - uint32_t Type; // Section type (See below) - uint32_t Offset; // Offset with in the file - StringRef Name; // Section name (User-defined sections only) - ArrayRef Content; // Section content +struct WasmSignature { + std::vector ParamTypes; + int32_t ReturnType; +}; + +struct WasmImport { + StringRef Module; + StringRef Field; + uint32_t Kind; + union { + uint32_t SigIndex; + int32_t GlobalType; + }; + bool GlobalMutable; +}; + +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 { + int32_t Int32; + int64_t Int64; + int32_t Float32; + int64_t Float64; + uint32_t Global; + } Value; +}; + +struct WasmGlobal { + int32_t Type; + bool Mutable; + WasmInitExpr InitExpr; +}; + +struct WasmLocalDecl { + int32_t Type; + uint32_t Count; +}; + +struct WasmFunction { + std::vector Locals; + ArrayRef Body; +}; + +struct WasmDataSegment { + uint32_t Index; + WasmInitExpr Offset; + ArrayRef Content; +}; + +struct WasmElemSegment { + uint32_t TableIndex; + WasmInitExpr Offset; + std::vector Functions; +}; + +struct WasmRelocation { + uint32_t Type; // The type of the relocation. + int32_t Index; // Index into function to global index space. + uint64_t Offset; // Offset from the start of the section. + uint64_t Addend; // A value to add to the symbol. }; enum : unsigned { @@ -86,6 +158,10 @@ WASM_NAMES_LOCAL = 0x2, }; +enum : unsigned { + WASM_LIMITS_FLAG_HAS_MAX = 0x1, +}; + // Subset of types that a value can have enum class ValType { I32 = WASM_TYPE_I32, @@ -100,6 +176,8 @@ #include "WasmRelocs/WebAssembly.def" }; +#undef WASM_RELOC + } // end namespace wasm } // end namespace llvm Index: llvm/trunk/lib/Object/WasmObjectFile.cpp =================================================================== --- llvm/trunk/lib/Object/WasmObjectFile.cpp +++ llvm/trunk/lib/Object/WasmObjectFile.cpp @@ -38,12 +38,33 @@ return std::move(ObjectFile); } +#define VARINT7_MAX ((1<<7)-1) +#define VARINT7_MIN (-(1<<7)) +#define VARUINT7_MAX (1<<7) +#define VARUINT1_MAX (1) + +static uint8_t readUint8(const uint8_t *&Ptr) { return *Ptr++; } + static uint32_t readUint32(const uint8_t *&Ptr) { uint32_t Result = support::endian::read32le(Ptr); Ptr += sizeof(Result); return Result; } +static int32_t readFloat32(const uint8_t *&Ptr) { + int32_t Result = 0; + memcpy(&Result, Ptr, sizeof(Result)); + Ptr += sizeof(Result); + return Result; +} + +static int64_t readFloat64(const uint8_t *&Ptr) { + int64_t Result = 0; + memcpy(&Result, Ptr, sizeof(Result)); + Ptr += sizeof(Result); + return Result; +} + static uint64_t readULEB128(const uint8_t *&Ptr) { unsigned Count; uint64_t Result = decodeULEB128(Ptr, &Count); @@ -58,12 +79,98 @@ return Return; } -static Error readSection(wasm::WasmSection &Section, const uint8_t *&Ptr, +static int64_t readLEB128(const uint8_t *&Ptr) { + unsigned Count; + uint64_t Result = decodeSLEB128(Ptr, &Count); + Ptr += Count; + return Result; +} + +static uint8_t readVaruint1(const uint8_t *&Ptr) { + int64_t result = readLEB128(Ptr); + assert(result <= VARUINT1_MAX && result >= 0); + return result; +} + +static int8_t readVarint7(const uint8_t *&Ptr) { + int64_t result = readLEB128(Ptr); + assert(result <= VARINT7_MAX && result >= VARINT7_MIN); + return result; +} + +static uint8_t readVaruint7(const uint8_t *&Ptr) { + uint64_t result = readULEB128(Ptr); + assert(result <= VARUINT7_MAX && result >= 0); + return result; +} + +static int32_t readVarint32(const uint8_t *&Ptr) { + int64_t result = readLEB128(Ptr); + assert(result <= INT32_MAX && result >= INT32_MIN); + return result; +} + +static uint32_t readVaruint32(const uint8_t *&Ptr) { + uint64_t result = readULEB128(Ptr); + assert(result <= UINT32_MAX && result >= 0); + return result; +} + +static int64_t readVarint64(const uint8_t *&Ptr) { + return readLEB128(Ptr); +} + +static uint8_t readOpcode(const uint8_t *&Ptr) { + return readUint8(Ptr); +} + +static Error readInitExpr(wasm::WasmInitExpr &Expr, const uint8_t *&Ptr) { + Expr.Opcode = readOpcode(Ptr); + + switch (Expr.Opcode) { + case wasm::WASM_OPCODE_I32_CONST: + Expr.Value.Int32 = readVarint32(Ptr); + break; + case wasm::WASM_OPCODE_I64_CONST: + Expr.Value.Int64 = readVarint64(Ptr); + break; + case wasm::WASM_OPCODE_F32_CONST: + Expr.Value.Float32 = readFloat32(Ptr); + break; + case wasm::WASM_OPCODE_F64_CONST: + Expr.Value.Float64 = readFloat64(Ptr); + break; + case wasm::WASM_OPCODE_GET_GLOBAL: + Expr.Value.Global = readUint32(Ptr); + break; + default: + return make_error("Invalid opcode in init_expr", + object_error::parse_failed); + } + + uint8_t EndOpcode = readOpcode(Ptr); + if (EndOpcode != wasm::WASM_OPCODE_END) { + return make_error("Invalid init_expr", + object_error::parse_failed); + } + return Error::success(); +} + +static wasm::WasmLimits readLimits(const uint8_t *&Ptr) { + wasm::WasmLimits Result; + Result.Flags = readVaruint1(Ptr); + Result.Initial = readVaruint32(Ptr); + if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) + Result.Maximum = readVaruint32(Ptr); + return Result; +} + +static Error readSection(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.Type = readVaruint7(Ptr); + uint32_t Size = readVaruint32(Ptr); if (Size == 0) return make_error("Zero length section", object_error::parse_failed); @@ -73,7 +180,7 @@ } WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) - : ObjectFile(Binary::ID_Wasm, Buffer) { + : ObjectFile(Binary::ID_Wasm, Buffer), StartFunction(-1) { ErrorAsOutParameter ErrAsOutParam(&Err); Header.Magic = getData().substr(0, 4); if (Header.Magic != StringRef("\0asm", 4)) { @@ -90,22 +197,391 @@ } const uint8_t *Eof = getPtr(getData().size()); - wasm::WasmSection Sec; + WasmSection Sec; while (Ptr < Eof) { if ((Err = readSection(Sec, Ptr, getPtr(0)))) return; - if (Sec.Type == wasm::WASM_SEC_CUSTOM) { - if ((Err = - parseCustomSection(Sec, Sec.Content.data(), Sec.Content.size()))) - return; - } + if ((Err = parseSection(Sec))) + return; + Sections.push_back(Sec); } } -Error WasmObjectFile::parseCustomSection(wasm::WasmSection &Sec, - const uint8_t *Ptr, size_t Length) { +Error WasmObjectFile::parseSection(WasmSection &Sec) { + const uint8_t* Start = Sec.Content.data(); + const uint8_t* End = Start + Sec.Content.size(); + switch (Sec.Type) { + case wasm::WASM_SEC_CUSTOM: + return parseCustomSection(Sec, Start, End); + case wasm::WASM_SEC_TYPE: + return parseTypeSection(Start, End); + case wasm::WASM_SEC_IMPORT: + return parseImportSection(Start, End); + case wasm::WASM_SEC_FUNCTION: + return parseFunctionSection(Start, End); + case wasm::WASM_SEC_TABLE: + return parseTableSection(Start, End); + case wasm::WASM_SEC_MEMORY: + return parseMemorySection(Start, End); + case wasm::WASM_SEC_GLOBAL: + return parseGlobalSection(Start, End); + case wasm::WASM_SEC_EXPORT: + return parseExportSection(Start, End); + case wasm::WASM_SEC_START: + return parseStartSection(Start, End); + case wasm::WASM_SEC_ELEM: + return parseElemSection(Start, End); + case wasm::WASM_SEC_CODE: + return parseCodeSection(Start, End); + case wasm::WASM_SEC_DATA: + return parseDataSection(Start, End); + default: + return make_error("Bad section type", + object_error::parse_failed); + } +} + +Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { + while (Ptr < End) { + uint8_t Type = readVarint7(Ptr); + uint32_t Size = readVaruint32(Ptr); + switch (Type) { + case wasm::WASM_NAMES_FUNCTION: { + uint32_t Count = readVaruint32(Ptr); + while (Count--) { + /*uint32_t Index =*/readVaruint32(Ptr); + StringRef Name = readString(Ptr); + if (Name.size()) + Symbols.emplace_back(Name, + WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME); + } + break; + } + // Ignore local names for now + case wasm::WASM_NAMES_LOCAL: + default: + Ptr += Size; + break; + } + } + + if (Ptr != End) + return make_error("Name section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +WasmSection* WasmObjectFile::findCustomSectionByName(StringRef Name) { + for (WasmSection& Section : Sections) { + if (Section.Type == wasm::WASM_SEC_CUSTOM && Section.Name == Name) + return &Section; + } + return nullptr; +} + +WasmSection* WasmObjectFile::findSectionByType(uint32_t Type) { + assert(Type != wasm::WASM_SEC_CUSTOM); + for (WasmSection& Section : Sections) { + if (Section.Type == Type) + return &Section; + } + return nullptr; +} + +Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr, + const uint8_t *End) { + uint8_t SectionCode = readVarint7(Ptr); + WasmSection* Section = nullptr; + if (SectionCode == wasm::WASM_SEC_CUSTOM) { + StringRef Name = readString(Ptr); + Section = findCustomSectionByName(Name); + } else { + Section = findSectionByType(SectionCode); + } + if (!Section) + return make_error("Invalid section code", + object_error::parse_failed); + uint32_t RelocCount = readVaruint32(Ptr); + while (RelocCount--) { + wasm::WasmRelocation Reloc; + memset(&Reloc, 0, sizeof(Reloc)); + Reloc.Type = readVaruint32(Ptr); + Reloc.Offset = readVaruint32(Ptr); + Reloc.Index = readVaruint32(Ptr); + switch (Reloc.Type) { + case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + break; + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + Reloc.Addend = readVaruint32(Ptr); + break; + default: + return make_error("Bad relocation type", + object_error::parse_failed); + } + Section->Relocations.push_back(Reloc); + } + if (Ptr != End) + return make_error("Reloc section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseCustomSection(WasmSection &Sec, + const uint8_t *Ptr, const uint8_t *End) { Sec.Name = readString(Ptr); + if (Sec.Name == "name") { + if (Error Err = parseNameSection(Ptr, End)) + return Err; + } else if (Sec.Name.startswith("reloc.")) { + if (Error Err = parseRelocSection(Sec.Name, Ptr, End)) + return Err; + } + return Error::success(); +} + +Error WasmObjectFile::parseTypeSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + Signatures.reserve(Count); + while (Count--) { + wasm::WasmSignature Sig; + Sig.ReturnType = wasm::WASM_TYPE_NORESULT; + int8_t Form = readVarint7(Ptr); + if (Form != wasm::WASM_TYPE_FUNC) { + return make_error("Invalid signature type", + object_error::parse_failed); + } + uint32_t ParamCount = readVaruint32(Ptr); + Sig.ParamTypes.reserve(ParamCount); + while (ParamCount--) { + uint32_t ParamType = readVarint7(Ptr); + Sig.ParamTypes.push_back(ParamType); + } + uint32_t ReturnCount = readVaruint32(Ptr); + if (ReturnCount) { + if (ReturnCount != 1) { + return make_error( + "Multiple return types not supported", object_error::parse_failed); + } + Sig.ReturnType = readVarint7(Ptr); + } + Signatures.push_back(Sig); + } + if (Ptr != End) + return make_error("Type section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + Imports.reserve(Count); + while (Count--) { + wasm::WasmImport Im; + Im.Module = readString(Ptr); + Im.Field = readString(Ptr); + Im.Kind = readUint8(Ptr); + switch (Im.Kind) { + case wasm::WASM_EXTERNAL_FUNCTION: + Im.SigIndex = readVaruint32(Ptr); + Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::FUNCTION_IMPORT); + break; + case wasm::WASM_EXTERNAL_GLOBAL: + Im.GlobalType = readVarint7(Ptr); + Im.GlobalMutable = readVaruint1(Ptr); + Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT); + break; + default: + // TODO(sbc): Handle other kinds of imports + return make_error( + "Unexpected import kind", object_error::parse_failed); + } + Imports.push_back(Im); + } + if (Ptr != End) + return make_error("Import section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseFunctionSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + FunctionTypes.reserve(Count); + while (Count--) { + FunctionTypes.push_back(readVaruint32(Ptr)); + } + if (Ptr != End) + return make_error("Function section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseTableSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + Tables.reserve(Count); + while (Count--) { + wasm::WasmTable Table; + Table.ElemType = readVarint7(Ptr); + if (Table.ElemType != wasm::WASM_TYPE_ANYFUNC) { + return make_error("Invalid table element type", + object_error::parse_failed); + } + Table.Limits = readLimits(Ptr); + Tables.push_back(Table); + } + if (Ptr != End) + return make_error("Table section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseMemorySection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + Memories.reserve(Count); + while (Count--) { + Memories.push_back(readLimits(Ptr)); + } + if (Ptr != End) + return make_error("Memory section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + Globals.reserve(Count); + while (Count--) { + wasm::WasmGlobal Global; + Global.Type = readVarint7(Ptr); + Global.Mutable = readVaruint1(Ptr); + size_t offset = Ptr - getPtr(0); + if (Error Err = readInitExpr(Global.InitExpr, Ptr)) { + offset = Ptr - getPtr(0); + return Err; + } + Globals.push_back(Global); + } + if (Ptr != End) + return make_error("Global section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + Exports.reserve(Count); + while (Count--) { + wasm::WasmExport Ex; + Ex.Name = readString(Ptr); + Ex.Kind = readUint8(Ptr); + Ex.Index = readVaruint32(Ptr); + Exports.push_back(Ex); + switch (Ex.Kind) { + case wasm::WASM_EXTERNAL_FUNCTION: + Symbols.emplace_back(Ex.Name, WasmSymbol::SymbolType::FUNCTION_EXPORT); + break; + case wasm::WASM_EXTERNAL_GLOBAL: + Symbols.emplace_back(Ex.Name, WasmSymbol::SymbolType::GLOBAL_EXPORT); + break; + default: + // TODO(sbc): Handle other kinds of exports + return make_error( + "Unexpected export kind", object_error::parse_failed); + } + } + if (Ptr != End) + return make_error("Export section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseStartSection(const uint8_t *Ptr, const uint8_t *End) { + StartFunction = readVaruint32(Ptr); + if (StartFunction < FunctionTypes.size()) + return make_error("Invalid start function", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseCodeSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t FunctionCount = readVaruint32(Ptr); + if (FunctionCount != FunctionTypes.size()) { + return make_error("Invalid function count", + object_error::parse_failed); + } + + CodeSection = ArrayRef(Ptr, End - Ptr); + + while (FunctionCount--) { + wasm::WasmFunction Function; + uint32_t FunctionSize = readVaruint32(Ptr); + const uint8_t *FunctionEnd = Ptr + FunctionSize; + + uint32_t NumLocalDecls = readVaruint32(Ptr); + Function.Locals.reserve(NumLocalDecls); + while (NumLocalDecls--) { + wasm::WasmLocalDecl Decl; + Decl.Count = readVaruint32(Ptr); + Decl.Type = readVarint7(Ptr); + Function.Locals.push_back(Decl); + } + + uint32_t BodySize = FunctionEnd - Ptr; + Function.Body = ArrayRef(Ptr, BodySize); + Ptr += BodySize; + assert(Ptr == FunctionEnd); + Functions.push_back(Function); + } + if (Ptr != End) + return make_error("Code section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseElemSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + ElemSegments.reserve(Count); + while (Count--) { + wasm::WasmElemSegment Segment; + Segment.TableIndex = readVaruint32(Ptr); + if (Segment.TableIndex != 0) { + return make_error("Invalid TableIndex", + object_error::parse_failed); + } + if (Error Err = readInitExpr(Segment.Offset, Ptr)) + return Err; + uint32_t NumElems = readVaruint32(Ptr); + while (NumElems--) { + Segment.Functions.push_back(readVaruint32(Ptr)); + } + ElemSegments.push_back(Segment); + } + if (Ptr != End) + return make_error("Elem section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + DataSegments.reserve(Count); + while (Count--) { + wasm::WasmDataSegment Segment; + Segment.Index = readVaruint32(Ptr); + if (Error Err = readInitExpr(Segment.Offset, Ptr)) + return Err; + uint32_t Size = readVaruint32(Ptr); + Segment.Content = ArrayRef(Ptr, Size); + Ptr += Size; + DataSegments.push_back(Segment); + } + if (Ptr != End) + return make_error("Data section ended prematurely", + object_error::parse_failed); return Error::success(); } @@ -117,37 +593,47 @@ 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_symbol_index; -} +void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.a++; } uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { - llvm_unreachable("not yet implemented"); - return 0; + const WasmSymbol &Sym = getWasmSymbol(Symb); + switch (Sym.Type) { + case WasmSymbol::SymbolType::FUNCTION_IMPORT: + return object::SymbolRef::SF_Undefined | SymbolRef::SF_Executable; + case WasmSymbol::SymbolType::FUNCTION_EXPORT: + return object::SymbolRef::SF_Global | SymbolRef::SF_Executable; + case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: + return object::SymbolRef::SF_Executable; + case WasmSymbol::SymbolType::GLOBAL_IMPORT: + return object::SymbolRef::SF_Undefined; + case WasmSymbol::SymbolType::GLOBAL_EXPORT: + return object::SymbolRef::SF_Global; + } } basic_symbol_iterator WasmObjectFile::symbol_begin() const { - return BasicSymbolRef(DataRefImpl(), this); + DataRefImpl Ref; + Ref.d.a = 0; + return BasicSymbolRef(Ref, this); } basic_symbol_iterator WasmObjectFile::symbol_end() const { - return BasicSymbolRef(DataRefImpl(), this); + DataRefImpl Ref; + Ref.d.a = Symbols.size(); + return BasicSymbolRef(Ref, this); +} + +const WasmSymbol &WasmObjectFile::getWasmSymbol(DataRefImpl Symb) const { + return Symbols[Symb.d.a]; } Expected WasmObjectFile::getSymbolName(DataRefImpl Symb) const { - llvm_unreachable("not yet implemented"); - return errorCodeToError(object_error::invalid_symbol_index); + const WasmSymbol &Sym = getWasmSymbol(Symb); + return Sym.Name; } Expected WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { - llvm_unreachable("not yet implemented"); - return errorCodeToError(object_error::invalid_symbol_index); + return (uint64_t)Symb.d.a; } uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { @@ -181,7 +667,7 @@ std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, StringRef &Res) const { - const wasm::WasmSection &S = Sections[Sec.d.a]; + const WasmSection &S = Sections[Sec.d.a]; #define ECase(X) \ case wasm::WASM_SEC_##X: \ Res = #X; \ @@ -211,13 +697,13 @@ uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; } uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const { - const wasm::WasmSection &S = Sections[Sec.d.a]; + const 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]; + const WasmSection &S = Sections[Sec.d.a]; // This will never fail since wasm sections can never be empty (user-sections // must have a name and non-user sections each have a defined structure). Res = StringRef(reinterpret_cast(S.Content.data()), @@ -234,13 +720,11 @@ } bool WasmObjectFile::isSectionText(DataRefImpl Sec) const { - const wasm::WasmSection &S = Sections[Sec.d.a]; - return S.Type == wasm::WASM_SEC_CODE; + return getWasmSection(Sec).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; + return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA; } bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; } @@ -249,31 +733,28 @@ 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); +relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const { + DataRefImpl RelocRef; + RelocRef.d.a = Ref.d.a; + RelocRef.d.b = 0; + return relocation_iterator(RelocationRef(RelocRef, this)); } -section_iterator WasmObjectFile::getRelocatedSection(DataRefImpl Sec) const { - llvm_unreachable("not yet implemented"); - SectionRef Ref; - return section_iterator(Ref); +relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const { + const WasmSection &Sec = getWasmSection(Ref); + DataRefImpl RelocRef; + RelocRef.d.a = Ref.d.a; + RelocRef.d.b = Sec.Relocations.size(); + return relocation_iterator(RelocationRef(RelocRef, this)); } void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { - llvm_unreachable("not yet implemented"); + Rel.d.b++; } -uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Rel) const { - llvm_unreachable("not yet implemented"); - return 0; +uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const { + const wasm::WasmRelocation &Rel = getWasmRelocation(Ref); + return Rel.Offset; } symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const { @@ -282,14 +763,28 @@ return symbol_iterator(Ref); } -uint64_t WasmObjectFile::getRelocationType(DataRefImpl Rel) const { - llvm_unreachable("not yet implemented"); - return 0; +uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const { + const wasm::WasmRelocation &Rel = getWasmRelocation(Ref); + return Rel.Type; } void WasmObjectFile::getRelocationTypeName( - DataRefImpl Rel, SmallVectorImpl &Result) const { - llvm_unreachable("not yet implemented"); + DataRefImpl Ref, SmallVectorImpl &Result) const { + const wasm::WasmRelocation& Rel = getWasmRelocation(Ref); + StringRef Res = "Unknown"; + +#define WASM_RELOC(name, value) \ + case wasm::name: \ + Res = #name; \ + break; + + switch (Rel.Type) { +#include "llvm/Support/WasmRelocs/WebAssembly.def" + } + +#undef WASM_RELOC + + Result.append(Res.begin(), Res.end()); } section_iterator WasmObjectFile::section_begin() const { @@ -316,7 +811,25 @@ bool WasmObjectFile::isRelocatableObject() const { return false; } -const wasm::WasmSection * +const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const { + assert(Ref.d.a >= 0 && Ref.d.a < Sections.size()); + return Sections[Ref.d.a]; +} + +const WasmSection & WasmObjectFile::getWasmSection(const SectionRef &Section) const { - return &Sections[Section.getRawDataRefImpl().d.a]; + return getWasmSection(Section.getRawDataRefImpl()); +} + +const wasm::WasmRelocation & +WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const { + return getWasmRelocation(Ref.getRawDataRefImpl()); +} + +const wasm::WasmRelocation & +WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const { + assert(Ref.d.a >= 0 && Ref.d.a < Sections.size()); + const WasmSection& Sec = Sections[Ref.d.a]; + assert(Ref.d.b >= 0 && Ref.d.b < Sec.Relocations.size()); + return Sec.Relocations[Ref.d.b]; } Index: llvm/trunk/lib/ObjectYAML/CMakeLists.txt =================================================================== --- llvm/trunk/lib/ObjectYAML/CMakeLists.txt +++ llvm/trunk/lib/ObjectYAML/CMakeLists.txt @@ -6,5 +6,6 @@ ELFYAML.cpp MachOYAML.cpp ObjectYAML.cpp + WasmYAML.cpp YAML.cpp ) Index: llvm/trunk/lib/ObjectYAML/ObjectYAML.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/ObjectYAML.cpp +++ llvm/trunk/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: llvm/trunk/lib/ObjectYAML/WasmYAML.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/WasmYAML.cpp +++ llvm/trunk/lib/ObjectYAML/WasmYAML.cpp @@ -0,0 +1,348 @@ +//===- 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/ObjectYAML/WasmYAML.h" +#include "llvm/Object/Wasm.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); + IO.mapOptional("Relocations", Section.Relocations); +} + +static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Name", Section.Name); + IO.mapRequired("Payload", Section.Payload); +} + +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::GlobalSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Globals", Section.Globals); +} + +static void sectionMapping(IO &IO, WasmYAML::ExportSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Exports", Section.Exports); +} + +static void sectionMapping(IO &IO, WasmYAML::StartSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("StartFunction", Section.StartFunction); +} + +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("Functions", Section.Functions); +} + +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_CUSTOM: + if (!IO.outputting()) + Section.reset(new WasmYAML::CustomSection()); + sectionMapping(IO, *cast(Section.get())); + break; + 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_GLOBAL: + if (!IO.outputting()) + Section.reset(new WasmYAML::GlobalSection()); + 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_START: + if (!IO.outputting()) + Section.reset(new WasmYAML::StartSection()); + 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; + default: + llvm_unreachable("Unknown section type"); + } +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::SectionType &Type) { +#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_SEC_##X); + ECase(CUSTOM); + 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.mapOptional("Index", Signature.Index); + 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::Function &Function) { + IO.mapRequired("Locals", Function.Locals); + IO.mapRequired("Body", Function.Body); +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::Relocation &Relocation) { + IO.mapRequired("Type", Relocation.Type); + IO.mapRequired("Index", Relocation.Index); + IO.mapRequired("Offset", Relocation.Offset); + IO.mapRequired("Addend", Relocation.Addend); +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::LocalDecl &LocalDecl) { + IO.mapRequired("Type", LocalDecl.Type); + IO.mapRequired("Count", LocalDecl.Count); +} + +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); + if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) { + IO.mapRequired("SigIndex", Import.SigIndex); + } else if (Import.Kind == wasm::WASM_EXTERNAL_GLOBAL) { + IO.mapRequired("GlobalType", Import.GlobalType); + IO.mapRequired("GlobalMutable", Import.GlobalMutable); + } else { + llvm_unreachable("unhandled import type"); + } +} + +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, + WasmYAML::Global &Global) { + IO.mapRequired("Type", Global.Type); + IO.mapRequired("Mutable", Global.Mutable); + IO.mapRequired("InitExpr", Global.InitExpr); +} + +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_OPCODE_I32_CONST: + IO.mapRequired("Value", Expr.Value.Int32); + break; + case wasm::WASM_OPCODE_I64_CONST: + IO.mapRequired("Value", Expr.Value.Int64); + break; + case wasm::WASM_OPCODE_F32_CONST: + IO.mapRequired("Value", Expr.Value.Float32); + break; + case wasm::WASM_OPCODE_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(ANYFUNC); + ECase(FUNC); + ECase(NORESULT); +#undef ECase +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::ExportKind &Kind) { +#define ECase(X) IO.enumCase(Kind, #X, wasm::WASM_EXTERNAL_##X); + ECase(FUNCTION); + 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_OPCODE_##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 +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::RelocType &Type) { +#define WASM_RELOC(name, value) IO.enumCase(Type, #name, wasm::name); +#include "llvm/Support/WasmRelocs/WebAssembly.def" +#undef WASM_RELOC +} + +} // end namespace yaml +} // end namespace llvm Index: llvm/trunk/test/ObjectYAML/wasm/code_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/code_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/code_section.yaml @@ -0,0 +1,72 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - ReturnType: F32 + ParamTypes: + - I32 + - ReturnType: NORESULT + ParamTypes: + - I32 + - I64 + - Type: FUNCTION + FunctionTypes: + - 0 + - 1 + - Type: CODE + Relocations: + - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB + Index: 0 + Offset: 0x00000006 + Addend: 0x00000000 + - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB + Index: 1 + Offset: 0x00000025 + Addend: 0x00000000 + Functions: + - Locals: + - Type: I32 + Count: 3 + Body: 418080808000210020002101200111808080800000210220020F0B + - Locals: + - Type: I32 + Count: 1 + Body: 108180808000210020000F0B +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: TYPE +# CHECK: Signatures: +# CHECK: - Index: 0 +# CHECK: ReturnType: F32 +# CHECK: ParamTypes: +# CHECK: - I32 +# CHECK: - Index: 1 +# CHECK: ReturnType: NORESULT +# CHECK: ParamTypes: +# CHECK: - I32 +# CHECK: - I64 +# CHECK: - Type: CODE +# CHECK: Relocations: +# CHECK: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +# CHECK: Index: 0 +# CHECK: Offset: 0x00000006 +# CHECK: Addend: 0x00000000 +# CHECK: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +# CHECK: Index: 1 +# CHECK: Offset: 0x00000025 +# CHECK: Addend: 0x00000000 +# CHECK: Functions: +# CHECK: - Locals: +# CHECK: - Type: I32 +# CHECK: Count: 3 +# CHECK: Body: 418080808000210020002101200111808080800000210220020F0B +# CHECK: - Locals: +# CHECK: - Type: I32 +# CHECK: Count: 1 +# CHECK: Body: 108180808000210020000F0B Index: llvm/trunk/test/ObjectYAML/wasm/custom_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/custom_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/custom_section.yaml @@ -0,0 +1,17 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: CUSTOM + Name: foo + Payload: 03666F6F0401020304 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: CUSTOM +# CHECK: Name: foo +# CHECK: Payload: 03666F6F0401020304 +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/data_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/data_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/data_section.yaml @@ -0,0 +1,28 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: MEMORY + Memories: + - Initial: 0x00000003 + - Type: DATA + Segments: + - Index: 0 + Offset: + Opcode: I32_CONST + Value: 4 + Content: '10001000' +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: DATA +# CHECK: Segments: +# CHECK: - Index: 0 +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 4 +# CHECK: Content: '10001000' +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/elem_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/elem_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/elem_section.yaml @@ -0,0 +1,42 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +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: 0x00000001 +# 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: llvm/trunk/test/ObjectYAML/wasm/export_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/export_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/export_section.yaml @@ -0,0 +1,27 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: EXPORT + Exports: + - Name: foo + Kind: FUNCTION + Index: 0 + - Name: bar + Kind: FUNCTION + Index: 1 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: EXPORT +# CHECK: Exports: +# CHECK: - Name: foo +# CHECK: Kind: FUNCTION +# CHECK: Index: 0 +# CHECK: - Name: bar +# CHECK: Kind: FUNCTION +# CHECK: Index: 1 +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/function_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/function_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/function_section.yaml @@ -0,0 +1,19 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: FUNCTION + FunctionTypes: + - 1 + - 0 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: FUNCTION +# CHECK: FunctionTypes: +# CHECK: - 1 +# CHECK: - 0 +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/global_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/global_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/global_section.yaml @@ -0,0 +1,25 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: GLOBAL + Globals: + - Type: I32 + Mutable: false + InitExpr: + Opcode: I64_CONST + Value: -5 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: GLOBAL +# CHECK: Globals: +# CHECK: - Type: I32 +# CHECK: Mutable: false +# CHECK: InitExpr: +# CHECK: Opcode: I64_CONST +# CHECK: Value: -5 +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/header.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/header.yaml +++ llvm/trunk/test/ObjectYAML/wasm/header.yaml @@ -0,0 +1,9 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/header_invalid_version.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/header_invalid_version.yaml +++ llvm/trunk/test/ObjectYAML/wasm/header_invalid_version.yaml @@ -0,0 +1,8 @@ +# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s + +--- !WASM +FileHeader: + Version: 0x00000002 +... + +# CHECK: Error: 'Invalid data was encountered while parsing the file' Index: llvm/trunk/test/ObjectYAML/wasm/import_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/import_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/import_section.yaml @@ -0,0 +1,41 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - ReturnType: I32 + ParamTypes: + - I32 + - Type: IMPORT + Imports: + - Module: foo + Field: bar + Kind: FUNCTION + SigIndex: 0 + - Module: fiz + Field: baz + Kind: GLOBAL + GlobalType: I32 + GlobalMutable: false + - Type: FUNCTION + FunctionTypes: + - 0 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: IMPORT +# CHECK: Imports: +# CHECK: - Module: foo +# CHECK: Field: bar +# CHECK: Kind: FUNCTION +# CHECK: SigIndex: 0 +# CHECK: - Module: fiz +# CHECK: Field: baz +# CHECK: Kind: GLOBAL +# CHECK: GlobalType: I32 +# CHECK: GlobalMutable: false +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/memory_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/memory_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/memory_section.yaml @@ -0,0 +1,23 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: MEMORY + Memories: + - Flags: 0x00000001 + Initial: 0x00000002 + Maximum: 0x000000FF + - Initial: 0x00000003 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: MEMORY +# CHECK: Memories: +# CHECK: - Flags: 0x00000001 +# CHECK: Initial: 0x00000002 +# CHECK: Maximum: 0x000000FF +# CHECK: - Initial: 0x00000003 +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/start_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/start_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/start_section.yaml @@ -0,0 +1,15 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: START + StartFunction: 1 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: START +# CHECK: StartFunction: 1 +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/table_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/table_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/table_section.yaml @@ -0,0 +1,25 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TABLE + Tables: + - ElemType: ANYFUNC + Limits: + Flags: 0x00000001 + Initial: 0x00000010 + Maximum: 0x00000011 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: TABLE +# CHECK: Tables: +# CHECK: - ElemType: ANYFUNC +# CHECK: Limits: +# CHECK: Flags: 0x00000001 +# CHECK: Initial: 0x00000010 +# CHECK: Maximum: 0x00000011 +# CHECK: ... Index: llvm/trunk/test/ObjectYAML/wasm/type_section.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/type_section.yaml +++ llvm/trunk/test/ObjectYAML/wasm/type_section.yaml @@ -0,0 +1,33 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - ReturnType: I32 + ParamTypes: + - F32 + - F32 + - ReturnType: I64 + ParamTypes: + - F64 + - F64 +... +# CHECK: --- !WASM +# CHECK: FileHeader: +# CHECK: Version: 0x00000001 +# CHECK: Sections: +# CHECK: - Type: TYPE +# CHECK: Signatures: +# CHECK: - Index: 0 +# CHECK: ReturnType: I32 +# CHECK: ParamTypes: +# CHECK: - F32 +# CHECK: - F32 +# CHECK: - Index: 1 +# CHECK: ReturnType: I64 +# CHECK: ParamTypes: +# CHECK: - F64 +# CHECK: - F64 +# CHECK: ... Index: llvm/trunk/test/tools/llvm-objdump/wasm.txt =================================================================== --- llvm/trunk/test/tools/llvm-objdump/wasm.txt +++ llvm/trunk/test/tools/llvm-objdump/wasm.txt @@ -9,7 +9,7 @@ # CHECK: 4 EXPORT 0000000e 0000000000000000 # CHECK: 5 ELEM 00000007 0000000000000000 # CHECK: 6 CODE 0000002a 0000000000000000 TEXT -# CHECK: 7 name 0000002c 0000000000000000 +# CHECK: 7 name 0000003c 0000000000000000 # RUN: llvm-objdump -p %p/Inputs/test.wasm | FileCheck %s -check-prefix CHECK-HEADER Index: llvm/trunk/test/tools/llvm-readobj/sections.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/sections.test +++ llvm/trunk/test/tools/llvm-readobj/sections.test @@ -531,7 +531,7 @@ WASM-NEXT: } WASM-NEXT: Section { WASM-NEXT: Type: CUSTOM (0x0) -WASM-NEXT: Size: 44 +WASM-NEXT: Size: 60 WASM-NEXT: Offset: 119 WASM-NEXT: Name: name WASM-NEXT: } Index: llvm/trunk/tools/llvm-readobj/WasmDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/WasmDumper.cpp +++ llvm/trunk/tools/llvm-readobj/WasmDumper.cpp @@ -55,14 +55,14 @@ void printSections() override { ListScope Group(W, "Sections"); for (const SectionRef &Section : Obj->sections()) { - const wasm::WasmSection *WasmSec = Obj->getWasmSection(Section); + const WasmSection &WasmSec = Obj->getWasmSection(Section); DictScope SectionD(W, "Section"); - const char *Type = wasmSectionTypeToString(WasmSec->Type); - W.printHex("Type", Type, WasmSec->Type); - W.printNumber("Size", (uint64_t)WasmSec->Content.size()); - W.printNumber("Offset", WasmSec->Offset); - if (WasmSec->Type == wasm::WASM_SEC_CUSTOM) { - W.printString("Name", WasmSec->Name); + const char *Type = wasmSectionTypeToString(WasmSec.Type); + W.printHex("Type", Type, WasmSec.Type); + W.printNumber("Size", (uint64_t)WasmSec.Content.size()); + W.printNumber("Offset", WasmSec.Offset); + if (WasmSec.Type == wasm::WASM_SEC_CUSTOM) { + W.printString("Name", WasmSec.Name); } } } Index: llvm/trunk/tools/obj2yaml/CMakeLists.txt =================================================================== --- llvm/trunk/tools/obj2yaml/CMakeLists.txt +++ llvm/trunk/tools/obj2yaml/CMakeLists.txt @@ -11,5 +11,6 @@ dwarf2yaml.cpp elf2yaml.cpp macho2yaml.cpp + wasm2yaml.cpp Error.cpp ) Index: llvm/trunk/tools/obj2yaml/obj2yaml.h =================================================================== --- llvm/trunk/tools/obj2yaml/obj2yaml.h +++ llvm/trunk/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,6 +24,8 @@ 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); // Forward decls for dwarf2yaml namespace llvm { Index: llvm/trunk/tools/obj2yaml/obj2yaml.cpp =================================================================== --- llvm/trunk/tools/obj2yaml/obj2yaml.cpp +++ llvm/trunk/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: llvm/trunk/tools/obj2yaml/wasm2yaml.cpp =================================================================== --- llvm/trunk/tools/obj2yaml/wasm2yaml.cpp +++ llvm/trunk/tools/obj2yaml/wasm2yaml.cpp @@ -0,0 +1,219 @@ +//===------ 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 object::WasmSection &WasmSec = Obj.getWasmSection(Sec); + std::unique_ptr S; + switch (WasmSec.Type) { + case wasm::WASM_SEC_CUSTOM: { + if (WasmSec.Name.startswith("reloc.")) { + // Relocations are attached the sections they apply to rather than + // being represented as a custom section in the YAML output. + continue; + } + auto CustomSec = make_unique(); + CustomSec->Name = WasmSec.Name; + CustomSec->Payload = yaml::BinaryRef(WasmSec.Content); + S = std::move(CustomSec); + break; + } + case wasm::WASM_SEC_TYPE: { + auto TypeSec = make_unique(); + uint32_t Index = 0; + for (const auto &FunctionSig : Obj.types()) { + WasmYAML::Signature Sig; + Sig.Index = Index++; + Sig.ReturnType = FunctionSig.ReturnType; + for (const auto &ParamType : FunctionSig.ParamTypes) + Sig.ParamTypes.push_back(ParamType); + TypeSec->Signatures.push_back(Sig); + } + S = std::move(TypeSec); + break; + } + case wasm::WASM_SEC_IMPORT: { + auto ImportSec = make_unique(); + for (auto &Import : Obj.imports()) { + WasmYAML::Import Ex; + Ex.Module = Import.Module; + Ex.Field = Import.Field; + Ex.Kind = Import.Kind; + if (Ex.Kind == wasm::WASM_EXTERNAL_FUNCTION) { + Ex.SigIndex = Import.SigIndex; + } else if (Ex.Kind == wasm::WASM_EXTERNAL_GLOBAL) { + Ex.GlobalType = Import.GlobalType; + Ex.GlobalMutable = Import.GlobalMutable; + } + ImportSec->Imports.push_back(Ex); + } + S = std::move(ImportSec); + break; + } + case wasm::WASM_SEC_FUNCTION: { + auto FuncSec = make_unique(); + for (const auto &Func : Obj.functionTypes()) { + FuncSec->FunctionTypes.push_back(Func); + } + S = std::move(FuncSec); + break; + } + case wasm::WASM_SEC_TABLE: { + auto TableSec = make_unique(); + 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 = std::move(TableSec); + break; + } + case wasm::WASM_SEC_MEMORY: { + auto MemorySec = make_unique(); + 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 = std::move(MemorySec); + break; + } + case wasm::WASM_SEC_GLOBAL: { + auto GlobalSec = make_unique(); + for (auto &Global : Obj.globals()) { + WasmYAML::Global G; + G.Type = Global.Type; + G.Mutable = Global.Mutable; + G.InitExpr = Global.InitExpr; + GlobalSec->Globals.push_back(G); + } + S = std::move(GlobalSec); + break; + } + case wasm::WASM_SEC_START: { + auto StartSec = make_unique(); + StartSec->StartFunction = Obj.startFunction(); + S = std::move(StartSec); + break; + } + case wasm::WASM_SEC_EXPORT: { + auto ExportSec = make_unique(); + 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 = std::move(ExportSec); + break; + } + case wasm::WASM_SEC_ELEM: { + auto ElemSec = make_unique(); + 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 = std::move(ElemSec); + break; + } + case wasm::WASM_SEC_CODE: { + auto CodeSec = make_unique(); + for (auto &Func : Obj.functions()) { + WasmYAML::Function Function; + for (auto &Local : Func.Locals) { + WasmYAML::LocalDecl LocalDecl; + LocalDecl.Type = Local.Type; + LocalDecl.Count = Local.Count; + Function.Locals.push_back(LocalDecl); + } + Function.Body = yaml::BinaryRef(Func.Body); + CodeSec->Functions.push_back(Function); + } + S = std::move(CodeSec); + break; + } + case wasm::WASM_SEC_DATA: { + auto DataSec = make_unique(); + 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 = std::move(DataSec); + break; + } + default: + llvm_unreachable("Unknown section type"); + break; + } + for (const wasm::WasmRelocation &Reloc: WasmSec.Relocations) { + WasmYAML::Relocation R; + R.Type = Reloc.Type; + R.Index = Reloc.Index; + R.Offset = Reloc.Offset; + R.Addend = Reloc.Addend; + S->Relocations.push_back(R); + } + Y->Sections.push_back(std::move(S)); + } + + return Y.release(); +} + +} // namespace + +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: llvm/trunk/tools/yaml2obj/CMakeLists.txt =================================================================== --- llvm/trunk/tools/yaml2obj/CMakeLists.txt +++ llvm/trunk/tools/yaml2obj/CMakeLists.txt @@ -10,4 +10,5 @@ yaml2coff.cpp yaml2elf.cpp yaml2macho.cpp + yaml2wasm.cpp ) Index: llvm/trunk/tools/yaml2obj/yaml2obj.h =================================================================== --- llvm/trunk/tools/yaml2obj/yaml2obj.h +++ llvm/trunk/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: llvm/trunk/tools/yaml2obj/yaml2obj.cpp =================================================================== --- llvm/trunk/tools/yaml2obj/yaml2obj.cpp +++ llvm/trunk/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; } Index: llvm/trunk/tools/yaml2obj/yaml2wasm.cpp =================================================================== --- llvm/trunk/tools/yaml2obj/yaml2wasm.cpp +++ llvm/trunk/tools/yaml2obj/yaml2wasm.cpp @@ -0,0 +1,377 @@ +//===- 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/Object/Wasm.h" +#include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/Support/Endian.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 writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec); + int writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section); + 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::GlobalSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section); + int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &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)]; + support::endian::write64le(Data, Value); + OS.write(Data, sizeof(Data)); + return 0; +} + +static int writeUint32(raw_ostream &OS, uint32_t Value) { + char Data[sizeof(Value)]; + support::endian::write32le(Data, Value); + 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_OPCODE_I32_CONST: + encodeSLEB128(InitExpr.Value.Int32, OS); + break; + case wasm::WASM_OPCODE_I64_CONST: + encodeSLEB128(InitExpr.Value.Int64, OS); + break; + case wasm::WASM_OPCODE_F32_CONST: + writeUint32(OS, InitExpr.Value.Float32); + break; + case wasm::WASM_OPCODE_F64_CONST: + writeUint64(OS, InitExpr.Value.Float64); + break; + case wasm::WASM_OPCODE_GET_GLOBAL: + encodeULEB128(InitExpr.Value.Global, OS); + break; + default: + errs() << "Unknown opcode in init_expr: " << InitExpr.Opcode; + return 1; + } + writeUint8(OS, wasm::WASM_OPCODE_END); + return 0; +} + +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::CustomSection &Section) { + // writeStringRef(Section.Name, OS); + // encodeULEB128(Section.Payload.binary_size(), OS); + Section.Payload.writeAsBinary(OS); + 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_NORESULT) { + encodeSLEB128(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_FUNCTION: + encodeULEB128(Import.SigIndex, OS); + break; + case wasm::WASM_EXTERNAL_GLOBAL: + encodeSLEB128(Import.GlobalType, OS); + writeUint8(OS, Import.GlobalMutable); + 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::StartSection &Section) { + encodeULEB128(Section.StartFunction, 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::GlobalSection &Section) { + encodeULEB128(Section.Globals.size(), OS); + for (auto &Global : Section.Globals) { + encodeSLEB128(Global.Type, OS); + writeUint8(OS, Global.Mutable); + writeInitExpr(Global.InitExpr, 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) { + encodeULEB128(Section.Functions.size(), OS); + for (auto &Func : Section.Functions) { + std::string OutString; + raw_string_ostream StringStream(OutString); + + encodeULEB128(Func.Locals.size(), StringStream); + for (auto &LocalDecl : Func.Locals) { + encodeULEB128(LocalDecl.Count, StringStream); + encodeSLEB128(LocalDecl.Type, StringStream); + } + + Func.Body.writeAsBinary(StringStream); + + // Write the section size followed by the content + StringStream.flush(); + encodeULEB128(OutString.size(), OS); + OS << OutString; + } + 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::writeRelocSection(raw_ostream &OS, + WasmYAML::Section &Sec) { + StringRef Name; + switch (Sec.Type) { + case wasm::WASM_SEC_CODE: + Name = "reloc.CODE"; + break; + case wasm::WASM_SEC_DATA: + Name = "reloc.DATA"; + break; + default: + llvm_unreachable("not yet implemented"); + return 1; + } + + writeStringRef(Name, OS); + encodeULEB128(Sec.Type, OS); + encodeULEB128(Sec.Relocations.size(), OS); + + for (auto Reloc: Sec.Relocations) { + encodeULEB128(Reloc.Type, OS); + encodeULEB128(Reloc.Offset, OS); + encodeULEB128(Reloc.Index, OS); + switch (Reloc.Type) { + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + encodeULEB128(Reloc.Addend, 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 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; + } + + // write reloc sections for any section that have relocations + for (const std::unique_ptr &Sec : Obj.Sections) { + if (Sec->Relocations.empty()) + continue; + + encodeULEB128(wasm::WASM_SEC_CUSTOM, OS); + std::string OutString; + raw_string_ostream StringStream(OutString); + writeRelocSection(StringStream, *Sec); + StringStream.flush(); + + encodeULEB128(OutString.size(), OS); + OS << OutString; + } + + return 0; +} + +int yaml2wasm(llvm::WasmYAML::Object &Doc, raw_ostream &Out) { + WasmWriter Writer(Doc); + + return Writer.writeWasm(Out); +}